AWS 기술 블로그

IAM을 활용하여 Amazon MSK 주제 접근 제어하기

배경

현대의 많은 기업과 서비스에서 Apache Kafka의 사용은 빠른 시간 내에 굉장히 보편화되었고, 그 목적과 중요도에 따라 높은 확장성과 고가용성을 요구합니다. Apache Kafka와 같이 분산 환경에서 실행되는 이벤트 브로커는 다양한 팀과 사용자가 같이 사용하는 형태이기에 보안은 굉장히 중요합니다. 하지만 이를 관리해야 하는 관리자의 입장에서는 이러한 요구 사항을 만족시키며 설정하는 것은 Apache Kafka에 대한 깊은 수준의 이해도와 경험을 요구하고, 초기 설정 이후에도 지속적으로 변경되는 설정을 적용해야 하는 번거로움이 발생할 수 있습니다. 또한, Apache Kafka 뿐만 아니라 보안, 인증 및 인가 등에 대한 이해도 동시에 요구합니다.

Amazon Managed Streaming for Apache Kafka(Amazon MSK)는 Apache Kafka 인프라와 운영을 관리하는 AWS 스트리밍 데이터 서비스로서, Apache Kafka 운영 관련 전문 지식이 없는 개발자 및 DevOps 관리자도 손쉽게 AWS에서 Apache Kafka 애플리케이션과 Kafka Connect 커넥터를 실행할 수 있도록 지원합니다. Amazon MSK는 Apache Kafka 클러스터를 운영, 유지 관리, 크기 조정하고, 즉시 사용 가능한 엔터프라이즈급 보안 기능을 제공하며, 스트리밍 데이터 애플리케이션 개발 속도를 높여 주는 내장 AWS 통합 기능을 제공합니다. 시작하기 위해서는 기존 Apache Kafka 워크로드와 Kafka Connect 커넥터를 Amazon MSK로 마이그레이션하거나, 클릭 몇 번으로 새 워크로드를 처음부터 구축할 수도 있습니다. 클러스터 내 트래픽에는 데이터 전송 요금이 부과되지 않으며 약정 또는 선불 지급이 필요하지 않습니다. 사용한 리소스에 대해서만 지불하면 됩니다.

위와 같은 이유로 Amazon MSK의 활용도 증가하고 있는데, 고객의 상황에 따라 비용과 사용량을 고려하여 싱글 클러스터로 사용하는 경우도 많습니다. 이때 주제별로 접근을 제어하고자 하는 요구 사항을 빈번하게 확인할 수 있었습니다. Amazon MSK를 사용하는 고객의 경우 AWS Identity and Access Management (IAM) 역할 혹은 정책을 활용하여 이를 제어할 수 있습니다.

Amazon MSK 접근 제어 방법

Amazon MSK에서 지원하는 접근 제어 방법은 아래 그림과 같이 네 가지입니다.

Unauthenticated 접근은 아무런 인증을 거치지 않기 때문에, Apache Kafka의 기본 포트인 9092를 통해 모든 리소스에 접근이 가능하고 액션이 가능합니다. 이런 상황에서는 Apache Kafka 클러스터를 사용하는 다수의 사용자 중에 누군가가 주제를 추가하거나 삭제할 수 있기 때문에, Unauthenticated 접근을 사용하는 것에는 운영 상의 리스크가 있습니다. 이를 제한하기 위해 Apache Kafka ACL을 활용하여 이러한 권한을 제어하여, 권한이 없는 사람의 주제를 추가하거나 삭제하는 것을 막을 수 있습니다. Amazon MSK에서 ZooKeeper에 대한 접근을 제공하므로 Amazon MSK에서도 Kafka ACL을 활용하는 방법으로 접근 관리가 가능합니다. 이러한 제어 작업은 그렇게 크지 않은 클러스터에서도 생각보다 다양한 관리 업무를 가중시킬 수 있습니다. 그래서 이번 게시글에서는 IAM을 활용하여 접근을 관리하는 것을 공유하고자 합니다.

위 내용 외에도 일반적으로 오픈소스로 Apache Kafka 클러스터를 운영하는 경우 흔히 사용하는 SASL/SCRAM 인증 방식을 통해 username, password 인증을 사용합니다. AWS 환경에서는 AWS Secrets Manager를 활용하여 이러한 인증 방법을 활용할 수 있습니다. 또한 CA를 활용하여 인증할 수 있는데, 이 때에는 AWS Certificate Manager (ACM)을 활용할 수 있습니다. Amazon MSK에서는 이렇게 다양한 접근 제어 옵션을 제공하고 있어서, 원하는 형태로 사용하면 됩니다. (*단, Amazon MSK Serverless의 경우 IAM 접근만 지원합니다.)

이러한 접근 제어 방법에 따라 아래와 같이 엔드포인트의 포트 번호가 달라지니 유의해서 확인이 필요합니다.

Authentication type Port
Plaintext 9092
IAM 9098
SASL/SCRAM 9096
TLS 9094

Amazon MSK를 위한 IAM 접근 제어를 사용하면 MSK 클러스터에 대한 인증과 권한 부여를 모두 처리할 수 있습니다. 이렇게 하면 인증에 한 메커니즘을 사용하고 권한 부여에 다른 메커니즘을 사용할 필요가 없습니다. 예를 들어 클라이언트가 클러스터에 쓰기를 시도할 때 Amazon MSK는 IAM을 사용하여 해당 클라이언트가 인증된 자격 증명인지 여부와 클러스터에 생성할 수 있는 권한이 있는지 여부를 확인합니다. Amazon MSK는 접근 이벤트를 기록하므로 이를 감사할 수 있습니다. 자세한 내용은 AWS CloudTrail을 사용하여 API 호출 로깅 섹션을 참조하세요.

IAM 접근 제어를 가능하게 하기 위해 Amazon MSK는 Apache Kafka 소스 코드를 약간 수정하였습니다. 이러한 수정 사항으로 인해 Apache Kafka 환경이 눈에 띄게 달라지지는 않습니다. 다만 이 IAM 접근 제어는 Apache ZooKeeper 노드에는 적용되지 않습니다. 이러한 노드에 대한 접근을 제어하는 방법에 대한 자세한 내용은 Apache ZooKeeper에 대한 접근 제어 섹션을 참조하세요. 클러스터에서 IAM 접근 제어를 사용하는 경우에는 Apache Kafka 설정 중 allow.everyone.if.no.acl.found이 적용되지 않습니다. IAM 접근 제어를 사용하는 MSK 클러스터에 대해 Apache Kafka ACL API를 호출할 수 있습니다. 그러나 Apache ZooKeeper에 저장된 Apache Kafka ACL은 IAM 역할에 대한 권한 부여에 영향을 미치지 않습니다. 따라서 IAM 정책을 사용하여 IAM 역할에 대한 접근을 제어해야 합니다.

IAM 접근 제어를 사용하는 Amazon MSK 클러스터 생성

아래와 같이 IAM을 선택하고, 클러스터를 생성합니다. IAM role-based 인증을 선택하지 않고 클러스터를 프로비저닝 후에 IAM role-based 인증으로 바꿀 수 없으며, 반대로 IAM role-based 인증으로 생성하고 추후에 IAM 접근을 삭제할 수는 없습니다.

IAM 접근 제어를 위한 클라이언트 구성

먼저 CLI로 IAM을 통한 접근을 하려면 client.properties 파일을 추가합니다.

#client.properties
ssl.truststore.location= /tmp/kafka.client.truststore.jks
security.protocol=SASL_SSL
sasl.mechanism=AWS_MSK_IAM
sasl.jaas.config=software.amazon.msk.auth.iam.IAMLoginModule required;
sasl.client.callback.handler.class=software.amazon.msk.auth.iam.IAMClientCallbackHandler

여기에 나오는 내용을 살펴보면 보안 프로토콜은 SASL_SSL을 사용하고, SASL 메커니즘이 AWS_MSK_IAM을 사용한다고 적어주면 됩니다. sasl.jaas.config에서는 software.amazon.msk.auth.iam.IAMLoginModule required; 내용을 포함해서 IAMLoginModule을 활용하고, callback handler로 IAMClientCallbackHandler를 사용합니다. IAM이 아닌 경우 이러한 Callback handler를 준비해야 되는데, IAM 접근 제어를 사용할 때 이를 바로 사용하면 되기 때문에 편리합니다.

안정적인 최신 aws-msk-iam-auth JAR 파일을 다운로드하여 클래스 경로에 배치합니다. Maven/Gradle을 사용하는 경우, 필요에 따라 버전 번호를 조정하여 다음 종속성을 추가합니다.

Amazon MSK 클라이언트 플러그인은 Apache 2.0 라이선스에 따라 오픈 소스로 제공됩니다.

#maven
<dependency>
    <groupId>software.amazon.msk</groupId>
    <artifactId>aws-msk-iam-auth</artifactId>
    <version>2.0.2</version>
</dependency>
#gradle
implementation group: 'software.amazon.msk', name: 'aws-msk-iam-auth', version: '2.0.2'

권한 부여 정책 생성

권한 부여 정책을 클라이언트에 해당하는 IAM 역할에 연결합니다. 권한 부여 정책에서 역할에 대해 허용하거나 거부할 작업을 지정합니다. 클라이언트가 Amazon EC2 인스턴스를 사용하는 경우 권한 부여 정책을 해당 Amazon EC2 인스턴스의 IAM 역할에 연결합니다. 또는 명명된 프로필을 사용하도록 클라이언트를 구성한 다음 권한 부여 정책을 해당 명명된 프로필의 역할과 연결할 수 있습니다. IAM 접근 제어를 위한 클라이언트 구성에서는 명명된 프로필을 사용하도록 클라이언트를 구성하는 방법에 대해 설명합니다.

IAM 자격 증명 기반 정책을 사용하면 허용되거나 거부되는 작업과 리소스뿐 아니라 작업이 허용되거나 거부되는 조건을 지정할 수 있습니다. Amazon MSK는 특정 작업, 리소스, 조건 키를 지원합니다. JSON 정책에서 사용하는 모든 요소에 대해 알고 싶다면 IAM 사용 설명서의 IAM JSON 정책 요소 참조를 확인하세요.

클라이언트가 IAM 접근 제어를 사용하는 MSK 클러스터와 통신할 수 있도록 하려면 두 가지 API에 대한 인증 및 권한에 대한 이해가 필요합니다. 아래 그림에서처럼 IAM 정책에서 MSK와 Apache Kafka APIs for MSK 두 가지 내용을 확인할 수 있습니다. 이 둘의 구분은 MSK는 클러스터에 대한 생성, 수정, 삭제 등과 관련된 권한이고, kafka:으로 시작합니다. 주제와 같이 클러스터의 리소스에 대한 권한은 Apache Kafka APIs for MSK를 활용해야 하는데 이는 kafka-cluster:으로 시작합니다.

아래와 같이 리전, 클러스터 이름, 클러스터 uuid, 주제 등을 지정해줄 수 있습니다. 지정하지 않고, Any로 허용하고 싶은 경우에는 *를 사용하면 됩니다.

IAM 접근 제어를 위한 부트스트랩 브로커 가져오기

IAM 접근을 활성화한 후, 콘솔에서 클러스터 요약 – 클라이언트 정보 보기에서 아래와 같이 부트스트랩 서버의 엔드포인트가 9098 포트로 제공되는 것을 확인할 수 있습니다.

콘솔이 아닌 CLI나 API를 활용하여 부트스트랩 서버를 가져오는 방법은 Amazon MSK 클러스터를 위한 부트스트랩 브로커 가져오기 섹션을 참조하시면 됩니다.

리소스

다음 표에는 Amazon MSK를 위한 IAM 접근 제어를 사용할 때 권한 부여 정책에 사용할 수 있는 4가지 유형의 리소스를 보여줍니다. 클러스터 Amazon 리소스 이름(ARN)은 AWS Management Console, DescribeCluster API 또는 describe-cluster AWS CLI 명령을 사용하여 가져올 수 있습니다. 그런 다음 클러스터 ARN을 사용하여 주제, 그룹, 트랜잭션 ID ARN을 구성할 수 있습니다. 권한 부여 정책에서 리소스를 지정하려면 해당 리소스의 ARN을 사용합니다.

리소스 ARN 형식
클러스터 arn:aws:kafka:region:account-id:cluster/cluster-name/cluster-uuid
주제 arn:aws:kafka:region:account-id:topic/cluster-name/cluster-uuid/topic-name
그룹 arn:aws:kafka:region:account-id:group/cluster-name/cluster-uuid/group-name
트랜잭션 ID arn:aws:kafka:region:account-id:transactional-id/cluster-name/cluster-uuid/transactional-id

데모 소개

이번 게시글에서 소개하는 아키텍처는 아래 그림과 같습니다. 하나의 VPC에 Kafka 브로커를 3대로 하기 위해 가용영역을 3개로 하여 각 가용영역에 브로커가 1대씩 위치하게 했습니다. 왼쪽 가용영역(AZ-1)의 Kafka 클라이언트는 모든 주제에 접근이 가능한 권한을 가졌고, 가운데 가용영역(AZ-2)는 특정 주제에만 접근할 수 있게 권한을 적용했습니다.

IAM 접근 제어를 사용하기 위해 client.properties (데모에서는 client_iam.properties 이름으로 사용) 파일은 아래와 같이 적용했습니다.

ssl.truststore.location의 값을 지정하지 않고 주석 처리하고, Java 프로세스에서 기본 인증서를 사용합니다.

#client_iam.properties
# ssl.truststore.location=<PATH_TO_TRUST_STORE_FILE>
security.protocol=SASL_SSL
sasl.mechanism=AWS_MSK_IAM 
sasl.jaas.config=software.amazon.msk.auth.iam.IAMLoginModule required; 
sasl.client.callback.handler.class=software.amazon.msk.auth.iam.IAMClientCallbackHandler

권한 부여 정책을 아래와 같이 구분하여 설정합니다.

아래 정책은 전체 클러스터에 모든 액션을 할 수 있는 슈퍼 유저 권한입니다.

#iam_policy_full_access
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "kafka-cluster:*",
                "kafka-cluster:AlterGroup",
                "kafka:*",
                "kafka-cluster:AlterTopic",
                "kafka-cluster:ReadData",
                "kafka-cluster:DescribeTopic",
                "kafka-cluster:DescribeGroup",
                "kafka-cluster:Connect",
                "kafka-cluster:WriteData"
            ],
            "Resource": "*"
        }
    ]
}

아래 정책은 위 정책과 비교해서 kafka:*는 동일하게 모든 권한을 부여했지만, kafka-cluster: 액션 내용 중 세 가지 주제에 대해서만 권한을 허용해주었습니다.

#iam_policy_limited_access
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "kafka:*",
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "kafka-cluster:*",
                "kafka-cluster:ReadData",
                "kafka-cluster:DescribeTopic",
                "kafka-cluster:DescribeGroup"
            ],
            "Resource": [
                "arn:aws:kafka:*:031273582910:topic/*/*/iam-access-topic",
                "arn:aws:kafka:*:031273582910:topic/*/*/__consumer_offsets",
                "arn:aws:kafka:*:031273582910:topic/*/*/__amazon_msk_canary",
                "arn:aws:kafka:*:031273582910:group/*/*/*",
                "arn:aws:kafka:*:031273582910:cluster/*/*",
                "arn:aws:kafka:*:031273582910:transactional-id/*/*/*"
            ]
        }
    ]
}

동일한 CLI를 활용했지만 첫 번째 그림에서는 모든 주제를 조회하고, 두 번째 그림에서는 normal-topic을 조회하지 못하는 모습입니다.

#Topic_list_check
./kafka-topics.sh --bootstrap-server $BS_IAM --command-config /tmp/client_iam.properties --list


Kafka-console-producer/consumer를 활용해서 간단한 pub/sub 테스트를 해보겠습니다.

콘솔 프로듀서를 활용해서 iam-access-topic에 메시지를 몇 개 보내봤습니다.

#Producer_commands
./kafka-console-producer.sh --bootstrap-server $BS_IAM --producer.config /tmp/client_iam.properties --topic {topic_name}


첫 번째 그림에서는 iam-access-topic에 대한 권한을 가지고 있기 때문에, 콘솔 컨슈머는 정상적으로 메시지를 수신하고 있습니다.

반면 주제 리스트에서 조회할 수 없었던 normal-topic을 조회하는 경우, 아래와 같이 메시지가 조회되지 않고 에러가 발생합니다.

#Consumer_commands
./kafka-console-consumer.sh --bootstrap-server $BS_IAM --consumer.config /tmp/client_iam.properties --topic {topic_name}

위와 같이 CLI를 통해 특정 주제에만 접근 제어가 잘 되는 것을 확인했습니다.

Spring Boot를 사용하는 사용자의 경우 아래의 내용으로 이러한 내용을 동일하게 설정할 수 있습니다.

#application.yml
spring:
  kafka:
    bootstrap-servers: "<bootstrap-servers-iam-endpoint>"
    security:
      protocol: SASL_SSL
    properties:
      sasl:
        mechanism: AWS_MSK_IAM
        jaas:
          config: "software.amazon.msk.auth.iam.IAMLoginModule required;"
        client:
          callback:
            handler:
              class: software.amazon.msk.auth.iam.IAMClientCallbackHandler

결론

Amazon MSK를 사용하는 경우, IAM 접근 제어를 활용하여 손쉽게 주제에 대한 권한 제어가 가능한 것을 확인했습니다. 이번 게시글에서 보여준 주제 제어 외에도 다른 리소스(클러스터, 그룹, 트랜잭션 ID)에 대한 제어도 가능합니다. 또한 싱글 클러스터의 예시로 가정하여 설명을 했으나, 멀티 클러스터에서도 역시 적절한 접근 제어는 동일하게 필요한 내용입니다. IAM을 활용할 수 있다는 점은 IaC를 활용하는 방법을 적용할 수 있게 확장시켜주므로, 관리자의 업무를 매우 효율적으로 개선할 수 있습니다. 또한 IAM 접근 제어는 Apache Kafka 리소스의 변경과 관련된 이벤트를 Amazon CloudTrail에 기록할 수 있습니다. 주제 생성, 파티션 추가 등 Apache Kafka 클러스터에 감사 계층을 추가하는데 매우 유용합니다.

게시글에서 데모를 CLI로 보여드리고, Java/Spring 기준으로 추가 설명을 드렸습니다. 23년 11월에 IAM 인증에 대한 다른 언어들에 대한 지원도 추가되어 Java 외에도 Python, Go, JavaScript와 .NET도 IAM 을 활용하여 Amazon MSK 접근 제어가 가능합니다. 지금까지 IAM을 활용하여 Amazon MSK 접근 제어하기를 설명드렸습니다.

마지막으로 주의할 점은 IAM을 통한 접근 제어는 ZooKeeper에 저장되지 않으므로, Kafka ACL에 적용한 내용이 적용되지 않는 점입니다. 또한, Amazon MSK serverless의 경우 IAM 접근 제어 방법만 제공하므로, IAM 접근 제어의 활용이 필수입니다. 앞서 설명드린 내용을 바탕으로 기존에 오픈소스 Apache Kafka를 활용하여 사용 중이거나, 주제 등 다양한 리소스에 대한 편리한 접근 제어를 희망하는 경우 Amazon MSK로 마이그레이션하여 이번 게시글과 같이 활용할 수 있습니다.

감사합니다.

참고 자료

Jaemin Jung

Jaemin Jung

정재민 Solutions Architect는 고객이 AWS와 함께 성공적인 Cloud 여정을 시작하기 위해 최적의 아키텍트를 구성하고 지원하는 역할을 하고 있습니다.