WireGuard 투명 암호화
WireGuard 투명 암호화
Cilium이 WireGuard®를 사용해 Cilium 관리 엔드포인트 간 트래픽을 투명하게 암호화하도록 구성하는 방법을 설명하는 문서예요. 노드 간 WireGuard 터널 설정과 검증 방법을 다뤄요.
본문
이 가이드는 WireGuard®를 사용해 Cilium 관리 엔드포인트 간 트래픽을 투명하게 암호화하도록 Cilium을 구성하는 방법을 설명해요.
이 가이드 외에도, WireGuard가 네트워크 트래픽을 암호화하는 방법을 eCHO episode 3: WireGuard에서 볼 수도 있어요.
Cilium에서 WireGuard가 활성화되면, 각 클러스터 노드에서 실행되는 에이전트는 자신과 클러스터의 다른 모든 알려진 노드 사이에 보안 WireGuard 터널을 설정해요. 각 노드는 자체 암호화 키 쌍을 자동으로 만들고, Kubernetes CiliumNode 커스텀 리소스 객체의 network.cilium.io/wg-pub-key 애너테이션을 통해 공개 키를 배포해요. 각 노드의 공개 키는 다른 노드가 해당 노드에서 실행되는 Cilium 관리 엔드포인트로/로부터의 트래픽을 복호화·암호화하는 데 사용돼요.
패킷이 전송된 노드와 같은 노드를 목적지로 할 때는 암호화되지 않아요. 이 동작은 의도된 거예요. 그 경우 어차피 원시 트래픽을 노드에서 관찰할 수 있으므로 암호화로 얻을 이점이 없어요.
WireGuard 터널 엔드포인트는 각 노드의 UDP 포트 51871에 노출돼요. 연결을 가능하게 하는 방화벽 규칙이 필요한 환경에서 Cilium을 실행한다면, 모든 Cilium 클러스터 노드가 해당 포트를 통해 서로 도달할 수 있도록 해야 해요.
참고: 터널 라우팅 모드에서 실행할 때 파드 간 트래픽은 두 번 캡슐화돼요. 먼저 VXLAN/Geneve 터널 인터페이스로 보내지고, 그 다음 WireGuard 터널로도 다시 캡슐화돼요.
Cilium에서 WireGuard 활성화 (Enable WireGuard in Cilium)
Cilium에서 WireGuard를 활성화하기 전에, 클러스터 노드에서 실행되는 Linux 배포판이 커널 모드에서 WireGuard를 지원하는지 확인하세요(즉, Linux 5.6 이상에서는 CONFIG_WIREGUARD=m, 오래된 커널에서는 out-of-tree WireGuard 모듈).
Linux 배포판에 커널 모듈을 설치하는 방법에 대한 자세한 내용은 WireGuard Installation을 참고하세요.
Cilium CLI로 Cilium을 배포한다면 다음 옵션을 전달하세요.
cilium install 1.20.2 \
--set encryption.enabled=true \
--set encryption.type=wireguard
Helm을 사용해 Cilium을 배포한다면 다음 옵션을 전달하세요.
helm install cilium cilium/cilium --version 1.20.2 \
--namespace kube-system \
--set encryption.enabled=true \
--set encryption.type=wireguard
helm install cilium oci://quay.io/cilium/charts/cilium 1.20.2 \
--namespace kube-system \
--set encryption.enabled=true \
--set encryption.type=wireguard
WireGuard는 Cilium ConfigMap의 enable-wireguard: true 옵션을 설정하고 각 Cilium 에이전트 인스턴스를 재시작해 수동으로 활성화할 수도 있어요.
참고: CNI 체이닝(예: AWS VPC CNI 플러그인)으로 실행할 때는 Helm 옵션
cni.enableRouteMTUForCNIChaining을true로 설정해 Cilium이 파드에 올바른 MTU를 설정하도록 강제하세요. 그렇지 않으면 WireGuard로 암호화된 파드 트래픽이 조각화(fragment)되어 네트워크 성능 저하를 일으킬 수 있어요.
설정 검증 (Validate the Setup)
kubectl -n kube-system exec -ti ds/cilium -- bash로 Cilium 파드 중 하나에서 bash 셸을 실행하고 다음 명령을 실행하세요.
- WireGuard가 활성화됐는지 확인하세요(피어 수는 노드 수에서 1을 뺀 값과 일치해야 해요).
cilium-dbg status | grep EncryptionEncryption: Wireguard [cilium_wg0 (Pubkey: <..>, Port: 51871, Peers: 2)] - tcpdump 설치:
apt-get updateapt-get -y install tcpdump - 트래픽이 cilium_wg0 터널 디바이스를 통해 전송되는지 확인하세요.
tcpdump -n -i cilium_wg0tcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on cilium_wg0, link-type RAW (Raw IP), capture size 262144 bytes15:05:24.643427 IP 10.244.1.35.51116 > 10.244.3.78.8080: Flags [S], seq 476474887, win 64860, options [mss 1410,sackOK,TS val 648097391 ecr 0,nop,wscale 7], length 015:05:24.644185 IP 10.244.3.78.8080 > 10.244.1.35.51116: Flags [S.], seq 4032860634, ack 476474888, win 64308, options [mss 1410,sackOK,TS val 4004186138 ecr 648097391,nop,wscale 7], length 015:05:24.644238 IP 10.244.1.35.51116 > 10.244.3.78.8080: Flags [.], ack 1, win 507, options [nop,nop,TS val 648097391 ecr 4004186138], length 015:05:24.644277 IP 10.244.1.35.51116 > 10.244.3.78.8080: Flags [P.], seq 1:81, ack 1, win 507, options [nop,nop,TS val 648097392 ecr 4004186138], length 80: HTTP: GET / HTTP/1.115:05:24.644370 IP 10.244.3.78.8080 > 10.244.1.35.51116: Flags [.], ack 81, win 502, options [nop,nop,TS val 4004186139 ecr 648097392], length 015:05:24.645536 IP 10.244.3.78.8080 > 10.244.1.35.51116: Flags [.], seq 1:1369, ack 81, win 502, options [nop,nop,TS val 4004186140 ecr 648097392], length 1368: HTTP: HTTP/1.1 200 OK15:05:24.645569 IP 10.244.1.35.51116 > 10.244.3.78.8080: Flags [.], ack 1369, win 502, options [nop,nop,TS val 648097393 ecr 4004186140], length 015:05:24.645578 IP 10.244.3.78.8080 > 10.244.1.35.51116: Flags [P.], seq 1369:2422, ack 81, win 502, options [nop,nop,TS val 4004186140 ecr 648097392], length 1053: HTTP15:05:24.645644 IP 10.244.1.35.51116 > 10.244.3.78.8080: Flags [.], ack 2422, win 494, options [nop,nop,TS val 648097393 ecr 4004186140], length 015:05:24.645752 IP 10.244.1.35.51116 > 10.244.3.78.8080: Flags [F.], seq 81, ack 2422, win 502, options [nop,nop,TS val 648097393 ecr 4004186140], length 015:05:24.646431 IP 10.244.3.78.8080 > 10.244.1.35.51116: Flags [F.], seq 2422, ack 82, win 502, options [nop,nop,TS val 4004186141 ecr...
문제 해결 (Troubleshooting)
파드 간 버려지거나 암호화되지 않은 패킷을 문제 해결할 때 다음 명령이 도움이 될 수 있어요.
# From node A:
cilium-dbg debuginfo --output json | jq .encryption
{
"wireguard": {
"interfaces": [
{
"listen-port": 51871,
"name": "cilium_wg0",
"peer-count": 1,
"peers": [
{
"allowed-ips": [
"10.154.1.107/32",
"10.154.1.195/32"
],
"endpoint": "192.168.61.12:51871",
"last-handshake-time": "2021-05-05T12:31:24.418Z",
"public-key": "RcYfs/GEkcnnv6moK5A1pKnd+YYUue21jO9I08Bv0zo="
}
],
"public-key": "DrAc2EloK45yqAcjhxerQKwoYUbLDjyrWgt9UXImbEY="
}
]
}
}
# From node B:
cilium-dbg debuginfo --output json | jq .encryption
{
"wireguard": {
"interfaces": [
{
"listen-port": 51871,
"name": "cilium_wg0",
"peer-count": 1,
"peers": [
{
"allowed-ips": [
"10.154.2.103/32",
"10.154.2.142/32"
],
"endpoint": "192.168.61.11:51871",
"last-handshake-time": "2021-05-05T12:31:24.631Z",
"public-key": "DrAc2EloK45yqAcjhxerQKwoYUbLDjyrWgt9UXImbEY="
}
],
"public-key": "RcYfs/GEkcnnv6moK5A1pKnd+YYUue21jO9I08Bv0zo="
}
]
}
}
파드 간 패킷이 성공적으로 암호화·복호화되려면 다음이 성립해야 해요.
peers[*].public-key섹션의 원격 노드 WireGuard 공개 키가 원격 노드의 실제 공개 키(원격 노드에서 같은 명령으로 가져온public-key)와 일치해야 해요.peers[*].allowed-ips에는 원격에서 실행 중인 파드 IP 주소 목록이 포함되어야 해요.
Cluster Mesh
WireGuard가 활성화된 Cilium 클러스터는 Multi-Cluster(Cluster Mesh)로 연결할 수 있어요. clustermesh-apiserver가 필요한 WireGuard 공개 키를 원격 클러스터로 자동으로 전달해요. 이러한 설정에서는 모든 참여 클러스터가 WireGuard 암호화를 활성화해야 한다는 점이 중요해요. 즉, 혼합 모드는 현재 지원되지 않아요. 또한 서로 다른 클러스터의 노드 사이에서 포트 51871의 UDP 트래픽이 허용되어야 해요.
노드 간 암호화 (Node-to-Node Encryption, beta)
기본적으로 WireGuard 기반 암호화는 Cilium 관리 파드 간의 트래픽만 암호화해요. 노드 간, 파드-노드, 노드-파드 트래픽도 추가로 암호화하는 노드 간 암호화를 활성화하려면 다음 구성 옵션을 사용하세요.
Cilium CLI로 Cilium을 배포한다면 다음 옵션을 전달하세요.
cilium install 1.20.2 \
--set encryption.enabled=true \
--set encryption.type=wireguard \
--set encryption.nodeEncryption=true
Helm을 사용해 Cilium을 배포한다면 다음 옵션을 전달하세요.
helm install cilium cilium/cilium --version 1.20.2 \
--namespace kube-system \
--set encryption.enabled=true \
--set encryption.type=wireguard \
--set encryption.nodeEncryption=true
helm install cilium oci://quay.io/cilium/charts/cilium 1.20.2 \
--namespace kube-system \
--set encryption.enabled=true \
--set encryption.type=wireguard \
--set encryption.nodeEncryption=true
경고: Cilium은 Kubernetes 컨트롤 플레인 노드로/로부터의 노드 간 암호화를 자동으로 비활성화해요. 즉,
node-role.kubernetes.io/control-plane라벨이 있는 노드는 노드 간 암호화에서 제외돼요.이는 워커 노드가 항상 Kubernetes API와 통신해 WireGuard 공개 키를 갱신할 수 있도록 보장하기 위한 거예요. 노드 간 암호화가 활성화되면 kube-apiserver로의 연결도 WireGuard로 암호화돼요. 이는 WireGuard 공개 키를 갱신하는 데 사용되는 연결 자체가 교체하려는 공개 키로 암호화되는 부트스트래핑 문제를 만든다.
이는 노드가 공개 키를 변경해야 할 때(예: 노드 재부팅이나 재프로비저닝 후 새 개인 키를 생성) 문제가 돼요.
따라서 kube-apiserver 호스트 네트워크로/로부터의 연결을 WireGuard로 암호화하지 않음으로써 워커 노드가 컨트롤 플레인에서 실수로 잠기지 않도록 보장해요. 이 노드들에서 WireGuard 노드 간 암호화가 비활성화되더라도, Kubernetes 컨트롤 플레인 자체는 보통 Kubernetes가 mTLS로 암호화하고, 컨트롤 플레인 노드의 Cilium 관리 파드 간 트래픽도 Cilium의 WireGuard 구현으로 계속 암호화된다는 점을 유의하세요.
노드 간 암호화에 참여하지 않을 컨트롤 플레인 노드를 일치시키는 라벨 선택기는
node-encryption-opt-out-labelsConfigMap 옵션으로 구성할 수 있어요. 기본값은node-role.kubernetes.io/control-plane이에요.이 옵션으로 빈 라벨 선택기를 사용해 컨트롤 플레인 노드로/로부터의 노드 간 암호화를 강제할 수도 있어요. 다만 워커 노드가 스스로 갱신할 수 없으므로, 워커 노드의 공개 키가 변경될 때 해당
CiliumNodeCRD에서 노드의 공개 키를 항상 수동으로 갱신해야 하므로 권장되지 않아요.
중간 노드가 다음 로드 밸런서 구성으로 요청을 다른 노드로 리다이렉션할 때 N/S 로드 밸런서 트래픽은 암호화되지 않아요.
- LoadBalancer & NodePort XDP Acceleration
- Direct Server Return (DSR) in non-Geneve dispatch mode
XDP Acceleration이 활성화되면 Egress Gateway 응답은 암호화되지 않아요.
어떤 트래픽이 암호화되나 (Which traffic is encrypted)
다음 표는 모드에 따라 WireGuard로 어떤 패킷이 암호화되는지를 나타내요. 표에 없는 구성이나 통신 쌍은 WireGuard 암호화 대상이 아니므로 암호화되지 않은 것으로 가정해요.
| 출발지 | 목적지 | 구성 | 암호화 모드 |
|---|---|---|---|
| Pod | remote Pod | any | default |
| Pod | remote Node | any | node-to-node |
| Node | remote Pod | any | node-to-node |
| Node | remote Node | any | node-to-node |
| Pod | remote Pod via ClusterIP Service | any | default |
| Pod | remote Pod via non ClusterIP Service (e.g., NodePort) | Socket LB | default |
| Pod | remote Pod via non ClusterIP Service | kube-proxy | node-to-node |
| Client outside cluster | remote Pod via Service | KPR, overlay routing, without DSR, without XDP | default |
| Client outside cluster | remote Pod via Service | native routing, without XDP | node-to-node |
| Client outside cluster | remote Pod or remote Node via Service | DSR in Geneve mode, without XDP | default |
| Pod | remote Pod via L7 Proxy or L7 Ingress Service | L7 Proxy / Ingress | default |
| Egress Gateway | Pod | Egress Gateway node | default |
| Egress Gateway | node | Pod | Egress Gateway without XDP |
- Pod: 비호스트 네트워크 네임스페이스에서 실행되는 Cilium 관리 K8s 파드.
- Node: Cilium을 실행하는 K8s 호스트, 또는 Cilium이 관리하는 호스트 네트워크 네임스페이스에서 실행되는 파드.
- Service: K8s Service(ClusterIP, NodePort, LoadBalancer, ExternalIP).
- Client outside cluster: K8s 클러스터 밖에서 실행되는 모든 클라이언트. 클라이언트와 노드 사이의 요청은 암호화되지 않아요. Cilium 구성(이 섹션 시작 부분의 표 참고)에 따라, 중간 노드(클라이언트 요청을 처음 받은)와 목적지 노드 사이에서만 암호화될 수 있어요.
알려진 이슈 (Known Issues)
- WireGuard 디바이스를 구성할 때 패킷이 버려져 연결 문제가 발생할 수 있어요. 이는 엔드포인트가 추가·제거되거나 노드 갱신이 발생할 때 일어나요. 어떤 경우에는
sendmsg와sendto호출 실패로 이어질 수 있어요. 자세한 내용은 GitHub issue 33159를 참고하세요.
법적 고지 (Legal)
"WireGuard"는 Jason A. Donenfeld의 등록 상표예요.