이 블로그 게시물에서는 NGINX가 SSL로 암호화된 웹사이트를 호스팅할 때 사용하는 SSL 개인 키를 안전하게 배포하는 여러 가지 방법을 설명합니다. 주요 내용은 다음과 같습니다:
- NGINX에서 SSL을 구성하는 표준 방식과 잠재적인 보안상의 한계
- NGINX 구성과 별도로 저장된 비밀번호를 사용하여 키를 암호화하는 방법 using passwords that are stored separately from the NGINX configuration
- 암호화 비밀번호를 안전하게 배포하고, 디스크에 저장하지 않으며 필요할 때 폐기하는 방법
많은 배포 환경에서는 표준 접근 방식으로 충분합니다. 이 글에서 다루는 두 가지 고급 접근 방식은 공격자가 다른 경로로 SSL 개인 키를 탈취하는 것을 차단합니다. 후속 글에서는 몇 가지 기법을 더 살펴보겠습니다:
- HashiCorp Vault와 같은 타사 비밀 저장소를 사용하여 비밀번호를 안전하게 배포
- Vault에서 NGINX Plus의 키-값 저장소로 인증서를 자동 프로비저닝하여 개인 키 자료가 디스크에 저장되지 않도록 합니다
이 게시물에서 소개하는 접근 방식은 자체 키를 관리하고 안전한 키 배포 전략을 직접 수립해야 하는 사용자에게 적합합니다. Kubernetes와 같이 이미 비밀 저장소와 통합된 환경에서 NGINX를 실행하는 사용자에게는 이러한 접근 방식이 필요하지 않습니다.
이 게시물은 NGINX Open Source와 NGINX Plus 모두에 적용됩니다. 읽기 쉽도록 이 글에서는 모두 NGINX로 지칭하겠습니다.
편집자 주 – 이 글은 NGINX에서 SSL 개인 키를 안전하게 보호하는 방법을 다루는 시리즈의 첫 번째 글입니다. 시리즈의 다른 글도 참조하세요:
- HashiCorp Vault를 사용하여 NGINX의 SSL 개인 키 보호 – HashiCorp Vault 또는 하드웨어 보안 모듈(HSM)을 사용해 키 보호 시스템을 자동화하고 확장하는 방법을 설명합니다
- NGINX Plus 키-값 저장소를 사용하여 HashiCorp Vault의 임시 SSL 키 보호 – HashiCorp Vault에서 임시 SSL 키를 생성하고 NGINX Plus 인메모리 키-값 저장소에 저장하여 SSL 키를 디스크에 저장하지 않는 방법을 설명합니다
SSL 개인 키를 보호해야 하는 이유
SSL/TLS는 네트워크 트랜잭션을 인증 및 암호화하고 무결성을 검증하는 데 사용됩니다. 웹사이트는 인증 기관(CA)이 서명한 공개 인증서를 사용하여 자신을 인증하고, 해당 인증서에 대응하는 개인 키(반드시 비밀로 유지해야 함)를 사용해 연산을 수행함으로써 인증서의 소유권을 증명합니다.
비공개 키가 유출되어 다른 주체에게 공개되면 두 가지 주요 위험이 발생합니다.
- 위험 1: 사칭. 개인 키를 보유한 공격자는 네트워크 트래픽을 가로챈 다음 중간자(MITM) 공격을 수행할 수 있습니다. 이 공격은 클라이언트나 웹사이트가 알아차리지 못하는 사이에 모든 트래픽을 캡처하고 복호화하며, 경우에 따라 이를 변조하기도 합니다.
- 위험 2: 복호화. 개인 키를 보유하고 네트워크 트래픽을 기록한 공격자는 이후 오프라인에서 해당 네트워크 트래픽을 복호화할 수 있습니다. 단, 이 공격은 완전 순방향 비밀성(PFS) 암호화 방식을 사용하는 연결에는 적용할 수 없습니다.
개인 키가 유출된 경우, 유일한 대응 방법은 CA에 연락하여 인증서 폐기를 요청하는 것입니다. 그런 다음 클라이언트가 폐기 상태를 확인하고 이를 준수하기를 기대해야 합니다.
또한 유효 기간이 짧은 인증서를 사용하는 것이 좋습니다(예: Let’s Encrypt 인증서는 90일 후에 만료됩니다). 인증서가 만료되기 직전에 새 개인 키를 생성하고 CA에서 새 인증서를 발급받아야 합니다. 이렇게 하면 개인 키가 유출되었을 때의 위험을 줄일 수 있습니다.
NGINX 보안 경계
NGINX에서 SSL 개인 키에 액세스할 수 있는 사용자와 프로세스는 무엇인가요?
우선, NGINX가 실행 중인 서버에 root 액세스 권한을 얻은 사용자는 누구나 NGINX 자체에서 사용하는 모든 리소스를 읽고 사용할 수 있습니다. 예를 들어 실행 중인 프로세스의 메모리에서 SSL 개인 키를 추출하는 것으로 알려진 방법들이 있습니다.
따라서 개인 키를 어떤 방식으로 저장하고 배포하더라도 호스트 서버에서 root 권한을 가진 공격자로부터 개인 키를 보호할 수는 없습니다.
다음으로, NGINX 구성을 수정하고 커밋할 수 있는 사용자는 누구나 그 권한을 다양한 방식으로 사용할 수 있습니다. 예를 들어 내부 서비스에 대한 프록시 액세스를 허용하거나 인증 조치를 우회할 수 있습니다. 또한 NGINX 구성을 수정하여 서버에 대한 root 액세스 권한(또는 이에 상응하는 권한)을 얻을 수도 있지만, SELinux 및 AppArmor와 같은 도구를 사용하면 이러한 가능성을 줄일 수 있습니다.
따라서 NGINX 구성을 수정하고 커밋할 수 있는 공격자로부터 비공개 키를 보호하는 것은 일반적으로 불가능합니다.
다행히도 역량 있는 조직이라면 공격자가 root 권한을 획득하거나 NGINX 구성을 변경하기 어렵도록 체계적인 보안 프로세스를 갖추고 있습니다.
하지만 권한이 더 적은 공격자가 개인 키에 접근할 수 있는 다른 두 가지 방법이 있습니다:
- 사용자는 정당한 사유로 NGINX 구성을 확인해야 할 수도 있고, 구성 데이터베이스나 백업에 대한 액세스 권한을 얻을 수도 있습니다. NGINX 개인 키는 일반적으로 구성에 저장됩니다.
- 사용자는 하이퍼바이저나 시스템 백업 등을 통해 NGINX 서버의 파일 시스템에 액세스할 수 있습니다. 이 경우 개인 키 자료를 비롯하여 파일 시스템에 저장된 모든 데이터에 액세스할 가능성이 있습니다.
이 문서에서 설명하는 프로세스는 이 두 가지 공격 경로를 차단합니다.
표준 NGINX 구성
먼저 일반적인 SSL/TLS 적용 NGINX 구성이 어떤 모습인지 살펴보겠습니다:
server {
listen 443 ssl;
server_name a.dev0;
ssl_certificate ssl/a.dev0.crt;
ssl_certificate_key ssl/a.dev0.key;
location / {
return 200 "Hello from service A\n";
}
}SSL 공개 인증서(a.dev0.crt)와 개인 키(a.dev0.key)는 파일 시스템의 /etc/nginx/ssl/에 저장됩니다. 개인 키는 일반적으로 root로 실행되는 NGINX 마스터 프로세스만 읽으므로, 가능한 한 가장 엄격한 접근 권한을 설정할 수 있습니다:
root@web1:/etc/nginx/ssl# ls -l a.dev0.key-r-------- 1 root root 1766 Aug 15 16:32 a.dev0.key개인 키는 항상 사용할 수 있어야 합니다. NGINX 마스터 프로세스는 NGINX 소프트웨어가 시작되거나, 구성을 다시 로드하거나, 구문 검사를 수행할 때마다 개인 키를 읽습니다(nginx -t).
SSL/TLS 구성에 대한 자세한 내용은 NGINX Plus 관리 가이드를 참조하세요.
표준 구성의 보안 영향
앞서 언급했듯이, 공격자가 NGINX 소프트웨어가 실행 중인 컨테이너, 가상 머신 또는 서버에 root 액세스 권한을 획득하면 SSL 개인 키를 읽을 수 있습니다.
SSL 개인 키 암호화
NGINX는 AES256과 같은 안전한 알고리즘으로 암호화된 개인 키를 지원합니다:
root@web1:/etc/nginx/ssl# mv a.dev0.key a.dev0.key.plainroot@web1:/etc/nginx/ssl# openssl rsa -aes256 -in a.dev0.key.plain -out a.dev0.key
writing RSA key
Enter PEM pass phrase: secure password
Verifying - Enter PEM pass phrase: secure password again그런 다음 NGINX를 시작하거나 NGINX 구성을 다시 로드 또는 테스트하면 NGINX에서 대화형으로 복호화 암호를 입력하라는 메시지가 표시됩니다:
root@web1:/etc/nginx# nginx -tEnter PEM pass phrase: secure password
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulSSL 비밀번호 파일 사용
대화형으로 비밀번호를 입력하는 방식은 불편하고 자동화하기도 어렵지만, NGINX가 ssl_password_file 지시문으로 지정한 별도의 파일에 저장된 비밀번호 목록을 사용하도록 구성할 수 있습니다. NGINX는 개인 키를 읽어야 할 때 파일에 있는 각 비밀번호를 차례로 사용하여 키 복호화를 시도합니다. 유효한 비밀번호가 하나도 없으면 NGINX가 시작되지 않습니다.
ssl_password_file /var/lib/nginx/ssl_passwords.txt;The ssl_password_file은(는) 구성과 별도로 배포해야 하며, root 사용자만 읽을 수 있어야 합니다. 이를 신뢰할 수 있는 서버에 배치되는 인증 토큰으로 간주할 수 있습니다. NGINX는 인증 토큰이 있는 서버에서 실행될 때만 개인 키를 복호화할 수 있습니다.
암호화된 키를 별도 파일에 저장할 때의 보안 고려 사항
이 방법은 NGINX 구성만으로는 공격자에게 쓸모가 없도록 하여 공격 표면을 줄입니다. 공격자는 다음 파일의 내용도 확보해야 합니다: ssl_password_file.
공격자가 root 권한으로 ssl_password_file이 저장된 파일 시스템에 액세스할 수 있게 되면(예: 백업 또는 호스트 시스템을 통해), 해당 파일을 읽고 그 안의 비밀번호를 사용하여 SSL 개인 키를 복호화할 수 있습니다.
이러한 위험을 줄이려면 ssl_password_file을 RAM 디스크 또는 tmpfs에 저장할 수 있습니다. 이러한 저장소는 일반적으로 외부 공격자가 접근하기가 더 어렵고(예: 서버를 다시 시작하면 내용이 삭제됨), 시스템 백업에서 제외할 수도 있습니다. 시스템 부팅 시 비밀번호 파일이 초기화되도록 해야 합니다.
SSL 비밀번호 목록을 더 안전하게 배포하기
아래 절차에서는 중앙 배포 지점에서 SSL 비밀번호 목록을 보다 안전하게 배포하는 방법을 설명합니다.
NGINX는 SSL 키를 복호화해야 할 때마다 중앙 배포 지점에 질의하고, 비밀번호를 로컬 디스크에 저장하지 않은 채 사용합니다. NGINX 인스턴스는 중앙 비밀번호 서버에 자신을 인증하기 위해 토큰을 사용하며, 언제든지 이 토큰을 취소하여 비밀번호에 대한 접근을 차단할 수 있습니다.
중앙 비밀번호 배포 지점 만들기
먼저 비밀번호 배포 지점(PDP)을 생성합니다. 이 간단한 구현에서는 사용자 이름과 비밀번호로 인증된 HTTPS 서비스를 사용하여 비밀번호 목록을 전달합니다:
$ curl -u dev0:mypassword https://pdpserver.local/ssl_passwords.txt
password1
password2
...그런 다음 필요에 따라 PDP에서 인증 토큰을 추가하거나 제거하여 액세스 권한을 부여하거나 취소할 수 있습니다. 비밀번호 배포 서버는 NGINX와 같은 웹 서버를 사용하여 구현할 수 있으며, 적절한 유형의 인증 토큰을 사용하면 됩니다.
다음으로, NGINX가 PDP에서 비밀번호를 가져오도록 설정해야 합니다. 먼저 다음 내용으로 connector.sh라는 셸 스크립트를 만듭니다:
#!/bin/sh
# Usage: connector.sh
CONNECTOR=$1
CREDS=$2
PDP_URL=$3
[ -e $CONNECTOR ] && /bin/rm -f $CONNECTOR
mkfifo $CONNECTOR; chmod 600 $CONNECTOR
while true; do
curl -s -u $CREDS -k $PDP_URL -o $CONNECTOR
done스크립트는 다음과 같이 호출하여 백그라운드 프로세스로 실행해야 합니다:
root@web1:~# ./connector.sh /var/run/nginx/ssl_passwords \dev0:mypassword https://pdpserver.local/ssl_passwords.txt &커넥터는 지정된 로컬 경로(/var/run/nginx/ssl_passwords)에 연결되며, ssl_password_file 지시어를 사용하여 NGINX가 해당 경로에 액세스하도록 구성합니다:
ssl_password_file /var/run/nginx/ssl_passwords;커넥터 경로에서 데이터를 읽어 커넥터를 테스트합니다:
root@web1:~# cat /var/run/nginx/ssl_passwords
password1
password2
...NGINX가 비밀번호를 읽고 SSL 키를 복호화할 수 있는지 확인합니다:
root@web1:~# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful중앙 PDP 방식을 사용하면 개별 개인 키나 기타 민감한 데이터 등 NGINX가 일반적으로 디스크에서 읽는 모든 리소스를 안전하게 배포할 수 있습니다.
PDP의 보안 영향
이 솔루션은 SSL 비밀번호를 디스크에 저장하는 방식과 비교해 다음과 같은 여러 이점이 있습니다:
- SSL 비밀번호는 서버의 파일 시스템에 저장되지 않습니다. 따라서 파일 시스템에 접근할 수 있는 공격자도 SSL 비밀번호에 직접 접근할 수 없습니다.
- 비밀번호는 중앙 액세스 지점에서 배포됩니다, 따라서 모니터링과 감사가 더 쉬워집니다.
- 개별 서버에 대한 액세스를 중앙에서 제어할 수 있습니다. 예를 들어 서버가 폐기되면 해당 서버의 액세스 토큰을 취소합니다.
파일 시스템에 액세스할 수 있는 사용자는 PDP에 액세스하는 데 사용되는 자격 증명을 추출할 가능성이 있다는 점에 유의하세요. 이러한 자격 증명이 더 이상 필요하지 않으면 반드시 폐기해야 합니다.
요약
SSL 개인 키의 노출을 방지하는 방법은 다양하며, 보안 수준이 높아질수록 복잡성도 증가합니다:
- 대다수의 조직에서는 권한이 없는 사용자가
root권한을 획득하거나 NGINX 구성을 열람할 수 없도록 NGINX가 실행되는 환경에 대한 접근을 제한하는 것으로 충분합니다. - 일부 환경에서는 NGINX 구성에 대한 액세스를 완전히 제한하지 못할 수 있으므로 SSL 암호 파일을 사용할 수 있습니다.
- 일부 제한적인 경우에는 조직에서 키와 비밀번호가 디스크에 저장되지 않도록 해야 할 수 있습니다. 비밀번호 배포 지점 프로세스는 이 솔루션의 개념 증명을 보여 줍니다.
이 시리즈의 다른 게시물에서는 SSL 키를 안전하게 보호하기 위해 취할 수 있는 추가 조치를 설명합니다:
- HashiCorp Vault로 NGINX의 SSL 개인 키 보호하기 – HashiCorp Vault를 PDP로 설정하여 세분화된 액세스 제어를 통해 확장 가능하고 안전하게 비밀 정보를 배포하는 방법을 설명합니다. 또한 하드웨어 보안 모듈(HSM)에 개인 키를 원격으로 저장하고, 필요할 때 키 작업을 수행하는 데 사용할 수 있는 API를 제공하는 방법도 다룹니다.
- NGINX Plus 키-값 저장소를 사용하여 HashiCorp Vault의 임시 SSL 키 보호하기 – HashiCorp Vault에서 임시 SSL 키를 생성하고 NGINX Plus 인메모리 키-값 저장소에 저장하여 SSL 키를 디스크에 저장하지 않는 방법을 보여줍니다.
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에게서 알아보세요.