This guide provides instructions for setting up an Apache server to use a Cloud HSM key for TLS signing on Debian 11 (Bullseye). You might need to modify these commands to work with your OS or Linux distribution.
You can find a Terraform-based blueprint version of this tutorial in the kms-solutions GitHub repository.
Before you begin
As a prerequisite, complete the configuration documented in OpenSSL Setup.
Once OpenSSL setup is complete, ensure that a recent version of Apache is installed:
sudo apt-get update
sudo apt-get install apache2
Configuration
Create a Cloud KMS-hosted signing key
Create a Cloud KMS EC-P256-SHA256
signing key in your
Google Cloud project, in the key ring that you previously configured
for 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"
Create a self-signed certificate with OpenSSL
Generate a self-signed certificate with the Cloud KMS-hosted signing key. You can use OpenSSL to use a PKCS #11 URI instead of a file path and identify the key by its label. In the Cloud KMS PKCS #11 library, the key label is the CryptoKey name.
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
Replace the following:
CERTIFICATE_NAME
: a name for the certificate.DIGEST_FLAG
: the digest algorithm used by the asymmetric signing key. Use-sha256
,-sha384
, or-sha512
depending on the key.PKCS_KEY_TYPE
: the type of identifier used to identify the key. To use the latest key version, usepkcs11:object
with the key's name. To use a specific key version, usepkcs11:id
with the full resource ID of the key version.KEY_IDENTIFIER
: an identifier for the key. If you're usingpkcs11:object
, use the key's name—for example,KEY_NAME
. If you're usingpkcs11:id
, use the full resource ID of the key or key version—for example,projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME/cryptoKeyVersions/KEY_VERSION
.PATH_TO_CERTIFICATE
: the path where you want to save the certificate file.
If this command fails, PKCS11_MODULE_PATH
might have been set incorrectly, or
you might not have the right permissions to use the Cloud KMS
signing key.
You should now have a certificate that looks like this:
-----BEGIN CERTIFICATE-----
...
...
...
-----END CERTIFICATE-----
Set up the Apache server
Create a directory in
/etc/apache2
to store your self-signed certificate in:sudo mkdir /etc/apache2/ssl sudo mv ca.cert /etc/apache2/ssl
Edit the
000-default.conf
virtual host configuration files located in/etc/apache2/sites-available
to provide the certificate file path and ensure that the SSLEngine is on.Here is a sample configuration listening on port 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>
Ensure Apache exports the environment variables correctly by adding them to the
/etc/apache2/envvars
file using your text editor of choice. You might need to edit the file as root usingsudo
. Add the following lines to the end of the file: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
Replace the following:
PATH_TO_LIBKMSP11
: the path tolibkmsp11.so
.PATH_TO_PKCS11_CONFIG
: the path topkcs11-config.yaml
.
GRPC_ENABLE_FORK_SUPPORT
is needed for gRPC to include fork support and correctly run the Cloud KMS PKCS #11 library as part of the Apache server.If you want to authenticate using a service account key, you must also export a value for the
GOOGLE_APPLICATION_CREDENTIALS
environment variable.
Run your server
Enable the Apache SSL module, enable the virtualhost configuration, and add a test web page in your DocumentRoot folder:
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
Restart your Apache server and test with curl
that the configuration works as
expected. The --insecure
flag is needed to ignore self-signed certificate
checks.
sudo systemctl restart apache2
curl -v --insecure https://127.0.0.1
If you encounter any errors, the Apache error log is a good starting place to
see what went wrong. Authentication issues are a common source of errors. If you
see PERMISSION_DENIED
errors, make sure that you are fully authenticated and
that the credentials file has the right permissions. To make sure you are fully
authenticated, run the following command:
gcloud auth application-default login
To confirm that authentication was successful, the output should include the
line Credentials saved to file: [/path/to/credentials.json]
.