From 99e265cc6a97420bde0aef08b4cbeb9335a668ef Mon Sep 17 00:00:00 2001 From: xstecuc Date: Tue, 30 Sep 2025 15:30:23 +0200 Subject: [PATCH 1/9] Updates cloud-init logic and use auto-gen signing-key as EnclaveId --- aws/outputs.tf | 16 +- aws/servers.tf | 50 +++-- aws/signing-key.tf | 22 +++ aws/variables.tf | 29 ++- azure/outputs.tf | 14 +- azure/server.tf | 22 ++- azure/signing-key.tf | 22 +++ azure/variables.tf | 29 ++- .../cloud-init.yml => cloud-init/default.yml | 4 +- cloud-init/remote-attestation.yml | 65 +++++++ extensions/cloud-init-generator/README.md | 64 ------- .../cloud-init-generator/cloud-init-gen.sh | 178 ------------------ 12 files changed, 227 insertions(+), 288 deletions(-) create mode 100644 aws/signing-key.tf create mode 100644 azure/signing-key.tf rename commons/cloud-init.yml => cloud-init/default.yml (85%) create mode 100644 cloud-init/remote-attestation.yml delete mode 100644 extensions/cloud-init-generator/README.md delete mode 100755 extensions/cloud-init-generator/cloud-init-gen.sh diff --git a/aws/outputs.tf b/aws/outputs.tf index 09a7f23..55a898a 100644 --- a/aws/outputs.tf +++ b/aws/outputs.tf @@ -1,13 +1,25 @@ output "cvm-info" { description = "Details of the running CVM instance(s)" - value = <<-EOF + value = < + - name: ${USERNAME} sudo: false shell: /bin/bash ssh_authorized_keys: - - + - ${SSH_PUBKEY} timezone: UTC locale: "en_US.UTF-8" diff --git a/cloud-init/remote-attestation.yml b/cloud-init/remote-attestation.yml new file mode 100644 index 0000000..ef5f5ff --- /dev/null +++ b/cloud-init/remote-attestation.yml @@ -0,0 +1,65 @@ +#cloud-config +users: + - default + - name: ${USERNAME} + groups: [canarybit] + sudo: false + shell: /bin/bash + ssh_authorized_keys: + - ${SSH_PUBKEY} + +timezone: UTC +locale: "en_US.UTF-8" + +package_update: true +package_upgrade: true +package_reboot_if_required: true +packages: + - libtss2-dev + - jq + +write_files: + - path: /etc/environment + append: true + content: | + CB_TOKENS=${CB_TOKENS} + CBCLIENT_LOG_LEVEL=info + CBCLIENT_INSPECTOR_URL=${CBINSPECTOR_URL} + CBCLIENT_ENVIRONMENTS=${CC_ENVIRONMENTS} + + - path: /etc/udev/rules.d/61-canarybit-udev.rules + owner: root:root + content: | + # Custom udev rules for CanaryBit attestation client + # SNP on non-Hyper-V guest + # Preserves OWNER="root", gives the group "canarybit" ownership and read access + KERNEL=="sev-guest",MODE="0640",GROUP="canarybit" + # SNP on Hyper-V guest + # Preserves OWNER="tss" and MODE="0660", gives the group "canarybit" ownership and read/write access + KERNEL=="tpmrm0",MODE="0660",GROUP="canarybit" + + - path: /home/${USERNAME}/signing-key.pem + owner: ${USERNAME}:${USERNAME} + defer: true + permissions: '0600' + content: | + ${SIGNING_KEY} + + - path: /home/${USERNAME}/launch-cbclient.sh + owner: ${USERNAME}:${USERNAME} + defer: true + permissions: '0755' + content: | + #!/bin/bash + ############################# + # FETCH & RUN THE CBCLIENT + ############################# + curl -fsSL https://canarybit-public-binaries.s3.eu-west-1.amazonaws.com/cb-cli/${CBCLI_V}/cb-x86_64-unknown-linux-gnu -o cb; chmod +x cb + ./cb download cbclient ${CBCLIENT_V}/cbclient; chmod +x cbclient + ./cbclient attestation --token $(./cb login inspector) --key signing-key.pem 2> cbclient-logs.txt + +runcmd: + - udevadm trigger + - su -c '/home/${USERNAME}/launch-cbclient.sh' - ${USERNAME} + +final_message: "========== TOWER SETUP COMPLETED IN $UPTIME secs ==========" \ No newline at end of file diff --git a/extensions/cloud-init-generator/README.md b/extensions/cloud-init-generator/README.md deleted file mode 100644 index 8ccc288..0000000 --- a/extensions/cloud-init-generator/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Cloud-init Generator - -Generate a cloud-init.yml file extending the standard Confidential VM configuration with CanaryBit Remote Attestation service (Inspector). - -## Requirements - -- `jq` installed - -## Instructions - -### 1. Downlaod `cb` CLI - -#### Linux - -``` -$Β curl -fsSL https://canarybit-public-binaries.s3.eu-west-1.amazonaws.com/cb-cli/0.1.0/cb-x86_64-unknown-linux-gnu -o cb; chmod +x cb -``` - -#### Windows - -``` -curl -fsSL https://canarybit-public-binaries.s3.eu-west-1.amazonaws.com/cb-cli/0.1.0/cb-x86_64-pc-windows-msvc.exe -o cb; chmod +x cb -``` - -#### MacOS - -**M-series** - -``` -curl -fsSL https://canarybit-public-binaries.s3.eu-west-1.amazonaws.com/cb-cli/0.1.0/cb-aarch64-apple-darwin -o cb; chmod +x cb -``` - -**Intel** - -``` -curl -fsSL https://canarybit-public-binaries.s3.eu-west-1.amazonaws.com/cb-cli/0.1.0/cb-x86_64-apple-darwin -o cb; chmod +x cb -``` - -### 2. Login and get your CanaryBit credentials - -Source your credentials: -``` -export CB_USERNAME="***" -export CB_PASSWORD="***" -``` - -and retrieve your CanaryBit tokens: - -``` -export $CB_TOKENS=$(./cb login | jq -c) -``` - -### 4. Generate the cloud-init file - -Example: -``` -$ ./cloud-init-gen.sh --cb-tokens $CB_TOKENS --environment snp --cvm-username demo --cvm-ssh-pubkey ~/.ssh/id_rsa.pub --cbclient-version 0.2.1 --inspector-url https://stag.inspector.confidentialcloud.cc -``` - -Need Help? - -``` -./cloud-init-gen.sh --help -``` diff --git a/extensions/cloud-init-generator/cloud-init-gen.sh b/extensions/cloud-init-generator/cloud-init-gen.sh deleted file mode 100755 index 1de83ab..0000000 --- a/extensions/cloud-init-generator/cloud-init-gen.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Generates cloud-init.yml with all template variables substituted by provided values. -usage() { - cat < CanaryBit id_ and auth_ token in a single json block - --environment Target environment: [ "snp", "tdx" ] - --cvm-username Username to access the VM - --cvm-ssh-pubkey Path to Public Key file - -Optional: - --custom-policy Path to Policy file - --inspector-url Default: https://inspector.confidentialcloud.io - --cbclient Default: latest - --cb-cli Default: latest - --output Default: ./cloud-init.yml - -h, --help Show this help - -Example: - - $0 \\ - --cb-tokens \$CB_TOKENS \\ - --environment snp \\ - --cvm-username john \\ - --cvm-ssh-pubkey ~/.ssh/id_rsa.pub \\ - --cbclient-version 0.2.1 \\ - --inspector-url https://stag.inspector.confidentialcloud.cc - -EOF - exit 1 -} - -# Parse args -while [[ $# -gt 0 ]]; do - case "$1" in - --cb-tokens) CB_TOKENS="$2"; shift 2 ;; - --environment) ENV="$2"; shift 2 ;; - --cvm-username) USERNAME="$2"; shift 2 ;; - --cvm-ssh-pubkey) SSH_PUBKEY_FILE="$2"; shift 2 ;; - --cbclient-version) CBCLIENT_VERSION="$2"; shift 2 ;; - --custom-policy) CUSTOM_POLICY="$2"; shift 2 ;; - --inspector-url) INSPECTOR_URL="$2"; shift 2 ;; - --output) OUTFILE="$2"; shift 2 ;; - -h|--help) usage ;; - *) echo "Unknown arg: $1"; usage ;; - esac -done - -# Check required arguments -: "${CB_TOKENS?:--cb-tokens is required}" -: "${ENV?:--environment is required: 'snp' or 'tdx'}" -: "${USERNAME?:--username is required}" -: "${SSH_PUBKEY_FILE?:--ssh-pubkey filepath is required}" -: "${CBCLIENT_VERSION?:--cbclient-version is required}" - -# Set arguments defaults -INSPECTOR_URL="${INSPECTOR_URL:-'https://inspector.confidentialcloud.io'}" -CBCLI_VERSION="${CBCLI_VERSION:-latest}" -CUSTOM_POLICY="${CUSTOM_POLICY:-}" -OUTFILE="${OUTFILE:-./cloud-init.yml}" - -# Set global variables defaults -CB_PUBLIC_REPO="https://canarybit-public-binaries.s3.eu-west-1.amazonaws.com" -CUSTOM_POLICY_CONFIG='' -CBCLIENT_ARG_POLICY='' - -# Get CB CLI 'latest' version -if [[ "${CBCLI_VERSION}" == "latest" ]]; then - CBCLI_VERSION=$(curl -fsSL $CB_PUBLIC_REPO/cb-cli/latest) -fi - -# Create the Policy file (policy.rego) if file exists -if [[ -n "${CUSTOM_POLICY}" ]]; then - CBCLIENT_ARG_POLICY="--policy policy.rego" - CUSTOM_POLICY_CONTENT=$(cat ${CUSTOM_POLICY}) - CUSTOM_POLICY_CONFIG=$(cat <&2 - exit 2 -fi - -# Read single-line public key and strip CR if present -SSH_PUBKEY="$(sed -e 's/\r$//' "${SSH_PUBKEY_FILE}" | tr -d '\n')" - -if [[ -z "${SSH_PUBKEY}" ]]; then - echo "Error: SSH public key file appears empty: ${SSH_PUBKEY_FILE}" >&2 - exit 2 -fi - -# Check Environment values -if [[ "${ENV}" != "snp" && "${ENV}" != "tdx" ]]; then - echo "Error: --environment must be either 'snp' or 'tdx'." >&2 - exit 2 -fi - -# Create output file (cloud-init YAML) -cat > "${OUTFILE}" < Date: Tue, 30 Sep 2025 16:01:42 +0200 Subject: [PATCH 2/9] Merge examples in one file --- aws/examples/single.tf | 29 ------------ azure/examples/.gitignore | 4 -- azure/examples/single.tf | 34 -------------- {aws/examples => examples}/.gitignore | 0 examples/single.tf | 64 +++++++++++++++++++++++++++ gcp/examples/.gitignore | 4 -- gcp/examples/single.tf | 29 ------------ 7 files changed, 64 insertions(+), 100 deletions(-) delete mode 100644 aws/examples/single.tf delete mode 100644 azure/examples/.gitignore delete mode 100644 azure/examples/single.tf rename {aws/examples => examples}/.gitignore (100%) create mode 100644 examples/single.tf delete mode 100644 gcp/examples/.gitignore delete mode 100644 gcp/examples/single.tf diff --git a/aws/examples/single.tf b/aws/examples/single.tf deleted file mode 100644 index fec4867..0000000 --- a/aws/examples/single.tf +++ /dev/null @@ -1,29 +0,0 @@ -terraform { - required_version = ">= 1.0" - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 5.5" - } - } -} - -provider "aws" {} - -// ===================== -// Confidential VM (CVM) -// ===================== -module "confidential-vm" { - source = "git@github.com:canarybit/tower//aws?ref=main" - - cvm_name = "my-confidential-vm" - cvm_cloud_init = "../../commons/cloud-init.yml" - cvm_ssh_enabled = true -} - -// ===================== -// Print CVM info -// ===================== -output "Confidential_VM_Info" { - value = module.confidential-vm.cvm-info -} diff --git a/azure/examples/.gitignore b/azure/examples/.gitignore deleted file mode 100644 index ae9e1f6..0000000 --- a/azure/examples/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.DS_Store -.terraform/ -.terraform.lock* -terraform.tfstate* diff --git a/azure/examples/single.tf b/azure/examples/single.tf deleted file mode 100644 index 656444b..0000000 --- a/azure/examples/single.tf +++ /dev/null @@ -1,34 +0,0 @@ -terraform { - required_version = ">= 1.0" - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = ">= 4.0.1" - } - } -} - -provider "azurerm" { - features {} -} - -// ===================== -// Confidential VM (CVM) -// ===================== -module "confidential-vm" { - source = "git@github.com:canarybit/tower//azure?ref=main" - - az_resource_group_name = "my-resource-group" - - cvm_name = "my-confidential-vm" - cvm_cloud_init = "../../commons/cloud-init.yml" - cvm_ssh_enabled = true - cvm_ssh_pubkey = "~/.ssh/id_rsa.pub" -} - -// ===================== -// Print CVM info -// ===================== -output "Confidential_VM_Info" { - value = module.confidential-vm.cvm-info -} diff --git a/aws/examples/.gitignore b/examples/.gitignore similarity index 100% rename from aws/examples/.gitignore rename to examples/.gitignore diff --git a/examples/single.tf b/examples/single.tf new file mode 100644 index 0000000..cab8c7f --- /dev/null +++ b/examples/single.tf @@ -0,0 +1,64 @@ +terraform { + required_version = ">= 1.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.5" + } + azurerm = { + source = "hashicorp/azurerm" + version = ">= 4.0.1" + } + google = { + source = "hashicorp/google" + version = "~> 6.8.0" + } + } +} + +provider "aws" {} +provider "azurerm" { + features { } +} +provider "gcp" {} + +// ===================== +// Tower Arguments +// ===================== + +variable "cb_login" { + description = "Enter your CanaryBit Authentication token." + type = string +} + +// ===================== +// Confidential VM (CVM) +// ===================== +module "confidential-vm" { + source = "canarybit/tower/canarybit/" // = aws,azure,gcp + cb_auth = var.cb_login + + az_resource_group_name = "" // Only for Azure deployments + + // Confidential VM + cvm_name = "demo-cvm" + cvm_ssh_enabled = true + cvm_ssh_pubkey = "~/.ssh/id_rsa.pub" + + // Remote Attestation + remote_attestation = { + cc_environments = "snp" + } +} + +// ===================== +// Print CVM info +// ===================== +output "cvm-info" { + value = module.confidential-vm.cvm-info +} + +output "cvm_cloud_init" { + value = module.confidential-vm.cloud-init + sensitive = true +} \ No newline at end of file diff --git a/gcp/examples/.gitignore b/gcp/examples/.gitignore deleted file mode 100644 index ae9e1f6..0000000 --- a/gcp/examples/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.DS_Store -.terraform/ -.terraform.lock* -terraform.tfstate* diff --git a/gcp/examples/single.tf b/gcp/examples/single.tf deleted file mode 100644 index 6b09f5e..0000000 --- a/gcp/examples/single.tf +++ /dev/null @@ -1,29 +0,0 @@ -terraform { - required_version = ">= 1.0" - required_providers { - google = { - source = "hashicorp/google" - version = "~> 6.8.0" - } - } -} - -provider "google" {} - -// ===================== -// Confidential VM (CVM) -// ===================== -module "confidential-vm" { - source = "git@github.com:canarybit/tower//gcp?ref=main" - - cvm_name = "my-confidential-vm" - cvm_cloud_init = "../../commons/cloud-init.yml" - cvm_ssh_enabled = true -} - -// ===================== -// Print CVM info -// ===================== -output "Confidential_VM_Info" { - value = module.confidential-vm.cvm-info -} From 475f46714b691927aae442a80ca0c3c00ad806e3 Mon Sep 17 00:00:00 2001 From: xstecuc Date: Tue, 30 Sep 2025 16:05:17 +0200 Subject: [PATCH 3/9] Update examples --- examples/single.tf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/single.tf b/examples/single.tf index cab8c7f..6d576f7 100644 --- a/examples/single.tf +++ b/examples/single.tf @@ -1,6 +1,7 @@ terraform { required_version = ">= 1.0" required_providers { + // Use only the required provider aws = { source = "hashicorp/aws" version = "~> 5.5" @@ -15,7 +16,8 @@ terraform { } } } - + +// Use only the required provider provider "aws" {} provider "azurerm" { features { } @@ -35,10 +37,11 @@ variable "cb_login" { // Confidential VM (CVM) // ===================== module "confidential-vm" { - source = "canarybit/tower/canarybit/" // = aws,azure,gcp + source = "canarybit/tower/canarybit/" // : aws, azure, gcp cb_auth = var.cb_login - az_resource_group_name = "" // Only for Azure deployments + // Azure deployments only, remove otherwise! + az_resource_group_name = "" // Confidential VM cvm_name = "demo-cvm" From 453052e790caa31e9751ccc57869c5064dfc3dff Mon Sep 17 00:00:00 2001 From: xstecuc Date: Tue, 30 Sep 2025 16:06:37 +0200 Subject: [PATCH 4/9] Move submodules to /modules --- {aws => modules/aws}/.gitignore | 0 {aws => modules/aws}/.pre-commit-config.yaml | 0 {aws => modules/aws}/README.md | 0 {aws => modules/aws}/outputs.tf | 0 {aws => modules/aws}/security.tf | 0 {aws => modules/aws}/servers.tf | 0 {aws => modules/aws}/signing-key.tf | 0 {aws => modules/aws}/terraform.tf | 0 {aws => modules/aws}/variables.tf | 0 {azure => modules/azure}/.gitignore | 0 {azure => modules/azure}/.pre-commit-config.yaml | 0 {azure => modules/azure}/README.md | 0 {azure => modules/azure}/data.tf | 0 {azure => modules/azure}/locals.tf | 0 {azure => modules/azure}/network.tf | 0 {azure => modules/azure}/outputs.tf | 0 {azure => modules/azure}/security.tf | 0 {azure => modules/azure}/server.tf | 0 {azure => modules/azure}/signing-key.tf | 0 {azure => modules/azure}/terraform.tf | 0 {azure => modules/azure}/variables.tf | 0 {gcp => modules/gcp}/.gitignore | 0 {gcp => modules/gcp}/.pre-commit-config.yaml | 0 {gcp => modules/gcp}/README.md | 0 {gcp => modules/gcp}/locals.tf | 0 {gcp => modules/gcp}/outputs.tf | 0 {gcp => modules/gcp}/security.tf | 0 {gcp => modules/gcp}/servers.tf | 0 {gcp => modules/gcp}/terraform.tf | 0 {gcp => modules/gcp}/variables.tf | 0 30 files changed, 0 insertions(+), 0 deletions(-) rename {aws => modules/aws}/.gitignore (100%) rename {aws => modules/aws}/.pre-commit-config.yaml (100%) rename {aws => modules/aws}/README.md (100%) rename {aws => modules/aws}/outputs.tf (100%) rename {aws => modules/aws}/security.tf (100%) rename {aws => modules/aws}/servers.tf (100%) rename {aws => modules/aws}/signing-key.tf (100%) rename {aws => modules/aws}/terraform.tf (100%) rename {aws => modules/aws}/variables.tf (100%) rename {azure => modules/azure}/.gitignore (100%) rename {azure => modules/azure}/.pre-commit-config.yaml (100%) rename {azure => modules/azure}/README.md (100%) rename {azure => modules/azure}/data.tf (100%) rename {azure => modules/azure}/locals.tf (100%) rename {azure => modules/azure}/network.tf (100%) rename {azure => modules/azure}/outputs.tf (100%) rename {azure => modules/azure}/security.tf (100%) rename {azure => modules/azure}/server.tf (100%) rename {azure => modules/azure}/signing-key.tf (100%) rename {azure => modules/azure}/terraform.tf (100%) rename {azure => modules/azure}/variables.tf (100%) rename {gcp => modules/gcp}/.gitignore (100%) rename {gcp => modules/gcp}/.pre-commit-config.yaml (100%) rename {gcp => modules/gcp}/README.md (100%) rename {gcp => modules/gcp}/locals.tf (100%) rename {gcp => modules/gcp}/outputs.tf (100%) rename {gcp => modules/gcp}/security.tf (100%) rename {gcp => modules/gcp}/servers.tf (100%) rename {gcp => modules/gcp}/terraform.tf (100%) rename {gcp => modules/gcp}/variables.tf (100%) diff --git a/aws/.gitignore b/modules/aws/.gitignore similarity index 100% rename from aws/.gitignore rename to modules/aws/.gitignore diff --git a/aws/.pre-commit-config.yaml b/modules/aws/.pre-commit-config.yaml similarity index 100% rename from aws/.pre-commit-config.yaml rename to modules/aws/.pre-commit-config.yaml diff --git a/aws/README.md b/modules/aws/README.md similarity index 100% rename from aws/README.md rename to modules/aws/README.md diff --git a/aws/outputs.tf b/modules/aws/outputs.tf similarity index 100% rename from aws/outputs.tf rename to modules/aws/outputs.tf diff --git a/aws/security.tf b/modules/aws/security.tf similarity index 100% rename from aws/security.tf rename to modules/aws/security.tf diff --git a/aws/servers.tf b/modules/aws/servers.tf similarity index 100% rename from aws/servers.tf rename to modules/aws/servers.tf diff --git a/aws/signing-key.tf b/modules/aws/signing-key.tf similarity index 100% rename from aws/signing-key.tf rename to modules/aws/signing-key.tf diff --git a/aws/terraform.tf b/modules/aws/terraform.tf similarity index 100% rename from aws/terraform.tf rename to modules/aws/terraform.tf diff --git a/aws/variables.tf b/modules/aws/variables.tf similarity index 100% rename from aws/variables.tf rename to modules/aws/variables.tf diff --git a/azure/.gitignore b/modules/azure/.gitignore similarity index 100% rename from azure/.gitignore rename to modules/azure/.gitignore diff --git a/azure/.pre-commit-config.yaml b/modules/azure/.pre-commit-config.yaml similarity index 100% rename from azure/.pre-commit-config.yaml rename to modules/azure/.pre-commit-config.yaml diff --git a/azure/README.md b/modules/azure/README.md similarity index 100% rename from azure/README.md rename to modules/azure/README.md diff --git a/azure/data.tf b/modules/azure/data.tf similarity index 100% rename from azure/data.tf rename to modules/azure/data.tf diff --git a/azure/locals.tf b/modules/azure/locals.tf similarity index 100% rename from azure/locals.tf rename to modules/azure/locals.tf diff --git a/azure/network.tf b/modules/azure/network.tf similarity index 100% rename from azure/network.tf rename to modules/azure/network.tf diff --git a/azure/outputs.tf b/modules/azure/outputs.tf similarity index 100% rename from azure/outputs.tf rename to modules/azure/outputs.tf diff --git a/azure/security.tf b/modules/azure/security.tf similarity index 100% rename from azure/security.tf rename to modules/azure/security.tf diff --git a/azure/server.tf b/modules/azure/server.tf similarity index 100% rename from azure/server.tf rename to modules/azure/server.tf diff --git a/azure/signing-key.tf b/modules/azure/signing-key.tf similarity index 100% rename from azure/signing-key.tf rename to modules/azure/signing-key.tf diff --git a/azure/terraform.tf b/modules/azure/terraform.tf similarity index 100% rename from azure/terraform.tf rename to modules/azure/terraform.tf diff --git a/azure/variables.tf b/modules/azure/variables.tf similarity index 100% rename from azure/variables.tf rename to modules/azure/variables.tf diff --git a/gcp/.gitignore b/modules/gcp/.gitignore similarity index 100% rename from gcp/.gitignore rename to modules/gcp/.gitignore diff --git a/gcp/.pre-commit-config.yaml b/modules/gcp/.pre-commit-config.yaml similarity index 100% rename from gcp/.pre-commit-config.yaml rename to modules/gcp/.pre-commit-config.yaml diff --git a/gcp/README.md b/modules/gcp/README.md similarity index 100% rename from gcp/README.md rename to modules/gcp/README.md diff --git a/gcp/locals.tf b/modules/gcp/locals.tf similarity index 100% rename from gcp/locals.tf rename to modules/gcp/locals.tf diff --git a/gcp/outputs.tf b/modules/gcp/outputs.tf similarity index 100% rename from gcp/outputs.tf rename to modules/gcp/outputs.tf diff --git a/gcp/security.tf b/modules/gcp/security.tf similarity index 100% rename from gcp/security.tf rename to modules/gcp/security.tf diff --git a/gcp/servers.tf b/modules/gcp/servers.tf similarity index 100% rename from gcp/servers.tf rename to modules/gcp/servers.tf diff --git a/gcp/terraform.tf b/modules/gcp/terraform.tf similarity index 100% rename from gcp/terraform.tf rename to modules/gcp/terraform.tf diff --git a/gcp/variables.tf b/modules/gcp/variables.tf similarity index 100% rename from gcp/variables.tf rename to modules/gcp/variables.tf From a62c34fede63192ff4ff942b020a5b24907f733d Mon Sep 17 00:00:00 2001 From: xstecuc Date: Wed, 1 Oct 2025 09:44:19 +0200 Subject: [PATCH 5/9] Aligns code for Terraform Registry support --- versions.tf | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 versions.tf diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..a8e6192 --- /dev/null +++ b/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 1.0.0" +} \ No newline at end of file From 602c8e0a714d408f3a9319d01e44a711ee2d562a Mon Sep 17 00:00:00 2001 From: xstecuc Date: Wed, 1 Oct 2025 20:38:16 +0200 Subject: [PATCH 6/9] Updates README.md --- README.md | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 8628ce3..460ebda 100644 --- a/README.md +++ b/README.md @@ -4,35 +4,32 @@ maintain Confidential VM instances. Tower integrates with a long list of Cloud Service Providers (CSPs), private and bare-metal infrastructure to provide governance of the resources defining your Trusted Execution Environment (TEE). -It implements Infrastructure-as-Code (IaC) and SecDevOps methodologies to provide integrity and state of the art security -to your workloads runtime. + +It implements Infrastructure-as-Code (IaC) and SecDevOps best-practices to provide integrity and state of the art security to your workloads runtime. ## 🌟 Features - 🀹 **Confidential VM Orchestration**: Deploy confidential VMs on AMD SEV-SNP and Intel TDX platforms. +- πŸ”¬ **Hardware & Environment Verification**: Integrate with [CanaryBit Inspector](https://www.canarybit.eu/confidential-cloud-inspector/) to support Remote Attestation of deployed confidential VMs. (* Requires a CanaryBit account) - πŸ›  **Extensible Configuration**: Configure your confidential VM using available configuration options or write your own. - βš–οΈ **No lock-in**: Support for multiple hardware platforms and virtualisation software. -- πŸ”¬ **Attestation verification support**: Integrates with [Inspector](https://www.canarybit.eu/confidential-cloud-inspector/) -to support remote attestation of deployed confidential VMs. Contact hi@canarybit.eu to learn more about CanaryBit's solution for remote attestation of confidential VMs. ## 🧩 Integrations - **Galaxy server**: Support for the [Galaxy project](https://github.com/galaxyproject) for data-intensive computation. -- **Write your own**: Simple to crate new integrations using the [cloud-init-generator](https://github.com/canarybit/tower/tree/main/extensions/cloud-init-generator) - +- **Write your own**: Simple to create new integrations with custom `cloud-init` configurations. + ## πŸ› οΈ How It Works 1. **Clone** the repository to get the configurations. 2. **Configure** the cloud-init script fine-tune your target setup. 3. **Run** the Terraform scripts for your target Cloud Service Provider. 4. **Need help?** Check the examples to help you get started. - ## 🧱 Requirements - [Terraform](https://developer.hashicorp.com/terraform) or [OpenTofu](https://opentofu.org/docs/intro/install/) installed; -- Credentials to access your favourite Cloud Service Provider; -- An SSH key to access Confidential VM instances. +- Credentials to access your target Cloud Service Provider; +- A SSH RSA keypair to access Confidential VM instances. ## πŸ“– Documentation -For setup instructions, API references, and usage examples, see the documentation: -πŸ”— [Documentation Link](https://docs.confidentialcloud.io/tower/) +For setup instructions, API references, and usage examples, read the [technical documentation](https://docs.confidentialcloud.io/tower/). ## πŸ€ Use Cases - πŸ€– **Confidential AI**: Train models in a secure environment to protect intellectual property at all times. @@ -44,23 +41,32 @@ For setup instructions, API references, and usage examples, see the documentatio ## πŸ’ͺ Contributing Contributions are welcome! Please check the [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to get started. -## πŸ“‘ License -Tower is licensed under the **Apache-2.0 License**. See the [LICENSE](LICENSE) file for more details. -The Standard version contains the Terraform/OpenTofu configurations for deploying Confidential VMs in **Public Clouds**. -Currently Tower supports the following platforms and public cloud providers: +## 🎟️ Licences + +Tower is a Freemium service: basic features are free for Public Cloud setups while additional features, such as Remote Attestation and On-prem support, are offered via a paid subscription. + +### πŸ”° Standard +The [Apache-2.0 License](LICENSE) *free* version contains the Terraform/OpenTofu configurations for deploying Confidential VMs in **Public Clouds**. -| Cloud Platform | AMD SEV-SNP | Intel TDX | -|-----------------| ------- |------- | -| [AWS](/aws) | yes | upcoming | -| [Azure](/azure) | yes | upcoming | -| [GCP](/gcp) | yes | yes | +Currently, Tower supports the following platforms and public cloud providers: + +| Cloud Platform | AMD SEV-SNP | Intel TDX | +|-------------------------| ----------- |------------ | +| [AWS](/modules/aws) | yes | upcoming | +| [Azure](/modules/azure) | yes | upcoming | +| [GCP](/modules/gcp) | yes | yes | ### πŸ’Ž Premium The Premium version contains the Terraform configurations for deploying Confidential VMs **on-premise** and for **bare-metal** setups. -Currently Tower supports the following virtualisation plaftorms: + +Currently, Tower supports the following virtualisation plaftorms: - [Libvirt/Qemu/KVM](https://libvirt.org/) - [Proxmox](https://www.proxmox.com/) - [VMware vSphere 9.0](https://www.vmware.com/products/cloud-infrastructure/vsphere) -Reach out to [hi@canarybit.eu](mailto:hi@canarybit.eu) if you want to use Tower to deploy confidential VMs in on-prem deployments (that requires the Premium version). + +## 🎟️ Contacts +Reach us out at [hi@canarybit.eu](mailto:hi@canarybit.eu) for more information. + +/Β The CanaryBit Team \ No newline at end of file From 933f3da5eec43db64d1f4c5885c5ea075d9dda91 Mon Sep 17 00:00:00 2001 From: xstecuc Date: Thu, 2 Oct 2025 21:24:49 +0200 Subject: [PATCH 7/9] Updates GCP config --- modules/gcp/locals.tf | 6 +++++ modules/gcp/outputs.tf | 12 ++++++++++ modules/gcp/servers.tf | 27 +++++++++++++++++----- modules/gcp/signing-key.tf | 22 ++++++++++++++++++ modules/gcp/variables.tf | 47 ++++++++++++++++++++++++-------------- 5 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 modules/gcp/signing-key.tf diff --git a/modules/gcp/locals.tf b/modules/gcp/locals.tf index 771671d..84d8902 100644 --- a/modules/gcp/locals.tf +++ b/modules/gcp/locals.tf @@ -1,3 +1,9 @@ locals { cvm_running_os = split("/", google_compute_instance.cvm.boot_disk.0.initialize_params.0.image) + // Map VM size with CPU type + cvm_size_prefix = split("-",var.cvm_size)[0] + cvm_size_cpu_type_map = { + TDX = ["c3"] + SEV_SNP = ["n2d"] + } } \ No newline at end of file diff --git a/modules/gcp/outputs.tf b/modules/gcp/outputs.tf index 7db07ff..c1a3e00 100644 --- a/modules/gcp/outputs.tf +++ b/modules/gcp/outputs.tf @@ -8,9 +8,21 @@ output "cvm-info" { Disk: 0 GB PublicIp: ${google_compute_instance.cvm.network_interface.0.access_config.0.nat_ip} SshEnabled: ${var.cvm_ssh_enabled} + Username: ${var.cvm_username} Secure Boot: ${google_compute_instance.cvm.shielded_instance_config.0.enable_secure_boot} vTPM: ${google_compute_instance.cvm.shielded_instance_config.0.enable_vtpm} + EnclaveID / Signing Key Fingerprint: + ${data.local_file.signing-key-fingerprint.content} + + EOF +} + +output "cloud-init" { + value = < 0 - error_message = "Valid values are n2d-* or c3-standard-* series" + condition = length(regexall("^[n2d,c3]+", var.cvm_size)) > 0 + error_message = "ERROR - Invalid VM size" } } -variable "cvm_cpu_platform" { - // All CPU platforms here: https://cloud.google.com/compute/docs/instances/specify-min-cpu-platform - description = "Supported CPU Platforms are ['AMD Milan','AMD Genoa'] for AMD SNP and ['sapphirerapids'] for Intel TDX" - type = string - default = "AMD Milan" +/////////////////////// +// DEFAULT +/////////////////////// + +variable "remote_attestation" { + description = "Enable CanaryBit Inspector Remote Attestation" + type = object({ + cc_environments = string + cbinspector_url = optional(string, "https://inspector.confidentialcloud.io") + cbclient_version = optional(string, "0.2.2") + cbcli_version = optional(string, "0.2.0") + signing_key = optional(string) + }) + default = null } variable "cvm_os" { @@ -41,10 +48,16 @@ variable "cvm_os" { default = "ubuntu-2404-lts-amd64" } +variable "cvm_username" { + description = "" + type = string + default = "tower" +} + variable "cvm_disk_size_gb" { description = "" type = string - default = "30" + default = "0" } variable "cvm_ports_open" { From e8701a4b3d596816bd0320cde790c1be532b4e18 Mon Sep 17 00:00:00 2001 From: xstecuc Date: Thu, 2 Oct 2025 21:25:58 +0200 Subject: [PATCH 8/9] Fix bug in path --- modules/aws/servers.tf | 17 +++++++++-------- modules/azure/server.tf | 15 ++++++++------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/modules/aws/servers.tf b/modules/aws/servers.tf index ad728fa..2f82f47 100644 --- a/modules/aws/servers.tf +++ b/modules/aws/servers.tf @@ -10,13 +10,8 @@ resource "aws_instance" "cvm" { ami = var.cvm_os instance_type = var.cvm_size - // Select the right cloud-init: default or with Remote Attestation support. - user_data = var.remote_attestation == false ? base64encode(templatefile("${path.module}/../cloud-init/default.yml", - { - USERNAME = var.cvm_username - SSH_PUBKEY = file(var.cvm_ssh_pubkey) - } - )) : base64encode(templatefile("${path.module}/../cloud-init/remote-attestation.yml", + // Select the right cloud-init: with Remote Attestation support or default. + user_data = var.remote_attestation != null ? base64encode(templatefile("${path.module}/../../cloud-init/remote-attestation.yml", { USERNAME = var.cvm_username SSH_PUBKEY = file(var.cvm_ssh_pubkey) @@ -29,7 +24,13 @@ resource "aws_instance" "cvm" { // Indent the signing key otherwise cloud-init will fail SIGNING_KEY = indent(6,tls_private_key.rsa-4096.private_key_pem_pkcs8) } - )) + )) : base64encode(templatefile("${path.module}/../../cloud-init/default.yml", + { + USERNAME = var.cvm_username + SSH_PUBKEY = file(var.cvm_ssh_pubkey) + } + ) + ) vpc_security_group_ids = [aws_security_group.default.id] associate_public_ip_address = true diff --git a/modules/azure/server.tf b/modules/azure/server.tf index 733e943..fc483bd 100644 --- a/modules/azure/server.tf +++ b/modules/azure/server.tf @@ -5,12 +5,7 @@ resource "azurerm_linux_virtual_machine" "cvm" { size = var.cvm_size // Select the right cloud-init: default or with Remote Attestation support. - user_data = var.remote_attestation == false ? base64encode(templatefile("${path.module}/../cloud-init/default.yml", - { - USERNAME = var.cvm_username - SSH_PUBKEY = file(var.cvm_ssh_pubkey) - } - )) : base64encode(templatefile("${path.module}/../cloud-init/remote-attestation.yml", + user_data = var.remote_attestation != null ? base64encode(templatefile("${path.module}/../../cloud-init/remote-attestation.yml", { USERNAME = var.cvm_username SSH_PUBKEY = file(var.cvm_ssh_pubkey) @@ -23,7 +18,13 @@ resource "azurerm_linux_virtual_machine" "cvm" { // Indent the signing key otherwise cloud-init will fail SIGNING_KEY = indent(6,tls_private_key.rsa-4096.private_key_pem_pkcs8) } - )) + )) : base64encode(templatefile("${path.module}/../../cloud-init/default.yml", + { + USERNAME = var.cvm_username + SSH_PUBKEY = file(var.cvm_ssh_pubkey) + } + ) + ) # The required AZ approach to add a VM user in addition to cloud-init config admin_username = var.cvm_username From f76c469665db6a15390ffe4ebdb2b413f91e1e9e Mon Sep 17 00:00:00 2001 From: xstecuc Date: Thu, 2 Oct 2025 21:30:18 +0200 Subject: [PATCH 9/9] Refactoring --- modules/aws/variables.tf | 29 ++++++++++++++--------------- modules/azure/variables.tf | 2 -- modules/gcp/variables.tf | 1 + 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/modules/aws/variables.tf b/modules/aws/variables.tf index dfcba56..21cf3ee 100644 --- a/modules/aws/variables.tf +++ b/modules/aws/variables.tf @@ -17,6 +17,20 @@ variable "cvm_ssh_pubkey" { type = string } +variable "cvm_size" { + description = < 0 + error_message = "Supported sizes are M6a, C6a, R6a for AMD SNP and nd M7i, M7i-flex for Intel TDX" + } +} + /////////////////////// // DEFAULT /////////////////////// @@ -33,21 +47,6 @@ variable "remote_attestation" { default = null } -variable "cvm_size" { - description = < 0 - error_message = "Supported sizes are M6a, C6a, R6a for AMD SNP and nd M7i, M7i-flex for Intel TDX" - } -} - variable "cvm_os" { description = "AMI of the OS image" type = string diff --git a/modules/azure/variables.tf b/modules/azure/variables.tf index b49a96c..5fc9d11 100644 --- a/modules/azure/variables.tf +++ b/modules/azure/variables.tf @@ -42,10 +42,8 @@ variable "remote_attestation" { variable "cvm_size" { description = "Supported sizes are `Standard_DC*` or `Standard_EC*` series" type = string - default = "Standard_DC2as_v5" validation { - # Check if it's a supported size condition = length(regexall("^Standard_[D,E]C+", var.cvm_size)) > 0 error_message = "Valid values are Standard_DC* or Standard_EC* series" } diff --git a/modules/gcp/variables.tf b/modules/gcp/variables.tf index 2da4641..4b93706 100644 --- a/modules/gcp/variables.tf +++ b/modules/gcp/variables.tf @@ -20,6 +20,7 @@ variable "cvm_ssh_pubkey" { variable "cvm_size" { description = "Supported VM sizes: N2D for AMD SNP or C3 for Intel" type = string + validation { condition = length(regexall("^[n2d,c3]+", var.cvm_size)) > 0 error_message = "ERROR - Invalid VM size"