CloudNet@팀의 EKS 스터디 AEWS 2기에 작성된 자료를 토대로 작성합니다.
이번 포스팅에서는 iptables 사용시 이슈사항을 소개해보겠습니다.
운영환경의 경험을 기반으로 풀어보는 시간을 가지도록 하겠습니다.
✅ iptables 란 ?
우선 문서에서 보는것처럼 iptables의 정의를 나열하지 않겠습니다.
정말 쉽게 풀어서 이야기 드려도 여러번 읽어보셔야 자기것이 됩니다.
자 이제 iptables에 대해서 이야기 해보죠.
다음과 같은 그림을 먼저 봐주세요.
netfilter hook ( 후크 선장 아시죠? ) 입니다.
iptables는 방화벽 소프트웨어고 5개의 후크를 가지고 있습니다.
netfilter hook에 (firewall 관련한) kernel modules들을 등록해두고 traffic이 지나갈때 검사를 합니다.
이 모듈들 이름이 nat, mangle, raw ,filter , security 입니다.
✅ Hook ?
무슨말인지 하나도 모르시겠죠 ....
조금더 구체화 해보겠습니다.
5개의 후크는 VM에서 간단한 명령어를 한번 쳐보면서 알아볼게요
단어 그대로 이해 해보죠 어렵지 않습니다.
- INPUT 노드로 들어오는 트래픽에 대한 트리거
- OUTPUT 노드에서 나가는 트래픽에 대한 트리거
- FORWARD는 다른 노드로 넘어가는 트래픽에 대한 트리거
- PREROUTING 라우팅 전에 트리거
- POSTROUTING 라우팅 하고 트리거
+================+ +=====================+
| hostNetwork IP | | hostNetwork process |
+================+ +=====================+
^ |
- - - - - - - - | - - - - - [*] - - - - - - - - -
| v
+-------+ +--------+
| input | | output |
+-------+ +--------+
^ |
+------------+ | +---------+ v +-------------+
| prerouting |-[*]-+-->| forward |--+-[*]->| postrouting |
+------------+ +---------+ +-------------+
^ |
- - - - | - - - - - - - - - - - - - - | - - - -
| v
+---------+ +--------+
--->| ingress | | egress |--->
+---------+ +--------+
iptables -t nat -S
# 모든 룰이 출력됩니다. 그중에 제일 위에 4개만 보죠
# 5개의 후크중에 4개
[root@ip-192-168-3-215 ~]#
[root@ip-192-168-3-215 ~]# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
중략
[root@ip-192-168-3-215 modules-load.d]# iptables -t filter -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N KUBE-EXTERNAL-SERVICES
-N KUBE-FIREWALL
-N KUBE-FORWARD
-N KUBE-KUBELET-CANARY
-N KUBE-NODEPORTS
-N KUBE-PROXY-CANARY
-N KUBE-PROXY-FIREWALL
-N KUBE-SERVICES
-A INPUT -m conntrack --ctstate NEW -m comment --comment "kubernetes load balancer firewall" -j KUBE-PROXY-FIREWALL
-A INPUT -m comment --comment "kubernetes health check service ports" -j KUBE-NODEPORTS
-A INPUT -m conntrack --ctstate NEW -m comment --comment "kubernetes externally-visible service portals" -j KUBE-EXTERNAL-SERVICES
-A INPUT -j KUBE-FIREWALL
-A INPUT -p udp -m udp --dport 9999 -m limit --limit 5/min -j LOG --log-prefix "UDP_DROP: "
-A INPUT -p udp -m udp --dport 9999 -j DROP
-A FORWARD -m conntrack --ctstate NEW -m comment --comment "kubernetes load balancer firewall" -j KUBE-PROXY-FIREWALL
-A FORWARD -m comment --comment "kubernetes forwarding rules" -j KUBE-FORWARD
-A FORWARD -m conntrack --ctstate NEW -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A FORWARD -m conntrack --ctstate NEW -m comment --comment "kubernetes externally-visible service portals" -j KUBE-EXTERNAL-SERVICES
-A OUTPUT -m conntrack --ctstate NEW -m comment --comment "kubernetes load balancer firewall" -j KUBE-PROXY-FIREWALL
-A OUTPUT -m conntrack --ctstate NEW -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A OUTPUT -j KUBE-FIREWALL
-A KUBE-FIREWALL ! -s 127.0.0.0/8 -d 127.0.0.0/8 -m comment --comment "block incoming localnet connections" -m conntrack ! --ctstate RELATED,ESTABLISHED,DNAT -j DROP
-A KUBE-FORWARD -m conntrack --ctstate INVALID -m nfacct --nfacct-name ct_state_invalid_dropped_pkts -j DROP
-A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT
-A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
[root@ip-192-168-3-215 modules-load.d]#
netfilter hooks
- NF_IP_PRE_ROUTING : incoming 트래픽을 라우팅 하기 전에 트리거
- NF_IP_LOCAL_IN : incoming 패킷의 목적지가 “로컬” 라우팅 이후 트리거
- NF_IP_FORWARD : incoming 패킷이 다른 호스트로 포워딩되는 경우로 해당 호스트로 라우팅 이후 트리거
- NF_IP_LOCAL_OUT : 로컬에서 생성된 Outbound 트래픽에 의해 트리거
- NF_IP_POST_ROUTING : 라우팅 이후 Outbound or 포워딩 트래픽에 의해 트리거
✅ Tables 과 Chain
후크에 있는 트리거가 발동되면 해당 커널 netfilter hook에 있던 모듈이 실행 됩니다.
어떤 함수가 동작하는거죠.
다음으론 , 두가지 개념을 익혀두어야 하는데요 Tables과 Chain입니다.
☑️ tables (define general aim of the rules)
테이블은 = 어떤 결정을 하느냐 ?
NAT? NAT 패킷의 src,dst address의 수정/방법 여부를 결정.
Filter? 필터링. 패킷의 전송 여부를 결정
mangle
raw
security
Known 이슈사항 정리
istio iptables environment, xtables parameter problem: iptables-restore: unable to initialize table 'nat' issue # 44118
- istio 설치시 워커노드에 iptable 모듈이 없는 경우 발생
# iptable과 nf_table의 차이점 :
iptables는 기존 Netfilter 기반의 패킷 필터링 및 NAT 프레임워크로, istio 와 같은 서비스 메시의 트래픽 리다이렉션을 위해 이를 적극적으로 활용합니다.
[root@ip-192-168-3-215 modules-load.d]# lsmod
Module Size Used by
nft_chain_nat 16384 7
nf_nat 57344 3 xt_nat,nft_chain_nat,xt_MASQUERADE
nfnetlink_acct 16384 4 xt_nfacct
xt_conntrack 16384 19
nf_conntrack 184320 7 xt_conntrack,nf_nat,xt_state,xt_nat,nf_conntrack_netlink,xt_connmark,xt_MASQUERADE
nf_defrag_ipv6 24576 1 nf_conntrack
nf_defrag_ipv4 16384 1 nf_conntrack
xt_comment 16384 96
nft_compat 20480 169
nf_tables 311296 354 nft_compat,nft_chain_nat,nft_limit
nfnetlink 20480 8 nft_compat,nfnetlink_acct,nf_conntrack_netlink,nf_tables
- 모듈 설치 /etc/modules-load.d
$ cd /etc/modules-load.d/
$ vi istio-iptables.conf
iptable_nat
iptable_mangle
iptable_filter
iptable_raw
$ modprobe iptable_nat
$ modprobe iptable_mangle
$ modprobe iptable_filter
$ modprobe iptable_raw
- 모듈 확인
[root@ip-192-168-3-215 modules-load.d]# lsmod
Module Size Used by
iptable_raw 16384 0
iptable_filter 16384 0
iptable_mangle 16384 0
iptable_nat 16384 0
☑️ chains (determine when rules will be evaluated)
체인은 = hook 안에서 또 언제 트리거 되고 어떠한 위치에서 적용되는지
언제 트리거가 되고 방화벽 룰이 어떠한 위치에서 적용이 되는지에 대한 것이에요.
K8s service Network ( iptables)
해당 그림이 잘표현되어 있어서 가져와봤습니다. 감사합니다. ^^
✅ AWS iptables 정책 적용 순서
iptables 정책 적용 순서 : PREROUTING → KUBE-SERVICES → KUBE-SVC-### → KUBE-SEP-#<파드1> , KUBE-SEP-#<파드2> , KUBE-SEP-#<파드3>
# PREROUTING
[root@ip-192-168-3-215 ~]# iptables -v --numeric --table nat --list PREROUTING | column -t
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
36909 3519K KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
16 960 AWS-CONNMARK-CHAIN-0 all -- eni+ * 0.0.0.0/0 0.0.0.0/0 /* AWS, outbound connections */
26383 2892K CONNMARK all -- * * 0.0.0.0/0 0.0.0.0/0 /* AWS, CONNMARK */ CONNMARK restore mask 0x80
# KUBE-SERVICES
[root@ip-192-168-3-215 ~]# iptables -v --numeric --table nat --list KUBE-SERVICES | column
Chain KUBE-SERVICES (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SVC-ERIFXISQEP7F7OF4 tcp -- * * 0.0.0.0/0 10.100.0.10 /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:53
0 0 KUBE-SVC-JD5MR3NA4I4DYORP tcp -- * * 0.0.0.0/0 10.100.0.10 /* kube-system/kube-dns:metrics cluster IP */ tcp dpt:9153
0 0 KUBE-SVC-Z4ANX4WAEWEBLCTM tcp -- * * 0.0.0.0/0 10.100.254.40 /* kube-system/metrics-server:https cluster IP */ tcp dpt:443
0 0 KUBE-SVC-NPX46M4PTMTKRN6Y tcp -- * * 0.0.0.0/0 10.100.0.1 /* default/kubernetes:https cluster IP */ tcp dpt:443
0 0 KUBE-SVC-I7SKRZYQ7PWYV5X7 tcp -- * * 0.0.0.0/0 10.100.227.12 /* kube-system/eks-extension-metrics-api:metrics-api cluster IP */ tcp dpt:443
0 0 KUBE-SVC-7EJNTS7AENER2WX5 tcp -- * * 0.0.0.0/0 10.100.153.164 /* kube-system/kube-ops-view:http cluster IP */ tcp dpt:8080
0 0 KUBE-SVC-UAGC4PYEYZJJEW6D tcp -- * * 0.0.0.0/0 10.100.79.8 /* kube-system/aws-load-balancer-webhook-service:webhook-server cluster IP */ tcp dpt:443
0 0 KUBE-SVC-TCOU7JCQXEZGVUNU udp -- * * 0.0.0.0/0 10.100.0.10 /* kube-system/kube-dns:dns cluster IP */ udp dpt:53
1120 61085 KUBE-NODEPORTS all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL
#KUBE-SVC-XXX
[root@ip-192-168-3-215 ~]# iptables -v --numeric --table nat --list KUBE-SVC-TCOU7JCQXEZGVUNU | column
Chain KUBE-SVC-TCOU7JCQXEZGVUNU (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-4JJWD7DPDSPAPXRS all -- * * 0.0.0.0/0 0.0.0.0/0 /* kube-system/kube-dns:dns -> 192.168.1.77:53 */ statistic mode random probability 0.50000000000
0 0 KUBE-SEP-CMUTYLZJRO6PLWPI all -- * * 0.0.0.0/0 0.0.0.0/0 /* kube-system/kube-dns:dns -> 192.168.2.64:53 */
[root@ip-192-168-3-215 ~]# iptables -v --numeric --table nat --list KUBE-SEP-4JJWD7DPDSPAPXRS | column
#KUBE-SEP-XXX
Chain KUBE-SEP-4JJWD7DPDSPAPXRS (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-MARK-MASQ all -- * * 192.168.1.77 0.0.0.0/0 /* kube-system/kube-dns:dns */
0 0 DNAT udp -- * * 0.0.0.0/0 0.0.0.0/0 /* kube-system/kube-dns:dns */ udp to:192.168.1.77:53
[root@ip-192-168-3-215 ~]#
이슈사항 정리 ( ingress-controller-pod)
Dockershim 사용 종료에 따른 Known issue (SideEffect)
- 프라이빗 클라우드에서 ingress-controller 사용시 PREROUTING을 보면 다음과 같다.
[root@mzctest-w-worker1 ~]# iptables -t nat -L PREROUTING -nv
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
42M 5365M cali-PREROUTING all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:6gwbT8clXdHdC1b1 */
42M 5365M KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
13M 2085M DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
13M 2085M CNI-HOSTPORT-DNAT all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
- PREROUTING 체인의 타겟에 CNI-HOSTPORT-DNAT 라는 타겟이 있는데 해당 타겟의 조건은 로컬 노드의 IP로 향하는 트래픽을 처리 한다.
- CNI-HOSTPORT-DNAT 일반적으로 CNI 플러그인이 관리하는 HostPort 기능을 처리하는 역할을 한다.
- 즉, Pod가 특정 호스트의 포트를 바인딩 했을때, 해당 트래픽을 해당 Pod로 DNAT(목적지 변경) 처리 하는것이다.
- k8s 버전 업그레이드 , 드레인 , etcd 롤백 간에 해당 체인의 타겟에 대한 삭제와 재생성이 제대로 이루어지지 않는 경우 ingress 서비스 통신 장애를 일으킨다.
[root@mzctest-w-worker1 ~]# iptables -t nat -L PREROUTING -nv
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
42M 5365M cali-PREROUTING all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:6gwbT8clXdHdC1b1 */
42M 5365M KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
13M 2085M DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
13M 2085M CNI-HOSTPORT-DNAT all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
#### 중복
0 0 CNI-HOSTPORT-DNAT all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
- HOSTPORT 파드에 대한 메타데이터 마운트 위치 확인
- k8s version 1.23.6까지는 HOSTPORT로 생성된 파드들의 메타데이터가 /var/lib/dockershim/sandbox 내부에존재함
- 해당 파일을 지우고 HOSTPORT 파드를 재기동 하면 다음과 같이 Duplicate 된다.
해결방법
- 쿠버네티스 버전 1.24 이상에서는 없는 이슈임 ( 1.23에서 1.24로 올릴때만 주의)
- kubelet의 /var/lib/dockershim 경로를 VM에 매핑시켜주면 해결됨
services:
kubelet:
extra_binds:
-"/var/lib/dockershim:/var/lib/dockershim"
- 엔진에 따라 kubelet 설정을 수정하는 config들 위치가 다를수 있음.
- 이미 1.23.6에서 HOSTPORT iptables 중복이 발생한 상태에서 진행
- kubelet 컨테이너 내부의 Pod metadata 를 삭제하고 nginx-ingress-controller를 재기동 하면, 1.23.6에서 중복이 발생한 규칙을 제외하고는 정상 상태 유지
- 1.23.6에서 중복이 발생한 규칙을 없애기 위해서는 iptables 명령어를 통해 해당 규칙을 제거하거나 노드 재기동하여 flush
'DevOps' 카테고리의 다른 글
[AWS EKS] (7) EKS 스터디 3주차 ( Storage - provsioner와 CSI driver 차이점 ) (0) | 2025.02.19 |
---|---|
[AWS EKS] (6) EKS 스터디 2주차 ( DNS ) (0) | 2025.02.14 |
[AWS EKS] (4) EKS 스터디 2주차 ( VPC CNI ) (0) | 2025.02.12 |
[AWS EKS] (3) EKS 스터디 1주차 ( diskio - CPU성능 관계 ) (0) | 2025.02.04 |
[AWS EKS] (2) EKS 스터디 1주차 ( eviction ) (0) | 2025.02.04 |