Use uma chave de HSM na nuvem para o descarregamento de TLS com o NGINX

Este guia fornece instruções para configurar o NGINX de modo a usar uma chave do Cloud HSM para descarregar o TLS no Debian 11 (Bullseye). Pode ter de modificar estes comandos para funcionarem com o seu SO ou distribuição Linux.

Pode encontrar uma versão baseada no Terraform deste tutorial no repositório do GitHub kms-solutions.

Exemplos de utilização

A utilização de uma chave do HSM na nuvem com o NGINX para a transferência de TLS ajuda a satisfazer as seguintes necessidades de segurança empresarial:

  • Quer que o seu servidor Web NGINX transfira as operações criptográficas TLS para o Cloud HSM.
  • Não quer armazenar a chave privada do seu certificado no sistema de ficheiros local da instância do Compute Engine que está a alojar a sua aplicação Web.
  • Tem de cumprir os requisitos regulamentares em que as aplicações viradas para o público precisam que os respetivos certificados sejam protegidos por um HSM com a certificação FIPS 140-2 Level 3.
  • Quer usar o NGINX para criar um proxy inverso com terminação TLS para proteger a sua aplicação Web.

Antes de começar

Antes de continuar, conclua os passos em Usar uma chave de HSM na nuvem com o OpenSSL.

Quando a configuração do OpenSSL estiver concluída, certifique-se de que tem instalada uma versão recente do nginx:

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 aloja o NGINX com as seguintes recomendações:

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

    1. Atribua as seguintes funções:
      • roles/cloudkms.signerVerifier
      • roles/cloudkms.viewer
  2. Configure as políticas da organização da seguinte forma para limitar os IPs externos e a criação de chaves de contas de serviço.

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

  4. Configure regras de firewall.

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

    • Selecione a conta de serviço correta que criou anteriormente.
    • Selecione a estação que criou anteriormente.
      • Adicione etiquetas adequadas para quaisquer regras de firewall.
      • Certifique-se de que o campo "IP externo" da sub-rede está definido como none.
  6. Conceda à sua identidade a função de utilizador do túnel protegido por IAP (roles/iap.tunnelResourceAccessor) na instância.

Crie e configure uma chave de assinatura alojada no Cloud KMS

As secções seguintes detalham os passos necessários para criar e configurar uma chave de assinatura alojada no Cloud KMS.

Crie uma chave de assinatura alojada no Cloud KMS

Crie uma EC-P256-SHA256chave de assinatura do Cloud KMSGoogle Cloud no seu projeto, no conjunto de chaves que 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"

Faça SSH para a sua VM através do IAP

Faça SSH para a sua VM através do IAP com o seguinte comando:

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

Se tiver um problema, confirme que usou a flag --tunnel-through-iap. Além disso, confirme que tem a função de utilizador do túnel protegido por IAP (roles/iap.tunnelResourceAccessor) na instância para a identidade autenticada com a CLI gcloud.

Crie um certificado com o OpenSSL

Para um ambiente de produção, crie um pedido de assinatura de certificado (CSR). Saiba mais lendo o exemplo para gerar um CSR. Faculte o CSR à sua autoridade de certificação (AC) para que esta possa criar um certificado para si. Use o certificado fornecido pela sua CA nas secções subsequentes.

Para fins de exemplo, pode gerar um certificado autoassinado com a chave de assinatura alojada no Cloud KMS. Para tal, o OpenSSL permite-lhe usar URIs PKCS n.º 11 em vez de um caminho normal, identificando a chave pela respetiva etiqueta (para chaves do Cloud KMS, a etiqueta é 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 o seguinte:

  • 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, consoante a tecla.
  • 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 de recurso completo da versão da chave.
  • KEY_IDENTIFIER: um identificador da chave. Se estiver a usar o pkcs11:object, use o nome da chave, por exemplo, NGINX_KEY. Se estiver a usar pkcs11:id, use o ID do recurso completo da chave ou da versão da chave, por exemplo, projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/NGINX_KEY/cryptoKeyVersions/KEY_VERSION.
  • CA_CERT: o caminho onde quer guardar o ficheiro do certificado.

Se o comando falhar, o PKCS11_MODULE_PATH pode ter sido definido incorretamente ou pode não ter as autorizações corretas para usar a chave de assinatura do Cloud KMS.

Agora, deve ter um certificado com o seguinte aspeto:

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

Instale o seu certificado para o NGINX

Execute os seguintes comandos para criar uma localização onde colocar o seu certificado público:

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

Configure o seu ambiente para usar a biblioteca PKCS #11

As secções seguintes detalham os passos necessários para preparar e testar o seu ambiente.

Prepare as configurações da biblioteca para o NGINX

Permita que o NGINX registe as operações do respetivo motor PKCS #11 com a biblioteca com o seguinte:

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

Crie um ficheiro de configuração da biblioteca vazio com as autorizações adequadas para o NGINX.

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

Edite o ficheiro de configuração vazio e adicione a configuração necessária, conforme mostrado no fragmento seguinte:

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

Teste a configuração do OpenSSL

Execute o seguinte comando:

openssl engine -tt -c -v pkcs11

Deverá ver uma saída semelhante à seguinte:

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

Configure o NGINX para usar o Cloud HSM

Permita a transferência de TLS editando alguns ficheiros NGINX. Primeiro, edite o ficheiro /etc/nginx/nginx.conf em dois locais para adicionar algumas diretivas de configuração do NGINX para usar o PKCS #11.

Após o bloco event e antes do bloco http, adicione as seguintes diretivas:

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

No mesmo ficheiro /etc/nginx/nginx.conf, configure as diretivas SSL para usar o seu certificado e a respetiva chave privada 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 ficheiro /etc/nginx/nginx.conf deve ter o seguinte aspeto:

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;

        #...
        #...

}

Configure o NGINX para ouvir o tráfego TLS

Edite o ficheiro /etc/nginx/sites-enabled/default para ouvir o tráfego TLS. Descomente a configuração SSL no bloco server. A alteração resultante deve ser semelhante ao seguinte exemplo:


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

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

        # ...
        # ...
}

Forneça variáveis de ambiente ao serviço NGINX

Execute o seguinte comando:

sudo systemctl edit nginx.service

No editor resultante, adicione as seguintes linhas e substitua LIBPATH pelo valor da localização onde 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 estes valores, tem de executar o seguinte comando para os disponibilizar:

sudo systemctl daemon-reload

Reinicie o NGINX com a transferência de TLS

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

sudo systemctl start nginx

Teste se o NGINX usa a transferência de TLS para o Cloud HSM

Use o openssl s_client para testar a ligação ao seu servidor NGINX executando o seguinte comando:

openssl s_client -connect localhost:443

O cliente deve concluir o handshake SSL e pausar. O cliente está a aguardar a sua introdução, conforme mostrado abaixo:

# 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 seus registos de auditoria devem agora mostrar operações na chave NGINX_KEY. Para ver os registos, navegue para Registos na nuvem na consola do Google Cloud. No projeto que tem usado, adicione o seguinte filtro:

resource.type="cloudkms_cryptokeyversion"

Depois de executar a consulta, deve ver operações de chaves assimétricas na sua chave NGINX_KEY.

Configurações opcionais

Pode ter de criar um balanceador de carga de rede de encaminhamento externo para expor o seu servidor NGINX com um IP externo.

Se precisar de usar o NGINX como um proxy inverso com equilíbrio de carga, considere atualizar o ficheiro de configuração do NGINX. Saiba mais sobre a configuração do NGINX como um proxy inverso lendo o artigo HA totalmente ativo para o NGINX Plus na Google Cloud Platform.

Passos seguintes

Configurou o servidor NGINX para usar a transferência de carga do TLS para o Cloud HSM.