Kubernetes/네트워크

Kubernetes NodePort Networking 분석 (kube-proxy : iptable mode) New version

이쿠우우 2024. 7. 15. 20:25
반응형

kubernetes NodePort Networking 분석 New version

kube-proxy = iptable mode
CNI = Flannel

목적

예전 글에서도 동일 환경으로 리서치를 한 글이 있지만
iptables netfilter chain 부분을 더 자세하게 리서치하기 위해 다시 한번 정리를 진행해봄.
3년전에 작성한 글이긴 한데... 
추가한 내용이 있어서 공유하면 좋을 것 같아서 작성함

 

 

환경

 
[Master Node server]
OS = CentOS 7
리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64
containerd version = 1.4.10

 

 
 
[Worker Node server]
OS = CentOS 7
리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64
containerd version = 1.4.10

 

 
[kubernetes version]
1.22.2

 

[CNI : flannel version]
quay.io/coreos/flannel:v0.14.0
 
 
[Test Pod 정보]
사용한 yaml파일
apiVersion: apps/v1
kind: Deployment
metadata:
  name: iksoon-deployment
  labels:
    app: iksoon-tomcat
spec:
  replicas: 3
  selector:
    matchLabels:
      app: iksoon-pod-tomcat
  template:
    metadata:
      labels:
        app: iksoon-pod-tomcat
    spec:
      containers:
      - name: iksoon-tomcat
        image: peksoon/iksoon_tomcat:1.0.6
        ports:
        - containerPort: 8080


---


apiVersion: v1
kind: Service
metadata:
  name: iksoon-tomcat-service
  labels:
    name: service-tomcat-service
spec:
  type: NodePort
  ports:
  - name: "iksoon-tomcat8-network-setting"
    port: 8088
    protocol: TCP
    targetPort: 8080
    nodePort: 30001
  selector:
    app: iksoon-pod-tomcat
tomcat container를 deployment로 생성
replicaset = 3
 
Pod는 worker node1에 배포되어 있음
tomcat container port = 8080

 


 
 

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

 

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이 수행함.
참고 : 
 
 
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.2, 10.244.1.3, 10.244.1.4
Service Object Type = NodePort 30001

 

Tomcat Pod 배포 Node = Worker Node1
Tomcat Pod Port = 8080
 
Master Node IP = 10.0.2.15
Worker Node IP = 10.0.2.7

이외의 정보는 문서 상단위 "환경"에서 설명한 정보와 동일
 
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:33:4f:49  (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 맵핑을 확인할 수 있음

 

패킷 흐름 분석

해당 인터페이스의 내용은 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에 매칭되면 지정한 규칙에 따라서 
패킷을 포워딩 함.
 
 

3. Master Node : kube-proxy iptables Routing 분석

 

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

 

3.1. raw PREROUTING 확인

 
raw table
Netfilter Framework는 Hook 뿐만 아니라 Connection Tracking 기능을 제공.
이전에 도착한 Packet들을 바탕으로 방금 도착한 Packet의 Connection을 추적함.
Raw Table은 특정 Packet이 Connection Tracking에서 제외되도록 설정함.

[raw table - PREROUTING chain 확인 명령어]
iptables -t raw -L PREROUTING

[결과]
생성되어있는 PREROUTING chain이 없음으로 다음 table로 넘어감
 
 
 

3.2. mangle PREROUTING 확인

 
mangle table
Packet의 IP header를 바꿈. Packet의 TTL 변경, Marking하여
다른 iptables의 Table이나 Network tool에서 Packet을 구분 할 수 있도록 함

[mangle table - PREROUTING chain 확인 명령어]
iptables -t mangle -L PREROUTING

[결과]
생성되어있는 PREROUTING chain이 없음으로 다음 table로 넘어감
 

3.3. nat PREROUTING 확인

nat table

Packet NAT(Network Address Translation)을 위한 table. packet의 source/destination address를 변경
모든 IP 패킷에는 Source IP와 Destination IP가 있다.
NAT란, Network Address Translation, 즉 IP 패킷 헤더의 IP 주소를 변경하는 기능 혹은 절차를 뜻한다. 1:1 NAT 혹은 1:다 NAT가 있다.
PREROUTING : DNAT을 이용하여 패킷이 생길 때 사용됨.
POSTROUTING : SNAT을 이용하여 패킷이 나갈 때 사용됨.

[mangle nat - PREROUTING chain 확인 명령어]
iptables -t nat -L PREROUTING

[결과]
생성되어있는 KUBE-SERVICES chain을 확인.
kube-proxy 문서를 확인해보면 nat에만 규칙을 생성한다고함.
문서에서 설명하는 규칙이 바로 KUBE-SERVICES chain임.
패킷은 해당 KUBE-SERVICES chain의
src = anywhere
dst = anywhere 
에 매칭되어 
kube-proxy가 생성한 KUBE-SERVICES Chain Rule에 적용되기 시작함.
 

 

3.3.0. nat table - PREROUTING chain 도식화

 

3.3.1. 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.101.89.226 인것을 확인 할 수 있는데 
실제로 service object를 확인해보면

다음과 같이 10.101.89.226로 IP가 동일한 것을 확인할 수 있음
ClusterIP를 확인했지만
해당 Service는 NodePort Type임으로 
NodePort 정보도 확인해야함
그러기 위해서 위에서 확인한 
KUBE-NODEPORTS Rule을 확인함.
 
 
[패킷 흐름]
패킷은 raw table의 PREROUTING Chain Rule에 의해 
KUBE-SERVICES Chain Rule의 영향을 받게됨.
KUBE-SVC-????에 설정된 src, dst, dpt 와 
패킷 정보과 일치한다면 해당 KUBE-SVC-??? Chain Rule이 적용되지만
예제에서는 
[MAC 정보]
출발지 : 52:54:00:12:35:00  (virtualbox router mac)
도착지 : 08:00:27:33:4f:49 (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-SERVICES 하위 chain 중 
source : 0.0.0.0/0
destination : 0.0.0.0/0
으로 설정되어있는 KUBE-NODEPORTS 매칭되어
다음으로 KUBE-NODEPORTS chain을 진행하게 됨.
 
 

3.3.2. 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 로 설정되었음을 알 수 있음.
 
 
[패킷 흐름]
예제 환경의 패킷 중 도착지 Port 번호를 확인함.
[MAC 정보]
출발지 : 52:54:00:12:35:00  (virtualbox router mac)
도착지 : 08:00:27:33:4f:49 (Master Node의 enp0s3 인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 192.168.56.1 (external에서 접근한 ip주소)
도착지 : 10.0.2.15 (Master Node의 IP주소)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : pago-services1 (설정된 NodePort 번호)
위와같이 도착지 Port번호가 pago-services1 즉 30001 로
KUBE-NODEPORTS 정보 중 dpt가 30001인
KUBE-SVC-D7CQFPLTU3IZSXTJ 와 매칭이 됨.
 
 

3.3.3. KUBE-SVC-D7CQFPLTU3IZSXTJ Chain의 Rule을 확인

 
[명령어]
iptables -t nat -L KUBE-SVC-D7CQFPLTU3IZSXTJ -n

[분석]
KUBE-SVC-XXX Table에서는
iptables의 statistic 기능을 이용하여 
요청 Packet은 Service를 구성하는 Pod들로 랜덤하고 균등하게 
Load Balancing하는 역할을 수행함.
예제 환경에서 해당 service object에 매칭 되어있는 pod가 3개 임으로
위와같이 3개의 KUBE-SEP가 조회 됨.
해당 SEP 중에 한곳으로 Load Balancing 됨.
 
[KUBE-MARK-MASQ]
kube-proxy가 생성한 KUBE-MARK-MASQ Chain은 Netfilter Mark 기능에 해당함.
패킷의 Source IP 주소를 Node(Host) IP주소로 변경하는 SNAT을 수행하기 위해 Marking함.
Marking 된 Packet은 이후 MASQUERADE Rule에 의해서 실제 SNAT이 진행됨.
미리 설명하자면 KUBE-MARK-MASQ을 통해 mark된 패킷은 
이후 nat table의 POSTROUTING chain 하위의 KUBE-POSTROUTING chain에 의해 Masquerade 되어 Src IP가 Host의 IP로 SNAT 됨.
현재 KUBE-SVC-D7CQFPLTU3IZSXTJ을 보면 2개의 KUBE-MARK-MASQ Chain이 존재함.
 
두개 중
source : 0.0.0.0/0
destination : 0.0.0.0/0
에 해당하는 아래 KUBE-MARK-MASQ에 매칭되어 Marking 됨.
 
실제로 패킷이 매칭되는 chain을 확인해보면 아래와 같이
두 번째 KUBE-MARK-MASQ와
KUBE-SEP-EIUFBJG7JND3UXZR chain에 매칭되는 것을 확인할 수 있음.
 
[명령어]
watch -n 1 iptables -t nat -L KUBE-SVC-D7CQFPLTU3IZSXTJ -nv

[패킷 흐름]
예제 환경에서는 KUBE-SEP가 
KUBE-SEP-EIUFBJG7JND3UXZR 
KUBE-SEP-EBIMPUXHEGPVZNOT
KUBE-SEP-MHY7UNHEGUVFS2IT
3개 있음으로 
3개 중 한곳으로 매칭됨.
 
 

3.3.4. KUBE-SEP-EIUFBJG7JND3UXZR Chain의 Rule을 확인

 
KUBE-SEP-EIUFBJG7JND3UXZR 
KUBE-SEP-EBIMPUXHEGPVZNOT
KUBE-SEP-MHY7UNHEGUVFS2IT
3개 중
KUBE-SEP-EIUFBJG7JND3UXZR 
를 기준으로 flow를 확인해봄
 
[명령어]
iptables -t nat -L KUBE-SEP-EIUFBJG7JND3UXZR  -n

[분석]
KUBE-MARK-MASQ와 DNAT가 존재하고
현재 패킷은 아래와 같음
[MAC 정보]
출발지 : 52:54:00:12:35:00  (virtualbox router mac)
도착지 : 08:00:27:33:4f:49 (Master Node의 enp0s3 인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 192.168.56.1 (external에서 접근한 ip주소)
도착지 : 10.0.2.15 (Master Node의 IP주소)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : pago-services1 (설정된 NodePort 번호)
출발지 정보가 10.244.1.2 임으로 
KUBE-MARK-MASQ는 매칭되지 않고
DNAT에 매칭됨.
실제 패킷을 확인해보면 DNAT에만 매칭되는 것을 확인할 수 있음.
 
[명령어]
watch -n 1 iptables -t nat -L KUBE-SEP-EIUFBJG7JND3UXZR -nv

위와같이 KUBE-MARK-MASQ는 카운팅되지 않고 DNAT만 카운팅됨
 
[DNAT]
Chain의 끝에 도달하여 최종적으로 도착지 정보를 DNAT을 통해 변경해줌.
목적지 IP주소와 Port로 패킷을 변경해줌.
즉 kube-proxy가 생성한 Netfilter Chain을 통과한 결과물임.
도착지 Mac의 경우는 Host의 ARP Table에 따라서 입력됨.
[MAC 정보]
출발지 : 52:54:00:12:35:00  (virtualbox router mac)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 192.168.56.1 (external에서 접근한 ip주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소로 변경)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경)
 
 
 

3.4. Routing

[분석]
현재 Routing table을 거치게 되는 packet은 아래와 같음
[MAC 정보]
출발지 : 52:54:00:12:35:00  (virtualbox router mac)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 192.168.56.1 (external에서 접근한 ip주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소로 변경)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경)
도착지 정보가 10.244.1.2로  현재 host가 아닌 외부 host에 해당함.
 
[iptables의 routing 규칙]
들어오는 패킷이 local system을 목적지로 한다 : PREROUTING -> INPUT
들어오는 패킷이 다른 호스트로 목적지로 한다 : PREROUTING -> FORWARD -> POSTROUTING
 
위 규칙으로 인해 도착지 정보가 외부임으로 
PREROUTING 다음으로 FORWARD -> POSTROUTING을 진행하게 됨.
 
 

3.5. mangle FORWARD

[mangle table - FORWARD chain 확인 명령어]
iptables -t mangle -L FORWARD

[결과]
생성되어있는 PREROUTING chain이 없음으로 다음 table로 넘어감
 

3.6. filter FORWARD

 

filter table

packet을 drop할지 전달할지 결정
  • ACCEPT : 패킷을 허용한다.
  • DROP : 패킷을 차단한다.
  • REJECT : 패킷을 거부한다.
  • RETURN : 패킷을 맨 아래 규칙으로 내린다.
  • MARK : 패킷에 마크를 표시한다.
  • LOG : 로그를 남긴다.(/var/log/messages)
  • MASQUERADE : 패킷의 출발지를 나가는 장치의 아이피로 바꾼다.
  • SNAT : 패킷의 출발지를 지정한 아이피로 바꾼다.
  • DNAT : 패킷의 도착지를 지정한 아이피로 바꾼다.

[mangle table - FORWARD chain 확인 명령어]
iptables -t filter -L FORWARD | column -t

[결과]
생성되어있는 FORWARD chain이 있음.
 
 

3.6.1. KUBE-FORWARD Chain의 Rule을 확인

[명령어]
iptables -t filter -L KUBE-FORWARD  | column -t

[분석]
source, destination이 모두 anywhere로 매칭이되지만
mark에 따라 chain이 걸림.
현재 패킷에는 ctstate INVALID mark가 되어있지 않아서
DROP은 pass하고
하위 kuberentes 관련 chain에 해당되어 ACCEPT 처리됨.
위와 같이 생각하는 근거는 아래와 같음
 
watch -n 1 iptables -t filter -L KUBE-FORWARD -nv

pod에 접속할 때 마다 두번째 ACCEPT가 counting되는 것을 확인함.
 
 

 

3.6.2. KUBE-SERVICES Chain의 Rule을 확인
 
[명령어]
iptables -t filter -L KUBE-SERVICES  | column -t

[분석]
KUBE-SERVICES chain하위에 생성되어있는 정보가 없음으로 PASS처리함.
 
 

3.6.3. KUBE-EXTERNAL-SERVICES Chain의 Rule을 확인

 
[명령어]
iptables -t filter -L KUBE-EXTERNAL-SERVICES   | column -t

[분석]
KUBE-EXTERNAL-SERVICES  chain하위에 생성되어있는 정보가 없음으로 PASS처리함.
 
 

3.7. mangle POSTROUTING

[mangle table - POSTROUTING chain 확인 명령어]
iptables -t mangle -L POSTROUTING | column -t

[결과]
생성되어있는 POSTROUTING chain이 있음.
CHECKSUM인데 protocol 설정이 UDP로 되어있어서 해당 chain에 해당되지 않고 PASS함
 

 

3.8. nat POSTROUTING

[nat table - POSTROUTING chain 확인 명령어]
 

[결과]
생성되어있는 다수의 POSTROUTING chain이 있음.
패킷은 이 중 source, destination이 anywhere로 설정된
KUBE-POSTROUTING에 유일하게 매칭됨.
 
 

3.7.1. KUBE-POSTROUTING Chain의 Rule을 확인

 
[명령어]
iptables -t nat -L KUBE-POSTROUTING | column -t

[분석]
RETURN 은 mark가 !0x4000|0x4000 에 해당함.
현재 확인한 진행중인 패킷은 해당 mark가 없으니 PASS함.
이후 MARK와 MASQUERADE는 아래 watch 명령을 통해 pod 접속히 count가 증가되는 것을 확인함.
해당 chain에 매칭됨.
watch -n 1 iptables -t nat -L KUBE-POSTROUTING -nv

raw table의 PREROUTING chain하위 KUBE-MARK-MASQ에서 mark가 되었었기 때문에
해당 KUBE-POSTROUTING chain에서 Masquerade 되어 Src IP가 Host의 IP로 SNAT 됨.
실제 watch로 확인해보면 pod에 접근할 때 마다 MASQUERADE가 counting되는 것을 확인 할 수 있음.
 
[SNAT]
Chain의 끝에 도달하여 출발지 정보를 SNAT을 통해 변경해줌.
출발지 IP주소와 Port로 패킷을 변경해줌.
도착지 Mac의 경우는 Host의 ARP Table에 따라서 입력됨.
[MAC 정보]
출발지 : 56:61:6c:31:0f:4f (Master Node flannel.1인터페이스 MAC주소)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 10.244.0.0 (Master Node의 flannel.1 인터페이스 ip주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소로 변경)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경)
 
 

 

4. Master Node : flannel.1

[Routing table 확인]
route

 
[분석]
현재 Routing table을 거치게 되는 packet은 아래와 같음
[MAC 정보]
출발지 : 56:61:6c:31:0f:4f  (Master Node flannel.1인터페이스 MAC주소)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소로 변경)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경)
도착지 정보가10.244.1.2 임으로 
routing table 정보의 
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
에 매칭됨.
 
 
[명령어]
tcpdump -i flannel.1   -ne tcp  -vv -c 10

[MAC 정보]
출발지 : 56:61:6c:31:0f:4f    (Master Node flannel.1인터페이스 MAC주소)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소로 변경)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경)
 
참고) webcache = 8080을 의미함

 
패킷 흐름 분석
kube-proxy에서 netfilter flow를 설명하면서 최종적으로 생성될 
패킷을 예상했는데 flannel1 장치에서 확인한 패킷과 동일한 결과를 확인함.
일단 flannel.1 인터페이스에서 위와같은 패킷을 확인함.
이제 해당 패킷이 다음으로 어떤 인터페이스로 가는지 확인해야함.
 
 
 
 

5. 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-dphph  -n kube-system  -- arp -a
 
명령으로 Master Node Flannel 의 ARP Table확인

확인 결과
[MAC 정보]
출발지 : 56:61:6c:31:0f:4f  (Master Node의 flannel.1인터페이스 MAC주소)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 10.244.0.0  (master node의 flannel.1 인터페이스 ip 주소)
도착지 : 10.244.1.2 (목적지 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인터페이스를 확인해야함.
 
 

6. 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:33:4f:49 (Master Node의 enp0s3 인터페이스의 MAC)
도착지 : 08:00:27:31:b4:a1 (Worker Node 2의 enp0s3 인터페이스의 MAC)
 
[IP주소 정보]
출발지 : 10.0.2.15 (Master Node의 IP)
도착지 : 10.0.2.7  (Worker Node의 IP)
 
[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : 8472(otv)
 
 
VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : 56:61:6c:31:0f:4f  (Master Node의 flannel.1인터페이스 MAC주소)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 10.244.0.0  (master node의 flannel.1 인터페이스 ip 주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)
다음으로는 Worker Node에서 패킷을 확인해야함.
 
 
 

7. 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:33:4f:49 (Master Node의 enp0s3 인터페이스의 MAC)
도착지 : 08:00:27:31:b4:a1 (Worker Node 2의 enp0s3 인터페이스의 MAC)
 
[IP주소 정보]
출발지 : 10.0.2.15 (Master Node의 IP)
도착지 : 10.0.2.7  (Worker Node의 IP)
 
[Port 정보]
출발지 : 랜덤한 Port 번호
도착지 : 8472(otv)
 
 
 
VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : 56:61:6c:31:0f:4f  (Master Node의 flannel.1인터페이스 MAC주소)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 10.244.0.0  (master node의 flannel.1 인터페이스 ip 주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)
해당 패킷은 flannel.1 인터페이스에서 캡슐화를 해제할 수 있음.
 
 
 

8. Worker Node : flannel.1

iptables를 통과하지만 Chain Rule에 해당하지 않기 때문에
그대로 통과함
 
[명령어]
tcpdump -i flannel.1   -ne tcp  -vv -c 10

패킷 흐름 분석
encapsulated (캡슐화)를 해제한 패킷을 확인할 수 있음.
 
 
VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : 56:61:6c:31:0f:4f  (Master Node의 flannel.1인터페이스 MAC주소)
도착지 : f2:3b:9f:cb:37:fd  (Worker Node의 flannel.1인터페이스 MAC주소)
 
[IP주소 정보]
출발지 : 10.244.0.0  (master node의 flannel.1 인터페이스 ip 주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)
 
Worker Node의 ARP Table에 
해당 도착지 정보가 있음으로 다음 인터페이스로 cni0로
패킷이 전달됨.
 

9. Worker Node : cni0

[명령어]
tcpdump -i cni0 -ne tcp and dst 10.244.1.2 -vv -c 10

 
패킷 흐름 분석
encapsulated (캡슐화)를 해제한 패킷을 확인할 수 있음.
MAC 주소만 변경 되어 있음
 
VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : 82:32:81:9c:27:23  (Worker Node의cni0 인터페이스의 MAC)
도착지 : d2:f2:43:1f:e2:1e
 
[IP주소 정보]
출발지 : 10.244.0.0  (master node의 flannel.1 인터페이스 ip 주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)
[도착지 MAC 정보 d2:f2:43:1f:e2:1e]
kubectl -it exec kube-flannel-ds-5qrzc -n kube-system  -- arp -a | grep 10.244.1.117
worker node에 배포되어있는 flannel pod의 arp 정보를 확인하는 상위 명령으로 
ARP Table을 확인해보면 아래와 같은 정보를 확인할 수 있고
도착지 MAC주소 또한 
조회된 MAC주소를 가지고 있음.

 

 

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

vethbf625505 인터페이스가 
목적지인 tomcat pod에 해당하는 인터페이스임.
Pod에 해당하는 veth 장비 찾기 참고 : Pod의 veth (Virtual Ethernet Interface) 장치 찾기
 

 

[명령어]
tcpdump -i vethd92f7dc2  -ne tcp  -vv -c 10​
그리고 Pod의 tomcat container로 들어가서 
tcpdump를 설치한 후 패킷을 확인해봄.
 
[명령어]
tcpdump -ne tcp  -vv -c 10
 
패킷 흐름 분석
vethd92f7dc2  인터페이스에 확인한 정보와 Pod의 tomcat container안에서 확인해본 결과가 동일함.
cni0에서 확인했던 패킷을 Pod내부의 tomcat container가 받는것을 확인할 수 있음.
VXLAN으로 캡슐화 된 패킷 정보
[MAC 정보]
출발지 : 82:32:81:9c:27:23  (Worker Node의cni0 인터페이스의 MAC)
도착지 : d2:f2:43:1f:e2:1e
 
[IP주소 정보]
출발지 : 10.244.0.0  (master node의 flannel.1 인터페이스 ip 주소)
도착지 : 10.244.1.2 (목적지 Pod의 IP주소)
 
[Port]
출발지 : 랜덤한 Port 번호
도착지 : webcache (목적지 Pod의 tomcat container port = 8080)
 

분석 완료

 

 
 
iptables 참고

 

 


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


 

반응형