Strimzi: 간단한 mTLS 인증 만들기
출처: Dev.to
Strimzi. Strimzi는 Kubernetes에서 Kafka를 실행할 수 있게 해 주는 도구이며, 그 자체만으로도 충분합니다. 그래서 이번 글에서는 Strimzi 자체에 대해서는 다루지 않고, 그 위에 간단한 mTLS 인증을 만드는 방법에 집중하겠습니다. 이 글을 따라 하면 어떻게 하는지 바로 알 수 있습니다.
- OpenShift Container Platform에 설치된 Apache Kafka Operator (Strimzi 커뮤니티 버전을 vanilla Kubernetes에 설치해도 동일하게 동작합니다);
- 로컬 머신에
openssl도구가 설치되어 있음; - OpenShift 프로젝트에 이미 생성된
KafkaNodePool; - 로컬 환경에 Kafka 배포판/클라이언트가 설치되어 있음.
Kafka 클러스터는 Kafka Custom Resource (CR)를 YAML 형태로 정의하고 OpenShift 클러스터에 적용함으로써 생성됩니다. 이번 예제에서 중요한 부분은 listener 설정입니다.
이것은 Kafka Custom Resource의 일부 스니펫일 뿐입니다
apiVersion: kafka.strimzi.io/v1
kind: Kafka
metadata:
name: test-kafka-cluster
spec:
kafka:
listeners:
- name: tls
port: 9093
type: route
tls: true
authentication:
type: tls
위 설정을 보면 tls 를 활성화하고 인증 타입을 tls 로 지정했습니다. 첫 번째 옵션은 일반 TLS 암호화를, 두 번째 옵션은 TLS 인증(즉, Mutual TLS)을 활성화합니다. 이번 글의 주제는 바로 이 Mutual TLS 입니다.
Strimzi를 사용할 경우, 사용자 인증서 를 직접 만들 필요가 없습니다. KafkaUser Custom Resource (CR)만 생성하면, 모든 인증서는 Strimzi Operator가 자동으로 만들어 줍니다. 아래는 KafkaUser CR 예시이며, 인증 타입이 tls 로 지정된 점에 주목하세요.
apiVersion: kafka.strimzi.io/v1
kind: KafkaUser
metadata:
labels:
strimzi.io/cluster: test-kafka-cluster
name: test-kafka-user
spec:
authentication:
type: tls
생성된 KafkaUser 와 동일한 이름을 가진 Secret이 만들어졌는지 확인합니다.
oc describe secret test-kafka-user
Operator가 Secret 안에 다섯 개의 파일을 생성합니다. 명령 출력 예시는 다음과 같습니다.
Name: test-kafka-user
Namespace: test-kafka-project
Labels: app.kubernetes.io/instance=test-kafka-user
app.kubernetes.io/managed-by=strimzi-user-operator
app.kubernetes.io/name=strimzi-user-operator
app.kubernetes.io/part-of=strimzi-test-kafka-user
strimzi.io/cluster=test-kafka-cluster
strimzi.io/kind=KafkaUser
Annotations:
Type: Opaque
Data
====
ca.crt: 1854 bytes
user.crt: 1521 bytes
user.key: 1704 bytes
user.p12: 2974 bytes
user.password: 32 bytes
이것으로 Kafka 클러스터 쪽 설정은 끝났습니다. 이제 클라이언트를 만들어 보겠습니다.
클라이언트를 실행하기 위해서는 표준 kafka-console-producer.sh 와 kafka-console-consumer.sh 스크립트를 사용할 것입니다. 이 스크립트들은 일반 Kafka 배포판에 포함되어 있으니 먼저 다운로드해 주세요.
스크립트를 실행하기 전에 클라이언트가 사용할 인증서를 받아야 합니다. 클러스터 인증서는 -cluster-ca-cert Secret에, 사용자 인증서는 앞서 만든 Secret에 각각 들어 있습니다. 여기서는 클러스터 이름이 test-kafka-cluster 라 가정하고, 인증서를 가져오는 명령을 보여 줍니다.
# Kafka 클러스터 인증서 가져오기
oc get secret test-kafka-cluster-cluster-ca-cert -o jsonpath='{.data.ca\.p12}' | base64 -d > test-kafka-cluster-ca.p12
# KafkaUser 인증서 가져오기
oc get secret test-kafka-user -o jsonpath='{.data.user\.p12}' | base64 -d > test-kafka-user.p12
여기서는 P12 파일, 즉 PKCS#12 형식의 암호화된 인증서 저장소를 사용했습니다. (Java KeyStore를 떠올리시면 됩니다.)
두 인증서를 모두 확보했으면 client.properties 파일을 만들어 mTLS 설정을 지정합니다.
security.protocol=SSL
# Truststore 에는 Kafka 클러스터 인증서를 넣습니다
ssl.truststore.location=test-kafka-cluster-ca.p12
ssl.truststore.password=PasswdForSecret
ssl.truststore.type=PKCS12
# Keystore 에는 KafkaUser 인증서를 넣습니다
ssl.keystore.location=test-kafka-user.p12
ssl.keystore.password=PasswdForSecret
ssl.keystore.type=PKCS12
# mTLS 활성화
ssl.client.auth=required
ssl.endpoint.identification.algorithm=
위와 같이 클러스터 인증서는 truststore, 사용자 인증서는 keystore 로 지정했습니다.
마지막으로, OpenShift 외부에서 Kafka 클러스터에 접근하기 위한 Route URL 을 알아야 합니다. 부트스트랩 라우트를 확인하려면 다음 명령을 실행합니다.
oc get routes
이제 클라이언트 스크립트를 실행할 준비가 모두 끝났습니다.
메시지 전송 (Producer)
./kafka-console-producer.sh --bootstrap-server test-kafka-cluster-kafka-tls-bootstrap-test-kafka-project.apps-crc.testing:443 --topic test-topic --command-config client.properties
메시지 수신 (Consumer)
./kafka-console-consumer.sh --bootstrap-server test-kafka-cluster-kafka-tls-bootstrap-test-kafka-project.apps-crc.testing:443 --topic test-topic --command-config client.properties --from-beginning
커스텀 인증서를 사용하고 싶다면
리스너에 커스텀 인증서를 적용하고 싶다면 다음과 같이 진행합니다.
-
커스텀 인증서 생성
(openssl을 사용했지만keytool로도 가능)# openssl 예시 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout custom-key.key -out custom-cert.crt -
생성한 인증서를 Kafka 클러스터에 업로드
oc create secret tls custom-certificate --cert=custom-cert.crt --key=custom-key.key -
기존 Kafka CR에 커스텀 인증서 설정을 추가 (아래는 전체 CR이 아니라 일부 스니펫)
## 이것은 전체 CR이 아니라 일부 스니펫임을 기억하세요 apiVersion: kafka.strimzi.io/v1 kind: Kafka metadata: name: kafka-cluster spec: kafka: listeners: - name: tls port: 9093 type: route tls: true authentication: type: tls configuration: brokerCertChainAndKey: certificate: tls.crt key: tls.key secretName: custom-certificate여기서
tls.crt와tls.key라는 이름은 OpenShift가 Secret 내부에서 자동으로 바꾸어 주는 것이니, 이름이 다르다고 걱정하지 마세요. -
클라이언트 측에서 커스텀 인증서를 사용하려면 PKCS#12 형식의 truststore 를 새로 만들고
client.properties를 수정합니다.# 작업 디렉터리에 custom-cert.crt 와 custom-key.key 가 이미 있다고 가정 openssl pkcs12 -export -out custom-certificate.p12 -inkey custom-key.key -in custom-cert.crt# client.properties 의 일부 # Truststore 에는 새 커스텀 Kafka 클러스터 인증서를 넣습니다 ssl.truststore.location=custom-certificate.p12 ssl.truststore.password=passwd ssl.truststore.type=PKCS12이후에는 앞서 사용했던 것과 동일하게 스크립트를 실행하면 됩니다.
인증서 설정에 문제가 있을 때
인증서 설정이 제대로 되지 않거나 연결 오류가 발생한다면 다음 팁을 활용해 보세요.
-
SSL 디버그 활성화
클라이언트 스크립트를 실행하기 전에 아래 환경 변수를 설정하면 SSL 핸드쉐이크 과정을 상세히 로그로 볼 수 있습니다.export KAFKA_OPTS="-Djavax.net.debug=ssl" -
스크립트 자체 디버깅
스크립트 로직을 디버깅하고 싶다면client.log4j2.properties와 같은 Log4J2 설정 파일을 만들어 DEBUG 레벨 로깅을 활성화하면 됩니다. (구체적인 설정 내용은 필요에 따라 추가하세요.)