Blog
clouderatlsopensslkeytoolsecurity

Cloudera 요구사항에 맞는 self-signed TLS 인증서 만들기

sha256WithRSAEncryption, SAN, clientAuth + serverAuth 를 모두 만족하는 내부 CA 와 호스트별 인증서를 openssl 로 만드는 방법.

Data Dynamics2026년 4월 11일17 min read

운영 환경에서는 공인 CA 발급 인증서를 쓰는 것이 원칙이지만, 내부 테스트 클러스터나 PoC 환경에서는 자체 CA 를 만들어 호스트별 인증서를 발급 하는 편이 훨씬 빠릅니다. 이 글은 Cloudera CDP Private Cloud Base 의 TLS 인증서 요구사항 문서 를 만족하는 self-signed 인증서를 생성하는 정확한 절차를 정리합니다. 자동화가 필요하면 TheOpenCloudEngine/certificates-generator 를 바로 쓰면 되고, 이 글은 그 스크립트가 내부적으로 무엇을 하는지, 왜 각 옵션이 필요한지를 한 줄씩 풀어서 설명합니다.

1. Cloudera 가 요구하는 조건

문서에 명시된 조건을 먼저 한 표로 정리합니다. 생성 스크립트가 이 모든 조건을 동시에 만족해야 합니다.

항목요구사항
Signature algorithmsha256WithRSAEncryption (SHA-256)
Extended Key Usage (EKU)clientAuthserverAuth 모두 포함
Key UsageDigitalSignature, 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/ca

3.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.com

4.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, clientAuthEKU 양쪽 필수. 하나라도 빠지면 Cloudera 서비스 일부가 인식 못함
subjectAltName = @alt_namesSAN 필수 조건
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: criticalDigital Signature, Key Encipherment
  • X509v3 Extended Key Usage:TLS Web Server Authentication, TLS Web Client Authentication
  • X509v3 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}" \
  -noprompt

Cloudera 문서의 "KeyStore password 와 certificate password 가 같거나 둘 다 미설정" 조건은 여기서 충족됩니다. srcstorepassdeststorepass 를 동일한 값으로 맞추세요. 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 엔지니어링 팀