Usar una clave de Cloud HSM para servir tráfico de Apache

En esta guía se explica cómo configurar un servidor Apache para que use una clave de Cloud HSM para la firma TLS en Debian 11 (Bullseye). Es posible que tengas que modificar estos comandos para que funcionen con tu sistema operativo o distribución de Linux.

Puedes encontrar una versión de este tutorial basada en Terraform en el repositorio de GitHub kms-solutions.

Antes de empezar

Como requisito previo, completa la configuración que se describe en Configuración de OpenSSL.

Una vez que se haya completado la configuración de OpenSSL, asegúrate de que esté instalada una versión reciente de Apache:

sudo apt-get update
sudo apt-get install apache2

Configuración

Crear una clave de firma alojada en Cloud KMS

Crea una EC-P256-SHA256clave de firmaGoogle Cloud de Cloud KMS en tu proyecto, en el conjunto de claves que hayas configurado anteriormente para OpenSSL:

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

Crear un certificado autofirmado con OpenSSL

Genera un certificado autofirmado con la clave de firma alojada en Cloud KMS. Puedes usar OpenSSL para usar un URI PKCS #11 en lugar de una ruta de archivo e identificar la clave por su etiqueta. En la biblioteca PKCS #11 de Cloud KMS, la etiqueta de la clave es el nombre de CryptoKey.

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

Haz los cambios siguientes:

  • CERTIFICATE_NAME: un nombre para el certificado.
  • DIGEST_FLAG: el algoritmo de resumen usado por la clave de firma asimétrica. Usa -sha256, -sha384 o -sha512 en función de la clave.
  • PKCS_KEY_TYPE: el tipo de identificador que se usa para identificar la clave. Para usar la versión de clave más reciente, usa pkcs11:object con el nombre de la clave. Para usar una versión de clave específica, usa pkcs11:id con el ID de recurso completo de la versión de clave.
  • KEY_IDENTIFIER: identificador de la clave. Si usas pkcs11:object, utiliza el nombre de la clave (por ejemplo, KEY_NAME). Si usas pkcs11:id, utiliza el ID de recurso completo de la clave o de la versión de la clave. Por ejemplo, projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME/cryptoKeyVersions/KEY_VERSION.
  • PATH_TO_CERTIFICATE: la ruta en la que quieres guardar el archivo de certificado.

Si este comando falla, es posible que PKCS11_MODULE_PATH se haya configurado de forma incorrecta o que no tengas los permisos adecuados para usar la clave de firma de Cloud KMS.

Ahora debería tener un certificado con este aspecto:

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

Configurar el servidor Apache

  1. Crea un directorio en /etc/apache2 para almacenar tu certificado autofirmado:

    sudo mkdir /etc/apache2/ssl
    sudo mv ca.cert /etc/apache2/ssl
    
  2. Edita los archivos de configuración del host virtual 000-default.conf, que se encuentran en /etc/apache2/sites-available, para proporcionar la ruta del archivo de certificado y asegúrate de que SSLEngine esté activado.

    A continuación, se muestra un ejemplo de configuración que escucha en el puerto 443:

      <VirtualHost *:443>
            ServerAdmin webmaster@localhost
            DocumentRoot /var/www/html
            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined
            SSLEngine on
            SSLCertificateFile /etc/apache2/ssl/ca.cert
            SSLCertificateKeyFile "PKCS_KEY_TYPE=KEY_IDENTIFIER"
      </VirtualHost>
    
  3. Asegúrate de que Apache exporta las variables de entorno correctamente añadiéndolas al archivo /etc/apache2/envvars con el editor de texto que prefieras. Es posible que tengas que editar el archivo como root con sudo. Añade las siguientes líneas al final del archivo:

    export PKCS11_MODULE_PATH="<var>PATH_TO_LIBKMSP11</var>"
    export KMS_PKCS11_CONFIG="<var>PATH_TO_PKCS11_CONFIG</var>"
    export GRPC_ENABLE_FORK_SUPPORT=1
    

    Haz los cambios siguientes:

    • PATH_TO_LIBKMSP11: la ruta a libkmsp11.so.
    • PATH_TO_PKCS11_CONFIG: la ruta a pkcs11-config.yaml.

    GRPC_ENABLE_FORK_SUPPORT es necesario para que gRPC incluya la compatibilidad con fork y ejecute correctamente la biblioteca PKCS #11 de Cloud KMS como parte del servidor Apache.

    Si quieres autenticarte con una clave de cuenta de servicio, también debes exportar un valor para la variable de entorno GOOGLE_APPLICATION_CREDENTIALS.

Ejecutar el servidor

Habilita el módulo SSL de Apache, habilita la configuración de virtualhost y añade una página web de prueba en tu carpeta DocumentRoot:

sudo a2enmod ssl
sudo a2ensite 000-default.conf
echo '<!doctype html><html><body><h1>Hello World!</h1></body></html>' | \
  sudo tee /var/www/html/index.html

Reinicia el servidor Apache y comprueba con curl que la configuración funciona como se espera. Se necesita la marca --insecure para ignorar las comprobaciones de certificados autofirmados.

sudo systemctl restart apache2
curl -v --insecure https://127.0.0.1

Si se produce algún error, el registro de errores de Apache es un buen punto de partida para ver qué ha fallado. Los problemas de autenticación son una causa habitual de errores. Si ves errores PERMISSION_DENIED, asegúrate de que te has autenticado correctamente y de que el archivo de credenciales tiene los permisos adecuados. Para asegurarte de que tienes la autenticación completa, ejecuta el siguiente comando:

gcloud auth application-default login

Para confirmar que la autenticación se ha realizado correctamente, el resultado debe incluir la línea Credentials saved to file: [/path/to/credentials.json].