diff --git a/oss-terraform-automation/1-apache-web-server/Dockerfile b/oss-terraform-automation/1-apache-web-server/Dockerfile
new file mode 100644
index 00000000..77c09361
--- /dev/null
+++ b/oss-terraform-automation/1-apache-web-server/Dockerfile
@@ -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 "\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\
+ " >> /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 '
Hello World!
' | \
+ tee /var/www/html/index.html
+
+EXPOSE 443
+
+# Start Apache in the foreground
+CMD ["apache2ctl", "-D", "FOREGROUND"]
diff --git a/oss-terraform-automation/1-apache-web-server/README.md b/oss-terraform-automation/1-apache-web-server/README.md
new file mode 100644
index 00000000..b3512d56
--- /dev/null
+++ b/oss-terraform-automation/1-apache-web-server/README.md
@@ -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 ` 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.
+
+
+## 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. |
+
+
diff --git a/oss-terraform-automation/1-apache-web-server/main.tf b/oss-terraform-automation/1-apache-web-server/main.tf
new file mode 100644
index 00000000..366c5081
--- /dev/null
+++ b/oss-terraform-automation/1-apache-web-server/main.tf
@@ -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
+}
diff --git a/oss-terraform-automation/1-apache-web-server/outputs.tf b/oss-terraform-automation/1-apache-web-server/outputs.tf
new file mode 100644
index 00000000..f9feeaf0
--- /dev/null
+++ b/oss-terraform-automation/1-apache-web-server/outputs.tf
@@ -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
+}
diff --git a/oss-terraform-automation/1-apache-web-server/terraform.example.tfvars b/oss-terraform-automation/1-apache-web-server/terraform.example.tfvars
new file mode 100644
index 00000000..67dc1727
--- /dev/null
+++ b/oss-terraform-automation/1-apache-web-server/terraform.example.tfvars
@@ -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."
diff --git a/oss-terraform-automation/1-apache-web-server/variables.tf b/oss-terraform-automation/1-apache-web-server/variables.tf
new file mode 100644
index 00000000..36044426
--- /dev/null
+++ b/oss-terraform-automation/1-apache-web-server/variables.tf
@@ -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 = "./"
+}
diff --git a/oss-terraform-automation/1-apache-web-server/versions.tf b/oss-terraform-automation/1-apache-web-server/versions.tf
new file mode 100644
index 00000000..0c50890a
--- /dev/null
+++ b/oss-terraform-automation/1-apache-web-server/versions.tf
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+terraform {
+ required_version = ">= 1.5.7"
+ required_providers {
+
+ google = {
+ source = "hashicorp/google"
+ version = ">= 5.11, < 6"
+ }
+ }
+}
diff --git a/oss-terraform-automation/2-nginx-ssl-offloading/Dockerfile b/oss-terraform-automation/2-nginx-ssl-offloading/Dockerfile
new file mode 100644
index 00000000..8c0e3638
--- /dev/null
+++ b/oss-terraform-automation/2-nginx-ssl-offloading/Dockerfile
@@ -0,0 +1,97 @@
+# 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 nginx:1.24.0-bullseye
+
+# Install the OpenSSL PKCS #11 library
+RUN apt-get update && apt-get install -y libengine-pkcs11-openssl wget curl opensc
+
+# 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 /tmp/libkmsp11 && \
+ tar -xf "libkmsp11-${ENV_PKCS11_LIB_VERSION}-linux-amd64.tar.gz" -C /tmp/libkmsp11
+
+RUN echo "---\ntokens:\n - key_ring: \"projects/${ENV_PROJECT_ID}/locations/${ENV_LOCATION}/keyRings/${ENV_KEYRING_NAME}\"\nlog_directory: \"/var/log/kmsp11\"" > /etc/nginx/pkcs11-config.yaml
+
+# Export PKCS #11 required env vars
+ENV PKCS11_MODULE_PATH="/tmp/libkmsp11/libkmsp11-${ENV_PKCS11_LIB_VERSION}-linux-amd64/libkmsp11.so"
+ENV KMS_PKCS11_CONFIG="/etc/nginx/pkcs11-config.yaml"
+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} > /tmp/ca.cert
+
+# Override the self-signed certificate if user provided a certificate as an input
+RUN [ -n "$ENV_CERTIFICATE_FILE" ] && echo "$ENV_CERTIFICATE_FILE" > /tmp/ca.cert || true
+
+RUN mkdir /etc/ssl/nginx
+RUN mv /tmp/ca.cert /etc/ssl/nginx
+
+RUN mkdir /var/log/kmsp11
+RUN chown www-data /var/log/kmsp11
+RUN chmod 666 /var/log/kmsp11
+RUN chmod 744 /etc/nginx/pkcs11-config.yaml
+
+# Add SSL configuration after the NGINX events block at /etc/nginx/nginx.conf file
+ENV STRING_BLOCK_1="\n\nssl_engine pkcs11;\nenv KMS_PKCS11_CONFIG=/etc/nginx/pkcs11-config.yaml;"
+RUN awk '/}/ && !inserted {print $0 "'"$STRING_BLOCK_1"'"; inserted=1; next} {print}' /etc/nginx/nginx.conf > tmpfile && mv tmpfile /etc/nginx/nginx.conf
+
+# Add SSL configuration in NGINX http block at /etc/nginx/nginx.conf file
+ENV STRING_BLOCK_2='\n ssl_certificate \"/etc/ssl/nginx/ca.cert\";\n ssl_certificate_key \"engine:pkcs11:pkcs11:object='${ENV_KEY_NAME}'\";\n ssl_protocols TLSv1.2 TLSv1.3;\n ssl_prefer_server_ciphers on;'
+RUN awk '/http {/ && !inserted {print $0 "'"$STRING_BLOCK_2"'"; inserted=1; next} {print}' /etc/nginx/nginx.conf > tmpfile && mv tmpfile /etc/nginx/nginx.conf
+
+# Add SSL configuration in NGIX server block in /etc/nginx/conf.d/default.conf file
+ENV STRING_BLOCK_3="\n listen 443 ssl default_server;\n listen [::]:443 ssl default_server;"
+RUN awk '/server {/ && !inserted {print $0 "'"$STRING_BLOCK_3"'"; inserted=1; next} {print}' /etc/nginx/conf.d/default.conf > tmpfile && mv tmpfile /etc/nginx/conf.d/default.conf
+
+# Add environment variables in NGINX service block at /lib/systemd/system/nginx.service file
+ENV STRING_BLOCK_4='\nEnvironment=\"GRPC_ENABLE_FORK_SUPPORT=1\"\nEnvironment=\"KMS_PKCS11_CONFIG=/etc/nginx/pkcs11-config.yaml\"\nEnvironment=\"PKCS11_MODULE_PATH='${PKCS11_MODULE_PATH}'\"'
+RUN awk '/Service]/ && !inserted {print $0 "'"$STRING_BLOCK_4"'"; inserted=1; next} {print}' /lib/systemd/system/nginx.service > tmpfile && mv tmpfile /lib/systemd/system/nginx.service
+
+# Restart apache service
+RUN /etc/init.d/nginx restart
+
+EXPOSE 443
+
+# Command to start Nginx when the container starts
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/oss-terraform-automation/2-nginx-ssl-offloading/README.md b/oss-terraform-automation/2-nginx-ssl-offloading/README.md
new file mode 100644
index 00000000..4a323466
--- /dev/null
+++ b/oss-terraform-automation/2-nginx-ssl-offloading/README.md
@@ -0,0 +1,95 @@
+# Use a Cloud HSM key for TLS offloading with NGINX
+
+## Overview
+
+This guide provides instructions for setting up a GCP infrastructure with NGINX to use a Cloud HSM key for TLS offloading 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 ` 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" "nginx-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:
+ ```sh
+ container_id=$(docker ps -q | head -n 1)
+ docker exec -it "$container_id" /bin/bash
+ openssl s_client -connect localhost:443
+ ```
+
+1. The previous `openssl` command you ran should return information about the SSL certificate and the cursor should be expecting some input. You can run the following `GET /` and should see a succesful output:
+ ```sh
+ GET /
+ ```
+**Note:** The successful output contain a `Welcome to nginx!` html string.
+
+
+## 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` | `"nginx-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. |
+
+
diff --git a/oss-terraform-automation/2-nginx-ssl-offloading/main.tf b/oss-terraform-automation/2-nginx-ssl-offloading/main.tf
new file mode 100644
index 00000000..366c5081
--- /dev/null
+++ b/oss-terraform-automation/2-nginx-ssl-offloading/main.tf
@@ -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
+}
diff --git a/oss-terraform-automation/2-nginx-ssl-offloading/outputs.tf b/oss-terraform-automation/2-nginx-ssl-offloading/outputs.tf
new file mode 100644
index 00000000..f9feeaf0
--- /dev/null
+++ b/oss-terraform-automation/2-nginx-ssl-offloading/outputs.tf
@@ -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
+}
diff --git a/oss-terraform-automation/2-nginx-ssl-offloading/terraform.example.tfvars b/oss-terraform-automation/2-nginx-ssl-offloading/terraform.example.tfvars
new file mode 100644
index 00000000..3b7bd465
--- /dev/null
+++ b/oss-terraform-automation/2-nginx-ssl-offloading/terraform.example.tfvars
@@ -0,0 +1,9 @@
+project_id = "REPLACE-WITH-YOUR-EXISTING-PROJECT-ID"
+keyring = "nginx-example-keyring-terraform"
+key = "nginx-example-key-terraform"
+artifact_image = "nginx-example-image-terraform"
+artifact_location = "us-central1"
+artifact_repository = "nginx-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."
diff --git a/oss-terraform-automation/2-nginx-ssl-offloading/variables.tf b/oss-terraform-automation/2-nginx-ssl-offloading/variables.tf
new file mode 100644
index 00000000..4718cae7
--- /dev/null
+++ b/oss-terraform-automation/2-nginx-ssl-offloading/variables.tf
@@ -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 = "nginx-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 = "./"
+}
diff --git a/oss-terraform-automation/2-nginx-ssl-offloading/versions.tf b/oss-terraform-automation/2-nginx-ssl-offloading/versions.tf
new file mode 100644
index 00000000..0c50890a
--- /dev/null
+++ b/oss-terraform-automation/2-nginx-ssl-offloading/versions.tf
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+terraform {
+ required_version = ">= 1.5.7"
+ required_providers {
+
+ google = {
+ source = "hashicorp/google"
+ version = ">= 5.11, < 6"
+ }
+ }
+}
diff --git a/oss-terraform-automation/3-cng-provider/Dockerfile b/oss-terraform-automation/3-cng-provider/Dockerfile
new file mode 100644
index 00000000..10be84d2
--- /dev/null
+++ b/oss-terraform-automation/3-cng-provider/Dockerfile
@@ -0,0 +1,79 @@
+# 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:latest
+
+# 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}\"\nlog_directory: \"/opt/libkmsp11/log/kmsp11\"" > /opt/libkmsp11/pkcs11-config.yaml
+
+# 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/pkcs11-config.yaml"
+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
+
+# Create a new certificate signing request (CSR) for a Cloud HSM signing key
+RUN openssl req -new -subj '/CN='${ENV_CERTIFICATE_NAME}'/' -${ENV_DIGEST_FLAG} \
+ -engine pkcs11 -keyform engine \
+ -key pkcs11:object=${ENV_KEY_NAME} > /opt/request-ca.csr
+
+RUN mkdir /opt/libkmsp11/log/
+RUN mkdir /opt/libkmsp11/log/kmsp11
+RUN chown www-data /opt/libkmsp11/log/kmsp11
+RUN chmod 666 /opt/libkmsp11/log/kmsp11
+RUN chmod 744 /opt/libkmsp11/pkcs11-config.yaml
+
+# Command to keep the container running without executing any application
+CMD ["tail", "-f", "/dev/null"]
diff --git a/oss-terraform-automation/3-cng-provider/README.md b/oss-terraform-automation/3-cng-provider/README.md
new file mode 100644
index 00000000..2d0a57b8
--- /dev/null
+++ b/oss-terraform-automation/3-cng-provider/README.md
@@ -0,0 +1,157 @@
+# Use CNG Provider and SignTool to sign Windows artifacts
+
+## Overview
+
+This guide provides instructions for creating a Cloud HSM key for Microsoft Authenticode signing through our CNG provider and [SignTool](https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool) with Terraform.
+
+**Note:** The Windows infrastructure itself is not automated by this Terraform. Just the resources need to run CNG provider in your Windows machine will be automated.
+
+## 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 ` 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`;
+
+- A Windows (10, Server 2012 R2 or newer versions) machine with the artifacts you want to sign.
+ - The latest Cloud KMS [CNG provider release](https://github.com/GoogleCloudPlatform/kms-integrations/releases?q=cng&expanded=true) installed on your Windows machine using the .msi installer.
+ - [Google Cloud CLI (`gcloud`)](https://cloud.google.com/sdk/docs/install-sdk) installed and authenticated.
+ - [Singtool](https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool) installed in your Windows machine. Signtool is included in [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/) - it's recommend to use [Windows SDK 8.1 version](https://go.microsoft.com/fwlink/p/?LinkId=323507) instead of the newer ones for [compatibility reasons](https://github.com/GoogleCloudPlatform/kms-integrations/issues/19#issuecomment-1914154893).
+
+**Note:** `gcloud` is listed twice in the pre requirements section because is not required to use the same machine to run the Terraform automation and sign the artifacts, even though it can be the same machine.
+
+**Note 2:** 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" "cng-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:
+ ```sh
+ container_id=$(docker ps -q | head -n 1)
+ docker exec -it "$container_id" /bin/bash
+ ```
+
+1. Optional step. If your certificate authority (CA) requires a CSR in order to generate a new certificate for code signing, you can have the certificate signing request (CSR) for a Cloud HSM signing key by running the following command:
+ ```sh
+ cat /opt/request-ca.csr
+ ```
+ **Note:** You should see a signing request that looks like this:
+
+ ```
+ -----BEGIN CERTIFICATE REQUEST-----
+
+ ...
+
+ -----END CERTIFICATE REQUEST-----
+ ```
+
+1. Optional step. If your certificate authority (CA) requires a proof that your key resides in an HSM to issue an Extended Validation (EV) certificate you can generate a HSM attestation by running the following commands:
+ ```sh
+ gcloud kms keys versions describe 1 \
+ --key REPLACE-WITH-YOUR-KEY-NAME \
+ --location REPLACE-WITH-YOUR-LOCATION \
+ --keyring REPLACE-WITH-YOUR-KEYRING-NAME
+ ```
+ ```sh
+ cloudshell download attestation-file # If you're using Cloud Shell, this extra command is required in order to download the file.
+ ```
+ **Note:** You can run the command above from Cloud Shell (recommended) or locally (additional permissions may be required).
+
+ **Note 2:** You can run `terraform output` locally to get all the info required in replaces.
+
+1. You can check the certificate used in the process of the automation (either self-signed or obtained from the Certificate Authority) by running the following command. You should copy it the output and create the same `ca.cert` file in your Windows machine.
+ ```sh
+ cat /opt/ca.cert
+ ```
+ **Note:** You should see a certificate that looks like this:
+
+ ```
+ -----BEGIN CERTIFICATE-----
+
+ ...
+
+ -----END CERTIFICATE-----
+ ```
+
+1. Now in your Windows machine, use SignTool to sign the artifacts, using your Cloud KMS key and your certificate:
+```powershell
+"PATH_TO_SIGNTOOL.EXE" sign ^
+ /v /debug /fd sha256 /t http://timestamp.digicert.com ^
+ /f PATH_TO_CA.CERT ^
+ /csp "Google Cloud KMS Provider" ^
+ /kc projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME/cryptoKeyVersions/KEY_VERSION ^
+ PATH_TO_ARTIFACT_TO_SIGN
+```
+
+**Note:** `PATH_TO_SIGNTOOL.EXE`: the path to `signtool.exe` (eg. `C:\\Program Files (x86)\\Windows Kits\\8\\bin\\x64\\signtool.exe`).
+
+**Note 2:** `PATH_TO_CA.CERT`: the path to your certificate `ca.cert`.
+
+**Note 3:** `PATH_TO_ARTIFACT_TO_SIGN`: the path to the artifact that you want to sign.
+
+**Note 4:** `KEY_VERSION`: the version of the Cloud HSM key. Usually `1` if you are using the key that the automation auto-generated.
+
+
+## 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` | `"cng-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. |
+
+
diff --git a/oss-terraform-automation/3-cng-provider/main.tf b/oss-terraform-automation/3-cng-provider/main.tf
new file mode 100644
index 00000000..366c5081
--- /dev/null
+++ b/oss-terraform-automation/3-cng-provider/main.tf
@@ -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
+}
diff --git a/oss-terraform-automation/3-cng-provider/outputs.tf b/oss-terraform-automation/3-cng-provider/outputs.tf
new file mode 100644
index 00000000..f9feeaf0
--- /dev/null
+++ b/oss-terraform-automation/3-cng-provider/outputs.tf
@@ -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
+}
diff --git a/oss-terraform-automation/3-cng-provider/terraform.example.tfvars b/oss-terraform-automation/3-cng-provider/terraform.example.tfvars
new file mode 100644
index 00000000..05df766d
--- /dev/null
+++ b/oss-terraform-automation/3-cng-provider/terraform.example.tfvars
@@ -0,0 +1,9 @@
+project_id = "REPLACE-WITH-YOUR-EXISTING-PROJECT-ID"
+keyring = "cng-example-keyring-terraform"
+key = "cng-example-key-terraform"
+artifact_image = "cng-example-image-terraform"
+artifact_location = "us-central1"
+artifact_repository = "cng-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."
\ No newline at end of file
diff --git a/oss-terraform-automation/3-cng-provider/variables.tf b/oss-terraform-automation/3-cng-provider/variables.tf
new file mode 100644
index 00000000..6cfe13d8
--- /dev/null
+++ b/oss-terraform-automation/3-cng-provider/variables.tf
@@ -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 = "cng-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 = "./"
+}
diff --git a/oss-terraform-automation/3-cng-provider/versions.tf b/oss-terraform-automation/3-cng-provider/versions.tf
new file mode 100644
index 00000000..0c50890a
--- /dev/null
+++ b/oss-terraform-automation/3-cng-provider/versions.tf
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+terraform {
+ required_version = ">= 1.5.7"
+ required_providers {
+
+ google = {
+ source = "hashicorp/google"
+ version = ">= 5.11, < 6"
+ }
+ }
+}
diff --git a/oss-terraform-automation/README.md b/oss-terraform-automation/README.md
new file mode 100644
index 00000000..c48f570f
--- /dev/null
+++ b/oss-terraform-automation/README.md
@@ -0,0 +1,21 @@
+# Terraform automation for example use cases on Cloud KMS using PKCS #11
+
+PKCS #11 is a standard that specifies an API for managing cryptographic keys, and performing operations with them.
+Cloud KMS provides a library that conforms to this standard, in order to interoperate with existing applications that consume the PKCS #11 API.
+
+This repository contains two terraform automated use cases examples for that library:
+
+- [Use a Cloud HSM key to serve Apache traffic](./1-apache-web-server/README.md)
+- [Use a Cloud HSM key for TLS offloading with NGINX](./2-nginx-ssl-offloading/README.md)
+
+You can find the PKCS #11 library documentation and the manual steps used to build this automation [here](https://cloud.google.com/kms/docs/reference/pkcs11-library).
+
+Microsoft Cryptography API: Next Generation (CNG) is an application programming interface that lets application developers add authentication, encoding, and encryption to Windows-based applications.
+CNG also lets you perform crypto operations with tools such as Windows signtool through CNG providers installed on the system.
+Cloud KMS offers a provider that conforms to this standard, in order to interoperate with existing applications that leverage the CNG API.
+
+This repository contains a terraform automation example for the provider:
+
+- [Use CNG Provider and SignTool to sign Windows artifacts](./3-cng-provider/README.md)
+
+Note that the automation also relies on the PKCS #11 library mentioned above. You can find more information about the CNG provider [here](https://cloud.google.com/kms/docs/reference/cng-provider).
diff --git a/oss-terraform-automation/common/modules/bootstrap-kms-hsm/README.md b/oss-terraform-automation/common/modules/bootstrap-kms-hsm/README.md
new file mode 100644
index 00000000..5878dd73
--- /dev/null
+++ b/oss-terraform-automation/common/modules/bootstrap-kms-hsm/README.md
@@ -0,0 +1,43 @@
+
+## 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` | n/a | yes |
+| artifact\_repository | Respository's name of the image stored in Artifact Registry. | `string` | n/a | yes |
+| artifact\_version | Version of the image stored in Artifact Registry. | `string` | n/a | yes |
+| 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 |
+| cos\_image | Custom OS image desired for the VM. | `string` | `"cos-stable-109-17800-66-57"` | 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 VM host. | `string` | n/a | yes |
+| key | Key name. | `string` | n/a | yes |
+| keyring | Keyring name. | `string` | n/a | yes |
+| location | Location for the resources (keyring, key, network, etc.). | `string` | n/a | yes |
+| machine\_type | Type of the GCE VM. | `string` | `"n1-standard-1"` | no |
+| network\_name | VPC network name. | `string` | `"custom-hsm-network"` | 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. To see more info about versions available: https://github.com/GoogleCloudPlatform/kms-integrations/releases?q=pkcs%2311&expanded=true | `string` | n/a | yes |
+| prevent\_destroy | Set the prevent\_destroy lifecycle attribute on keys. | `bool` | n/a | yes |
+| project\_id | GCP project ID to use for the creation of resources. | `string` | n/a | yes |
+| region | GCP region to use for the creation of resources. | `string` | `"us-central1"` | no |
+| service\_account | Service account to attach to the instance. See https://www.terraform.io/docs/providers/google/r/compute_instance_template#service_account. | object({
email = string,
scopes = set(string)
})
| `null` | no |
+| subnetwork\_name | VPC subnetwork name. | `string` | `"custom-hsm-subnetwork"` | no |
+| suffix | A suffix to be used as an identifier for resources. (e.g., suffix for KMS Key, Keyring, SAs, etc.). | `string` | n/a | yes |
+| zone | GCP zone to use for the creation of resources. | `string` | `"us-central1-a"` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| artifact\_registry\_repository\_name | Name of the Artifact Registry repository created. |
+| custom\_service\_account\_email | Service Account created and managed by Terraform used to trigger Cloud Build jobs. |
+| key | Name of the key created. |
+| keyring | Name of the keyring created. |
+| location | Location of the keyring. |
+| project\_id | ID of the GCP project being used. |
+| suffix | A suffix used as an identifier for resources. (e.g., suffix for KMS Key, Keyring, SAs, etc.) |
+
+
diff --git a/oss-terraform-automation/common/modules/bootstrap-kms-hsm/cloudbuild.tf b/oss-terraform-automation/common/modules/bootstrap-kms-hsm/cloudbuild.tf
new file mode 100644
index 00000000..42dbbb13
--- /dev/null
+++ b/oss-terraform-automation/common/modules/bootstrap-kms-hsm/cloudbuild.tf
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+locals {
+ certificate_file_string = var.certificate_file_path != null ? file(var.certificate_file_path) : ""
+}
+
+resource "null_resource" "pkcs11_docker_image_build_template" {
+
+ triggers = {
+ project_id = var.project_id
+ terraform_service_account = google_service_account.custom_sa.email
+ }
+
+ provisioner "local-exec" {
+ when = create
+ command = <