Skip to content

Commit

Permalink
feat: Add PKCS11 automations (#7)
Browse files Browse the repository at this point in the history
Co-authored-by: Alessio Buraggina <[email protected]>
  • Loading branch information
romanini-ciandt and tdbhacks authored May 3, 2024
1 parent 91b4ecb commit f7efb29
Show file tree
Hide file tree
Showing 37 changed files with 1,946 additions and 1 deletion.
90 changes: 90 additions & 0 deletions oss-terraform-automation/1-apache-web-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM ubuntu/apache2

# Install the OpenSSL PKCS #11 library
RUN apt-get update && apt-get install -y libengine-pkcs11-openssl wget curl

# Using ARGs so user can provide the custom variables required to create pkcs11 config file
ARG PROJECT_ID
ENV ENV_PROJECT_ID=$PROJECT_ID

ARG KEYRING_NAME
ENV ENV_KEYRING_NAME=$KEYRING_NAME

ARG KEY_NAME
ENV ENV_KEY_NAME=$KEY_NAME

ARG LOCATION
ENV ENV_LOCATION=$LOCATION

ARG PKCS11_LIB_VERSION
ENV ENV_PKCS11_LIB_VERSION=$PKCS11_LIB_VERSION

ARG CERTIFICATE_NAME
ENV ENV_CERTIFICATE_NAME=$CERTIFICATE_NAME

ARG CERTIFICATE_FILE
ENV ENV_CERTIFICATE_FILE=$CERTIFICATE_FILE

ARG DIGEST_FLAG
ENV ENV_DIGEST_FLAG=$DIGEST_FLAG

# Download the GCP pkcs11 library
RUN wget "https://github.com/GoogleCloudPlatform/kms-integrations/releases/download/pkcs11-v${ENV_PKCS11_LIB_VERSION}/libkmsp11-${ENV_PKCS11_LIB_VERSION}-linux-amd64.tar.gz"

# Extract the library to a specific directory
RUN mkdir -p /opt/libkmsp11 && \
tar -xf "libkmsp11-${ENV_PKCS11_LIB_VERSION}-linux-amd64.tar.gz" -C /opt/libkmsp11

RUN echo "---\ntokens:\n - key_ring: \"projects/${ENV_PROJECT_ID}/locations/${ENV_LOCATION}/keyRings/${ENV_KEYRING_NAME}\"\n" > /opt/libkmsp11/kms-pkcs11.conf

# Export PKCS #11 required env vars
ENV PKCS11_MODULE_PATH="/opt/libkmsp11/libkmsp11-${ENV_PKCS11_LIB_VERSION}-linux-amd64/libkmsp11.so"
ENV KMS_PKCS11_CONFIG="/opt/libkmsp11/kms-pkcs11.conf"
ENV GRPC_ENABLE_FORK_SUPPORT=1

# Create a self-signed certificate with the Cloud KMS-hosted signing key
RUN openssl req -new -x509 -days 3650 -subj '/CN='${ENV_CERTIFICATE_NAME}'/' \
-${ENV_DIGEST_FLAG} -engine pkcs11 -keyform engine \
-key pkcs11:object=${ENV_KEY_NAME} > /opt/ca.cert

# Override the self-signed certificate if user provided a certificate as an input
RUN [ -n "$ENV_CERTIFICATE_FILE" ] && echo "$ENV_CERTIFICATE_FILE" > /opt/ca.cert || true

RUN mkdir /etc/apache2/ssl
RUN mv /opt/ca.cert /etc/apache2/ssl

# Add the SSL conf to the Apache configuration file
RUN echo "<VirtualHost *:443>\n\
ServerAdmin webmaster@localhost\n\
DocumentRoot /var/www/html\n\
ErrorLog \${APACHE_LOG_DIR}/error.log\n\
CustomLog \${APACHE_LOG_DIR}/access.log combined\n\
SSLEngine on\n\
SSLCertificateFile /etc/apache2/ssl/ca.cert\n\
SSLCertificateKeyFile \"pkcs11:object=${ENV_KEY_NAME}\"\n\
</VirtualHost>" >> /etc/apache2/sites-available/000-default.conf

# Enable the Apache SSL module, enable the virtualhost configuration, and add a test web page in your DocumentRoot folder
RUN a2enmod ssl
RUN a2ensite 000-default.conf
RUN echo '<!doctype html><html><body><h1>Hello World!</h1></body></html>' | \
tee /var/www/html/index.html

EXPOSE 443

# Start Apache in the foreground
CMD ["apache2ctl", "-D", "FOREGROUND"]
89 changes: 89 additions & 0 deletions oss-terraform-automation/1-apache-web-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Use a Cloud HSM key for TLS offloading with NGINX

## Overview

This guide provides instructions for setting up a GCP infrastructure with Apache server using Cloud HSM key for TLS signing with Terraform.

## Prerequisites

- [Terraform](https://developer.hashicorp.com/terraform/downloads);
- [Google Cloud CLI (`gcloud`)](https://cloud.google.com/sdk/docs/install-sdk);
- You must be authenticated in your GCP account. If you're not you should run `gcloud auth login`;
- An existing [GCP project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project);
- Enable GCP services in the project created above:
- compute.googleapis.com
- iam.googleapis.com
- artifactregistry.googleapis.com
- cloudbuild.googleapis.com
- cloudkms.googleapis.com

**Note:** You can enable these services using `gcloud services enable <SERVICE>` command or terraform automation would auto-enable them for you.

- (Optional) An existing [GCP Organization](https://cloud.google.com/resource-manager/docs/creating-managing-organization);
- If you provide a `organization_id` variable in `terraform.tfvars`, the Terraform automation will configure the following organization policies: `constraints/compute.vmExternalIpAccess` and `constraints/iam.disableServiceAccountKeyCreation`;

**Note:** This automation won't work if you use `pkcs11_lib_version` variable lower than `1.3`

## Deploy infrastructure

1. Rename `terraform.example.tfvars` to `terraform.tfvars`:
```sh
mv terraform.example.tfvars terraform.tfvars
```

1. Update `terraform.tfvars` file with the required values.

1. Create the infrastructure.

```sh
terraform init
terraform plan
terraform apply
```

1. Connect into the Compute Engine VM using IAP and `gcloud` command:
```sh
gcloud compute ssh --zone "us-central1-a" "apache-hostname-example" --tunnel-through-iap --project "REPLACE-WITH-YOUR-EXISTING-PROJECT-ID"
```
**Note:** You can run the command above from Cloud Shell (recommended) or locally (additional permissions may be required)

1. Run the following command in the Compute Engine VM shell. You should see a succesful request output.
```sh
container_id=$(docker ps -q | head -n 1)
docker exec "$container_id" curl -v --insecure https://127.0.0.1
```
**Note:** The successful output should contain information about the certificate and a `HTTP/1.1 200 OK` string.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| artifact\_image | Image's name stored in Artifact Registry. | `string` | n/a | yes |
| artifact\_location | Location's name of the image stored in Artifact Registry. | `string` | `"us-central1"` | no |
| artifact\_repository | Respository's name of the image stored in Artifact Registry. | `string` | `"hsm-cloud-example"` | no |
| artifact\_version | Version of the image stored in Artifact Registry. | `string` | `"latest"` | no |
| certificate\_file\_path | Certificate file path to be used on sign process. This should be used when you have a certificate file signed by a Certificate Authority. If not provided, a self-signed certificate will be generated with OpenSSL. Use self-signed certificate for testing only. A self-signed certificate created this way is not appropriate for production use. | `string` | `null` | no |
| certificate\_name | A name for the certificate that you want to generate. This will be used on CN parameter for certificate signing requests or/and self-signed certificates. | `string` | `"TERRAFORM_CERT"` | no |
| digest\_flag | A flag indicating the type of digest. Use sha256, sha384, or sha512 depending on the algorithm of the key. | `string` | `"sha256"` | no |
| docker\_file\_path | The Dockerfile path. | `string` | `"./"` | no |
| hostname | Name of the GCE VM host. | `string` | `"apache-hostname-example"` | no |
| key | Name of the key to be created. | `string` | n/a | yes |
| keyring | Name of the keyring to be created. | `string` | n/a | yes |
| location | Location for the keyring. For available KMS locations see: https://cloud.google.com/kms/docs/locations. | `string` | `"us-central1"` | no |
| organization\_id | GCP organization ID that will used to apply desired Org Policies. If not provided, Org Policies won't be applied. | `string` | `""` | no |
| pkcs11\_lib\_version | Version of the PKCS #11 library version. This automation is not compatible with version lower than 1.3. To see more info about versions available: https://github.com/GoogleCloudPlatform/kms-integrations/releases?q=pkcs%2311&expanded=true | `string` | `"1.3"` | no |
| prevent\_destroy | Set the prevent\_destroy lifecycle attribute on keys. | `bool` | `true` | no |
| project\_id | GCP project ID to use for the creation of resources. | `string` | n/a | yes |
| suffix | A suffix to be used as an identifier for resources. (e.g., suffix for KMS Key, Keyring, SAs, etc.). If not provided, a 4 character random one will be generated. | `string` | `""` | no |

## Outputs

| Name | Description |
|------|-------------|
| key | Name of the key created. |
| keyring | Name of the keyring. |
| location | Location of the keyring created. |
| project\_id | ID of the GCP project being used. |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
37 changes: 37 additions & 0 deletions oss-terraform-automation/1-apache-web-server/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

module "bootstrap-kms-hsm" {
source = "../common/modules/bootstrap-kms-hsm"

project_id = var.project_id
keyring = var.keyring
key = var.key
location = var.location
prevent_destroy = var.prevent_destroy
suffix = var.suffix
artifact_image = var.artifact_image
artifact_location = var.artifact_location
artifact_repository = var.artifact_repository
artifact_version = var.artifact_version
hostname = var.hostname
organization_id = var.organization_id
pkcs11_lib_version = var.pkcs11_lib_version
certificate_file_path = var.certificate_file_path
digest_flag = var.digest_flag
certificate_name = var.certificate_name
docker_file_path = var.docker_file_path
}
35 changes: 35 additions & 0 deletions oss-terraform-automation/1-apache-web-server/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

output "keyring" {
description = "Name of the keyring."
value = module.bootstrap-kms-hsm.keyring
}

output "location" {
description = "Location of the keyring created."
value = module.bootstrap-kms-hsm.location
}

output "key" {
description = "Name of the key created."
value = module.bootstrap-kms-hsm.key
}

output "project_id" {
description = "ID of the GCP project being used."
value = module.bootstrap-kms-hsm.project_id
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
project_id = "REPLACE-WITH-YOUR-EXISTING-PROJECT-ID"
keyring = "apache-example-keyring-terraform"
key = "apache-example-key-terraform"
artifact_image = "apache-example-image-terraform"
artifact_location = "us-central1"
artifact_repository = "apache-example-repo-terraform"
artifact_version = "latest"
organization_id = "" # Optional. Org Policies mentioned in the README will be created if you provide this variable.
certificate_file_path = null # Optional. This should be used when you have a certificate file signed by a Certificate Authority. If not provided, a self-signed certificate will be generated with OpenSSL. Use self-signed certificate for testing only. A self-signed certificate created this way is not appropriate for production use."
113 changes: 113 additions & 0 deletions oss-terraform-automation/1-apache-web-server/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

variable "suffix" {
description = "A suffix to be used as an identifier for resources. (e.g., suffix for KMS Key, Keyring, SAs, etc.). If not provided, a 4 character random one will be generated."
type = string
default = ""
}

variable "project_id" {
description = "GCP project ID to use for the creation of resources."
type = string
}

variable "location" {
description = "Location for the keyring. For available KMS locations see: https://cloud.google.com/kms/docs/locations."
type = string
default = "us-central1"
}

variable "keyring" {
description = "Name of the keyring to be created."
type = string
}

variable "key" {
description = "Name of the key to be created."
type = string
}

variable "prevent_destroy" {
description = "Set the prevent_destroy lifecycle attribute on keys."
type = bool
default = true
}

variable "artifact_location" {
description = "Location's name of the image stored in Artifact Registry."
type = string
default = "us-central1"
}

variable "artifact_version" {
description = "Version of the image stored in Artifact Registry."
type = string
default = "latest"
}

variable "artifact_repository" {
description = "Respository's name of the image stored in Artifact Registry."
type = string
default = "hsm-cloud-example"
}

variable "artifact_image" {
description = "Image's name stored in Artifact Registry."
type = string
}

variable "organization_id" {
description = "GCP organization ID that will used to apply desired Org Policies. If not provided, Org Policies won't be applied."
type = string
default = ""
}

variable "hostname" {
description = "Name of the GCE VM host."
type = string
default = "apache-hostname-example"
}

variable "pkcs11_lib_version" {
description = "Version of the PKCS #11 library version. This automation is not compatible with version lower than 1.3. To see more info about versions available: https://github.com/GoogleCloudPlatform/kms-integrations/releases?q=pkcs%2311&expanded=true"
type = string
default = "1.3"
}

variable "certificate_file_path" {
description = "Certificate file path to be used on sign process. This should be used when you have a certificate file signed by a Certificate Authority. If not provided, a self-signed certificate will be generated with OpenSSL. Use self-signed certificate for testing only. A self-signed certificate created this way is not appropriate for production use."
type = string
default = null
}

variable "digest_flag" {
description = "A flag indicating the type of digest. Use sha256, sha384, or sha512 depending on the algorithm of the key."
type = string
default = "sha256"
}

variable "certificate_name" {
description = "A name for the certificate that you want to generate. This will be used on CN parameter for certificate signing requests or/and self-signed certificates."
type = string
default = "TERRAFORM_CERT"
}

variable "docker_file_path" {
description = "The Dockerfile path."
type = string
default = "./"
}
Loading

0 comments on commit f7efb29

Please sign in to comment.