IPsec 투명 암호화
IPsec 투명 암호화
Cilium이 Kubernetes 시크릿을 사용해 IPsec 키를 배포하는 IPsec 기반 투명 암호화를 구성하는 방법을 설명하는 문서예요. 구성 완료 후 모든 Cilium 관리 엔드포인트 간 트래픽은 IPsec으로 암호화돼요.
본문
이 가이드는 Kubernetes 시크릿을 사용해 IPsec 키를 배포하는 IPsec 기반 투명 암호화를 사용하도록 Cilium을 구성하는 방법을 설명해요. 이 구성이 완료되면 Cilium 관리 엔드포인트 간의 모든 트래픽이 IPsec으로 암호화돼요. 이 가이드는 Kubernetes 시크릿을 사용해 키를 배포해요. 또는 키를 수동으로 배포할 수도 있지만, 여기서는 다루지 않아요.
패킷이 전송된 노드와 같은 노드를 목적지로 할 때는 암호화되지 않아요. 이 동작은 의도된 거예요. 그 경우 어차피 원시 트래픽을 노드에서 관찰할 수 있으므로 암호화로 얻을 이점이 없어요.
PSK 생성 및 가져오기 (Generate & Import the PSK)
먼저 저장할 IPsec 구성용 Kubernetes 시크릿을 생성해요. 아래 예제는 cilium-ipsec-keys라는 Kubernetes 시크릿으로 배포될 필요한 IPsec 구성을 생성하는 방법을 보여줘요. Kubernetes 시크릿은 하나의 키-값 쌍으로 구성되어야 하는데, 키는 cilium-agent 파드에 볼륨으로 마운트될 파일 이름이고, 값은 다음 형식의 IPsec 구성이에요.
key-id encryption-algorithms PSK-in-hex-format key-size
참고:
Secret리소스는 Cilium과 같은 네임스페이스에 배포해야 해요! 이 예제에서는kube-system을 사용해요.
아래 예제에서는 GCM-128-AES를 사용해요. 하지만 Linux가 지원하는 어떤 알고리즘도 사용할 수 있어요. 시크릿을 생성하려면 다음 명령을 사용할 수 있어요.
$ cilium encrypt create-key --auth-algo rfc4106-gcm-aes
$ kubectl create -n kube-system secret generic cilium-ipsec-keys \
--from-literal="keys=3+ rfc4106(gcm(aes)) $(dd if=/dev/urandom count=20 bs=1 2> /dev/null | xxd -p -c 64) 128"
주의: 시크릿의
+기호는 강력히 권장돼요. 이것은 터널별 IPsec 키를 강제로 사용하게 해요. 이전의 전역 IPsec 키는 안전하지 않은 것으로 간주되며(GHSA-pwqm-x5x6-5586 참고) v1.16에서 폐기됐어요.+를 사용하면 생성한 시크릿에서 터널별 키가 파생돼요.
시크릿은 kubectl -n kube-system get secrets로 확인할 수 있으며 cilium-ipsec-keys로 나열돼요.
$ kubectl -n kube-system get secrets cilium-ipsec-keys
NAME TYPE DATA AGE
cilium-ipsec-keys Opaque 1 176m
Cilium에서 암호화 활성화 (Enable Encryption in Cilium)
Cilium CLI로 Cilium을 배포한다면 다음 옵션을 전달하세요.
cilium install 1.20.2 \
--set encryption.enabled=true \
--set encryption.type=ipsec
Helm을 사용해 Cilium을 배포한다면 다음 옵션을 전달하세요.
helm install cilium cilium/cilium --version 1.20.2 \
--namespace kube-system \
--set encryption.enabled=true \
--set encryption.type=ipsec
helm install cilium oci://quay.io/cilium/charts/cilium 1.20.2 \
--namespace kube-system \
--set encryption.enabled=true \
--set encryption.type=ipsec
encryption.enabled는 Cilium 관리 파드 간 트래픽의 암호화를 활성화해요. encryption.type은 암호화 방법을 지정하며, 기본값이 ipsec이므로 생략할 수 있어요.
주의: direct routing 구성에서 Cilium을 사용할 때는 네이티브 라우팅 CIDR이 올바르게 설정되었는지 확인하세요. CLI에서는
--ipv4-native-routing-cidr=CIDR로, Helm에서는--set ipv4NativeRoutingCIDR=CIDR로 설정해요.
이 시점에 Cilium 관리 노드는 모든 트래픽에 IPsec을 사용할 거예요. Cilium의 투명 암호화에 대한 자세한 내용은 eBPF Datapath를 참고하세요.
의존성 (Dependencies)
L7 프록시 지원이 활성화되면(--enable-l7-proxy=true), IPsec은 DNS 프록시가 투명 모드로 동작해야 해요(--dnsproxy-enable-transparent-mode=true).
암호화 인터페이스 (Encryption interface)
네트워크 대면 인터페이스를 식별하기 위한 추가 인자를 사용할 수 있어요. direct routing을 사용하고 인터페이스가 지정되지 않으면 라우팅 테이블을 검사해 기본 경로 링크를 선택해요. 이는 많은 경우에 동작하지만, 라우팅 규칙에 따라 사용자가 다음과 같이 암호화 인터페이스를 지정해야 할 수도 있어요.
cilium install 1.20.2 \
--set encryption.enabled=true \
--set encryption.type=ipsec \
--set encryption.ipsec.interface=ethX
--set encryption.ipsec.interface=ethX
설정 검증 (Validate the Setup)
kubectl -n kube-system exec -ti ds/cilium -- bash로 Cilium 파드 중 하나에서 bash 셸을 실행하고 다음 명령을 실행하세요.
- tcpdump 설치:
$ apt-get update$ apt-get -y install tcpdump - 트래픽이 암호화되는지 확인해요. 아래 예제에서 패킷이 IP Encapsulating Security Payload(ESP)를 운반한다는 사실로 확인할 수 있어요. 아래 예제에서 eth0은 파드 간 통신에 사용되는 인터페이스예요. 터널링이 활성화된 경우 이 인터페이스를
cilium_vxlan같은 것으로 바꾸세요.tcpdump -l -n -i eth0 esptcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes15:16:21.626416 IP 10.60.1.1 > 10.60.0.1: ESP(spi=0x00000001,seq=0x57e2), length 18015:16:21.626473 IP 10.60.1.1 > 10.60.0.1: ESP(spi=0x00000001,seq=0x57e3), length 18015:16:21.627167 IP 10.60.0.1 > 10.60.1.1: ESP(spi=0x00000001,seq=0x579d), length 10015:16:21.627296 IP 10.60.0.1 > 10.60.1.1: ESP(spi=0x00000001,seq=0x579e), length 10015:16:21.627523 IP 10.60.0.1 > 10.60.1.1: ESP(spi=0x00000001,seq=0x579f), length 18015:16:21.627699 IP 10.60.1.1 > 10.60.0.1: ESP(spi=0x00000001,seq=0x57e4), length 10015:16:21.628408 IP 10.60.1.1 > 10.60.0.1: ESP(spi=0x00000001,seq=0x57e5), length 100
키 로테이션 (Key Rotation)
주의: 키 로테이션은 업그레이드나 다운그레이드 중에 수행하면 안 돼요. 즉, 키를 로테이션하기 전에 클러스터(또는 clustermesh)의 모든 노드가 같은 Cilium 버전이어야 해요.
주의: 키 로테이션 중에 서로 다른 인증 키 길이를 수반하는 알고리즘을 변경하는 것은 권장되지 않아요. 시도하면 Cilium은 에이전트가 재시작될 때까지 새 키의 적용을 지연시키고 이전 키를 계속 사용해요. 이는 중단 없는 IPv6 파드 간 연결을 유지하기 위해 설계된 동작이에요.
cilium-ipsec-keys 시크릿을 새 키로 교체하려면:
KEYID=$(kubectl get secret -n kube-system cilium-ipsec-keys -o go-template --template={{.data.keys}} | base64 -d | grep -oP "^\d+")
if [[ $KEYID -ge 15 ]]; then KEYID=0; fi
data=$(echo "{\"stringData\":{\"keys\":\"$((($KEYID+1)))+ "rfc4106\(gcm\(aes\)\)" $(dd if=/dev/urandom count=20 bs=1 2> /dev/null | xxd -p -c 64) 128\"}}")
kubectl patch secret -n kube-system cilium-ipsec-keys -p="${data}" -v=1
전환 중에는 새 키와 이전 키가 모두 사용돼요. Cilium 에이전트는 각 엔드포인트가 어떤 키를 사용하는지에 대한 엔드포인트별 데이터를 유지하며, 어느 한쪽이 아직 갱신되지 않은 경우 올바른 키를 사용해요. 이런 방식으로 새 키가 롤아웃되는 동안에도 암호화가 동작해요.
위 예제의 KEYID 환경 변수는 Cilium이 사용하는 현재 키 ID를 저장해요. 키 변수는 1에서 15 사이의 값을 가지는 uint8이며, 15에서 1로 롤오버되며 재키잉(re-key) 때마다 단조 증가해야 해요. Cilium 에이전트는 시크릿에 지정되지 않은 경우 KEYID를 0으로 기본값 처리해요.
Cluster Mesh를 사용한다면 키 로테이션 절차를 메시의 모든 클러스터에 적용해야 해요. 새 키가 모든 클러스터에 배포·적용될 수 있도록 전환 시간을 늘려야 할 수도 있는데, 이는 ipsec-key-rotation-duration 에이전트 플래그로 할 수 있어요.
대규모 클러스터에서 키 로테이션은 모든 에이전트가 키 변경을 동시에 감지하고 CiliumNode 리소스를 한 번에 갱신해 Kubernetes API 서버를 압도할 수 있는 "떼 몰이(thundering herd)" 효과를 일으킬 수 있어요. 이를 완화하기 위해 Cilium은 새 키를 로드하기 전에 무작위 지터(jitter) 지연을 적용해요. 지터는 [0, keyRotationDuration/10]에서 무작위로 선택되며, 이전 키가 제거되기 전에 에이전트가 새 키를 로드할 충분한 시간을 보장하면서 Kubernetes API 서버의 부하를 분산시켜요.
모니터링 (Monitoring)
IPSec이 활성화된 노드에서 네트워크 트래픽을 모니터링할 때, 같은 인터페이스에서 ESP 암호화 페이로드를 운반하는 외부 패킷(노드 간)과 그 다음 복호화된 내부 패킷(파드 간)을 모두 관찰하는 것이 정상이에요. 이는 패킷이 복호화되면 추가 처리를 위해 같은 인터페이스로 재순환(recirculate)되기 때문이에요. 따라서 적용된 tcpdump 필터에 따라 캡처가 달라질 수 있지만, 이는 암호화가 제대로 동작하지 않는다는 뜻은 아니에요. 특히 다음을 관찰하려면:
- 암호화된 패킷만:
esp필터를 사용하세요. - 복호화된 패킷만: 파드가 사용하는 프로토콜(예: ping의
icmp)에 대한 특정 필터를 사용하세요. - 암호화·복호화된 패킷 모두: 필터를 사용하지 않거나 두 필터를 결합하세요(예:
esp or icmp).
다음 캡처는 필터 없이 Kind 클러스터에서 가져온 거예요(터널링이 활성화된 경우 eth0을 cilium_vxlan으로 바꾸세요). 노드 IP는 10.244.2.92와 10.244.1.148이고, 파드 IP는 10.244.2.189와 10.244.1.7이며, 통신에 ping(ICMP)을 사용해요.
tcpdump -l -n -i eth0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on cilium_vxlan, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:22:16.379908 IP 10.244.2.92 > 10.244.1.148: ESP(spi=0x00000003,seq=0x8), length 120
09:22:16.379908 IP 10.244.2.189 > 10.244.1.7: ICMP echo request, id 33, seq 1, length 64
문제 해결 (Troubleshooting)
- 암호화를 활성화한 후 cilium 파드가 시작에 실패하면, IPsec Secret과 Cilium이 같은 네임스페이스에 함께 배포됐는지 다시 확인하세요.
- Cilium 로그 파일에서
level=warning과level=error메시지를 확인하세요.Device eth0 does not exist와 유사한 경고 메시지가 있으면--set encryption.ipsec.interface=ethX를 사용해 암호화 인터페이스를 설정하세요. - Cilium 파드에서
cilium-dbg encrypt status를 실행하세요.$ cilium-dbg encrypt statusEncryption: IPsecDecryption interface(s): eth0, eth1, eth2Keys in use: 4Max Seq. Number: 0x1e3/0xffffffffffffffffErrors: 0오류 카운터가 0이 아니면 커널이 겪은 특정 오류에 대한 추가 정보가 표시돼요. 사용 중인 키 수는 IP 패밀리당 원격 노드당 2개여야 해요. 키 로테이션 중에는 IP 패밀리당 원격 노드당 4개로 두 배가 될 수 있어요. 예를 들어 3개 노드 클러스터에서 IPv4와 IPv6가 모두 활성화되고 키 로테이션이 진행 중이 아니면, 각 노드에서 8개의 키가 사용 중이어야 해요. 복호화 인터페이스 목록에는 파드 트래픽을 받을 수 있는 모든 네이티브 디바이스(예: ENI 인터페이스)가 있어야 해요.
모든 XFRM 오류는 커널에서의 패킷 드롭에 해당해요. 다음은 이러한 오류를 일으킬 수 있는 운영상 실수와 예상 동작을 설명해요.
- 노드가 재부팅되면, 그 노드와 통신하는 데 사용되는 키가 다른 노드에서 변경될 것으로 예상돼요. 새 노드 키가 배포되는 동안
XfrmInNoStates와XfrmOutNoStates카운터가 증가하는 것을 볼 수 있어요. - 키 로테이션 후, 새 키 설정이 모든 노드에 설치되기 전에 이전 키가 정리되면
XfrmInNoStates오류가 발생해요. 이전 키는 기본적으로 5분 간격 후 노드에서 제거돼요. 기본적으로 모든 에이전트는 키 갱신을 감시하고 키가 변경된 후 1분 안에 구성을 갱신하므로, 키가 제거되기 전에 충분한 시간이 남아요. 어떤 이유로든(예: 여러 클러스터를 갱신해야 하는 Cluster Mesh의 경우) 키 로테이션이 더 오래 걸릴 것으로 예상된다면ipsec-key-rotation-duration에이전트 플래그로 정리 전 지연을 늘릴 수 있어요. XfrmInStateProtoError오류는 다음 이유로 발생할 수 있어요.- SPI(위 Key Rotation 지침의 KEYID라고도 함)를 증가시키지 않고 키를 갱신한 경우. 새 키 로테이션을 제대로 수행하면 고칠 수 있어요.
- 출발지 노드가 목적지 노드의 anti-reply oseq와 다른 anti-replay 시퀀스로 패킷을 암호화한 경우. 새 키 로테이션을 제대로 수행하면 고칠 수 있어요.
XfrmFwdHdrError와XfrmInError는 커널이 복호화한 패킷의 경로를 조회하지 못할 때 발생해요. 파드가 삭제됐지만 일부 패킷이 아직 전송 중일 때 정당하게 발생할 수 있어요. 또한 커널이 메모리를 할당하지 못하는 메모리 압박 상황에서도 발생할 수 있어요.XfrmInStateInvalid는 XFRM 상태가 삭제되는 동안 패킷을 받으면 드물게 발생할 수 있어요. XFRM 상태는 노드 축소와 일부 업그레이드·다운그레이드의 일부로 삭제돼요.- 다음 표는 과거에 관찰된 여러 XFRM 오류에 대한 알려진 설명을 문서화한 거예요. 다른 많은 오류 유형도 존재하지만, 보통은 Cilium이 사용하지 않는 Linux 하위 기능(예: XFRM 만료)에 대한 거예요.
| 오류 | 알려진 설명 |
|---|---|
XfrmInError |
커널이 (1) 삭제된 파드에 대한 패킷을 복호화해 라우팅하려 했거나 (2) 메모리를 할당하지 못함. |
XfrmInNoStates |
복호화용 XFRM 구성의 버그. |
XfrmInStateProtoError |
노드 간 키 또는 anti-replay 시퀀스 불일치. |
XfrmInStateInvalid |
수신된 패킷이 삭제 중인 XFRM 상태와 일치함. |
XfrmInTmplMismatch |
복호화용 XFRM 구성의 버그. |
XfrmInNoPols |
복호화용 XFRM 구성의 버그. |
XfrmInPolBlock |
명시적 드롭. Cilium이 사용하지 않음. |
XfrmOutNoStates |
암호화용 XFRM 구성의 버그. |
XfrmOutStateSeqError |
암호화 XFRM 구성의 시퀀스 번호가 최대값에 도달함. |
XfrmOutPolBlock |
Cilium이 그렇지 않으면 평문으로 노드를 떠날 패킷을 버림. |
XfrmFwdHdrError |
커널이 (1) 삭제된 파드에 대한 패킷을 복호화해 라우팅하려 했거나 (2) 메모리를 할당하지 못함. |
- 위 XFRM 오류 외에도,
No node ID found(코드 197) 유형의 패킷 드롭도 정상 운영 중에 발생할 수 있어요. 이 드롭은 파드가 Cilium 에이전트가 아직 CiliumNode 객체를 받지 못한 새 노드의 파드, 또는 최근에 삭제된 노드의 파드로 트래픽을 보내려 할 때 발생할 수 있어요. 목적지 노드의 IP 주소가 변경됐지만 에이전트가 갱신된 CiliumNode 객체를 아직 받지 못한 경우에도 발생할 수 있어요. 두 경우 모두 커널의 IPsec 구성이 아직 준비되지 않았으므로 Cilium이 출발지에서 패킷을 버려요. CiliumNode 정보가 클러스터에 전파되면 이러한 드롭은 중지돼요.
Cilium의 XFRM 상태 스테일링 (XFRM State Staling in Cilium)
컨트롤 플레인 중단은 동기화되지 않은 IPsec anti-replay 카운터가 있는 스테일(stale) XFRM 상태로 인한 연결 문제로 이어질 수 있어요. 이로 인해 보통 Cilium이 관리하는 파드 사이에서 영구적인 연결 중단이 발생해요. 이 섹션은 이러한 문제가 어떻게 발생하는지, 그리고 무엇을 할 수 있는지 설명해요.
확인된 원인 (Identified Causes)
KVStore 모드(예: etcd)에서 스테일 XFRM 상태가 발생할 수 있어요.
- Cilium 에이전트가 오랫동안 다운되면, 임대 만료(Leases 참조)로 인해 kvstore의 해당 노드 항목이 삭제되어 스테일 XFRM 상태가 발생할 수 있어요.
- 키-값 저장소를 수동으로 재생성하면 Cilium 에이전트가 새 인스턴스에 너무 늦게 연결할 수 있어요. 이 지연은 에이전트가 중요한 노드 삭제·생성 이벤트를 놓쳐, Cilium이 해당 노드에 대한 오래된 XFRM 상태를 유지하게 만들 수 있어요.
CRD 모드에서는 CiliumNode 리소스를 삭제하고 Cilium 에이전트 DaemonSet을 재시작하면 스테일 XFRM 상태가 발생할 수 있어요. 다른 에이전트가 새 CiliumNode에 대한 새로운 XFRM 상태를 만드는 동안, 그 새 노드의 에이전트는 다른 모든 피어 노드에 대한 오래된 XFRM 상태를 유지할 수 있어요.
완화 (Mitigation)
이러한 경우 연결을 복원하려면 키 로테이션(Key Rotation 참조)을 수행하세요. 이 작업은 모든 노드에서 일관되고 유효한 새 XFRM 상태를 보장해요.
암호화 비활성화 (Disabling Encryption)
암호화를 비활성화하려면 encryption.enabled=false 옵션으로 YAML을 재생성하세요.
제한 사항 (Limitations)
- 투명 암호화는 다른 CNI 플러그인 위에 Cilium을 체이닝할 때 현재 지원되지 않아요. 자세한 내용은 GitHub issue 15596을 참고하세요.
- Host Policies는 IPsec 암호화와 함께 현재 지원되지 않아요.
- IPsec 암호화는 65535개 이상의 노드가 있는 클러스터나 clustermesh에서는 지원되지 않아요.
- Cilium IPsec의 복호화는 IPsec 터널당 단일 CPU 코어로 제한돼요. 두 노드 간 높은 처리량의 경우 성능에 영향을 줄 수 있어요.