GKE에서 Workload Identity Federation을 사용하여 AWS MSK와 OSS Kafka 동기화

1. 개요: GKE와 AWS MSK 간의 안전한 Kafka 데이터 동기화

  • ✨ 이 문서의 목표: Google Kubernetes Engine (GKE) 환경에서 Strimzi MirrorMaker2를 사용하여 AWS MSK (Managed Streaming for Kafka)의 데이터를 온프레미스 또는 다른 클라우드의 OSS Kafka로 안전하게 단방향 동기화하는 방법을 안내합니다.
  • 🔑 핵심 과제 해결: GKE의 서비스 계정(GCP SA)이 AWS IAM 역할을 통해 MSK에 직접 인증하도록 Workload Identity Federation을 구성하여, AWS 액세스 키를 직접 관리하는 위험 없이 보안을 강화합니다.
  • 📚 주요 학습 내용:
    • Workload Identity Federation 설정 이해 및 구성
    • AWS MSK IAM 인증을 위한 커스텀 Strimzi MirrorMaker2 이미지 빌드
    • Strimzi MirrorMaker2를 사용하여 MSK와 OSS Kafka 간의 데이터 미러링 설정

2. 시작하기 전에: 구성 환경 및 사전 지식

  • 🛠️ 구성 환경:
    • GKE (Google Kubernetes Engine)
    • GCP SA - AWS IAM Workload Identity Federation
    • Strimzi: 0.39.0
    • Kafka: 3.5.1 (소스: AWS MSK, 타겟: OSS Kafka)
    • AWS MSK IAM Auth Plugin: aws-msk-iam-auth-2.2.0.jar
    • 필수 도구: aws-cli, kubectl, docker
  • 🧠 필요한 사전 지식:
    • Kubernetes 및 GKE 기본 운영
    • Apache Kafka 및 Strimzi 기본 개념
    • AWS IAM 역할 및 정책
    • GCP 서비스 계정 및 Workload Identity Federation 개념

3. 동기화 아키텍처 및 흐름 🌬️

  • 🎯 동기화 목표: AWS MSK에서 GKE 클러스터 내 OSS Kafka로 단방향 데이터 동기화.
  • 🔐 인증 흐름:
    1. GKE Pod (MirrorMaker2)가 GCP 서비스 계정(SA)으로 실행됩니다.
    2. GCP SA는 Workload Identity Federation을 통해 AWS IAM 역할을 수임(AssumeRole)합니다.
    3. 수임된 AWS IAM 역할의 임시 자격 증명을 사용하여 AWS MSK에 IAM 방식으로 인증 및 접근합니다.
    4. MirrorMaker2는 MSK에서 데이터를 읽어 OSS Kafka로 전송합니다.

4. 1단계: AWS 및 GCP 환경 사전 설정 ⚙️

  • 목표: GKE 워크로드가 AWS IAM 역할을 수임할 수 있도록 Workload Identity Federation을 설정합니다.
  • 4.1. AWS IAM 역할 구성
    • MSK 접근 권한을 가진 IAM 정책 생성
    • GCP SA가 수임할 수 있는 신뢰 관계를 가진 IAM 역할 생성
  • 4.2. GCP 서비스 계정(SA) 생성 및 권한 부여
    • GKE에서 사용할 GCP SA 생성
    • 생성된 GCP SA에 iam.workloadIdentityUser 역할 부여 (특정 네임스페이스의 Kubernetes SA와 바인딩)
  • 4.3. GKE Workload Identity 설정
    • GKE 클러스터에서 Workload Identity 활성화
    • GCP SA와 Kubernetes SA(KSA) 간의 IAM 정책 바인딩 설정

5. 2단계: AWS IAM 인증을 위한 커스텀 Strimzi 이미지 빌드 🐳

  • 목표: Strimzi MirrorMaker2가 AWS MSK에 IAM 방식으로 인증하는 데 필요한 AWS CLI 및 Kafka IAM Auth 플러그인을 포함하는 커스텀 이미지를 생성합니다.
  • 5.1. Dockerfile 구성

## Stage 1: Install AWS CLI
FROM public.ecr.aws/amazonlinux/amazonlinux:2 AS installer
ARG EXE_FILENAME=awscli-exe-linux-x86_64.zip

## Docker 빌드 컨텍스트 내 ./awscli/ 디렉토리에 AWS CLI zip 파일이 있다고 가정
COPY ./awscli/$EXE_FILENAME .
RUN yum update -y \
  && yum install -y unzip \
  && unzip $EXE_FILENAME \
  && ./aws/install --bin-dir /aws-cli-bin/


## Stage 2: Build custom Strimzi Kafka image
FROM quay.io/strimzi/kafka:0.39.0-kafka-3.5.1
USER root:root


## Install necessary packages and create directories
RUN microdnf update -y \
    && microdnf --setopt=install_weak_deps=0 --setopt=tsflags=nodocs install -y jq less groff-base procps \
    && microdnf clean all -y \
    && mkdir -p /home/kafka/.aws


## Copy AWS CLI from installer stage
COPY --from=installer /usr/local/aws-cli/ /usr/local/aws-cli/
COPY --from=installer /aws-cli-bin/ /usr/local/bin/


## Copy Kafka IAM Auth plugin and AWS config/credentials setup scripts
# Docker 빌드 컨텍스트 내 ./libs/ 에 IAM auth plugin jar 파일(aws-msk-iam-auth-2.2.0.jar)이 있다고 가정
COPY ./libs/aws-msk-iam-auth-2.2.0.jar /opt/kafka/libs/

## Docker 빌드 컨텍스트 내 ./aws/ 에 AWS 설정 파일 (예: config)이 있다고 가정 (선택 사항)
COPY --chown=1001:0 ./aws/ /home/kafka/.aws/

## Docker 빌드 컨텍스트 내 ./scripts/ 에 관련 스크립트가 있다고 가정 (선택 사항)
# COPY --chown=1001:0 --chmod=755 ./scripts/ /home/kafka/

USER 1001

6. 3단계: Strimzi MirrorMaker2 배포 및 설정 🚀

  • 목표: 커스텀 이미지를 사용하여 Strimzi MirrorMaker2를 GKE에 배포하고, MSK와 OSS Kafka 간의 미러링을 구성합니다.
  • 6.1. MirrorMaker2 Kubernetes Manifest (YAML)
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaMirrorMaker2
metadata:
  name: msk-to-oss-kafka-mm2
  namespace: kafka-mm2 # 이 네임스페이스에 KSA가 Workload Identity로 GCP SA와 연결되어 있어야 함
spec:
  version: 3.5.1 # Kafka 버전
  image: registry.my.repo/strimzi/custom-mirrormaker2:dev # 5단계에서 빌드한 이미지
  replicas: 1
  connectCluster: gcp-oss-kafka # 타겟 Kafka 클러스터 alias (아래 clusters 정의와 일치)

  clusters:
  - alias: aws-msk # 소스 MSK 클러스터
    bootstrapServers: YOUR_MSK_BOOTSTRAP_SERVERS:9098 # 예: b-1.xxxx.xxxx.kafka.ap-northeast-2.amazonaws.com:9098
    config:
      group.id: msk-oss-kafka-mm2
      config.storage.topic: mm2-configs # MirrorMaker2 내부용 설정 토픽
      offset.storage.topic: mm2-offsets # MirrorMaker2 내부용 오프셋 토픽
      status.storage.topic: mm2-status # MirrorMaker2 내부용 상태 토픽
      # AWS MSK IAM 인증 설정
      security.protocol: SASL_SSL
      sasl.mechanism: AWS_MSK_IAM
      sasl.jaas.config: "software.amazon.msk.auth.iam.IAMLoginModule required awsProfileName=\"default\" awsDebugCreds=true;"
      sasl.client.callback.handler.class: software.amazon.msk.auth.iam.IAMClientCallbackHandler
      # plugin.path는 Strimzi가 /opt/kafka/libs 아래의 JAR를 자동으로 로드하므로 일반적으로 불필요

  - alias: gcp-oss-kafka # 타겟 OSS Kafka 클러스터
    bootstrapServers: gcp-oss-kafka.your-namespace.svc.cluster.local:9092 # 예시: GKE 내부 Kafka 서비스 주소
    config:
      group.id: msk-oss-kafka-mm2
      config.storage.topic: mm2-configs
      offset.storage.topic: mm2-offsets
      status.storage.topic: mm2-status
      config.storage.replication.factor: 1 # 환경에 맞게 조정
      offset.storage.replication.factor: 1 # 환경에 맞게 조정
      status.storage.replication.factor: 1 # 환경에 맞게 조정
      # 타겟 클러스터가 인증을 사용한다면 관련 security.protocol, sasl.* 설정 추가

  mirrors:
  - sourceCluster: aws-msk
    targetCluster: gcp-oss-kafka
    topicsPattern: "copy-target-topic" # 동기화할 토픽 패턴 (정규식 가능)
    # groupsPattern: ".*" # 소비자 그룹 오프셋 동기화 시 (필요시 주석 해제)
    sourceConnector: # Source -> Target 데이터 복제 설정
      # tasksMax: 1 # 병렬 작업 수 (기본값 사용 또는 필요시 조정)
      config:
        replication.factor: -1 # 타겟 클러스터의 브로커 기본값 사용
        refresh.topics.interval.seconds: 60
        sync.topic.acls.enabled: "false" # ACL 동기화 비활성화
    # checkpointConnector: # Target -> Source 오프셋 동기화 (단방향에서는 보통 불필요)
    #   config:
    #     sync.group.offsets.enabled: "false"

  template:
    pod:
      imagePullSecrets:
      - name: my-repo-secret # 커스텀 이미지 레지스트리 접근 시크릿
      serviceAccountName: ksa-for-mirrormaker # 4.3에서 설정한 Kubernetes 서비스 계정
    connectContainer:
      env:
      - name: AWS_ROLE_ARN
        value: arn:aws:iam::{YOUR_AWS_ACCOUNT_ID}:role/your-msk-access-role # 4.1에서 생성한 IAM 역할 ARN
      - name: AWS_WEB_IDENTITY_TOKEN_FILE # Workload Identity가 주입하는 토큰 경로
        value: /var/run/secrets/sts.amazonaws.com/serviceaccount/token
      # - name: AWS_STS_REGIONAL_ENDPOINTS # 리전 엔드포인트 사용 시 (예: regional)
      #   value: "regional"

  # metricsConfig: # JMX Prometheus Exporter 설정 (선택 사항)
  #   type: jmxPrometheusExporter
  #   valueFrom:
  #     configMapKeyRef:
  #       key: metrics-config.yml
  #       name: mirror-maker-2-metrics

  # rack: # GKE Zone 인식을 위한 설정 (선택 사항)
  #   topologyKey: topology.gke.io/zone
  • 6.2. YAML 파일 배포
    • kubectl apply -f mirrormaker2.yaml -n kafka-mm2
  • 6.3. 배포 확인 및 트러블슈팅
    • Pod 로그 확인: kubectl logs -f <mm2-pod-name> -n kafka-mm2 -c kafka
    • IAM 인증 오류, Kafka 연결 오류 등 확인

7. 추가 고려 사항 및 FAQ 🤔

  • 🔒 보안:
    • IAM 역할 권한 최소화 원칙 준수
    • GCP SA 및 KSA 권한 범위 제한
  • ⚡ 성능:
    • replicas, tasksMax 등 파라미터 튜닝
    • 네트워크 대역폭 및 지연 시간 고려

❓ FAQ:

  • Q: awsProfileName="default" 설정은 어떻게 동작하나요?
    • A: Docker 이미지 내 /home/kafka/.aws/config 파일에 [profile default] 섹션이 정의된 경우 이를 참조할 수 있습니다. Workload Identity Federation 사용 시에는 AWS_ROLE_ARNAWS_WEB_IDENTITY_TOKEN_FILE 환경 변수를 통해 AWS SDK가 자동으로 자격 증명을 얻으므로, 복잡한 프로필 설정이 필수는 아닙니다. awsDebugCreds=true 옵션은 인증 과정을 디버깅하는 데 도움이 됩니다.
  • Q: GCP_OAUTH_AUD 환경 변수 설정이 필요한가요?
    • A: AWS_WEB_IDENTITY_TOKEN_FILE 환경 변수를 사용하면 일반적으로 AWS SDK가 토큰의 audience를 자동으로 인식하여 GCP_OAUTH_AUD를 명시적으로 설정할 필요가 없습니다. 만약 문제가 발생하거나 특정 audience를 지정해야 한다면, GCP Workload Identity Pool Provider 설정에서 확인된 audience 값을 사용해야 합니다. 대부분의 경우, 이 변수 없이 정상 동작합니다.
  • Q: plugin.path 설정이 KafkaMirrorMaker2 YAML에 필요 없는 이유는 무엇인가요?
    • A: Strimzi Kafka 이미지는 기본적으로 /opt/kafka/libs 디렉토리를 플러그인 경로로 인식합니다. Dockerfile에서 aws-msk-iam-auth-2.2.0.jar 파일을 해당 위치에 복사했으므로 MirrorMaker2가 자동으로 플러그인을 로드합니다. 따라서 명시적인 plugin.path 설정은 생략 가능합니다.