Cloudera 요구사항에 맞는 self-signed TLS 인증서 만들기
sha256WithRSAEncryption, SAN, clientAuth + serverAuth 를 모두 만족하는 내부 CA 와 호스트별 인증서를 openssl 로 만드는 방법.
운영 환경에서는 공인 CA 발급 인증서를 쓰는 것이 원칙이지만, 내부 테스트 클러스터나 PoC 환경에서는 자체 CA 를 만들어 호스트별 인증서를 발급 하는 편이 훨씬 빠릅니다. 이 글은 Cloudera CDP Private Cloud Base 의 TLS 인증서 요구사항 문서 를 만족하는 self-signed 인증서를 생성하는 정확한 절차를 정리합니다. 자동화가 필요하면 TheOpenCloudEngine/certificates-generator 를 바로 쓰면 되고, 이 글은 그 스크립트가 내부적으로 무엇을 하는지, 왜 각 옵션이 필요한지를 한 줄씩 풀어서 설명합니다.
1. 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. 전체 흐름
[1] 내부 CA 생성
│
▼
ca.key + ca.crt
│
┌──────────┼──────────┐
▼ ▼ ▼
[2] host01 host02 host03
.key .key .key
.csr .csr .csr
.ext (SAN) .ext .ext
.crt (CA서명) .crt .crt
│
▼
[3] 검증 (openssl verify)
│
▼
[4] JKS TrustStore / PKCS12 KeyStore 로 패키징Cloudera 노드는 결국 두 종류의 키스토어 를 필요로 합니다.
- KeyStore — 그 노드 자신의 private key + 서명된 leaf cert. 노드마다 다름.
- TrustStore — 공통. 내부 CA 의 public cert 만 들어감. 모든 노드가 동일한 파일을 공유.
3. 내부 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. 호스트별 인증서 발급
이제 클러스터 노드마다 반복할 단계입니다. 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 요구사항을 만족하는지 여부를 결정 합니다.
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 로 옮기는 표준 절차는 다음과 같습니다.
6.1 PKCS12 로 먼저 묶기
openssl 은 JKS 를 직접 만들 수 없으므로 PKCS12 로 먼저 묶은 뒤 keytool 로 변환합니다.
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분 안에 발급받을 수 있습니다.
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 인증 적용하기" 에서 이어집니다.
질문이나 사내 환경에서만 나타나는 특이 케이스가 있으면 알려주세요.
— Data Dynamics 엔지니어링 팀