mTLS in Multi Clusters

mTLS in Multi Clusters

Kubernetes 다중 클러스터 환경에서 SPIFFE/SPIRE 기반 워크로드 아이덴티티를 발급하고, gRPC 통신에 mTLS와 상대 워크로드 검증을 적용한 학부 연구 프로젝트입니다.
담당: SPIRE 환경 구성, Federation 설정, mTLS 클라이언트/서버 구현 및 검증

1. Overview

Kubernetes 다중 클러스터 환경에서 SPIFFE/SPIRE를 활용하여 워크로드 간의 안전한 mTLS(Mutual TLS) 통신 환경을 구축하였습니다. 각 워크로드에 SVID를 자동 발급하고, 통신 상대의 아이덴티티를 검증하는 Zero-Trust 기반 통신을 구현했습니다.


SPIFFE Architecture

Architecture Diagram of mtls with SPIRE/SPIFFE


2. My Role

수행 기간담당 영역
2023-12 ~ 2024-02 (2개월)SPIRE/SPIFFE 환경 구성, 클러스터 간 Federation, mTLS 통신 구현 및 검증
  • SPIRE 환경 구성: SPIRE Server와 Agent를 두 개의 Kubernetes 클러스터에 배포/구성
  • Federation 구성: 서로 다른 Trust Domain(cluster1.org, cluster2.org) 간 연합 신뢰를 설정하여 클러스터를 넘는 아이덴티티 검증이 가능하도록 구성
  • 워크로드 아이덴티티 자동 발급: ClusterSPIFFEID CRD와 Pod Label(spiffe.io/spire-managed-identity) 기반으로 SVID 자동 발급
  • mTLS 통신 구현: go-spiffe v2로 gRPC 클라이언트/서버를 구현하고, 상대 워크로드의 SPIFFE ID를 검증한 뒤에만 통신하도록 구성

3. Design Decision: Workload API Access


SPIFFE CSI Driver Workflow

hostPath 마운트와 SPIFFE CSI Driver 방식 비교 (원본 크게 보기)

워크로드가 SVID를 받으려면 SPIRE Agent의 Workload API 소켓에 접근해야 합니다. 이 소켓을 워크로드 Pod에 노출하는 방법은 두 가지입니다.

방식내용문제
hostPath 마운트노드의 /run/secrets/workload-spiffe-uds를 Pod에 직접 마운트모든 워크로드 Pod에 hostPath 볼륨 권한이 필요. Pod Security 정책을 완화해야 함
SPIFFE CSI DriverCSI 볼륨으로 소켓 디렉터리를 read-only 마운트hostPath 권한 불필요

SPIFFE CSI Driver를 선택했습니다. 워크로드에 hostPath 권한을 주지 않고도 Workload API에 접근할 수 있고, 볼륨이 ephemeral/read-only라 Pod 종료 시 자동으로 정리되기 때문입니다.

# 워크로드 Pod: CSI 볼륨으로 Workload API 소켓 디렉터리를 마운트
env:
  - name: SPIFFE_ENDPOINT_SOCKET
    value: "unix:///tmp/spiffe-certs/socket"
volumes:
  - name: spiffe-csi
    csi:
      driver: csi.spiffe.io
      readOnly: true

주의할 점은 CSI Driver가 마운트하는 것은 SVID 파일이 아니라 Workload API 소켓 디렉터리라는 것입니다. SVID 자체는 애플리케이션이 런타임에 Workload API로 요청해 메모리에서 관리하며, 디스크에 인증서 파일이 놓이지 않습니다.

// 소켓을 통해 SVID를 받아 자동 갱신까지 관리
source, err := workloadapi.NewX509Source(ctx)

4. Peer Workload Verification

mTLS를 적용하는 것만으로는 “암호화된 통신”까지이고, 누구와 통신하는지는 별도로 통제해야 합니다.

클라이언트가 서버의 SPIFFE ID를 명시적으로 지정하고, 그 아이덴티티를 가진 워크로드와만 연결되도록 구성했습니다.

serverId := spiffeid.RequireFromString(
    "spiffe://cluster1.org/ns/default/sa/default/app/helloworld-server",
)
creds := grpc.WithTransportCredentials(
    grpccredentials.MTLSClientCredentials(
        source, source, tlsconfig.AuthorizeID(serverId),
    ))

검증은 클러스터 간 gRPC 호출에서 서버의 SPIFFE ID가 기대값과 일치할 때만 응답이 오는 것으로 확인했습니다.


5. Limitations & Next Steps

현재 구성은 Kubernetes 메타데이터(Label, Namespace, Service Account)를 Selector로 사용해 SVID를 발급합니다. 따라서 동일한 Label을 붙인 워크로드를 배포할 수 있는 권한을 가진 주체는 유효한 SVID를 받을 수 있습니다.

즉 이 구성은 통신 상대의 아이덴티티를 검증할 뿐, 워크로드 배포 권한 자체를 통제하지는 않습니다. 인증과 암호화를 적용했다는 것이 곧 모든 횡적 이동을 차단했다는 뜻은 아닙니다.

보완 방향:

  • RBAC로 특정 Service Account/Namespace만 SVID 발급 대상이 되도록 제한
  • OPA로 SVID 발급 요청에 대한 정책 정의 및 적용

6. Used Skills

  • Kubernetes (multi-cluster), VMWare
  • SPIRE / SPIFFE (Federation, ClusterSPIFFEID, SPIFFE CSI Driver)
  • go-spiffe v2, gRPC
  • MetalLB (클러스터 간 통신 경로)