Usar uma chave do Cloud HSM para descarregamento de TLS com o NGINX

Neste guia, você verá instruções sobre como configurar o NGINX para usar uma chave do Cloud HSM para descarregamento de TLS no Debian 11 (Bullseye). Talvez seja necessário modificar esses comandos para que funcionem com sua distribuição do SO ou Linux.

Casos de uso

O uso de uma chave do Cloud HSM com NGINX para descarregamento de TLS ajuda a atender às seguintes necessidades de segurança corporativa:

  • Você quer que o servidor da Web NGINX descarregue operações criptográficas TLS para o Cloud HSM.
  • Você não quer armazenar a chave privada do certificado no sistema de arquivos local da instância do Compute Engine que está hospedando seu aplicativo da Web.
  • Você precisa atender aos requisitos regulatórios em que aplicativos públicos precisam que os certificados sejam protegidos por um HSM com certificação FIPS 140-2 Nível 3.
  • Você quer usar o NGINX para criar um proxy reverso com terminação TLS para proteger seu aplicativo da Web.

Antes de começar

Antes de continuar, conclua as etapas em Como usar uma chave do Cloud HSM com o OpenSSL.

Depois que a configuração do OpenSSL estiver concluída, verifique se uma versão recente do nginx está instalada:

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

Recomendações de configuração de segurança

Proteja a instância que hospeda o NGINX com as seguintes recomendações:

  1. Siga as instruções para criar e ativar contas de serviço para instâncias a fim de hospedar o NGINX.

    1. Atribua os seguintes papéis:
      • roles/cloudkms.signerVerifier
      • roles/cloudkms.viewer
  2. Configure as políticas da organização da seguinte maneira para limitar os IPs externos e a criação de chaves de conta de serviço.

    • constraints/compute.vmExternalIpAccess
    • constraints/iam.disableServiceAccountKeyCreation
  3. Crie uma sub-rede personalizada que permita o acesso privado do Google.

  4. Configurar regras de firewall.

  5. Crie uma VM do Linux e configure-a da seguinte maneira:

    • Selecione a conta de serviço correta que você criou anteriormente.
    • Selecione a rede criada anteriormente.
      • Adicione os rótulos apropriados às regras de firewall.
      • Verifique se o campo "IP externo" da sub-rede está definido como none.
  6. Conceda à sua identidade o papel de usuário do túnel protegido pelo IAP (roles/iap.tunnelResourceAccessor) na instância.

Criar e configurar uma chave de assinatura hospedada no Cloud KMS

As próximas seções detalham as etapas necessárias para criar e configurar uma chave de assinatura hospedada no Cloud KMS.

Criar uma chave de assinatura hospedada no Cloud KMS

Crie uma chave de assinatura EC-P256-SHA256 do Cloud KMS no seu projeto do Google Cloud, no keyring que você configurou anteriormente para o OpenSSL:

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"

SSH na VM usando o IAP

Conecte-se via SSH à sua VM usando o IAP com o seguinte comando:

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

Se ocorrer um problema, confirme se você usou a flag --tunnel-through-iap. Além disso, confirme se você tem o papel de usuário do túnel protegido pelo IAP (roles/iap.tunnelResourceAccessor) na instância para a identidade autenticada com a CLI gcloud.

Criar um certificado com o OpenSSL

Para um ambiente de produção, crie uma solicitação de assinatura de certificado (CSR, na sigla em inglês). Saiba mais lendo o exemplo para gerar uma CSR. Forneça a CSR à sua autoridade certificadora (CA, na sigla em inglês) para que ela possa criar um certificado para você. Use o certificado fornecido pela sua CA nas próximas seções.

Por exemplo, é possível gerar um certificado autoassinado com a chave de assinatura hospedada no Cloud KMS. Para fazer isso, o OpenSSL permite usar URIs PKCS #11 em vez de um caminho regular, identificando a chave pelo rótulo (para chaves do Cloud KMS, o rótulo é o nome da 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

Substitua:

  • CERTIFICATE_NAME: um nome para o certificado.
  • DIGEST_FLAG: o algoritmo de resumo usado pela chave de assinatura assimétrica. Use -sha256, -sha384 ou -sha512, dependendo da chave.
  • PKCS_KEY_TYPE: o tipo de identificador usado para identificar a chave. Para usar a versão mais recente da chave, use pkcs11:object com o nome da chave. Para usar uma versão específica da chave, use pkcs11:id com o ID completo do recurso da versão da chave.
  • KEY_IDENTIFIER: um identificador da chave. Se você estiver usando pkcs11:object, use o nome da chave, por exemplo, NGINX_KEY. Se você estiver usando pkcs11:id, use o ID completo do recurso da chave ou versão da chave, por exemplo, projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/NGINX_KEY/cryptoKeyVersions/KEY_VERSION.
  • CA_CERT: o caminho em que você quer salvar o arquivo do certificado.

Se o comando falhar, é possível que PKCS11_MODULE_PATH tenha sido definido incorretamente ou você não tenha as permissões corretas para usar a chave de assinatura do Cloud KMS.

Agora você terá um certificado como este:

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

Instale o certificado para NGINX

Execute os seguintes comandos para criar um local para colocar o certificado público:

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

Configure o ambiente para usar a biblioteca PKCS #11

As próximas seções detalham as etapas necessárias para preparar e testar o ambiente.

Preparar configurações de biblioteca para o NGINX

Permita que o NGINX registre as operações do mecanismo PKCS no 11 com a biblioteca com o seguinte:

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

Crie um arquivo de configuração de biblioteca vazio com as permissões apropriadas para o NGINX.

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

Edite o arquivo de configuração vazio e adicione a configuração necessária, conforme mostrado no snippet a seguir:

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

Testar a configuração do OpenSSL

Execute este comando:

openssl engine -tt -c -v pkcs11

A saída será semelhante a esta:

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

Configurar o NGINX para usar o Cloud HSM

Permita o descarregamento de TLS editando alguns arquivos NGINX. Primeiro, edite o arquivo /etc/nginx/nginx.conf em dois locais para adicionar algumas diretivas e configurar o NGINX para usar o PKCS #11.

Depois do bloco event e antes do bloco http, adicione estas diretivas:

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

No mesmo arquivo /etc/nginx/nginx.conf, configure as diretivas SSL para usar seu certificado e a chave privada dele no Cloud HSM. No bloco http, adicione os seguintes atributos:

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.

O arquivo /etc/nginx/nginx.conf ficará assim:

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;

        #...
        #...

}

Configurar o NGINX para detectar o tráfego TLS

Edite o arquivo /etc/nginx/sites-enabled/default para detectar o tráfego TLS. Remova a marca de comentário da configuração SSL no bloco server. A alteração resultante será semelhante ao exemplo a seguir:


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

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

        # ...
        # ...
}

Fornecer variáveis de ambiente para o serviço NGINX

Execute este comando:

sudo systemctl edit nginx.service

No editor resultante, adicione as seguintes linhas e substitua LIBPATH pelo valor do local em que você instalou 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"

Depois de configurar esses valores, execute o seguinte comando para disponibilizá-los:

sudo systemctl daemon-reload

Reiniciar o NGINX com descarregamento de TLS

Execute o comando a seguir para que o NGINX seja reiniciado e use a configuração atualizada:

sudo systemctl start nginx

O NGINX de teste usa o descarregamento de TLS para o Cloud HSM

Use o openssl s_client para testar a conexão com o servidor NGINX executando o seguinte comando:

openssl s_client -connect localhost:443

O cliente deve concluir o handshake de SSL e fazer uma pausa. O cliente está aguardando sua entrada, conforme mostrado a seguir:

# 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.

Os registros de auditoria agora mostram operações para sua chave NGINX_KEY. Para conferir os registros, acesse o Cloud Logging no console do Cloud. No projeto que você está usando, adicione o seguinte filtro:

resource.type="cloudkms_cryptokeyversion"

Depois de executar a consulta, você verá operações de chave assimétrica na chave NGINX_KEY.

Configurações opcionais

Talvez seja necessário criar um balanceador de carga de rede de passagem externo para expor o servidor NGINX com um IP externo.

Se você precisar usar o NGINX como proxy reverso com balanceamento de carga, atualize o arquivo de configuração do NGINX. Saiba mais sobre como configurar o NGINX como um proxy reverso lendo Alta disponibilidade total para o NGINX Plus no Google Cloud Platform.

Próximas etapas

Agora você configurou o servidor NGINX para usar o descarregamento de TLS para o Cloud HSM.