通过 NGINX 使用 Cloud HSM 密钥进行 TLS 分流

本指南介绍了如何设置 NGINX,以便在 Debian 11 (Bullseye) 上使用 Cloud HSM 密钥进行 TLS 分流。您可能需要 修改这些命令,以配合您的操作系统或 Linux 发行版。

您可以在 kms-solutions GitHub 代码库

使用场景

将 Cloud HSM 密钥与 NGINX 搭配使用来进行 TLS 分流有助于 满足以下企业安全需求:

  • 您希望 NGINX Web 服务器将 TLS 加密操作分流到 Cloud HSM。
  • 您不想将证书的私钥存储在托管 Web 应用的 Compute Engine 实例的本地文件系统中。
  • 对于面向公众的应用,您需要满足相关法规要求 需要通过具有 FIPS 140-2 等级的 HSM 保护其证书 3 项认证。
  • 您想使用 NGINX 创建带有 TLS 的反向代理 以保护您的 Web 应用。

准备工作

在继续之前,请先完成 将 Cloud HSM 密钥与 OpenSSL 搭配使用

完成 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. 向受 IAP 保护的隧道的用户授予您的身份 (roles/iap.tunnelResourceAccessor) 角色。

创建和配置 Cloud KMS 托管的签名密钥

接下来的部分详细介绍了创建和配置 Cloud KMS 托管的签名密钥。

创建 Cloud KMS 托管的签名密钥

创建一个 Cloud KMSEC-P256-SHA256签名密钥 Google Cloud 项目(位于您之前配置的密钥环中) :

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 通过 SSH 连接到您的虚拟机

使用以下命令通过 IAP 通过 SSH 连接到您的虚拟机:

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

如果您遇到问题,请确认您是否使用了 --tunnel-through-iap 标志。 此外,请确认您拥有受 IAP 保护的隧道用户 针对身份的实例的 (roles/iap.tunnelResourceAccessor) 角色 已通过 gcloud CLI 进行身份验证。

使用 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 和密钥名称。接收者 使用特定密钥版本,请使用 pkcs11:id 以及相应密钥的完整资源 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 使用 库,其中包含以下代码:

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

将 NGINX 配置为使用 Cloud HSM

通过修改几个 NGINX 文件来允许 TLS 分流。首先,在两个位置修改 /etc/nginx/nginx.conf 文件,添加一些指令以配置 NGINX 以使用 PKCS #11。

event 代码块之后、http 代码块之前,添加以下代码 指令:

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

在同一个 /etc/nginx/nginx.conf 文件中,配置 SSL 指令以使用 证书及其私钥存储在 Cloud HSM 中。在 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;

        #...
        #...

}

配置 NGINX 以监听 TLS 流量

修改 /etc/nginx/sites-enabled/default 文件以监听 TLS 流量。 取消注释 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

在出现的编辑器中,添加以下几行代码,并将 将 LIBPATH 替换为安装位置的值 libkmsp11.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

Test NGINX 使用 TLS 分流到您的 Cloud HSM

使用 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 控制台中前往 Cloud Logging。在您一直在使用的项目中,添加以下过滤条件:

resource.type="cloudkms_cryptokeyversion"

运行查询后,您应该会看到 NGINX_KEY 键。

可选配置

您可能需要创建一个外部直通式网络负载平衡器, 使用外部 IP 公开您的 NGINX 服务器。

如果您需要使用 NGINX 作为具有负载均衡功能的反向代理, 请考虑更新 NGINX 配置文件。详细了解 将 NGINX 配置为反向代理 Google Cloud 上适用于 NGINX Plus 的全活跃高可用性 平台

后续步骤

您现在已将 NGINX 服务器配置为使用 TLS 分流 Cloud HSM。