CKS — 쿠버네티스 보안 전문가 · 전송 암호화, 업그레이드, 호스트 OS 최소화 · 이론
선 위의 암호화, 시간 위의 취약점, 노드 위의 표면
한 줄 요약
파드 사이의 트래픽을 암호화하는 방법은 둘입니다 — Cilium 의 투명 암호화는 노드 커널에서 WireGuard·IPsec 으로 감싸고, Istio 의 mTLS 는 파드 안의 사이드카에서 종단됩니다. 지원이 끝난 버전을 돌리는 것은 CVE 수정을 못 받겠다는 뜻이라 업그레이드 자체가 보안 항목이고, 노드 OS 는 kubelet·런타임·CNI 를 돌리는 데 필요한 것만 남기는 것이 원칙입니다.
왜 이게 필요했나
NetworkPolicy 는 누가 누구에게 연결할 수 있는가만 정합니다. 연결이 허용된 뒤 선 위를 지나는 바이트는 평문입니다. 같은 노드 안이라면 노드에서 다 보이니 암호화가 무의미하지만, 노드와 노드 사이는 물리 스위치·클라우드 가상 네트워크·다른 테넌트의 장비를 지납니다. [보안 점검표](https://kubernetes.io/docs/concepts/security/security-checklist/) 는 "모든 CNI 플러그인이 전송 중 암호화를 제공하지는 않으며, 선택한 플러그인에 그 기능이 없다면 서비스 메시가 대안" 이라고 적습니다. 그래서 CKS 는 Cilium 과 Istio 두 길을 묻습니다.
업그레이드가 보안 항목인 이유는 시간에 있습니다. 취약점은 고쳐진 버전으로만 막을 수 있고, 프로젝트는 최근 세 개 minor 만 패치합니다. 그 창을 벗어난 클러스터는 CVE 가 공개되어도 받을 수정본이 없습니다. 노드 OS 도 같은 원리입니다. 설치된 서비스·패키지·커널 모듈 하나하나가 공격자가 두드릴 수 있는 문이고, 쓰지 않는 문은 없애는 것이 가장 싼 방어입니다.
어떻게 동작하나
Cilium 투명 암호화 — 노드 커널에서
[Cilium 투명 암호화](https://docs.cilium.io/en/stable/security/network/encryption/) 문서에 따르면 Cilium 은 Cilium 이 관리하는 엔드포인트 사이의 트래픽을 IPsec 또는 WireGuard 로(그리고 베타로 ztunnel 로) 암호화합니다. 애플리케이션은 아무것도 모릅니다. 암호화와 복호화가 노드의 커널 데이터패스에서 일어나기 때문입니다.
[WireGuard](https://docs.cilium.io/en/stable/security/network/encryption-wireguard/) 를 켜면 각 노드의 에이전트가 자기 키 쌍을 만들고, 공개키를 CiliumNode 오브젝트의 network.cilium.io/wg-pub-key 어노테이션으로 알립니다. 다른 노드들은 그 공개키로 그 노드와의 터널을 세웁니다. 터널 엔드포인트는 UDP 51871 이라 방화벽이 있는 환경에서는 노드끼리 이 포트가 열려야 하고, 터널 라우팅 모드에서는 VXLAN·Geneve 로 한 번 감싼 패킷을 WireGuard 가 한 번 더 감쌉니다. 헬름 값은 encryption.enabled=true, encryption.type=wireguard 이고, 노드 사이·노드와 파드 사이 트래픽까지 넣으려면 encryption.nodeEncryption=true 를 더합니다. 커널이 WireGuard 를 지원해야 합니다(리눅스 5.6 이상은 내장).
[IPsec](https://docs.cilium.io/en/stable/security/network/encryption-ipsec/) 은 키를 쿠버네티스 Secret 으로 배포하고, 노드 사이에 ESP 트래픽이 흐르므로 보안 그룹이나 방화벽에서 ESP 를 열어야 합니다. Cilium 1.18 부터는 터널 모드에서 오버레이 캡슐화 뒤에 IPsec 을 적용해 정책용 보안 식별자까지 선 위에서 암호화됩니다. 문서가 밝힌 한계도 있습니다 — 다른 CNI 위에 체이닝한 구성에서는 지원되지 않고, IPsec 복호화는 터널당 CPU 코어 하나로 제한됩니다.
두 방식에 공통된 성질이 둘 있습니다. 첫째, 같은 노드로 가는 패킷은 암호화하지 않습니다. 노드에서 원문을 볼 수 있으니 의미가 없다는 설계입니다. 둘째, 암호화 여부는 정책 집행과 같은 방식으로 "목적지가 원격 Cilium 엔드포인트인가" 를 판단해 결정하므로, 새 엔드포인트의 정보가 아직 퍼지지 않은 짧은 순간에는 첫 패킷이 평문으로 나갈 수 있습니다. 문서는 대책으로 reserved:world 로의 egress 를 막는 정책이나 encryption.strictMode 를 제시합니다.
Istio mTLS — 파드 안 사이드카에서
[Istio 보안 개념](https://istio.io/latest/docs/concepts/security/) 문서의 흐름은 이렇습니다. 클라이언트의 요청은 파드 안의 사이드카 Envoy 로 돌려지고, 클라이언트 Envoy 가 서버 Envoy 와 mTLS 핸드셰이크를 하면서 secure naming 검사로 서버 인증서의 서비스 어카운트가 그 서비스를 운영할 권한이 있는지 확인합니다. 연결이 서면 서버 Envoy 가 요청을 인가하고, 통과하면 로컬 TCP 로 백엔드에 넘깁니다. 최소 TLS 버전은 1.2 입니다. 즉 암호화는 양쪽 사이드카 사이에서만 유효하고, 애플리케이션 컨테이너와 자기 사이드카 사이는 파드 안의 평문 loopback 입니다.
기본 모드는 PERMISSIVE 라 평문과 mTLS 를 모두 받습니다. 사이드카가 없는 클라이언트를 점진적으로 옮기기 위한 설계입니다. 전부 옮긴 뒤에는 [PeerAuthentication](https://istio.io/latest/docs/reference/config/security/peer_authentication/) 을 STRICT 로 바꿔 평문을 거부합니다.
apiVersion: security.istio.io/v1kind: PeerAuthenticationmetadata: name: default namespace: foospec: mtls: mode: STRICT메시 전체에 걸려면 루트 네임스페이스에 두고, 워크로드별로는 selector 를, 포트별 예외는 portLevelMtls 를 씁니다. [mTLS 이전](https://istio.io/latest/docs/tasks/security/authentication/mtls-migration/) 작업 문서의 결과가 이 차이를 보여 줍니다 — STRICT 를 건 뒤 사이드카 없는 legacy 네임스페이스에서 온 curl 만 실패합니다. 앰비언트 모드에서는 사이드카 대신 노드의 ztunnel 이 HBONE 프로토콜로 mTLS 를 맡고, 그래서 DISABLE 모드가 지원되지 않습니다.
Istio 의 [보안 모범 사례](https://istio.io/latest/docs/ops/best-practices/security/) 는 mTLS 의 한계를 분명히 적습니다. mTLS 는 인증이지 인가가 아니므로 유효한 인증서를 가진 누구나 서비스에 닿을 수 있고, 잠그려면 AuthorizationPolicy 를 default-deny 패턴으로 두어야 합니다. 사이드카는 TCP 만 가로채며 UDP·ICMP 는 지나가고, 22번 같은 몇몇 포트는 inbound 캡처에서 빠지며, 애플리케이션과 사이드카가 같은 네트워크·프로세스 네임스페이스에 있으므로 애플리케이션이 리다이렉션 규칙을 지워 사이드카를 우회할 수 있습니다. 그래서 문서는 NetworkPolicy 를 함께 두는 심층 방어를 권합니다.
| 비교 | Cilium 투명 암호화 | Istio mTLS |
| --- | --- | --- |
| 종단 지점 | 노드 커널 (WireGuard/IPsec) | 파드 안 사이드카 Envoy (앰비언트는 노드 ztunnel) |
| 애플리케이션 변경 | 없음 | 없음 (사이드카 주입 필요) |
| 신원 | 노드 키 (노드 단위) | 워크로드 서비스 어카운트 인증서 (워크로드 단위) |
| 인가와의 결합 | NetworkPolicy 와 별개 | AuthorizationPolicy 로 워크로드·요청 단위 인가 가능 |
| 범위 | Cilium 관리 엔드포인트 간 모든 L3 트래픽 | 사이드카가 가로챈 TCP 트래픽 |
업그레이드가 보안 항목인 이유
[패치 릴리스](https://kubernetes.io/releases/patch-releases/) 문서에 따르면 패치는 보통 매달 나오고, 각 minor 는 약 14개월 동안 지원됩니다 — 12개월의 표준 기간 뒤 2개월의 유지보수 모드에서는 CVE 가 배정된 취약점·의존성·핵심 구성요소 문제만 고칩니다. [버전 스큐 정책](https://kubernetes.io/releases/version-skew-policy/) 은 최근 세 minor 브랜치에만 보안 수정이 백포트된다고 적습니다. 지원 창을 벗어난 클러스터는 취약점이 공개돼도 받을 수정본이 없고, 그 상태로 남아 있는 것 자체가 결함입니다. [클러스터 보안](https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/) 문서는 보안 공지를 받도록 kubernetes-announce 그룹에 가입하라고 하고, kubeadm 인증서 문서는 최신 패치로 즉시 올리고 지원되는 minor 를 유지하는 것이 안전을 지키는 방법이라고 적습니다.
스큐 정책이 업그레이드 순서를 정하는 것도 보안과 연결됩니다. minor 를 건너뛸 수 없으므로 두 버전 뒤처진 클러스터는 두 번의 업그레이드를 거쳐야 하고, 미루는 만큼 따라잡는 비용이 커집니다. 업그레이드를 정기 작업으로 두어야 하는 이유입니다.
호스트 OS 최소화
쿠버네티스 문서가 노드 OS 에 대해 직접 말하는 것은 경계에 관한 것들입니다. [클러스터 보안](https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/) 문서는 kubelet 이 기본적으로 인증 없는 접근을 허용하므로 운영 클러스터는 kubelet 인증·인가를 켜야 하고, etcd 는 API 서버만 닿을 수 있게 방화벽 뒤에 격리하며, 클라우드 메타데이터 API 로의 파드 접근을 제한하고, 쓰지 않는 알파·베타 기능은 끄고, 자격 증명은 짧은 수명으로 자주 교체하라고 합니다. [보안 점검표](https://kubernetes.io/docs/concepts/security/security-checklist/) 는 API 서버·kubelet API·etcd 를 인터넷에 노출하지 말고, 민감도가 다른 워크로드는 노드를 나누어 배치하라고 적습니다.
그 위에 얹는 OS 하드닝의 원칙은 kubelet·컨테이너 런타임·CNI 를 돌리는 데 필요하지 않은 것은 두지 않는다입니다. 필요 없는 서비스와 패키지는 지웁니다 — 돌고 있지 않은 데몬은 취약점이 있어도 공격 표면이 아니고, 설치되지 않은 패키지는 패치할 필요도 없습니다. SSH 는 OpenSSH 의 [sshd_config](https://man.openbsd.org/sshd_config) 설명서에 따르면 PermitRootLogin 의 기본값이 prohibit-password 이고 PasswordAuthentication 의 기본값은 yes 이므로, 노드에서는 비밀번호 인증을 끄고 키 인증만 남기는 것이 통상의 설정입니다. 커널 모듈은 [커널 sysctl 문서](https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html) 의 kernel.modules_disabled 로 적재를 막을 수 있는데, 한 번 1 로 두면 모듈을 넣을 수도 뺄 수도 없고 되돌릴 수도 없으므로 필요한 모듈(런타임·CNI 가 쓰는 것)을 전부 올린 뒤에만 켭니다. 이 절의 SSH 와 커널 모듈 항목은 쿠버네티스 문서가 아니라 각 도구의 공식 설명서를 근거로 한 것이며, 어느 패키지를 지울지는 배포판과 CNI 에 따라 다르므로 여기서 목록을 정하지 않습니다.
현장에서 만나는 모습
STRICT 를 켰더니 모니터링이 끊겼다. 사이드카가 없는 Prometheus 가 메시 안 워크로드를 긁고 있었다면 STRICT 전환과 함께 스크레이프가 실패합니다. Istio 이전 문서가 말하는 절차 — PERMISSIVE 상태에서 평문으로 들어오는 클라이언트를 대시보드로 찾아내고, 전부 옮긴 뒤 네임스페이스 단위로 잠그기 — 를 건너뛴 결과입니다.
Cilium WireGuard 를 켰는데 노드 간 통신이 끊겼다. 클라우드 보안 그룹에 UDP 51871 이 없으면 터널이 서지 않습니다. IPsec 이면 ESP 입니다. 암호화를 켜는 것은 헬름 값 두 줄이지만, 그 값이 요구하는 포트를 네트워크 팀과 맞추지 않으면 파드 네트워크 전체가 멈춥니다.
다음 퀴즈에서 확인할 것
퀴즈에서는 두 암호화 방식의 종단 지점 차이, 같은 노드 트래픽의 처리, PERMISSIVE 와 STRICT 의 차이, mTLS 가 대신하지 못하는 것, 패치 지원 기간, 그리고 modules_disabled 의 성질을 묻습니다.