Generating self-signed certificates
출처: 문서
본문
자체 서명 인증서 생성하기
조직의 인증 기관(CA)에 접근할 수 없고 데모가 아닌 목적으로 OpenSearch를 사용하려면, OpenSSL{:target='_blank'}을 사용해 자체 서명 인증서를 직접 생성할 수 있어요.
OpenSSL은 대부분 운영체제의 패키지 관리자에서 찾을 수 있을 거예요.
CentOS에서는 Yum을 사용하세요:
sudo yum install openssl
macOS에서는 Homebrew{:target='_blank'}를 사용하세요:
brew install openssl
프라이빗 키 생성하기
이 과정의 첫 번째 단계는 openssl genrsa 명령어로 프라이빗 키를 생성하는 거예요. 이름에서 알 수 있듯이, 이 파일은 반드시 비밀로 유지해야 해요.
프라이빗 키는 보안을 위해 충분한 길이여야 하므로 2048을 지정하세요:
openssl genrsa -out root-ca-key.pem 2048
선택적으로 -aes256 옵션을 추가해 AES-256 표준으로 키를 암호화할 수 있어요. 이 옵션은 비밀번호를 필요로 해요.
루트 인증서 생성하기
다음으로, 프라이빗 키를 사용해 루트 CA의 자체 서명 인증서를 생성해요. CA가 제대로 동작하게 하고 잠재적인 Java SSL 오류를 피하려면, 인증서의 역할과 기능을 정의하는 X.509 v3 확장을 반드시 포함해야 해요:
openssl req -new -x509 -sha256 -key root-ca-key.pem -out root-ca.pem -days 730 \
-addext 'basicConstraints = critical, CA:TRUE, pathlen:0' \
-addext 'keyUsage = critical, keyCertSign, cRLSign' \
-addext 'authorityKeyIdentifier = keyid'
기본 -days 값인 30은 테스트 목적으로만 유용해요. 이 샘플 명령어는 인증서 만료일로 730(2년)을 지정하지만, 조직에 맞는 값을 사용하세요.
-x509옵션은 인증서 요청이 아닌 자체 서명 인증서를 원한다는 것을 지정해요.-sha256옵션은 해시 알고리즘을 SHA-256으로 설정해요. SHA-256은 최신 버전의 OpenSSL에서 기본값이지만, 이전 버전에서는 SHA-1을 사용할 수도 있어요.-addext옵션들은 인증서에 X.509 v3 확장을 추가해요:basicConstraints = critical, CA:TRUE, pathlen:0은 이 인증서가 인증서에 서명할 수 있지만 하위 CA에는 서명할 수 없는(종단 엔터티 인증서만 서명 가능한) CA 인증서임을 표시해요.keyUsage = critical, keyCertSign, cRLSign은 CA가 인증서와 인증서 폐기 목록에 서명할 수 있게 해줘요.authorityKeyIdentifier = keyid는 CA 공개 키를 식별하는 데 도움을 주며, 인증서 체인 검증에 유용해요.
이러한 확장은 X.509 v3 표준 준수를 보장하고 Java 애플리케이션에서 발생할 수 있는 낮은 수준의 SSL 오류를 예방하는 데 도움이 돼요. 인증서 확장에 대한 자세한 내용은 OpenSSL x509v3_config 문서를 참고하세요. {: .note}
프롬프트를 따라 조직의 세부 정보를 입력하세요. 이 정보들이 모여 CA의 고유 이름(DN)을 구성해요.
어드민 인증서 생성하기
어드민 인증서를 생성하려면 먼저 새 키를 만드세요:
openssl genrsa -out admin-key-temp.pem 2048
그다음, PKCS#12 호환 알고리즘(3DES)을 사용해 Java에서 쓸 수 있도록 해당 키를 PKCS#8 형식으로 변환하세요:
openssl pkcs8 -inform PEM -outform PEM -in admin-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out admin-key.pem
다음으로, 인증서 서명 요청(CSR)을 만들어요. 이 파일은 서명된 인증서를 CA에 신청하는 역할을 해요:
openssl req -new -key admin-key.pem -out admin.csr
프롬프트를 따라 세부 정보를 입력하세요. 챌린지 비밀번호는 지정할 필요가 없어요. OpenSSL Cookbook{:target='_blank'}에서 언급했듯이, "챌린지 비밀번호가 있다고 해서 CSR의 보안이 어떤 식으로든 향상되지는 않아요."
TLS 인증서를 생성하고 transport.ssl.enforce_hostname_verification를 true(기본값)로 설정해 호스트명 검증을 활성화했다면, 각 인증서 서명 요청(CSR)에 해당 노드의 DNS A 레코드와 일치하는 공통 이름(CN)을 반드시 지정하세요.
모든 노드에서 동일한 노드 인증서를 사용하려면(권장하지 않아요), 호스트명 검증을 false로 설정하세요. 자세한 내용은 TLS 인증서 구성하기를 참고하세요.
프라이빗 키와 서명 요청이 생성되었으니, 이제 인증서를 생성하세요:
openssl x509 -req -in admin.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out admin.pem -days 730
루트 인증서와 마찬가지로, -days 옵션을 사용해 30일보다 긴 만료일을 지정하세요.
(선택 사항) 노드 및 클라이언트 인증서 생성하기
어드민 인증서 생성하기의 단계와 유사하게, 각 노드마다 새 파일 이름으로 키와 CSR을 생성하고, 필요한 만큼 클라이언트 인증서를 생성하게 돼요. 예를 들어 OpenSearch Dashboards용 클라이언트 인증서 하나와 Python 클라이언트용 인증서 하나를 생성할 수 있어요. 각 인증서는 자체 프라이빗 키를 사용해야 하며, 대상 호스트에 맞는 SAN 확장을 포함하는 고유한 CSR로부터 생성해야 해요. 어드민 인증서는 특정 호스트에 묶여 있지 않기 때문에 SAN 확장이 필요하지 않아요.
노드 또는 클라이언트 인증서를 생성하려면 먼저 새 키를 만드세요:
openssl genrsa -out node1-key-temp.pem 2048
그다음, PKCS#12 호환 알고리즘(3DES)을 사용해 Java에서 쓸 수 있도록 해당 키를 PKCS#8 형식으로 변환하세요:
openssl pkcs8 -inform PEM -outform PEM -in node1-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out node1-key.pem
다음으로, CSR을 만드세요:
openssl req -new -key node1-key.pem -out node1.csr
모든 호스트 및 클라이언트 인증서에는 RFC 2818 (HTTP Over TLS) 준수를 보장하기 위해 주체 대체 이름(SAN)을 지정해야 해요. SAN은 대응하는 CN과 일치해야 두 값이 같은 DNS A 레코드를 가리키게 돼요. {: .note }
서명된 인증서를 생성하기 전에, 호스트의 DNS A 레코드를 기술하는 SAN 확장 파일을 만드세요. IPv4든 IPv6든 IP 주소만 있는 호스트에 연결하는 경우라면 IP 구문을 사용하세요:
IP 없음
echo 'subjectAltName=DNS:node1.dns.a-record' > node1.ext
IP 포함
echo subjectAltName=IP:127.0.0.1 > node1.ext
DNS A 레코드가 기술되었으니, 이제 인증서를 생성하세요:
openssl x509 -req -in node1.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out node1.pem -days 730 -extfile node1.ext
자체 서명 PEM 인증서를 생성하는 샘플 스크립트
인증서 세부 정보를 이미 알고 있고 대화형으로 입력하고 싶지 않다면, root-ca.pem과 CSR 명령어에서 -subj 옵션을 사용하세요. 이 스크립트는 루트 인증서, 어드민 인증서, 노드 인증서 두 개, 클라이언트 인증서를 생성하며, 모두 만료 기간이 2년(730일)이에요:
#!/bin/sh
# Root CA
openssl genrsa -out root-ca-key.pem 2048
openssl req -new -x509 -sha256 -key root-ca-key.pem -subj "/C=CA/ST=ONTARIO/L=TORONTO/O=ORG/OU=UNIT/CN=root.dns.a-record" -out root-ca.pem -days 730 \
-addext 'basicConstraints = critical, CA:TRUE, pathlen:0' \
-addext 'keyUsage = critical, keyCertSign, cRLSign' \
-addext 'authorityKeyIdentifier = keyid'
# Admin cert
openssl genrsa -out admin-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in admin-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out admin-key.pem
openssl req -new -key admin-key.pem -subj "/C=CA/ST=ONTARIO/L=TORONTO/O=ORG/OU=UNIT/CN=A" -out admin.csr
openssl x509 -req -in admin.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out admin.pem -days 730
# Node cert 1
openssl genrsa -out node1-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in node1-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out node1-key.pem
openssl req -new -key node1-key.pem -subj "/C=CA/ST=ONTARIO/L=TORONTO/O=ORG/OU=UNIT/CN=node1.dns.a-record" -out node1.csr
echo 'subjectAltName=DNS:node1.dns.a-record' > node1.ext
openssl x509 -req -in node1.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out node1.pem -days 730 -extfile node1.ext
# Node cert 2
openssl genrsa -out node2-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in node2-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out node2-key.pem
openssl req -new -key node2-key.pem -subj "/C=CA/ST=ONTARIO/L=TORONTO/O=ORG/OU=UNIT/CN=node2.dns.a-record" -out node2.csr
echo 'subjectAltName=DNS:node2.dns.a-record' > node2.ext
openssl x509 -req -in node2.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out node2.pem -days 730 -extfile node2.ext
# Client cert
openssl genrsa -out client-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in client-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out client-key.pem
openssl req -new -key client-key.pem -subj "/C=CA/ST=ONTARIO/L=TORONTO/O=ORG/OU=UNIT/CN=client.dns.a-record" -out client.csr
echo 'subjectAltName=DNS:client.dns.a-record' > client.ext
openssl x509 -req -in client.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out client.pem -days 730 -extfile client.ext
# Cleanup
rm admin-key-temp.pem
rm admin.csr
rm node1-key-temp.pem
rm node1.csr
rm node1.ext
rm node2-key-temp.pem
rm node2.csr
rm node2.ext
rm client-key-temp.pem
rm client.csr
rm client.ext
PEM 인증서를 keystore 및 truststore 파일로 변환하는 샘플 스크립트
다음 스크립트를 사용하면 앞서 생성한 PEM 인증서로부터 keystore와 truststore를 생성할 수 있어요:
#!/bin/sh
# Convert node certificate
cat root-ca.pem node1.pem node1-key.pem > combined-node1.pem
echo "Enter password for node1-cert.p12"
openssl pkcs12 -export -in combined-node1.pem -out node1-cert.p12 -name node1
echo "Enter password for keystore.jks"
keytool -importkeystore -srckeystore node1-cert.p12 -srcstoretype pkcs12 -destkeystore keystore.jks
# Convert admin certificate
cat root-ca.pem admin.pem admin-key.pem > combined-admin.pem
echo "Enter password for admin-cert.p12"
openssl pkcs12 -export -in combined-admin.pem -out admin-cert.p12 -name admin
echo "Enter password for keystore.jks"
keytool -importkeystore -srckeystore admin-cert.p12 -srcstoretype pkcs12 -destkeystore keystore.jks
# Import certificates to truststore
keytool -importcert -keystore truststore.jks -file root-ca.cer -storepass changeit -trustcacerts -deststoretype pkcs12
# Cleanup
rm combined-admin.pem
rm combined-node1.pem
opensearch.yml에 고유 이름 추가하기
모든 노드의 opensearch.yml에 어드민 인증서와 노드 인증서 전부의 고유 이름(DN)을 지정해야 해요. 앞선 샘플 스크립트의 인증서를 사용하면, opensearch.yml의 일부는 다음과 같을 수 있어요:
plugins.security.authcz.admin_dn:
- 'CN=A,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA'
plugins.security.nodes_dn:
- 'CN=node1.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA'
- 'CN=node2.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA'
하지만 인증서를 생성한 뒤 인증서의 subject를 살펴보면 다른 형식으로 표시될 수 있어요:
subject=/C=CA/ST=ONTARIO/L=TORONTO/O=ORG/OU=UNIT/CN=node1.dns.a-record
이 문자열을 앞선 문자열들과 비교해 보면, 요소의 순서를 뒤집고 슬래시 대신 콤마를 사용해야 한다는 것을 알 수 있어요. 올바른 문자열을 얻으려면 다음 명령어를 입력하세요:
openssl x509 -subject -nameopt RFC2253 -noout -in node.pem
그런 다음 출력 결과를 복사해서 opensearch.yml에 붙여 넣으세요.
opensearch.yml에 인증서 파일 추가하기
이 과정에서 많은 파일이 생성되지만, 각 노드에 추가해야 하는 파일은 다음과 같아요:
root-ca.pem- (선택 사항)
admin.pem - (선택 사항)
admin-key.pem - (선택 사항)
node1.pem - (선택 사항)
node1-key.pem
대부분의 사용자라면 admin.pem과 admin-key.pem 파일은 securityadmin 스크립트를 실행하거나 인증서를 다시 불러올 계획인 노드에만 추가하면 돼요. securityadmin 스크립트 사용 방법에 대한 자세한 내용은 구성 파일에 변경 사항 적용하기를 참고하세요. securityadmin 스크립트를 노드에서 직접 실행할 계획이라면, 해당 노드에 admin.pem과 admin-key.pem 사본이 있어야 해요.
한 노드에서 opensearch.yml의 보안 구성 부분은 다음과 같을 수 있어요:
plugins.security.ssl.transport.pemcert_filepath: node1.pem
plugins.security.ssl.transport.pemkey_filepath: node1-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
transport.ssl.enforce_hostname_verification: false
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: node1.pem
plugins.security.ssl.http.pemkey_filepath: node1-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pem
plugins.security.authcz.admin_dn:
- 'CN=A,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA'
plugins.security.nodes_dn:
- 'CN=node1.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA'
- 'CN=node2.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA'
자신의 환경에서 이 인증서들을 추가하고 사용하는 방법에 대한 자세한 내용은 Docker용 기본 보안 설정 구성하기, TLS 인증서 구성하기, 클라이언트 인증서 인증을 참고하세요.
OpenSearch Dashboards
루트 CA와 클라이언트 인증서를 사용해 OpenSearch Dashboards에 TLS를 활성화하는 방법에 대한 자세한 내용은 OpenSearch Dashboards용 TLS 구성하기를 참고하세요.