LabHub

ICA — 이스티오 인증 어소시에이트 · 워크로드 보안 · 이론

신원은 IP 가 아니라 서비스어카운트다

LabHub 에서 이어서 보기

한 줄 요약

Istio 에서 워크로드의 신원은 IP 도 파드 이름도 아닌 쿠버네티스 서비스어카운트입니다. 이 사실 하나에서 mTLS, 인가 정책, 그리고 대부분의 정책 디버깅이 파생됩니다.

왜 이게 필요했나

클러스터 내부는 흔히 신뢰할 수 있는 네트워크로 취급되지만, 실제로는 파드 하나만 탈취당해도 나머지 전부에 평문으로 접근할 수 있는 평평한 네트워크입니다. 제로트러스트는 이 가정을 뒤집습니다. 문제는 이것을 애플리케이션 코드로 구현하려면 모든 서비스에 인증서 발급·갱신, 상대 검증, 권한 검사 로직을 넣어야 한다는 점입니다. 언어 스택이 여럿인 조직에서 이를 일관되게 유지하는 것은 사실상 불가능합니다.

그래서 Istio 는 세 가지(암호화, 워크로드 인증, 인가)를 인프라 계층으로 내렸습니다. 그 토대가 신원 체계입니다. IP 는 파드가 재시작하면 바뀌고 스푸핑도 가능하지만, 서비스어카운트 기반 신원은 인증서에 새겨져 핸드셰이크에서 암호학적으로 검증됩니다.

어떻게 동작하나

신원은 SPIFFE 표준 형식을 따릅니다.

spiffe://cluster.local/ns/payments/sa/payments-api         트러스트 도메인   네임스페이스  서비스어카운트

인증서 발급 흐름에서 기억할 점은 개인키가 파드를 떠나지 않는다는 것입니다. 파드 안의 istio-agent 가 키 쌍을 만들고 CSR 만 istiod 에 보냅니다. istiod 는 서비스어카운트 토큰으로 요청자를 검증한 뒤 SPIFFE ID 를 SAN 에 새긴 인증서를 서명해 돌려줍니다. 인증서는 기본 24시간 유효하고, 수명의 절반쯤 지난 시점부터 agent 가 알아서 재발급받습니다. Envoy 는 SDS 로 인증서를 받으므로 갱신에 파드 재시작이나 커넥션 드레인이 필요 없습니다.

PeerAuthentication 은 "들어오는 트래픽에 mTLS 를 어떻게 요구할 것인가"를 정합니다. PERMISSIVE(둘 다 수락, 기본값), STRICT(mTLS 만), DISABLE 셋이고, 좁은 범위가 항상 이깁니다. 워크로드 > 네임스페이스 > 메시 전역 순입니다. 메시 전역 정책은 루트 네임스페이스(보통 istio-system)에 이름 default 로 둡니다. 헬스 체크나 메시 밖 프로메테우스가 긁어가는 포트 하나만 예외를 두고 싶다면 portLevelMtls 를 씁니다.

AuthorizationPolicy 의 평가 순서는 시험에 거의 반드시 나옵니다.

1. CUSTOM  → 외부 인가기가 거부하면 즉시 거부2. DENY    → 하나라도 매칭되면 즉시 거부3. ALLOW   → 대상 워크로드에 ALLOW 정책이 하나도 없으면 허용(기본 개방)             ALLOW 정책이 하나라도 있으면 매칭되어야 허용(기본 거부로 전환)

마지막 줄이 핵심 성질입니다. ALLOW 정책을 하나 추가하는 순간 그 워크로드는 화이트리스트 모드로 뒤집힙니다. 이 성질을 이용해 spec: {} 인 빈 정책 하나로 네임스페이스 기본 거부를 만듭니다. "ALLOW 정책은 존재하지만 매칭 규칙이 없다"는 뜻이라 아무것도 통과하지 못합니다.

또 하나 자주 걸리는 함정. principals 는 mTLS 인증서에서 나오므로 평문 요청에는 principal 이 비어 있어 절대 매칭되지 않습니다. PERMISSIVE 상태에서 인가 정책을 먼저 깔면 "정책은 맞는데 계속 403"이 됩니다. STRICT 전환이 인가 설계의 전제 조건인 이유입니다.

RequestAuthentication 은 최종 사용자 토큰(JWT)을 검증합니다. 여기서 가장 흔한 오해는 이 리소스만으로는 토큰 없는 요청이 그냥 통과한다는 점입니다. "JWT 가 있다면 유효해야 한다"만 강제하기 때문입니다. 토큰을 필수로 만들려면 AuthorizationPolicy 에서 requestPrincipals 조건을 걸어야 합니다.

정책을 운영에 올릴 때는 istio.io/dry-run: "true" 애너테이션을 먼저 붙입니다. 평가만 하고 실제로 차단하지 않으면서 "켰다면 무엇이 막혔을까"를 로그와 메트릭으로 보여 줍니다. 거부 목록이 의도와 일치할 때 애너테이션을 떼는 것이 안전한 순서입니다.

현장에서 만나는 모습

저자의 홈랩에서는 노드 간 파드 트래픽을 WireGuard 로 투명하게 암호화하고 있습니다. cilium status 에는 Encryption: Wireguard [cilium_wg0 (Port: 51871, Peers: 2)] 로 찍히고, Modules Health 는 OK 92 / Degraded 0 입니다.

여기서 시험에도 나오는 중요한 구분이 생깁니다. WireGuard 는 노드 간 전송 구간 암호화이고, Istio 의 mTLS 는 워크로드 신원 증명이 붙은 애플리케이션 계층 암호화입니다. 전자는 "선을 도청해도 못 읽는다"를 보장하지만 "누가 보냈는가"는 증명하지 않습니다. AuthorizationPolicy 의 principals 가 요구하는 것은 후자입니다. 두 계층을 겹쳐 쓸 수는 있지만, 어느 쪽이 암호화를 책임지는지 팀 차원에서 하나로 정해 두지 않으면 이중 정책으로 디버깅 지옥이 열립니다.

같은 클러스터에서 얻은 또 하나의 감각은 L7 판정의 로그 모양입니다. 정책 위반 요청은 DROPPED 로, 그에 대한 403 응답은 FORWARDED 로 찍혔습니다. Istio 의 RBAC 거부도 똑같이 "연결은 성립했고 403 이 돌아온" 형태입니다. 연결 자체가 안 되는 문제와 절대 혼동하지 마세요.

다음 실습에서 할 것

전용 서비스어카운트를 붙인 워크로드를 실제로 배포한 뒤, 메시 전역 STRICT 와 워크로드 단위 포트 예외를 작성하고, 기본 거부 → 최소 권한 ALLOW → 관리 경로 DENY(dry-run) → JWT 필수화 순서로 정책을 쌓아 올립니다.