NGINX를 사용한 TLS 오프로드에 Cloud HSM 키 사용

이 가이드에서는 Debian 11(Bullseye)에서 TLS 오프로드에 Cloud HSM 키를 사용하도록 NGINX를 설정하는 방법을 안내합니다. OS 또는 Linux 배포판에서 사용하려면 명령어를 수정해야 할 수 있습니다.

사용 사례

TLS 오프로드에 NGINX와 함께 Cloud HSM 키를 사용하면 다음 엔터프라이즈 보안 요구를 해결하는 데 도움이 됩니다.

  • NGINX 웹 서버가 TLS 암호화 작업을 Cloud HSM으로 오프로드하도록 설정합니다.
  • 웹 애플리케이션을 호스팅하는 Compute Engine 인스턴스의 로컬 파일 시스템에 인증서의 비공개 키를 저장하지 않습니다.
  • FIPS 140-2 레벨 3 인증을 포함하는 HSM으로 공개용 애플리케이션의 인증서를 보호해야 하는 규제 요구사항을 충족해야 합니다.
  • NGINX를 사용하여 웹 애플리케이션 보호를 위해 TLS 종료가 포함된 역방향 프록시를 만들어야 합니다.

시작하기 전에

작업을 계속하기 전에 OpenSSL에서 Cloud HSM 키 사용의 단계를 완료합니다.

OpenSSL 설정이 완료되면 최신 버전의 nginx가 설치되어 있는지 확인합니다.

sudo apt-get update
sudo apt-get install libengine-pkcs11-openssl opensc nginx

보안 구성 권장사항

다음 권장사항에 따라 NGINX를 호스팅하는 인스턴스를 보호합니다.

  1. 인스턴스의 서비스 계정 만들기 및 사용 설정의 안내에 따라 NGINX를 호스팅합니다.

    1. 다음 역할을 할당합니다.
      • roles/cloudkms.signerVerifier
      • roles/cloudkms.viewer
  2. 다음과 같이 조직 정책을 구성하여 외부 IP 및 서비스 계정 키 만들기를 제한합니다.

    • constraints/compute.vmExternalIpAccess
    • constraints/iam.disableServiceAccountKeyCreation
  3. 비공개 Google 액세스를 사용 설정하는 커스텀 서브넷을 만듭니다.

  4. 방화벽 규칙을 구성합니다.

  5. Linux VM을 만들고 다음과 같이 구성합니다.

    • 이전에 만든 올바른 서비스 계정을 선택합니다.
    • 앞에서 만든 네트워크를 선택합니다.
      • 방화벽 규칙에 대해 적합한 라벨을 추가합니다.
      • 서브넷의 '외부 IP' 필드가 none으로 설정되었는지 확인합니다.
  6. ID에 인스턴스에 대한 IAP 보안 터널 사용자(roles/iap.tunnelResourceAccessor) 역할을 부여합니다.

Cloud KMS 호스팅 서명 키 만들기 및 구성

다음 섹션에서는 Cloud KMS 호스팅 서명 키를 만들고 구성하는 데 필요한 단계를 자세히 설명합니다.

Cloud KMS 호스팅 서명 키 만들기

이전에 OpenSSL에 구성한 키링에서 Google Cloud 프로젝트에 Cloud KMS EC-P256-SHA256 서명 키를 만듭니다.

gcloud kms keys create NGINX_KEY \
  --keyring "KEY_RING" --project "PROJECT_ID" \
  --location "LOCATION" --purpose "asymmetric-signing" \
  --default-algorithm "ec-sign-p256-sha256" --protection-level "hsm"

IAP를 사용하여 VM에 SSH로 연결

다음 명령어로 IAP를 사용하여 VM에 SSH로 연결합니다.

gcloud compute ssh INSTANCE \
  --zone ZONE --tunnel-through-iap

문제가 발생하면 --tunnel-through-iap 플래그가 사용되었는지 확인합니다. 또한 gcloud CLI를 사용하여 인증된 ID의 인스턴스에 대해 IAP 보안 터널 사용자(roles/iap.tunnelResourceAccessor) 역할이 있는지 확인합니다.

OpenSSL로 인증서 만들기

프로덕션 환경의 경우 인증서 서명 요청(CSR)을 만듭니다. 자세한 내용은 CSR 생성 예시를 참조하세요. 인증서를 만들 수 있도록 CSR을 인증 기관(CA)에 제공합니다. 이후 섹션에서 CA에서 제공된 인증서를 사용합니다.

예시 목적으로 Cloud KMS 호스팅 서명 키로 자체 서명 인증서를 생성할 수 있습니다. 이를 위해 OpenSSL에서는 일반 경로 대신 PKCS #11 URI를 사용하여 해당 라벨로 키를 식별할 수 있습니다(Cloud KMS 키의 경우 라벨이 CryptoKey 이름임).

openssl req -new -x509 -days 3650 -subj '/CN=CERTIFICATE_NAME/' \
  DIGEST_FLAG -engine pkcs11 -keyform engine \
  -key PKCS_KEY_TYPE=KEY_IDENTIFIER > CA_CERT

다음을 바꿉니다.

  • CERTIFICATE_NAME: 인증서의 이름입니다.
  • DIGEST_FLAG: 비대칭 서명 키에 사용되는 다이제스트 알고리즘입니다. 키에 따라 -sha256, -sha384, -sha512를 사용합니다.
  • PKCS_KEY_TYPE: 키 식별에 사용되는 식별자 유형입니다. 최신 키 버전을 사용하려면 키 이름과 함께 pkcs11:object를 사용합니다. 특정 키 버전을 사용하려면 키 버전의 전체 리소스 ID와 함께 pkcs11:id를 사용합니다.
  • KEY_IDENTIFIER: 키의 식별자입니다. pkcs11:object를 사용하는 경우 키 이름을 사용합니다(예: NGINX_KEY). pkcs11:id를 사용하는 경우 키 또는 키 버전의 전체 리소스 ID를 사용합니다(예: projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/NGINX_KEY/cryptoKeyVersions/KEY_VERSION).
  • CA_CERT: 인증서 파일을 저장하려는 경로입니다.

명령어가 실패하면 PKCS11_MODULE_PATH가 잘못 설정되었거나 Cloud KMS 서명 키를 사용할 수 있는 권한이 없을 수 있습니다.

이제 다음과 같은 인증서가 준비되었습니다.

-----BEGIN CERTIFICATE-----
...
...
...
-----END CERTIFICATE-----

NGINX용 인증서 설치

다음 명령어를 실행하여 공개 인증서를 배치할 위치를 만듭니다.

sudo mkdir /etc/ssl/nginx
sudo mv CA_CERT /etc/ssl/nginx

PKCS #11 라이브러리를 사용하도록 환경 구성

다음 섹션에서는 환경 준비 및 테스트에 필요한 단계를 자세히 설명합니다.

NGINX용 라이브러리 구성 준비

NGINX가 다음을 사용하여 라이브러리에 PKCS #11 엔진 작업을 로깅하도록 허용합니다.

sudo mkdir /var/log/kmsp11
sudo chown www-data /var/log/kmsp11

NGINX에 적합한 권한이 있는 빈 라이브러리 구성 파일을 만듭니다.

sudo touch /etc/nginx/pkcs11-config.yaml
sudo chmod 744 /etc/nginx/pkcs11-config.yaml

빈 구성 파일을 수정하고 다음 스니펫에 표시된 대로 필요한 구성을 추가합니다.

# cat /etc/nginx/pkcs11-config.yaml
---
tokens:
  - key_ring: "projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING"
log_directory: "/var/log/kmsp11"

OpenSSL 구성 테스트

다음 명령어를 실행합니다.

openssl engine -tt -c -v pkcs11

다음과 비슷한 출력이 표시됩니다.

(pkcs11) pkcs11 engine
 [RSA, rsaEncryption, id-ecPublicKey]
     [ available ]
     SO_PATH, MODULE_PATH, PIN, VERBOSE, QUIET, INIT_ARGS, FORCE_LOGIN

Cloud HSM을 사용하도록 NGINX 구성

몇 가지 NGINX 파일을 수정하여 TLS 오프로드를 허용합니다. 먼저 두 위치에서 /etc/nginx/nginx.conf 파일을 수정하여 PKCS #11을 사용하도록 NGINX를 구성하는 몇 가지 지시어를 추가합니다.

event 블록 뒤와 http 블록 앞에 다음 지시어를 추가합니다.

ssl_engine pkcs11;
env KMS_PKCS11_CONFIG=/etc/nginx/pkcs11-config.yaml;

동일한 /etc/nginx/nginx.conf 파일에서 Cloud HSM에 인증서 및 해당 비공개 키를 사용하도록 SSL 지시어를 구성합니다. http 블록에서 다음 속성을 추가합니다.

ssl_certificate "/etc/ssl/nginx/CA_CERT";
ssl_certificate_key "engine:pkcs11:PKCS_KEY_TYPE=KEY_IDENTIFIER";
ssl_protocols TLSv1.2 TLSv1.3; # Consider changing the default to only TLS1.2 or newer

# Consider defining the `ssl_ciphers` to use ciphers approved by your security teams and handle
# appropriate client compatibility requirements.

/etc/nginx/nginx.conf 파일은 다음과 같아야 합니다.

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

ssl_engine pkcs11;
env KMS_PKCS11_CONFIG=/etc/nginx/pkcs11-config.yaml;

http {

        #...
        #...

        # SSL configuration
        ssl_certificate "/etc/ssl/nginx/CA_CERT";
        ssl_certificate_key "engine:pkcs11:pkcs11:object=NGINX_KEY";
        ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        # ssl_ciphers YOUR_CIPHERS
        ssl_prefer_server_ciphers on;

        #...
        #...

}

TLS 트래픽을 리슨하도록 NGINX 구성

TLS 트래픽을 리슨하도록 /etc/nginx/sites-enabled/default 파일을 수정합니다. server 블록에서 SSL 구성의 주석 처리를 없앱니다. 변경사항이 다음 예시와 같이 표시됩니다.


server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;

        # ...
        # ...
}

NGINX 서비스에 환경 변수 제공

다음 명령어를 실행합니다.

sudo systemctl edit nginx.service

결과 편집기에서 다음 줄을 추가하고 LIBPATHlibkmsp11.so를 설치한 위치의 값으로 바꿉니다.

[Service]
Environment="GRPC_ENABLE_FORK_SUPPORT=1"
Environment="KMS_PKCS11_CONFIG=/etc/nginx/pkcs11-config.yaml"
Environment="PKCS11_MODULE_PATH=LIBPATH/libkmsp11-1.0-linux-amd64/libkmsp11.so"

이러한 값을 구성한 후에는 다음 명령어를 실행하여 값을 사용할 수 있도록 해야 합니다.

sudo systemctl daemon-reload

TLS 오프로딩으로 NGINX 다시 시작

NGINX가 다시 시작되고 업데이트된 구성이 사용되도록 다음 명령어를 실행합니다.

sudo systemctl start nginx

Cloud HSM에 대한 NGINX의 TLS 오프로드 사용 테스트

openssl s_client로 다음 명령어를 실행하여 NGINX 서버에 대한 연결을 테스트합니다.

openssl s_client -connect localhost:443

클라이언트가 SSL 핸드셰이크 및 일시중지를 완료합니다. 아래 표시된 것처럼 클라이언트가 사용자 입력을 기다립니다.

# completes SSL handshake
# ...
# ...
# ...
    Verify return code: 18 (self signed certificate)
# ...
    Max Early Data: 0
---
read R BLOCK

# When the client pauses, it’s waiting for instructions.
# Have the client get the index.html file in the root path (“/”), by typing the following:

GET /

# Press enter.
# You should now see the default NGINX index.html file.

이제 감사 로그에 NGINX_KEY 키에 대한 작업이 표시됩니다. 로그를 보려면 Cloud Console에서 Cloud Logging으로 이동합니다. 사용 중인 프로젝트에서 다음 필터를 추가합니다.

resource.type="cloudkms_cryptokeyversion"

쿼리를 실행한 후 NGINX_KEY 키에 대한 비대칭 키 작업이 표시됩니다.

선택적 구성

외부 IP로 NGINX 서버를 노출하도록 외부 패스 스루 네트워크 부하 분산기를 만들어야 할 수 있습니다.

부하 분산을 사용하는 역방향 프록시로 NGINX를 사용하려면 NGINX 구성 파일을 업데이트해야 합니다. NGINX를 역방향 프록시로 구성하는 방법은 Google Cloud Platform에서 NGINX Plus의 모든 활성 HA를 참조하세요.

다음 단계

이제 Cloud HSM에 대해 TLS 오프로드를 사용하도록 NGINX 서버가 구성되었습니다.