NGINX SSL 개인 키(Private Key) 보호 방안
이 포스트에서는 SSL 암호를 배포하기 위해 HashiCorp Vault를 설정하여 NGINX SSL 개인 키(Private Key)를 보호하는 방법을 보여줍니다. 더 강력한 보안을 위해 외부 HSM(하드웨어 보안 모듈)을 설정할 수 있습니다.
이 시리즈의 첫 번째 포스트에서는 SSL 개인 키의 보안을 개선하는 몇 가지 접근 방식을 설명합니다. 이전 포스트는 NGINX 인스턴스와 암호화 암호를 안전하게 공유하는 데 사용되는 원격 암호 배포 지점(PDP)의 시연으로 마무리되었습니다.
HashiCorp Vault 와 같은 Secret 관리 시스템은 해당 샘플 PDP와 유사한 방식으로 작동합니다.
- HTTPS 또는 다른 API를 사용하여 액세스 되는 중앙(또는 고가용성 및 분산형) Secret 서비스를 사용합니다.
- 클라이언트는 인증 토큰 또는 기타 수단으로 인증됩니다.
- 암호에 대한 액세스를 제어하기 위해 필요에 따라 토큰을 취소할 수 있습니다.
SSL 인증서 키 쌍의 디스크 저장소를 완전히 제거하려면 이 시리즈의 세 번째 포스트인 NGINX Key-Value 사용하여 HashiCorp Vault에서 동적 SSL 인증서 관리를 참조하십시오. HashiCorp Vault에서 임시 SSL 키를 생성하고 NGINX Plus Key-Value Store의 메모리에 저장하는 방법을 설명합니다.
이 포스트는 NGINX Open Source와 NGINX Plus 모두에 적용됩니다. 쉽게 읽을 수 있도록 NGINX를 참고하도록 하겠습니다.
목차
1. HashiCorp Vault를 사용하여 NGINX SSL 개인 키 보호
1-1. PDP 서버에서 HashiCorp Vault 다운로드, 설치 및 초기화
1-2. Secret 저장
1-3. 웹 서버가 토큰을 검색할 수 있는지 확인
1-4. 웹 서버에서 NGINX Vault 커넥터 구성
1-5. 웹 서버의 인증 토큰 취소
1-6. 보안 관련 사항
2. 외부 HSM을 사용하여 NGINX SSL 개인 키 관리
2-1. HSM에 액세스하도록 NGINX SSL 구성
2-2. 보안 관련 사항
3. NGINX SSL 개인 키 보호 결론
1. HashiCorp Vault를 사용하여 NGINX SSL 개인 키 보호
이 섹션의 지침은 HashiCorp Vault를 사용하여 SSL 암호를 배포하는 중앙 PDP 서버를 설정합니다. DigitalOcean의 지침을 기반으로 합니다. 자체 Vault 정책을 준수하기 위해 필요에 따라 수정합니다.
이 예에서 각 원격 웹 서버에는 고유한 인증 토큰이 있습니다. 이 토큰은 Vault의 secret/webservers/
경로에 있는 Secret에 액세스하는 데 사용할 수 있으며 SSL 암호는 secret/webservers/ssl_passwords
에 저장됩니다.
토큰을 보호하는 방법과 필요한 경우 개별 인증 토큰을 취소하는 방법을 살펴보겠습니다.
1-1. PDP 서버에서 HashiCorp Vault 다운로드, 설치 및 초기화
1. DigitalOcean 지침에 따라 PDP 서버에서 Vault를 다운로드하고 압축을 풉니다. 다음 샘플 /etc/vault.hcl
파일을 사용하여 Vault에 원격으로 액세스하고 TLS를 비활성화합니다(테스트 시 사용 편의성을 위해).
backend "file" {
path = "/var/lib/vault"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 1
}
2. 시작 스크립트를 사용하거나 수동으로 Vault를 시작합니다.
user@pdp:~$ sudo /usr/local/bin/vault server -config=/etc/vault.hcl
3. Vault를 초기화하고 초기 루트 토큰을 얻습니다.
user@pdp:~$ export VAULT_ADDR=http://localhost:8200
user@pdp:~$ vault init -key-shares=3 -key-threshold=2
user@pdp:~$ vault operator unseal
Initial Root Token: 86c5c2a4-8ab2-24dd-1816-48449c83114e
4. 다음 명령에서 초기 루트 토큰을 제공해야 합니다. 편의를 위해 이를 root_token 쉘 변수에 할당합니다.
user@pdp:~$ root_token=86c5c2a4-8ab2-24dd-1816-48449c83114e
1-2. Secret 저장
5. PDP 서버에서 계속 작업하면서 암호가 포함된 /tmp/ssl_passwords.txt
라는 임시 파일을 만듭니다.
6. 이 파일을 Vault에 Secret로 저장하고 검색할 수 있는지 확인합니다.
user@pdp:~$ VAULT_TOKEN=$root_token vault kv put secret/webservers/ssl_passwords value=@/tmp/ssl_passwords.txt
user@pdp:~$ VAULT_TOKEN=$root_token vault kv get -field=value secret/webservers/ssl_passwords
password1
password2
...
7. 보안을 위해 /tmp/ssl_passwords.txt
를 삭제합니다.
8. 다음 내용으로 web.hcl
이라는 파일에 정책 사양을 만듭니다.
path "secret/webservers/*" {
capabilities = ["read"]
}
9. 정책을 Vault에 로드하고 이름을 web으로 지정합니다.
user@pdp:~$ VAULT_TOKEN=$root_token vault policy write web web.hcl
10. 새 인증 토큰을 만들고 웹 정책과 연결하고 선택적으로 표시 이름 매개 변수를 포함하여 사용자에게 친숙한 이름을 지정합니다. 토큰 및 token_accessor 값을 기록해 둡니다. 후속 명령에서 사용합니다.
user@pdp:~$ VAULT_TOKEN=$root_token vault token create -policy=web -display-name=webserver1
Key Value
--- -----
token dcf75ffd-a245-860f-6960-dc9e834d3385
token_accessor 0c1d6181-7adf-7b42-27be-b70cfa264048
NGINX 웹 서버는 이 토큰을 사용하여 SSL 암호를 검색합니다. 웹 정책은 웹 서버가 secret/webservers/*
경로 외부의 Secret을 검색하는 것을 방지합니다.
1-3. 웹 서버가 토큰을 검색할 수 있는지 확인
1. NGINX 웹 서버에서 작업하면서 Vault Binary를 설치합니다.
2. 원격 Vault 서버(여기서는 http://pdp:8200
)의 위치를 선언한 다음 웹 서버 시스템이 토큰을 사용하여 SSL 암호를 검색할 수 있는지 확인합니다.
user@web1:~$ export VAULT_ADDR=http://pdp:8200
user@web1:~$ VAULT_TOKEN=dcf75ffd-a245-860f-6960-dc9e834d3385 vault kv get -field=value secret/webservers/ssl_passwords
password1
password2
...
1-4. 웹 서버에서 NGINX Vault 커넥터 구성
3. 첫 번째 포스트에서 샘플 PDP 설정의 일부로 NGINX 호스트(웹 서버 시스템)에 connector.sh
라는 쉘 스크립트를 만들었습니다. 여기서는 Vault를 사용하도록 수정합니다.
#!/bin/sh
# Usage: connector_v.sh
CONNECTOR=$1
CREDS=$2
[ -e $CONNECTOR ] && /bin/rm -f $CONNECTOR
mkfifo $CONNECTOR; chmod 600 $CONNECTOR
export VAULT_ADDR=http://pdp:8200
export VAULT_TOKEN=$CREDS
while true; do
vault kv get -field=value secret/webservers/ssl_passwords > $CONNECTOR
sleep 0.1 # race condition, ensures EOF
done
4. 다음과 같이 호출되는 백그라운드 프로세스로 스크립트를 실행합니다.
root@web1:~# ./connector_v.sh /var/run/nginx/ssl_passwords \
dcf75ffd-a245-860f-6960-dc9e834d3385 &
5. Connector 경로에서 읽어 Connector를 테스트합니다.
root@web1:~$ cat /var/run/nginx/ssl_passwords
password1
password2
...
6. 시작 시 ssl_passwords
파일을 읽고 콘텐츠를 암호로 사용하여 암호화된 개인 키를 해독하도록 NGINX를 구성합니다. ssl_password_file 지시문을 server 블록(첫 번째 포스트의 표준 구성에 대해 생성된 것과 같은) 또는 http 컨텍스트에 포함하여 여러 가상 서버에 적용할 수 있습니다.
ssl_password_file /var/run/nginx/ssl_passwords;
7. NGINX가 암호를 읽고 SSL 키의 암호를 해독할 수 있는지 확인합니다.
root@web1:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
1-5. 웹 서버의 인증 토큰 취소
웹 서버가 손상되었거나 폐기된 경우 액세스 권한을 쉽게 취소할 수 있습니다. 이를 위해 웹 서버에서 사용하는 인증 토큰을 직접 취소할 수 있습니다.
user@pdp:~$ VAULT_TOKEN=$root_token vault token revoke dcf75ffd-a245-860f-6960-dc9e834d3385
Vault 토큰은 중요한 데이터 항목이며, 대부분의 Vault Workflow는 인증된 클라이언트에 발행된 토큰 사본을 저장하지 않습니다. 토큰 사본이 유출되면 공격자가 클라이언트를 가장할 수 있습니다.
대신 토큰에 대한 제한된 권한을 부여하고 토큰 값을 검색하는 데 사용할 수 없는 Accessor를 사용하여 활성 토큰을 관리하는 것이 일반적입니다. 발행될 때 토큰을 저장하는 대신 해당 Accessor를 저장하십시오.
웹 서버의 인증 토큰에 대한 Accessor를 결정해야 하는 경우 Vault 목록 명령을 실행하여 Accessor 목록을 검색하고 각 Accessor에 대한 Vault 토큰 조회 명령을 실행하여 관련 표시 이름 및 정책이 있는 Accessor를 찾습니다.
user@pdp:~$ VAULT_TOKEN=$root_token vault list /auth/token/accessors
Keys
----
83be5a73-9025-1221-cb70-4b0e8a3ba8df
0c1d6181-7adf-7b42-27be-b70cfa264048
f043b145-7a63-01db-ea85-9f22f413c55e
user@pdp:~$ VAULT_TOKEN=$root_token vault token lookup -accessor 0c1d6181-7adf-7b42-27be-b70cfa264048
Key Value
--- -----
...
display-name webserver1
...
policy web
...
그런 다음 Accessor를 사용하여 토큰을 취소할 수 있습니다.
user@pdp:~$ VAULT_TOKEN=$root_token vault token revoke -accessor 0c1d6181-7adf-7b42-27be-b70cfa264048
1-6. 보안 관련 사항
Vault 사용에는 첫 번째 포스트에서 설명한 샘플 PDP와 유사한 보안 프로파일을 가지고 있습니다. SSL 개인키는 해당 암호를 획득해야만 획득할 수 있으며, 이를 위해서는 공격자가 현재 인증 토큰의 값을 알아야 합니다.
Vault 사용의 주요 이점은 Secret 저장소를 자동화하고 확장하는 것입니다.
2. 외부 HSM을 사용하여 NGINX SSL 개인 키 관리
지금까지 시리즈에서 다룬 솔루션 중 어느 것도 공격자가 NGINX 서버에 대한 root 액세스 권한을 얻을 때 개인 키를 보호하지 않습니다. 공격자가 NGINX의 런타임 메모리에 액세스하거나 코어 덤프를 생성할 수 있는 경우 프로세스의 메모리를 스캔하고 개인 키 데이터를 찾는 잘 알려진 기술이 있습니다.
외부 하드웨어 보안 모듈(HSM)은 변조 방지 외부 하드웨어에 SSL 개인 키를 저장하여 이 문제를 해결합니다. 그들은 복호화를 서비스로 제공하며 NGINX는 케이가 필요한 SSL 작업을 수행해야 할 때마다 해당 서비스에 액세스합니다.
NGINX 서버는 SSL 개인 키 데이터를 볼 수 없습니다. 서버에 대한 root 액세스 권한을 얻은 공격자는 SSL 개인 키를 얻을 수 없지만 NGINX 자격 증명을 사용하여 HSM 암호 해독 서비스에 액세스하여 필요에 따라 데이터를 암호 해독할 수 있습니다.
2-1. HSM에 액세스하도록 NGINX SSL 구성
NGINX는 모든 SSL 개인 키 작업을 OpenSSL이라는 암호화 라이브러리에 위임합니다. 타사 HSM 디바이스는 HSM 공급업체의 OpenSSL 엔진을 사용하여 NGINX에서 사용할 수 있습니다.
NGINX 구성은 각 공급업체 HSM에 따라 다르지만 일반적으로 다음과 같은 간단한 경로를 따릅니다.
기본 소프트웨어 엔진이 아닌 공급업체의 OpenSSL 엔진을 사용하도록 NGINX를 구성합니다.
ssl_certificate_key engine:vendor-hsm-engine:...;
실제 개인 키를 사용하는 대신 공급업체에서 제공한 ‘fake(가짜)’ 키를 사용하도록 NGINX를 구성합니다. 이 키에는 HSM 디바이스에서 실제 키를 식별하는 핸들이 포함되어 있습니다.
ssl_certificate_key ssl/vendor.private.key;
키에는 HSM 디바이스에 액세스하기 위한 자격 증명이 포함될 수도 있고, 추가 공급업체별 구성을 사용하여 자격 증명을 제공할 수도 있습니다.
(선택 사항) NGINX Worker Processes 수를 늘리는 등 원하는 튜닝을 적용하여 NGINX 및 HSM의 성능을 최대화합니다.
HSM 설정의 예는 Amazon의 CloudHSM 설명서를 참조하십시오.
2-2. 보안 관련 사항
외부 HSM은 SSL 개인 키를 저장하는 매우 안전한 방법입니다. NGINX 서버에 대한 root 액세스 권한이 있는 공격자는 NGINX 자격 증명을 활용하여 HSM을 사용하여 임의의 데이터를 해독할 수 있지만 암호화되지 않은 개인 키를 얻을 수는 없습니다. HSM은 공격자가 웹 사이트를 가장하거나 오프라인에서 임의의 데이터를 해독하는 것을 상당히 어렵게 만듭니다.
3. NGINX SSL 개인키 보호 결론
공개의 결과가 매우 심각하기 때문에 SSL 개인 키와 같은 Secret 데이터를 완전히 보호되도록 하는 것이 중요합니다.
적절한 보안 프로세스가 있는 많은 조직의 경우 Frontend Load Balancer에 개인 키를 저장한 다음 해당 서버에 대한 모든 액세스를 제한하고 감사하는 것으로 충분합니다(첫 번째 포스에서 설명한 표준 구성).
NGINX 구성을 자주 배포해야 하는 조직의 경우 이 포스트와 첫 번째 포스트의 조치를 사용하여 개인 키 데이터를 볼 수 있는 사용자 또는 Entity를 제한할 수 있습니다.
NGINX Plus를 직접 사용해 보거나 테스트해 보려면 지금 30일 무료 평가판을 신청하거나 사용 사례에 대해 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.