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