이쿠의 슬기로운 개발생활

함께 성장하기 위한 보안 개발자 EverNote 내용 공유

클라우드/Kubernetes

74. Kubernetes NodePort Networking 분석 (kube-proxy : iptable mode)

이쿠우우 2021. 5. 6. 14:56
반응형

 

 

 

 

 

 

kubernetes NodePort Networking 분석

kube-proxy = iptable mode

CNI = Flannel

 


[kubernetes kube-proxy 관련 글 목록]

54. Kubernetes kube-proxy Mode 분석

70. Kubernetes kube-proxy IPVS Mode 설정

74. Kubernetes NodePort Networking 분석 (kube-proxy : iptable mode)

75. kubernetes LoadBalancer Networking 분석 (kube-proxy : iptable mode)

76. kubernetes NodePort Networking 분석 (kube-proxy : IPVS mode)

 


 

 

 

환경

 

[Master Node server]

OS = CentOS 7

리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64

docker version : 1.13.1

docker api verison : 1.26

 

 

[Worker Node server]

OS = CentOS 7

리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64

docker version : 1.13.1

api verison : 1.26

 

 

 

 

[kubernetes version]

1.19.2

 

 

 

[Test Pod 정보]

1개의 Pod 안에 tomcat 과 mysql container 2개를 생성

 

Pod는 worker node에 배포되어 있음

tomcat container port = 8080

mysql container port = 3306

 

 

 


 

 

글을 읽는데 필요한 기초 개념

 

 

 

Netfilter란?

Netfilter란 Network Packet Filtering Framework로 

Linux Kernel Space에 위치하여 

모든 오고 가는 패킷의 생명주기를 모니터링하고 통제 및 조작할 수 있는 기능을 제공함.

Netfilter는 Netfilter Hook Function을 제공하고 있음.

해당 function을 사용하여 Application을 개발하면 패킷 필터링을 할 수 있도록 해줌.

 

[Netfilter 5개 Hook point]

NF_IP_PRE_ROUTING: 외부에서 온 Packet이 Linux Kernel의 Network Stack을 통과하기 전에 발생하는 Hook이다. Packet을 Routing하기 전에 발생

NF_IP_LOCAL_IN: Packet이 Routing된 후 목적지가 자신일 경우, Packet을 Process에 전달하기 전에 발생

NF_IP_FORWARD: Packet이 Routing된 후 목적지가 자신이 아닐 경우, Packet을 다른 곳으로 Forwarding하는 경우 발생

NF_IP_LOCAL_OUT: Packet이 Process에서 나와 Network Stack을 통과하기 전 발생

NF_IP_POST_ROUTING: Packet이 Network Stack을 통과한 후 밖으로 보내기 전 발생

 

[Netfilter Framework를 사용하는 대표적인 Tool]

iptables, ip6tables, ebtables, arptables, ipset, nftables와 

추가로 IPVS 가 있음.

 

[Netfilter Tool 동작 원리]

Netfilter Framework를 사용해서 개발된 Tool의 동작원리를 좀 더 자세히 설명하자면

해당 Tool은 Netfilter 룰 셋 구축을 하는 역할을 수행하는 것임.

Netfilter Hook Function을 사용해서 Rule을 구축하고 패킷을 컨트롤 함.

즉 실질적으로 패킷 필터링은 Linux Kernel에 탑제된 Netfilter Function이 수행함.

참고 : 

https://ko.wikipedia.org/wiki/%EB%84%B7%ED%95%84%ED%84%B0

https://xenostudy.tistory.com/245

https://cognitive.tistory.com/99

https://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-4.html

 

 

iptables이란?

iptables는 Netfilter Framework를 이용하는 대표적인 Tool로

모든 오고 가는 패킷의 생명주기를 모니터링하고 통제 및 조작할 수 있음.

 

[iptables Chain (Rule)]

기본적으로 Iptables에는 세가지 chain이 있음.

모든 패킷은 INPUT, OUTPUT, FORWARD 이 세가지 chain중 하나를 통과하게 됨. 

컴퓨터로 들어가는 모든 패킷은 INPUT chain을 통과하고,

컴퓨터에서 나가는 모든 패킷은 OUTPUT chain을 통과함.

그리고 하나의 네트워크에서 다른 곳으로 보내는 모든 패킷은 FORWARD chain을 통과함.

iptables가 작동하는 방식은 이들 각각의 INPUT, OUTPUT, FORWARD chain에 어떠한 rule을 세우는 지에 따라 달라짐.

 

[iptables Tables]

iptables는 5가지 Table을 제공하고 있음.

 

1) fileter Table

packet을 drop할지 전달할지 결정

 

2) NAT table

Packet NAT(Network Address Translation)을 위한 table. packet의 source/destination address를 변경

 

3) Mangle Table

Packet의 IP header를 바꿈. Packet의 TTL 변경, Marking하여

다른 iptables의 Table이나 Network tool에서 Packet을 구분 할 수 있도록 함

 

4) Raw Table

Netfilter Framework는 Hook 뿐만 아니라 Connection Tracking 기능을 제공.

이전에 도착한 Packet들을 바탕으로 방금 도착한 Packet의 Connection을 추적함.

Raw Table은 특정 Packet이 Connection Tracking에서 제외되도록 설정함.

 

5) Security Table

SELinux에서 Packet을 어떻게 처리할지 결정하기 위한 Table

 

 

Netfilter, iptables와 tcpdump 우선순위

Wire -> NIC -> tcpdump -> netfilter/iptables

iptables -> tcpdump -> NIC -> Wire

 

 

Chain 종류

[PREROUTING (DNAT)]

패킷의 도착지(deatination) 주소를 변경한다. D(estination)NAT

 

[POSTROUTING (SNAT 또는 masquerade)]

패킷의 출발지(source) 주소를 변경한다. S(ource)NAT

 

[OUTPUT]

호스트에서 밖으로 흐르는 패킷의 도착지(destination) 주소를 변경한다. 

 

[INPUT]

밖에서 호스트로 흐르는 패킷의 출발지(source) 주소를 변경한다. 

 

 

NAT

모든 IP 패킷에는 Source IP와 Destination IP가 있다.

NAT란, Network Address Translation, 즉 IP 패킷 헤더의 IP 주소를 변경하는 기능 혹은 절차를 뜻한다. 1:1 NAT 혹은 1:다 NAT가 있다.

PREROUTING : DNAT을 이용하여 패킷이 생길 때 사용됨.

POSTROUTING : SNAT을 이용하여 패킷이 나갈 때 사용됨.

 

 

SNAT  개념

내부 -> 외부

패킷의 Source 주소를 변경하는 것으로  Source NAT, SNAT, 혹은 IP 마스커레이드라고 한다.

인터넷으로 나가는 패킷의 Source IP를 G/W의 Public IP로 바꾼다.

 

 

DNAT 개념

외부 -> 내부

Destination IP 주소를 변경하여 내부에 접근할 수 있도록 패킷을 변경한다.

대표적인 것은 Load Balancer이다.

 

 

lsof 명령

리눅스와 유닉스는 추상화된 파일 시스템(VFS - Virtual File System)을 사용함으로

일반 파일, 디렉터리, 네트워크 소켓, 라이브러리, 심볼릭 링크 등도 모두 파일로 처리되며

lsof 에서 상세한 정보를 확인할 수 있음.

특정 port를 사용하는 프로세스 정보를 확인하기 위해서는 i 옵션을 사용하면 됨.

 

 

 

 


 

 

 

 

tcpdump 

External -> Master Node IP:NodePort-> Container  

 

 

 

 

Pod는 Worker Node에 배포되어있는 상태.

 

 

 

 

예제 환경

 

Tomcat Pod IP  = 10.244.1.117

Service Object Type = NodePort 30001

Tomcat Pod 배포 Node = Worker Node

Tomcat Pod Port = 8080

 

Master Node IP = 10.0.2.15

Worker Node IP = 10.0.2.4

 

이외의 정보는 문서 상단위 "환경"에서 설명한 정보와 동일

 

external 환경에서 

curl [Master Node IP]:NodePort

명령으로 Pod에 접근

 

 

Routing 요약

 

 

 

 

 

1. Master Node : enp0s3 

 

 

VirtualBox의 경우 : enp0s3

VMware 의 경우 : ens192

에 해당하는 인터페이스임,

 

[명령어]

tcpdump -i enp0s3 -ne tcp  port 30001 -vv -c 10

 

 

[MAC 정보]
출발지 : 52:54:00:12:35:00  (virtualbox router mac)
도착지 : 08:00:27:02:06:7c  (Master Node의 enp0s3 인터페이스 MAC주소)



[IP주소 정보]
출발지 : 192.168.56.1  (external에서 접근한 ip주소)
도착지 : 10.0.2.15 (Master Node의 IP주소)


[Port]
출발지 : 랜덤한 Port 번호
도착지 : pago-services1 (설정된 NodePort 번호)

( 192.168.56.1, 52:54:00:12:35:00 )

external에서 접근한 ip주소와

vritualBox 의 router mac주소

 

test환경은 virtualbox 환경이라 해당 ip로 접근함.

virtualbox 에서 포트포워딩 설정되어있음.

 

 

[pago-services1]

pago-services1는 30001번 port를 뜻함

30002번 port는  pago-services2라고함

/etc/services 명령을 보면 port번호와 name 맵핑을 확인할 수 있음

참고 : https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=3&page=53

 

 

패킷 흐름 분석

해당 인터페이스의 내용은 virtualBox 포트포워딩에 관한 내용.

모든 Kubernetes Node의 해당 인터페이스에서 

NodePort로 설정된 Port 를 감시하고 있으면

external network에서 nodePort를 통해 접근한다는 것을 확인 가능.

 

 

 

 

 

 

 

2. Master Node : kube-proxy

 

 

패킷을 따라가다 보면 중간에 패킷이 갑자기 다른 패킷으로 변경되는데 

이를 찾다보니 패킷이 kube-proxy가 연관이 있다는것을 알아냄

 

lsof 명령으로 30001 port를 사용하는 프로세스를 확인

 

[명령어]

lsof -i:30001

 

[netstat 명령]

netstat -nap | grep kube-proxy

 

 

[확인 결과]

kube-proxy pod가 모든 NodePort 수신하고 있음.

NodePort Type의 service object를 생성하면

kube-proxy가 모든 NodePort를 포트 예약하고 

다른 프로세스가 사용할 수 없도록 함. 

즉 test환경에서는

30001대 port를 kube-proxy가 점유하고 있음.

 

 

2.1. kube-proxy Mode 확인

 

Kube-proxy는 user space, iptables, ipvs 와 같은 mode로 동작할 수 있음으로

어떤 mode로 동작하는지 확인해야함.

 

[kube-proxy mode 확인 명령어]

kubectl logs -f [베포되어있는 kube-proxy pod 이름] -n kube-system

예) kubectl logs -f pod/kube-proxy-8fc7f -n kube-system

 

[kube-porxy mode 확인 결과]

아래 log 내용을 보아

default mode의 경우 : iptables

test 환경의 kube-proxy의 경우 default 설정을 사용했음으로 

iptables mode로 동작함.

 

 

[kube-proxy iptable Mode란?]

kube-proxy의 iptables Mode는 

iptables를 사용해서 Chain Rule이라는 규칙을 지정한 뒤

패킷이 Chain Rule에 매칭되면 지정한 규칙에 따라서 

패킷을 포워딩 함.

 

 

 

2.2. kube-proxy Netfiler (iptables) 도식화

 

 

 

 

 

2.3. kube-proxy iptables 분석 

 

2.3.1. 모든 패킷은 kube-proxy가 생성한 Netfilter Chain를 거쳐야함.

 

[명령어]

iptables -t nat -L OUTPUT

 

[명령어]

iptables -t nat -L PREROUTING | column -t

 

[분석]

kube-proxy에 의해 생성된 KUBE-SERVICES Chain을 확인할 수 있음.

 

참고) PREROUTING Chain은 raw와 mangle에도 존재하는데 kube-proxy는 nat에만 규칙을 생성함.

 

 

[패킷 흐름]

enp0s3 인터페이스로 전달된 모든 패킷은

Host의 Network Namespace로 전달되고

해당 패킷은 OUTPUT Rule 중 

src = anywhere

dst = anywhere 

Rule에 매칭되어 

kube-proxy가 생성한 KUBE-SERVICES Chain Rule에 적용되기 시작함.

 

 

 

2.3.2. KUBE-SERVICES Chain의 Rule을 확인

 

[명령어]

iptables -t nat -L KUBE-SERVICES -n  | column -t

 

[분석]

현재 kubernetes cluster에 생성되어있는 모든 Service Object의 정보를 확인할 수 있음.

Service Object Type 중 ClusterIP의 경우는 해당 Rule에서 바로

할당된 ClusterIP를 확인할 수 있음.

예제에서 default/iksoon-tomcat-service 의

destination ip가 10.97.155.249 인것을 확인 할 수 있는데 

실제로 service object를 확인해보면

다음과 같이 10.97.155.249로 IP가 동일한 것을 확인할 수 있음

ClusterIP를 확인했지만

해당 Service는 NodePort Type임으로 

NodePort 정보도 확인해야함

그러기 위해서 위에서 확인한 

KUBE-NODEPORTS Rule을 확인함.

 

 

[패킷 흐름]

패킷은 PREROUTING Chain Rule에 의해 

KUBE-SERVICES Chain Rule의 영향을 받게됨.

KUBE-SVC-????에 설정된 src, dst, dpt 와 

패킷 정보과 일치한다면 해당 KUBE-SVC-??? Chain Rule이 적용되지만

예제에서는 

[MAC 정보]
출발지 : 52:54:00:12:35:00  (Master Node 의 virbr0 인터페이스 MAC주소)
도착지 : 08:00:27:02:06:7c  (Master Node 의 enp0s3 인터페이스 MAC주소)



[IP주소 정보]
출발지 : 192.168.56.1  (external에서 접근한 ip주소)
도착지 : 10.0.2.15 (Master Node의 IP주소)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : pago-services1 (설정된 NodePort 번호)

위와같이 도착지 IP가 Master Node 자신의 IP이기 때문에

KUBE-NODEPORTS로 전달됨.

 

 

 

 

 

2.3.3. KUBE-NODEPORTS Chain의 Rule을 확인

 

[명령어]

iptables -t nat -L KUBE-NODEPORTS -n  | column -t

 

[분석]

KUBE-NODEPORTS Rule을 확인해보면

Kubernetes Cluster에 있는 모든 NodePort정보를 확인할 수 있음

예제 환경에서는 NodePort가 한개 생성되어있어서 위와같이 1개를 확인할 수 있음

상위 정보의 주석부분( /*  default/iksoon-tomcat-service  */)을 통해 

namespace = default

service object name =  iksoon-tomcat-service

정보를 확인 할 수 있고

dpt:30001 정보를 통해

NodePort = 30001 로 설정되었음을 알 수 있음.

 

[KUBE-MARK-MASQ]

KUBE-MARK-MASQ는 iptables의 MASQUERADE (SNAT)옵션에 해당함.

external network에서 kubernetes cluster에 생성된 service obejct로 접근 할 시

접근하는 TCP 패킷에 Netfilter Mart를 추가하는 역할을 함. 

KUBE-NODEPORTS의 KUBE-MARK-MASQ는

Netfilter Mark로 패킷의 Source IP 주소를 Node(Host) IP주소로 변경함

[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f (Master Node flannel.1인터페이스 MAC주소로 변경됨)
도착지 : 08:00:27:02:06:7c  (Master Node의 enp0s3 인터페이스 MAC주소)



[IP주소 정보]
출발지 : 10.244.0.0 (external에서 접근한 ip주소를 Host IP주소로 변경함. master node의 flannel.1 인터페이스 ip주소가 됨.)   
도착지 : 10.0.2.15 (Master Node의 IP주소)


[Port]
출발지 : 랜덤한 Port 번호
도착지 : pago-services1 (설정된 NodePort 번호)

해당 KUBE-MARK-MASQ을 통과한다는 증거는 아래와 같음

[명령어]

watch -n 1 iptables -t nat -L KUBE-NODEPORTS -nv

패킷이 KUBE-MARK-MASQ와 KUBE-SVC가 동시에 올라감.

 

 

 

[패킷 흐름]

예제 환경의 패킷 중 도착지 Port 번호를 확인함.

[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f    (Master Node flannel.1인터페이스 MAC주소)
도착지 : 08:00:27:02:06:7c  (Master Node의 enp0s3 인터페이스 MAC주소)



[IP주소 정보]
출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip주소)
도착지 : 10.0.2.15 (Master Node의 IP주소)


[Port]
출발지 : 랜덤한 Port 번호
도착지 : pago-services1 (설정된 NodePort 번호)

위와같이 도착지 Port번호가 pago-services1 즉 30001 로

KUBE-NODEPORTS 정보 중 dpt가 30001인

KUBE-SVC-TV7YSFNMBFSIUZMD 와 매칭이 됨.

 

 

2.3.4. KUBE-SVC-TV7YSFNMBFSIUZMD Chain의 Rule을 확인

 

[명령어]

iptables -t nat -L KUBE-SVC-TV7YSFNMBFSIUZMD -n  | column -t

 

[분석]

KUBE-SVC-XXX Table에서는

iptables의 statistic 기능을 이용하여 

요청 Packet은 Service를 구성하는 Pod들로 랜덤하고 균등하게 

Load Balancing하는 역할을 수행함.

예제 환경에서 해당 service object에 매칭 되어있는 pod가 1개 임으로

위와같이 1개의 KUBE-SEP가 조회 되지만

Service Object에 다수의 pod가 매칭되는 환경이라면

다수의 KUBE-SEP가 생성되어 있고

해당 SEP 중에 한곳으로 Load Balancing 됨.

예시)

deployment replicaset 설정이 3인 경우 

service obejct 에 3개의 pod가 매칭되어 

아래와 같이 3개의 KUBE-SEP가 조회됨.

 

 

[패킷 흐름]

예제 환경에서는 KUBE-SEP가 

KUBE-SEP-72KKHLS3BKN7AUK6 하나 있음으로

KUBE-SEP-72KKHLS3BKN7AUK6로 전달됨.

 

 

2.3.5. KUBE-SEP-72KKHLS3BKN7AUK6 Chain의 Rule을 확인

 

[명령어]

iptables -t nat -L KUBE-SEP-72KKHLS3BKN7AUK6  -n  | column -t

 

[분석]

KUBE-MARK-MASQ와 DNAT가 존재함.

 

KUBE-SEP-XXX Table에서 요청 Packet은 

Pod의 IP 및 Service에서 설정한 Port로 DNAT를 수행한다. 

Pod의 IP로 DNAT된 요청 Packet은 CNI Plugin을 통해 

구축된 Container Network를 통해서 해당 Pod에게 전달됨.

즉 Master Node의 cni0로 아래의 패킷을 만들어서 보냄

 

 

[KUBE-MARK-MASQ]

Netfilter Mark로 패킷의 Source IP 주소를 Node(Host) IP주소로 변경함

상위 KUBE-NODEPORTS 과정에서 TCP 패킷의 Source IP주소를 변경했고

여기서는 prot가 all로 설정되어 있는데

NodePort로 접근한 경우 해당 KUBE-MARK-MASQ은 통과하지 않는것을 확인함.

위와같이 주장하는 근거는 아래와 같음

[명령어]

watch -n 1 iptables -t nat -L KUBE-SEP-72KKHLS3BKN7AUK6 -nv

위와같이 KUBE-MARK-MASQ는 카운팅되지 않고 DNAT만 카운팅됨

 

해당 KUBE-MARK-MASQ은 어떤 역할을 하는것인지

추후 리서치가 필요함.

 

 

[DNAT]

최종적으로 목표로 했던 Pod IP주소와 Port번호로 패킷을 변경해줌.

즉 kube-proxy가 생성한 Netfilter Chain을 통과한 결과물임.

도착지 Mac의 경우는 Host의 ARP Table에 따라서 입력됨.

[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f    (Master Node flannel.1인터페이스 MAC주소)
도착지 : 08:00:27:02:06:7c  (Master Node의 enp0s3 인터페이스 MAC주소)

 


[IP주소 정보]
출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip주소)
도착지 : 10.244.1.117 (목적지 Pod의 IP주소로 변경)


[Port]
출발지 : 랜덤한 Port 번호
도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경)

 

 

 

 

2.4. 패킷 흐름 분석

enp0s3 인터페이스로 전달된 모든 패킷은

kube-proxy가 설정한 iptables Chain Rule을 통과해야함.

iptables를 통과하면서 Marking 된 패킷은 아래와 같이

출발지 정보는 Node(Host)의 정보로 변경되고

도착지 정보는 Pod의 정보로 변경됨.

[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f    (Master Node flannel.1인터페이스 MAC주소)
도착지 : 08:00:27:02:06:7c  (Master Node의 enp0s3 인터페이스 MAC주소)



[IP주소 정보]
출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip주소)
도착지 : 10.244.1.117 (목적지 Pod의 IP주소로 변경)


[Port]
출발지 : 랜덤한 Port 번호
도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경)

해당 패킷은 다음 인터페이스인 flannel.1으로 전달됨.

 

 

 

 

 

3. Master Node : flannel.1

 

 

[명령어]

tcpdump -i flannel.1   -ne tcp  -vv -c 10

 

[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f  (Master Node flannel.1인터페이스 MAC주소)
도착지 : 12:38:cf:16:75:1b  (Worker Node의 flannel.1인터페이스 MAC주소)

 
[IP주소 정보]
출발지 : 10.244.0.0  (master node의 flannel.1 인터페이스 ip 주소)
도착지 : 10.244.1.117 (목적지 Pod의 IP주소)


[Port]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)

 

 

참고) webcache = 8080을 의미함

 

 

 

패킷 흐름 분석

2. kube-proxy에서 설명했던 것 처럼

iptables chain을 통과한 상태의 패킷과 

동일한 패킷을 확인할 수 있음

아직 이해하지 못함 부분으로는 

도착지 MAC주소가 Worker Node의 flannel.1 인터페이스 주소가 들어가 있는데

해당 부분은 DNAT 과정에서 ARP Tables 정보를 확인하고 

도착지 Mac 주소가 갱신됨.

일단 flannel.1 인터페이스에서 위와같은 패킷을 확인함.

이제 해당 패킷이 다음으로 어떤 인터페이스로 가는지 확인해야함.

 

 

 

 

 

 

4. Master Node : flannel.1의 ARP Table확인

 

해당 패킷이 다음으로 어떤 인터페이스로 가는지 확인하기 위해

Master Node의 ARP Table을 확인.

 

CentOS의 경우 arp 명령으로 확인할 수 있지만 아래와 같은 방법으로도 확인할 수 있음

 

[명령어]

kubectl get pod -o wide -n kube-system

 

명령으로 Master Node에서 동작 중인 Flannel Pod를 확인

 

[명령어]

kubectl -it exec kube-flannel-ds-ghksg -n kube-system  -- arp -a

 

명령으로 Master Node Flannel 의 ARP Table확인

 

확인 결과

[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f  (Master Node의 flannel.1인터페이스 MAC주소)
도착지 : 12:38:cf:16:75:1b  (Worker Node의 flannel.1인터페이스 MAC주소)



[IP주소 정보]
출발지 : 10.244.0.0  (master node의 flannel.1 인터페이스 ip 주소)
도착지 : 10.244.1.117 (목적지 Pod의 IP주소)


[Port]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)

이전에 통신을 했었음으로 ARP Table에 해당 MAC주소가 학습되어있음.

그래서 Master Node의 cni0 인터페이스로 가지 않고 

ARP Table내용대로 enp0s3 인터페이스로 감.

 

Flannel.1 인터페이스는 VXLAN에서 VTEP과 동일한 역할을 수행하는데 

그 작업으로 받은 패킷을 VXLAN 패킷으로 만들기 위해 

패킷을 UDP를 사용하여 실제 네트워크를 통해 전송하기 위해 L3패킷으로 encapsulated (캡슐화)함.

UDP Header에는 출발지와 목적지 정보가 저장되어있고 Port는 8285 혹은 8472로 설정되어있음.

다음으로 enp0s3 인터페이스를 확인해야함.

 

 

 

 

 

5. Master Node : enp0s3 

 

 

[명령어]

tcpdump -i enp0s3 -ne udp -vv -c 10

 

Port 참고) otv = 8472

 

 

패킷 흐름 분석

UDP Header에는 출발지와 목적지 정보가 저장되어있고 Port는 8472로 설정되어 있음.

확인 결과 아래와 같은 encapsulated (캡슐화) 정보를 확인할 수 있음.

Outer-packet
[MAC 정보]
출발지 : 08:00:27:02:06:7c (Master Node의 enp0s3 인터페이스의 MAC)
도착지 : 08:00:27:7c:5c:53 (Worker Node 2의 enp0s3 인터페이스의 MAC)

[IP주소 정보]
출발지 : 10.0.2.15 (Master Node의 IP)
도착지 : 10.0.2.4  (Worker Node의 IP)


[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : 8472




VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f  (Master Node의 flannel.1 인터페이스의 MAC)
도착지 : 12:38:cf:16:75:1b  (Worker Node의 flannel.1 인터페이스의 MAC)


[IP주소 정보]
출발지 : 10.244.0.0      (Master Node의 flannel.1 인터페이스의 IP주소)
도착지 : 10.244.1.117  (목적지 Pod의 IP)


[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)

 

다음으로는 Worker Node에서 패킷을 확인해야함.

 

 

 

 

 

 

6. Worker Node : enp0s3 

 

 

Master Node의 enp0s3 인터페이스가 패킷을 Worker Node로 보내기 위해

먼저 패킷을 enp0s3과 연결되어 있는 default Router로 전송함.

그리고 default Router가 전달한 패킷을

Worker Node에서 확인가능

 

[명령어]

tcpdump -i enp0s3 -ne udp -vv -c 10

 

패킷 흐름 분석

Master Node의 enp0s3에서 확인한 결과과 같은 encapsulated (캡슐화) 패킷을 확인할 수 있음.

Outer-packet
[MAC 정보]
출발지 : 08:00:27:02:06:7c (Master Node의 enp0s3 인터페이스의 MAC)
도착지 : 08:00:27:7c:5c:53 (Worker Node 2의 enp0s3 인터페이스의 MAC)


[IP주소 정보]
출발지 : 10.0.2.15 (Master Node의 IP)
도착지 : 10.0.2.4  (Worker Node의 IP)


[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : 8472




VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f  (Master Node의 flannel.1 인터페이스의 MAC)
도착지 : 12:38:cf:16:75:1b  (Worker Node의 flannel.1 인터페이스의 MAC)


[IP주소 정보]
출발지 : 10.244.0.0      (Master Node의 flannel.1 인터페이스의 IP주소)
도착지 : 10.244.1.117  (목적지 Pod의 IP)


[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)

해당 패킷은 flannel.1 인터페이스에서 캡슐화를 해제할 수 있음.

 

 

 

7. Worker Node : flannel.1

 

 

iptables를 통과하지만 Chain Rule에 해당하지 않기 때문에

그대로 통과함

 

[명령어]

tcpdump -i flannel.1   -ne tcp  -vv -c 10

 

패킷 흐름 분석

encapsulated (캡슐화)를 해제한 패킷을 확인할 수 있음.

VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : 2e:bf:78:0e:53:8f  (Master Node의 flannel.1 인터페이스의 MAC)
도착지 : 12:38:cf:16:75:1b  (Worker Node의 flannel.1 인터페이스의 MAC)


[IP주소 정보]
출발지 : 10.244.0.0      (Master Node의 flannel.1 인터페이스의 IP주소)
도착지 : 10.244.1.117  (목적지 Pod의 IP)


[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)

 

Worker Node의 ARP Table에 

해당 도착지 정보가 있음으로 다음 인터페이스로 cni0로

패킷이 전달됨.

 

 

8. Worker Node : cni0

 

 

[명령어]

tcpdump -i cni0 -ne tcp and dst 10.244.1.117 -vv -c 10

 

패킷 흐름 분석

encapsulated (캡슐화)를 해제한 패킷을 확인할 수 있음.

MAC 주소만 변경 되어 있음

VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : c2:c8:57:67:d6:27  (Worker Node의cni0 인터페이스의 MAC)
도착지 : ca:22:4b:8f:5b:79  


[IP주소 정보]
출발지 : 10.244.0.0      (Master Node의 flannel.1 인터페이스의 IP주소)
도착지 : 10.244.1.117  (목적지 Pod의 IP)


[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)

 

 

[도착지 MAC 정보 ca:22:4b:8f:5b:79]

kubectl -it exec kube-flannel-ds-5qrzc -n kube-system  -- arp -a | grep 10.244.1.117

명령으로 ARP Table을 확인해보면 아래와 같은 정보를 확인할 수 있고

도착지 MAC주소 또한 

조회된 MAC주소를 가지고 있음.

 

 

 

9. Worker Node : vethbf625505 (목적지 Pod)

 

 

vethbf625505 인터페이스가 

목적지인 tomcat pod에 해당하는 인터페이스임.

Pod에 해당하는 veth 장비 찾기 참고 : Pod의 veth (Virtual Ethernet Interface) 장치 찾기

 

[명령어]

tcpdump -i vethbf625505  -ne tcp  -vv -c 10

 

그리고 Pod의 tomcat container로 들어가서 

tcpdump를 설치한 후 패킷을 확인해봄.

 

[명령어]

tcpdump -ne tcp  -vv -c 10

 

 

 

패킷 흐름 분석

vethbf625505 인터페이스에 확인한 정보와 Pod의 tomcat container안에서 확인해본 결과가 동일함.

cni0에서 확인했던 패킷을 Pod내부의 tomcat container가 받는것을 확인할 수 있음.

VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : c2:c8:57:67:d6:27  (Worker Node의cni0 인터페이스의 MAC)
도착지 : ca:22:4b:8f:5b:79  


[IP주소 정보]
출발지 : 10.244.0.0      (Master Node의 flannel.1 인터페이스의 IP주소)
도착지 : 10.244.1.117  (목적지 Pod의 IP)


[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : 8080 (목적지 Pod의 tomcat container port)

 

 

 

 

분석 완료..

 

 

 

 

 

 


 

 

 

 

 

 

 

tcpdump 

External -> Worker Node IP:NodePort-> Container  

 

 

Pod는 Worker Node에 배포되어있는 상태.

 

특징 : flannel.1 인터페이스를 거치지 않음

 

 

 

 

 

 

 

 


 

 

 

 

 

Pod 통신 시 netstat 명령 log 확인

 

한개의 Pod안에 tomcat, mysql 2개의 container 존재함.

Pod IP = 10.244.1.117

NodePort = 30001:8080

 

 

Container1 -> Container2  [localhost 주소로 통신]

 

[사용 명령어]

kubectl exec -it [pod이름] -c [mysql container 이름] -- /bin/bash

curl localhost:8080

 

Pod 내부에 있는 

mysql container에서 

tomcat container로 

localhost:8080 통신

 

[결과]

로컬 = tcp6 loopback ip : 랜덤한 Port번호

외부 = tcp6 loopback ip : 8080

 

 

Container1 -> Container2  [IP 주소로 통신]

 

[사용 명령어]

kubectl exec -it [pod이름] -c [mysql container 이름] -- /bin/bash

curl 10.244.1.117:8080

 

mysql container에서 

tomcat container로 

[pod ip주소]:8080 통신

 

[결과]

로컬 = tcp Pod IP : 랜덤한 Port번호

외부 = Pod IP : 8080

 

 

External -> Master Node ip: NodePort-> Container

 

[사용 명령어]

curl [master node ip]:30001

 

(Pod는 worker node에 배포되어 있음)

master node ip : nodePort 주소를 통해서 

pod ip의 8080 port로 접근

 

 

[결과]

로컬 = Pod IP : 8080

외부 = worker node의 cni0 인터페이스 : 랜덤 port 번호

 

 

 

External -> Worker Node ip: NodePort-> Container

 

[사용 명령어]

curl [worker node ip]:30001

 

(Pod는 worker node에 배포되어 있음)

worker node ip : nodePort 주소를 통해서 

pod ip의 8080 port로 접근

 

[결과]

netstat 결과가 생성되지 않음

 

 

 

 

 

 

 


제 글을 복사할 시 출처를 명시해주세요.
글에 오타, 오류가 있다면 댓글로 알려주세요! 바로 수정하겠습니다!


 

 

 

 

 

 

 

iptable 모니터링 명령어

 

watch -n1 iptables -vnL

watch -n 1 iptables -t nat -L PREROUTING -nv

watch -n 1 iptables -t nat -L KUBE-SERVICES -nv

watch -n 1 iptables -t nat -L KUBE-NODEPORTS -nv

watch -n 1 iptables -t nat -L KUBE-SEP-72KKHLS3BKN7AUK6 -nv

 

일정시간이 지난 후 카운팅이됨.

 

 

 

 

 

 

 


 

 

참고

 

[kube-proxy iptable]

https://rtfm.co.ua/en/kubernetes-service-load-balancing-kube-proxy-and-iptables/

https://kubernetes.io/docs/concepts/services-networking/service/

https://sktelecom-oslab.github.io/Virtualization-Software-Lab/ExposeService/

https://arthurchiao.art/blog/cracking-k8s-node-proxy/

https://www.system-rescue.org/networking/Load-balancing-using-iptables-with-connmark/

 

[LoadBalancer Type의 경우 kubernetes Routing 참고]

https://www.stackrox.com/post/2020/01/kubernetes-networking-demystified/

 

[kubernetes routing]

https://medium.com/finda-tech/kubernetes-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%A0%95%EB%A6%AC-fccd4fd0ae6

https://ronaknathani.com/blog/2020/07/kubernetes-nodeport-and-iptables-rules/

 

[kube-proxy mode 설명]

https://ssup2.github.io/theory_analysis/Kubernetes_Service_Proxy/ 

https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

 

[iptable 개념 : KUBE-MARK-MASQ 의 MASQUERADE 패킷]

http://blog.naver.com/PostView.nhn?blogId=alice_k106&logNo=221305928714&parentCategoryNo=&categoryNo=22&viewDate=&isShowPopularPosts=false&from=postView

 

[tcpdump]

https://m.blog.naver.com/PostView.nhn?blogId=hanajava&logNo=221004225619&proxyReferer=https:%2F%2Fwww.google.com%2F

 

 

반응형