이 시리즈의 첫 번째 게시물에서는 SSL 개인 키의 보안을 강화하는 몇 가지 방법을 설명합니다. 게시물의 마지막에는 암호화 비밀번호를 NGINX 인스턴스와 안전하게 공유하는 데 사용되는 원격 비밀번호 배포 지점(PDP)을 시연합니다.
다음과 같은 비밀 관리 시스템은 HashiCorp Vault 앞서 예로 든 PDP와 유사한 방식으로 작동합니다:
- HTTPS 또는 다른 API를 통해 액세스하는 중앙 집중식(또는 고가용성 분산형) 비밀 관리 서비스를 사용합니다
- 클라이언트는 인증 토큰 또는 기타 수단을 통해 인증됩니다
- 비밀 정보에 대한 액세스를 제어하기 위해 필요에 따라 토큰을 폐기할 수 있습니다
이 게시물에서는 SSL 비밀번호를 배포하도록 HashiCorp Vault를 설정하는 방법을 설명합니다. 보안을 한층 더 강화하려면 외부 하드웨어 보안 모듈을 설정할 수 있습니다(HSM).
SSL 인증서-키 쌍을 디스크에 저장하지 않도록 완전히 제거하려면 이 시리즈의 세 번째 게시물인 NGINX Plus 키-값 저장소를 사용하여 HashiCorp Vault의 임시 SSL 키 보호하기를 참조하세요. 이 게시물에서는 HashiCorp Vault에서 임시 SSL 키를 생성하고 NGINX Plus 키-값 저장소를 통해 메모리에 저장하는 방법을 설명합니다.
이 게시물은 NGINX Open Source와 NGINX Plus 모두에 적용됩니다. 읽기 쉽도록 이 글에서는 모두 NGINX로 지칭하겠습니다.
HashiCorp Vault를 사용하여 SSL 개인 키 보호하기
이 섹션의 지침에서는 Vault를 사용하여 SSL 비밀번호를 배포하는 중앙 PDP 서버를 설정합니다. 이 지침은 DigitalOcean의 지침을 기반으로 하며, 자체 Vault 정책을 준수하도록 필요에 따라 수정하십시오.
이 예시에서는 각 원격 웹 서버에 고유한 인증 토큰이 있습니다. 이러한 토큰을 사용하여 Vault의 secret/webservers/ 경로에 있는 비밀 정보에 액세스할 수 있으며, SSL 비밀번호는 secret/webservers/ssl_passwords에 저장합니다.
토큰을 안전하게 보호하는 방법과 필요할 때 개별 인증 토큰을 폐기하는 방법을 살펴보겠습니다.
PDP 서버에서 HashiCorp Vault 다운로드, 설치 및 초기화
- 다음 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
}- 시작 스크립트를 만든 경우 해당 스크립트를 사용하여 Vault를 시작하거나, 다음과 같이 수동으로 시작합니다:
user@pdp:~$ sudo /usr/local/bin/vault server -config=/etc/vault.hcl- 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- 다음 명령 중 다수에서 초기 루트 토큰을 제공해야 합니다. 편의를 위해 이 토큰을
root_token셸 변수에 할당합니다:
user@pdp:~$ root_token=86c5c2a4-8ab2-24dd-1816-48449c83114e비밀 정보 저장
- 계속해서 PDP 서버에서 작업하여, 비밀번호를 저장할 임시 파일인 /tmp/ssl_passwords.txt을 생성합니다.
- 이 파일을 Vault에 시크릿으로 저장한 후, 정상적으로 가져올 수 있는지 확인합니다:
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
...- 보안을 위해 /tmp/ssl_passwords.txt 파일을 삭제합니다.
- 다음 정책 사양을 web.hcl 파일에 작성합니다:
path "secret/webservers/*" {
capabilities = ["read"]
}- 정책을 Vault에 로드하고 이름을
web으로 지정합니다:
user@pdp:~$ VAULT_TOKEN=$root_token vault policy write web web.hcl- 새 인증 토큰을 생성하고
web정책에 연결합니다. 필요에 따라display-name매개변수를 포함하여 알아보기 쉬운 이름을 지정할 수 있습니다.token및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 비밀번호를 가져옵니다.
web정책은 웹 서버가 secret/webservers/* 경로 외부의 시크릿을 가져오지 못하도록 합니다.
웹 서버가 토큰을 가져올 수 있는지 확인
- NGINX 웹 서버에서 Vault 바이너리를 설치합니다.
- 원격 Vault 서버의 위치(여기서는 http://pdp:8200)를 선언한 다음, 웹 서버 머신이 토큰을 사용하여 SSL 비밀번호를 가져올 수 있는지 확인합니다:
user@web1:~$ export VAULT_ADDR=http://pdp:8200user@web1:~$ VAULT_TOKEN=dcf75ffd-a245-860f-6960-dc9e834d3385 vault kv get -field=value secret/webservers/ssl_passwords
password1
password2
...웹 서버에서 NGINX Vault Connector 구성
- 샘플 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- 다음과 같이 스크립트를 호출하여 백그라운드 프로세스로 실행합니다:
root@web1:~# ./connector_v.sh /var/run/nginx/ssl_passwords \dcf75ffd-a245-860f-6960-dc9e834d3385 &- 커넥터 경로에서 데이터를 읽어 커넥터를 테스트합니다:
root@web1:~$ cat /var/run/nginx/ssl_passwordspassword1
password2
...- NGINX가 시작 시 ssl_passwords 파일을 읽고, 그 내용을 암호화된 개인 키를 복호화하는 비밀번호로 사용하도록 구성합니다.
ssl_password_file지시문은server블록(첫 번째 게시물의 표준 구성에서 만든 블록과 같은 블록)에 포함하거나, 여러 가상 서버에 적용하려면http컨텍스트에 포함할 수 있습니다.
ssl_password_file /var/run/nginx/ssl_passwords;- 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웹 서버의 인증 토큰 해지
웹 서버가 침해되었거나 폐기되는 경우 액세스 권한을 손쉽게 취소할 수 있습니다. 이렇게 하려면 웹 서버에서 사용하는 인증 토큰을 직접 취소하면 됩니다:
user@pdp:~$ VAULT_TOKEN=$root_token vault token revoke dcf75ffd-a245-860f-6960-dc9e834d3385Vault 토큰은 민감한 데이터이며, 많은 Vault 워크플로에서는 인증된 클라이언트에 발급된 토큰의 사본을 저장하지 않습니다. 토큰 사본이 유출되면 공격자가 해당 클라이언트로 위장할 수 있습니다.
대신 활성 토큰은 일반적으로 해당 토큰의 접근자를 사용하여 관리합니다. 접근자는 토큰에 대해 제한된 권한만 제공하며 토큰 값을 가져오는 데 사용할 수 없습니다. 토큰이 발급될 때 토큰 자체를 저장하는 대신 해당 접근자를 저장하세요.
웹 서버의 인증 토큰에 대한 접근자를 확인해야 하는 경우, vault list 명령을 실행하여 접근자 목록을 가져온 다음, 각 접근자에 대해 vault token lookup 명령을 실행하여 관련 표시 이름과 정책이 있는 접근자를 찾으세요:
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
...그런 다음 해당 토큰의 접근자를 사용하여 토큰을 취소할 수 있습니다:
user@pdp:~$ VAULT_TOKEN=$root_token vault token revoke -accessor 0c1d6181-7adf-7b42-27be-b70cfa264048보안에 미치는 영향
Vault를 사용할 때의 보안 특성은 첫 번째 게시물에서 설명한 샘플 PDP와 유사합니다. SSL 개인 키는 해당 비밀번호를 확보해야만 얻을 수 있으며, 이를 위해 공격자는 현재 유효한 인증 토큰의 값을 알아야 합니다.
Vault를 사용하는 가장 큰 이점은 비밀 저장소를 자동화하고 확장할 수 있다는 것입니다.
외부 HSM을 사용하여 개인 키 관리
지금까지 이 시리즈에서 살펴본 솔루션 중 공격자가 NGINX 서버에 root 권한으로 액세스했을 때 개인 키를 보호할 수 있는 것은 없습니다. 공격자가 NGINX의 런타임 메모리에 액세스하거나 코어 덤프를 생성할 수 있다면, 프로세스 메모리를 스캔하여 개인 키 데이터를 찾아내는 잘 알려진 기법을 사용할 수 있습니다.
외부 하드웨어 보안 모듈(HSM)은 SSL 개인 키를 변조 방지 기능이 있는 외부 하드웨어에 저장하여 이 문제를 해결합니다. HSM은 복호화 기능을 서비스로 제공하며, NGINX는 키가 필요한 SSL 작업을 수행할 때마다 해당 서비스에 액세스합니다.
NGINX 서버는 SSL 개인 키 데이터를 전혀 볼 수 없습니다. 서버에서 root 액세스 권한을 획득한 공격자는 SSL 개인 키를 얻을 수는 없지만, NGINX 자격 증명을 사용하여 HSM 복호화 서비스에 액세스해 필요할 때 데이터를 복호화할 수 있습니다.
HSM에 액세스하도록 NGINX 구성
NGINX는 모든 SSL 개인 키 작업을 OpenSSL이라는 암호화 라이브러리에 위임합니다. HSM 공급업체의 OpenSSL 엔진을 사용하면 타사 HSM 장치를 NGINX에서 사용할 수 있습니다.
NGINX 구성은 각 HSM 공급업체에 따라 다르지만, 일반적으로 다음과 같은 간단한 절차를 따릅니다:
- 기본 소프트웨어 엔진 대신 공급업체의 OpenSSL 엔진을 사용하도록 NGINX를 구성합니다:
ssl_certificate_key engine:vendor-hsm-engine:...;- 실제 개인 키를 사용하는 대신, 공급업체에서 제공한 ‘가짜’ 키를 사용하도록 NGINX를 구성합니다. 이 키에는 HSM 장치에서 실제 키를 식별하는 핸들이 포함되어 있습니다:
ssl_certificate_key ssl/vendor.private.key;- 키에는 HSM 장치에 액세스하기 위한 자격 증명이 포함될 수도 있으며, 추가적인 공급업체별 구성을 통해 자격 증명을 제공할 수도 있습니다.
- (선택 사항) NGINX와 HSM의 성능을 극대화하려면 NGINX 작업자 프로세스 수를 늘리는 등 원하는 대로 조정합니다.
HSM 설정 예시는 Amazon의 CloudHSM 설명서를 참조하세요.
보안 관련 고려 사항
외부 HSM은 SSL 개인 키를 매우 안전하게 저장하는 방법입니다. NGINX 서버에 root 액세스 권한이 있는 공격자는 NGINX 자격 증명을 이용해 HSM으로 임의의 데이터를 복호화할 수 있지만, 암호화되지 않은 개인 키를 획득할 수는 없습니다. HSM을 사용하면 공격자가 웹사이트를 사칭하거나 오프라인에서 임의의 데이터를 복호화하기가 훨씬 더 어려워집니다.
결론
SSL 개인 키와 같은 기밀 데이터는 유출될 경우 그 결과가 매우 심각하므로 철저히 보호해야 합니다.
적절한 보안 프로세스를 갖춘 많은 조직에서는 프라이빗 키를 프런트엔드 로드 밸런서에 저장한 다음 해당 서버에 대한 모든 액세스를 제한하고 감사하는 것으로 충분합니다(첫 번째 게시물에서 설명한 표준 구성).
NGINX 구성을 자주 배포해야 하는 조직은 이 게시물과 첫 번째 게시물에서 설명한 조치를 활용하여 비공개 키 데이터를 볼 수 있는 사용자나 엔터티를 제한할 수 있습니다.
이 시리즈의 세 번째 게시물인 NGINX Plus 키-값 저장소를 사용하여 HashiCorp Vault의 임시 SSL 키 보호하기에서는 NGINX Plus API를 사용해 Vault에서 NGINX Plus의 키-값 저장소로 키와 인증서를 자동으로 프로비저닝하는 방법을 설명합니다.
다시 한번 강조하지만, 이러한 방법 중 어느 것도 실행 중인 NGINX 인스턴스를 원격 액세스나 구성 조작으로부터 완벽하게 보호해야 할 필요성을 줄여 주지는 않습니다.
NGINX Plus를 직접 사용해 보세요. 지금 30일 무료 체험을 시작하거나 사용 사례에 대해 논의하려면 문의해 주세요.
작성자 소개

관련 블로그 게시물
시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric
이 영상에서는 KubeCon의 NGINX 부스를 찾아가, 저희가 공개한 Kubernetes Gateway API 구현을 살펴봅니다.
F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법
앱 보안을 강화하는 두 가지 방법을 소개합니다. NGINX Management Suite를 통해 WAF 운영에 대한 가시성을 높이고, NGINX App Protect WAF를 활용해 코드형 보안을 구현하는 것입니다.
Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션
개발 주체, 개발 철학, 프로덕션 환경 준비도, 보안 및 지원을 기준으로 어떤 NGINX Ingress 컨트롤러가 가장 적합한지 알아보세요.
진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법
NGINX App Protect Denial of Service(DoS)가 계층 7 DoS 공격을 방어하기 위해 완화 방법을 실시간으로 조정하는 방식을 설명합니다. 정상적인 사용자 행동과 서버 상태에 대한 모델을 생성하여 공격을 나타내는 이상 징후를 감지하고 맞춤형 완화 시그니처를 적용할 수 있습니다.
NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리
NGINX Instance Manager 버전 1.0에는 두 가지 새로운 기능이 도입되었습니다. NGINX 인스턴스에 태그와 사용자 역할을 지정하면 전체 그룹에 구성을 한 번에 적용할 수 있습니다. 인증서 검사는 만료 예정인 인증서를 감지하여 서비스 중단을 방지할 수 있도록 인증서를 교체할 수 있게 해줍니다.
Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유
Netflix가 글로벌 콘텐츠 전송 네트워크인 Open Connect의 스트리밍 미디어 기술로 NGINX를 선택한 이유를 NGINX 개발자 Gleb Smirnoff에게서 알아보세요.