Cloudera 요구사항에 맞는 self-signed TLS 인증서 만들기
sha256WithRSAEncryption, SAN, clientAuth + serverAuth 를 모두 만족하는 내부 CA 와 호스트별 인증서를 openssl 로 만드는 방법.
공인 CA 에서 인증서를 발급받으려면 며칠씩 걸리는 경우도 있습니다. 내부 테스트 클러스터나 PoC 환경에서는 기다릴 여유가 없죠. 마치 이사 들어가는 날 자물쇠 열쇠를 직접 만드는 것처럼, 자체 CA 를 만들어 호스트별 인증서를 발급 하면 몇 분 만에 준비가 끝납니다. 이 글은 Cloudera CDP Private Cloud Base 의 TLS 인증서 요구사항 문서 를 만족하는 self-signed 인증서를 생성하는 정확한 절차를 정리합니다. 자동화가 필요하면 TheOpenCloudEngine/certificates-generator 를 바로 쓰면 되고, 이 글은 그 스크립트가 내부적으로 무엇을 하는지, 왜 각 옵션이 필요한지를 한 줄씩 풀어서 설명합니다.
이 글에서 배우는 것
- Cloudera CDP 가 TLS 인증서에 요구하는 조건 7가지
- openssl 로 내부 CA 를 만들고 호스트별 인증서를 발급하는 정확한 절차
.ext파일로 EKU(clientAuth + serverAuth), SAN 을 올바르게 설정하는 법- JKS TrustStore / PKCS12 KeyStore 로 패키징하는 방법
- 자동화 스크립트 활용 시 주의사항
1. Cloudera 가 요구하는 조건
인증서를 만들기 전에 Cloudera 가 무엇을 요구하는지 먼저 파악해야 합니다. 이 표의 조건 하나라도 빠뜨리면 Cloudera 서비스가 인증서를 거부하니, 생성 스크립트가 이 모든 조건을 동시에 만족하도록 해야 합니다.
| 항목 | 요구사항 |
|---|---|
| Signature algorithm | sha256WithRSAEncryption (SHA-256) |
| Extended Key Usage (EKU) | clientAuth 와 serverAuth 모두 포함 |
| Key Usage | DigitalSignature, KeyEncipherment |
| Subject Alternative Name (SAN) | 필수. 최소한 호스트의 FQDN 포함. 로드밸런서 FQDN 도 필요 시 추가 |
| Wildcard 인증서 | 사용 불가. 클러스터 노드마다 고유 인증서 발급 |
| KeyStore | 한 KeyStore 에 PrivateKeyEntry 는 하나만 |
| KeyStore 비밀번호 | KeyStore 비밀번호와 인증서 비밀번호가 같거나 양쪽 모두 미설정. 클러스터 전체 노드에서 동일 |
추가로 문서가 권장하는 것은 "가능하면 공인 CA 를 쓰고 self-signed 는 피하라" 이지만, 이 글은 테스트/내부 환경 에서 self-signed 가 필요할 때의 정공법을 다룹니다.
2. 전체 흐름
Cloudera 노드는 결국 두 종류의 키스토어 를 필요로 합니다. 학교 신분증(KeyStore)은 학생마다 다르지만, 학교 직인(TrustStore)은 모든 학생이 같은 것을 신뢰하는 것과 비슷한 구조입니다.
- KeyStore — 그 노드 자신의 private key + 서명된 leaf cert. 노드마다 다름.
- TrustStore — 공통. 내부 CA 의 public cert 만 들어감. 모든 노드가 동일한 파일을 공유.
3. 내부 CA 생성
CA 는 한 번만 만들면 끝입니다. 한 번 만들어두면 클러스터의 모든 노드 인증서를 이 CA 로 서명할 수 있으니, 만료를 길게 (10년 / 3650일) 잡고 키 크기를 4096 비트 로 크게 가져가는 것이 관행입니다. 일단 CA 를 분실하면 모든 하위 인증서가 의미 없어지기 때문에 CA 키의 보안을 강하게 잡는 것이 맞습니다.
3.1 디렉터리 준비
mkdir -p certs/ca
cd certs/ca3.2 CA 개인키
openssl genrsa -out ca.key 4096
chmod 600 ca.key
ca.key는 절대 외부로 유출되면 안 됩니다. 생성 즉시 권한을600으로 내려두고, 운영 배포 아티팩트에 포함되지 않도록 주의하세요.
3.3 CA self-signed 인증서
openssl req -x509 -new -nodes \
-key ca.key \
-sha256 \
-days 3650 \
-out ca.crt \
-subj "/C=KR/ST=Gyeonggi-do/L=Yongin-si/O=Data Dynamics/OU=Infrastructure/CN=Data Dynamics Internal CA" \
-extensions v3_ca \
-config <(cat <<'EOF'
[req]
distinguished_name = req_dn
prompt = no
[req_dn]
CN = Data Dynamics Internal CA
[v3_ca]
basicConstraints = critical, CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
EOF
)여기서 중요한 포인트는 세 가지입니다.
-sha256: Cloudera 가 요구하는 signature algorithm 을 지정. 이 옵션이 없으면 openssl 기본값이 MD5 나 SHA1 일 수 있어서 검증을 통과하지 못합니다.basicConstraints = critical, CA:TRUE: 이 인증서가 "다른 인증서를 서명할 수 있는 CA" 임을 명시.critical플래그로 반드시 검사하게 만듭니다.keyUsage = critical, keyCertSign, cRLSign: CA 역할에 필요한 최소 Key Usage 만 부여. 이 CA 는 "다른 인증서 서명" 과 "CRL 서명" 만 할 수 있고 자기 자신이 서버가 되지는 못합니다.
3.4 CA 인증서 확인
openssl x509 -in ca.crt -noout -text | \
grep -A1 -E "Signature Algorithm|Basic Constraints|Key Usage|Subject:"출력에 Signature Algorithm: sha256WithRSAEncryption, CA:TRUE, Certificate Sign, CRL Sign 이 모두 보이면 정상입니다.
4. 호스트별 인증서 발급
CA 를 만들었다면 이제 각 노드에 발급할 차례입니다. 이 단계는 클러스터 노드 수만큼 반복됩니다. hosts.txt 같은 파일에 호스트 목록을 적어두고 루프를 돌리는 것이 편합니다.
hosts.txt
---------
node01.example.com
node02.example.com
node03.example.com
cm-server.example.com4.1 디렉터리와 경로
HOST="node01.example.com"
mkdir -p "certs/${HOST}"
cd "certs/${HOST}"4.2 노드 개인키
openssl genrsa -out "${HOST}.key" 2048
chmod 600 "${HOST}.key"노드 인증서는 2048 비트로 충분합니다. CA 와 달리 수명이 짧고 (보통 825일 이내, 이후 설명) 갱신 주기가 있기 때문에 4096 까지 키울 필요는 없습니다.
4.3 CSR (Certificate Signing Request)
openssl req -new \
-key "${HOST}.key" \
-out "${HOST}.csr" \
-subj "/C=KR/ST=Gyeonggi-do/L=Yongin-si/O=Data Dynamics/OU=Infrastructure/CN=${HOST}"CN=${HOST}: 과거에는 CN 을 hostname 으로 쓰는 것이 표준이었습니다. 지금도 관행적으로 채우긴 하지만, 현대 TLS 클라이언트(Java 11+, 최신 브라우저, gRPC 등)는 CN 을 무시하고 SAN 만 본다 는 점을 기억하세요. SAN 이 없으면 CN 만으로는 절대 검증되지 않습니다.
4.4 확장 파일 (.ext) — Cloudera 요구사항의 핵심
이 파일이 이 과정의 핵심입니다. openssl 이 CSR 에 서명할 때 붙일 확장들을 별도 파일로 준비하는데, 이 파일 하나가 Cloudera 요구사항을 만족하는지 여부를 결정 합니다. 한 줄이라도 빠지면 Cloudera 서비스가 인증서를 거부합니다.
cat > "${HOST}.ext" <<EOF
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
[alt_names]
DNS.1 = ${HOST}
DNS.2 = ${HOST%%.*}
EOF각 필드가 Cloudera 요구사항의 어느 항목을 커버하는지 짚고 넘어갑니다.
| ext 파일 필드 | Cloudera 요구사항 |
|---|---|
basicConstraints = CA:FALSE | 이 인증서는 leaf 이며 다른 인증서를 서명할 수 없음을 명시 |
keyUsage = digitalSignature, keyEncipherment | 요구되는 Key Usage 2종 |
extendedKeyUsage = serverAuth, clientAuth | EKU 양쪽 필수. 하나라도 빠지면 Cloudera 서비스 일부가 인식 못함 |
subjectAltName = @alt_names | SAN 필수 조건 |
DNS.1 = ${HOST} | FQDN 포함 |
DNS.2 = ${HOST%%.*} | bare hostname (짧은 이름). 노드 간 통신에서 짧은 이름을 쓰는 환경을 위해 |
주의: 참고한 오픈소스 스크립트는 SAN 에
DNS.3 = *.example.com같은 와일드카드 를 포함하지만, 이 글이 목표로 하는 Cloudera CDP Private Cloud Base 7.3.1 의 요구사항에는 "certificates must not use wildcards" 가 명시되어 있습니다. 와일드카드 SAN 은 넣지 말고 노드별로 정확한 FQDN 만 나열하세요. 로드밸런서를 앞에 두는 경우에는DNS.3 = lb.example.com처럼 LB FQDN 을 추가로 명시하면 됩니다.
4.5 CA 로 CSR 서명
openssl x509 -req \
-in "${HOST}.csr" \
-CA ../ca/ca.crt \
-CAkey ../ca/ca.key \
-CAcreateserial \
-out "${HOST}.crt" \
-days 825 \
-sha256 \
-extfile "${HOST}.ext"-sha256: 서명 알고리즘을 SHA-256 으로 명시. Cloudera 요구사항의 핵심.-days 825: 825일. 이는 현재 대부분의 브라우저와 라이브러리가 허용하는 leaf 인증서 최대 유효기간입니다 (Apple/Google 이 2020년 이후 브라우저에 적용한 상한). Cloudera 자체는 이 값을 강제하지 않지만, 같은 인증서를 감시 대시보드의 HTTPS UI 에서 신뢰시키려면 825일 이하로 맞추는 편이 안전합니다.-extfile: 위에서 만든 확장 파일을 주입. 이게 없으면 openssl 은 기본 확장만 붙이고 EKU/SAN 이 모두 사라집니다.-CAcreateserial: 첫 실행 시 CA 의 일련번호 파일(ca.srl)을 자동 생성. 두 번째 호스트부터는-CAserial ../ca/ca.srl로 대체해도 동일.
4.6 체인 파일 조립
배포 편의상 "leaf cert + CA cert" 를 한 파일로 합친 체인 파일 을 만들어 두는 것이 일반적입니다.
cat "${HOST}.crt" ../ca/ca.crt > "${HOST}-chain.pem"또한 "private key + 체인" 을 한 파일로 합친 풀 번들 도 유용합니다 (nginx, HAProxy 등 일부 서버가 이 형식을 요구).
cat "${HOST}.key" "${HOST}.crt" ../ca/ca.crt > "${HOST}-full.pem"
chmod 600 "${HOST}-full.pem"5. 생성된 인증서 검증
5.1 CA 가 정말로 서명했는가
openssl verify -CAfile ../ca/ca.crt "${HOST}.crt"node01.example.com.crt: OK 가 나오면 통과입니다.
5.2 Cloudera 요구 확장이 다 들어갔는가
openssl x509 -in "${HOST}.crt" -noout -text | \
grep -A1 -E "Signature Algorithm|Key Usage|Extended Key Usage|Subject Alternative Name"출력에서 반드시 확인해야 할 것:
Signature Algorithm: sha256WithRSAEncryption— 두 번 나옵니다 (tbsCertificate 와 outer)X509v3 Key Usage: critical→Digital Signature, Key EnciphermentX509v3 Extended Key Usage:→TLS Web Server Authentication, TLS Web Client AuthenticationX509v3 Subject Alternative Name:→DNS:node01.example.com, DNS:node01
하나라도 빠져 있으면 .ext 파일과 -extfile 옵션을 다시 확인하세요.
6. KeyStore / TrustStore 패키징
인증서를 만들었다고 끝이 아닙니다. Cloudera 서비스와 Java 기반 컴포넌트(HiveServer2, Impala coordinator, KMS 등) 는 Java KeyStore 형식 을 원합니다. openssl 이 만든 .key/.crt 를 JKS 로 옮겨야 비로소 Cloudera 가 인식합니다. 절차는 PKCS12 를 경유하는 두 단계입니다.
6.1 PKCS12 로 먼저 묶기
openssl 은 JKS 를 직접 만들 수 없습니다. 먼저 PKCS12 포맷으로 묶은 뒤 keytool 로 JKS 로 변환하는 2단계 접근을 씁니다.
openssl pkcs12 -export \
-in "${HOST}-chain.pem" \
-inkey "${HOST}.key" \
-name "${HOST}" \
-out "${HOST}.p12" \
-password pass:"${STORE_PASSWORD}"-name "${HOST}": KeyStore 내부 alias. 노드 식별용.-password: 프로덕션에서는env:STORE_PASSWORD로 바꿔 환경변수에서 읽게 하는 편이 안전합니다.
6.2 JKS 로 변환
keytool -importkeystore \
-srckeystore "${HOST}.p12" \
-srcstoretype PKCS12 \
-srcstorepass "${STORE_PASSWORD}" \
-destkeystore "${HOST}.jks" \
-deststoretype JKS \
-deststorepass "${STORE_PASSWORD}" \
-nopromptCloudera 문서의 "KeyStore password 와 certificate password 가 같거나 둘 다 미설정" 조건은 여기서 충족됩니다.
srcstorepass와deststorepass를 동일한 값으로 맞추세요.keypass를 별도로 지정하지 않으면 keytool 은 자동으로 storepass 와 동일한 값을 쓰므로 이 조건이 자연스럽게 맞아떨어집니다.
6.3 공용 TrustStore 만들기 (CA 만)
TrustStore 는 클러스터 전체가 공유합니다. 여기에는 CA 인증서만 들어가며 private key 는 들어가지 않습니다.
keytool -importcert -noprompt \
-file ../ca/ca.crt \
-alias internal-ca \
-keystore truststore.jks \
-storepass "${TRUSTSTORE_PASSWORD}" \
-storetype JKS이 truststore.jks 한 파일을 모든 노드에 배포하면 됩니다.
7. 자동화 — 참고 스크립트
노드가 수십 대라면 위 절차를 매번 손으로 돌리는 건 고문이나 다름없습니다. 저희가 이 글을 준비하면서 참고한 오픈소스 스크립트가 그 반복 작업을 대신해줍니다.
이 스크립트는 hosts.txt 를 입력으로 받아 위에서 설명한 3~6단계를 자동으로 반복 해서 certs/<host>/ 디렉터리 안에 .key, .csr, .crt, .ext, 체인 파일, 풀 번들까지 한꺼번에 생성합니다. 사용 순서는 이렇습니다.
git clone https://github.com/TheOpenCloudEngine/certificates-generator.git
cd certificates-generator
# hosts.txt 에 클러스터 노드 FQDN 을 한 줄씩 입력
cat > hosts.txt <<EOF
node01.example.com
node02.example.com
node03.example.com
cm-server.example.com
EOF
./generate_certs.sh단, 그대로 운영에 쓰기 전에 아래 두 가지는 반드시 확인 하세요.
- 스크립트 상단의 CA Subject (
C,ST,O,CN) 가 조직 규칙에 맞는지. 기본값은 샘플이라 회사 정보로 수정이 필요합니다. - SAN 에 와일드카드 도메인 을 추가하는 부분이 있다면 제거. 앞서 설명했듯이 Cloudera CDP Private Cloud Base 7.3.1 은 wildcard 를 금지합니다. 노드별 FQDN 만 넣도록 루프를 수정하세요.
이 두 부분만 회사 환경에 맞게 손보면, 사실상 Cloudera 요구사항을 만족하는 인증서 묶음을 5분 안에 발급받을 수 있습니다.
한 문장으로: 자동화 스크립트는 편리하지만, CA Subject 와 와일드카드 SAN 부분을 반드시 수동으로 검토해야 합니다.
8. 운영 주의사항
인증서를 만들었다고 일이 끝난 게 아닙니다. 운영에서는 인증서 관리 자체가 또 하나의 숙제입니다.
- CA 키 보관:
ca.key는 암호화된 별도 볼트(HashiCorp Vault, AWS KMS, 사내 HSM 등)에 보관하는 것이 원칙입니다. 일반 Git 리포에 절대 커밋하지 마세요. 이 키가 유출되면 이 CA 로 서명된 모든 노드 인증서 가 동시에 신뢰를 잃습니다. - 만료 모니터링: leaf 인증서(825일)뿐 아니라 CA 인증서(3650일)도 만료일을 모니터링해야 합니다. CA가 만료되면 재발급해야 하는 범위가 전 노드로 퍼집니다.
- 일련번호(serial) 파일 관리:
ca.srl은 다음 발급에서 이어서 써야 합니다. 분실하거나 여러 팀이 병렬로 인증서를 발급하면 같은 일련번호가 두 인증서에 부여되어 충돌이 날 수 있습니다. 중앙에서 단일 CA 워크스테이션을 정해두는 편이 안전합니다. - 재발급 절차 미리 연습: "만료 2주 전에 갱신" 정책을 문서화해두고, 1년에 한 번 이상 실제 재발급을 돌려 절차가 유효한지 확인하세요. 첫 만료일이 닥쳐서야 스크립트를 찾는 것이 가장 흔한 장애 패턴입니다.
이 글은 인증서를 만드는 쪽만 다뤘습니다. 만든 CA 인증서를 JDBC 클라이언트 쪽에서 신뢰하도록 TrustStore 에 import 하고 실제로 Impala 에 연결하는 과정은 "Cloudera Impala JDBC 에 TLS + LDAP 인증 적용하기" 에서 이어집니다.
마치며 — 핵심 요약
- Cloudera TLS 인증서는 SHA-256, EKU(clientAuth+serverAuth), SAN 세 가지가 반드시 있어야 합니다.
- 내부 CA 는 한 번만 만들고, 노드별 인증서는 이 CA 로 서명합니다.
.ext파일이 요구사항을 충족하는 핵심 파일입니다. 와일드카드 SAN(*.example.com)은 넣으면 안 됩니다.- openssl → PKCS12 → JKS 변환 순서로 패키징합니다.
ca.key는 절대 Git 에 올리지 마세요. CA 가 유출되면 모든 노드 인증서가 동시에 무효화됩니다.- 자동화 스크립트를 쓸 때는 CA Subject 와 와일드카드 SAN 제거 여부를 반드시 확인하세요.
인증서 설정은 한 번 제대로 해두면 한동안 신경 쓸 일이 없습니다. 이 글의 체크포인트를 하나씩 짚어가며 진행해 보세요.
질문이나 사내 환경에서만 나타나는 특이 케이스가 있으면 알려주세요.
— Data Dynamics 엔지니어링 팀