Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Terraform for CI HAB PKI #78

Merged
merged 6 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion deployment/build_and_release/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ resource "google_storage_bucket" "armored_witness_firmware_log_ci_1" {
uniform_bucket_level_access = true
}

# KMS key rings
# KMS key rings & data sources
resource "google_kms_key_ring" "firmware_release_ci" {
location = var.signing_keyring_location
name = "firmware-release-ci"
Expand Down Expand Up @@ -227,6 +227,10 @@ resource "google_kms_key_ring" "firmware_release_prod" {
# }
#}

############################################################
## Terraform state bucket
############################################################

resource "google_kms_key_ring" "terraform_state" {
name = "armored-witness-bucket-tfstate"
location = var.tf_state_location
Expand Down
4 changes: 2 additions & 2 deletions deployment/build_and_release/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
project_id = "1071548024491"
project_id = "armored-witness"
signing_keyring_location = "global"
tf_state_location = "europe-west2"
tf_state_location = "europe-west2"
335 changes: 335 additions & 0 deletions deployment/hab_pki/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
# Configure remote terraform backend for state.
terraform {
backend "gcs" {
bucket = "armored-witness-bucket-tfstate"
prefix = "terraform/hab_pki/state"
}
}

# Project
provider "google" {
project = var.project_id
}

data "google_project" "project" {
project_id = var.project_id
}

# Enable necessary APIs
resource "google_project_service" "cloudkms_googleapis_com" {
service = "cloudkms.googleapis.com"
}
resource "google_project_service" "logging_googleapis_com" {
service = "logging.googleapis.com"
}
resource "google_project_service" "serviceusage_googleapis_com" {
service = "serviceusage.googleapis.com"
}
resource "google_project_service" "privateca_api" {
service = "privateca.googleapis.com"
disable_on_destroy = false
}

# KMS key rings & data sources
resource "google_kms_key_ring" "hab" {
location = var.signing_keyring_location
name = "hab-ci"
}
data "google_kms_key_ring" "hab" {
location = google_kms_key_ring.hab.location
name = google_kms_key_ring.hab.name
}

### KMS keys

# CI HAB CSF key & data sources for each of the SRK intermediates below.
#
# The resource creates the key within the keyring, and the data sections below
# ultimately provide a mechanism for getting the public key out from the HSM
# so that it can be certified by the leaf certificates of the HAB PKI below.
resource "google_kms_crypto_key" "hab_csf" {
for_each = toset(local.hab_intermediates)

key_ring = google_kms_key_ring.hab.id
name = format("hab-csf%d-rev%d-ci", each.value, var.hab_ci_revision)
purpose = "ASYMMETRIC_SIGN"
version_template {
algorithm = format("RSA_SIGN_PKCS1_%d_SHA256", var.hab_keylength)
protection_level = "HSM"
}
}
data "google_kms_crypto_key" "hab_csf" {
for_each = toset(local.hab_intermediates)

name = format("hab-csf%s-rev%d-ci", each.value, var.hab_ci_revision)
key_ring = data.google_kms_key_ring.hab.id

depends_on = [
google_kms_crypto_key.hab_csf
]
}
data "google_kms_crypto_key_version" "hab_csf" {
for_each = toset(local.hab_intermediates)

crypto_key = data.google_kms_crypto_key.hab_csf[each.key].id
}
# CI HAB IMG key & data sources for each of the SRK intermediates below.
resource "google_kms_crypto_key" "hab_img" {
for_each = toset(local.hab_intermediates)

key_ring = google_kms_key_ring.hab.id
name = format("hab-img%d-rev%d-ci", each.value, var.hab_ci_revision)
purpose = "ASYMMETRIC_SIGN"
version_template {
algorithm = format("RSA_SIGN_PKCS1_%d_SHA256", var.hab_keylength)
protection_level = "HSM"
}
}
data "google_kms_crypto_key" "hab_img" {
for_each = toset(local.hab_intermediates)

name = format("hab-img%s-rev%d-ci", each.value, var.hab_ci_revision)
key_ring = data.google_kms_key_ring.hab.id

depends_on = [
google_kms_crypto_key.hab_img
]
}
data "google_kms_crypto_key_version" "hab_img" {
for_each = toset(local.hab_intermediates)

crypto_key = data.google_kms_crypto_key.hab_img[each.key].id
}

###########################################################################
## CI HAB Certificate Authority config.
##
## This should construct a CA hierarchy as below for use with HAB signing:
## .--------.
## | Root |
## `--------'
## |
## ---------------------------------------------------
## | | | |
## .--------. .--------. .--------. .--------.
## | SRK1 | | SRK2 | | SRK3 | | SRK4 |
## `--------' `--------' `--------' `--------'
## / \ / \ / \ / \
## .----. .----. .----. .----. .----. .----. .----. .----.
## |CSF1| |IMG1| |CSF2| |IMG2| |CSF3| |IMG3| |CSF4| |IMG4|
## `----' `----' `----' `----' `----' `----' `----' `----'
###########################################################################

# CI HAB CA pool
resource "google_privateca_ca_pool" "hab" {
name = "aw-hab-ca-pool-rev0-ci"
location = "us-central1"
tier = "ENTERPRISE"
publishing_options {
publish_ca_cert = true
publish_crl = false
}
issuance_policy {
baseline_values {
ca_options {
is_ca = true
}
key_usage {
base_key_usage {
cert_sign = true
crl_sign = true
digital_signature = true
}
extended_key_usage {
}
}
}
}
}

# CI HAB Root CA authority
resource "google_privateca_certificate_authority" "hab_root" {
pool = google_privateca_ca_pool.hab.name
certificate_authority_id = format("hab-root-rev%d-ci", var.hab_ci_revision)
location = "us-central1"
lifetime = format("%ds", var.hab_pki_lifetime)
deletion_protection = true

type = "SELF_SIGNED"
config {
subject_config {
subject {
organization = "TrustFabric"
organizational_unit = "ArmoredWitness CI"
common_name = "ArmoredWitness Root CI"
}
}
x509_config {
ca_options {
# is_ca *MUST* be true for certificate authorities
is_ca = true
}
key_usage {
base_key_usage {
# cert_sign and crl_sign *MUST* be true for certificate authorities
cert_sign = true
crl_sign = true
}
extended_key_usage {
}
}
}
}
key_spec {
algorithm = format("RSA_PKCS1_%d_SHA256", var.hab_keylength)
}
}

locals {
// This simply gives us a list we can use, in combination with the for_each meta attribute, to create
// multiple instances of the subordinate CAs & certs below.
hab_intermediates = [for i in range(1, 1 + var.hab_num_intermediates) : format("%s", i)]
}

# CI HAB SRK intermediates (one each for hab_intermediates above)
resource "google_privateca_certificate_authority" "hab_srk" {
for_each = toset(local.hab_intermediates)

pool = google_privateca_ca_pool.hab.name
certificate_authority_id = format("hab-srk%s-rev%d-ci", each.value, var.hab_ci_revision)
location = "us-central1"
lifetime = format("%ds", var.hab_pki_lifetime)
deletion_protection = "true"

type = "SUBORDINATE"
subordinate_config {
certificate_authority = google_privateca_certificate_authority.hab_root.name
}
config {
subject_config {
subject {
organization = "TrustFabric"
organizational_unit = "ArmoredWitness CI"
common_name = format("ArmoredWitness SRK%s CI", each.value)
}
}
x509_config {
ca_options {
is_ca = true
# Force the sub CA to only issue leaf certs
max_issuer_path_length = 0
}
key_usage {
base_key_usage {
cert_sign = true
crl_sign = true
}
extended_key_usage {
}
}
}
}
key_spec {
algorithm = format("RSA_PKCS1_%d_SHA256", var.hab_keylength)
}
}

# CI HAB CSF cert for each of the SRK intermediates above.
resource "google_privateca_certificate" "hab_csf" {
for_each = google_privateca_certificate_authority.hab_srk

name = format("hab-csf%s-rev%d-ci", each.key, var.hab_ci_revision)
location = "us-central1"
pool = each.value.pool
certificate_authority = each.value.certificate_authority_id
lifetime = format("%ds", var.hab_pki_lifetime)
config {
subject_config {
subject {
organization = "TrustFabric"
organizational_unit = "ArmoredWitness CI"
common_name = format("ArmoredWitness SRK%s CSF CI", each.key)
}
}
x509_config {
ca_options {
is_ca = false
}
key_usage {
base_key_usage {
digital_signature = true
}
extended_key_usage {
}
}
}
public_key {
format = "PEM"
key = base64encode(data.google_kms_crypto_key_version.hab_csf[each.key].public_key[0].pem)
}
}
}

# CI HAB IMG cert for each of the SRK intermediates above.
resource "google_privateca_certificate" "hab_img" {
for_each = google_privateca_certificate_authority.hab_srk

name = format("hab-img%s-rev%d-ci", each.key, var.hab_ci_revision)
location = "us-central1"
pool = each.value.pool
certificate_authority = each.value.certificate_authority_id
lifetime = format("%ds", var.hab_pki_lifetime)
config {
subject_config {
subject {
organization = "TrustFabric"
organizational_unit = "ArmoredWitness CI"
common_name = format("ArmoredWitness SRK%s IMG CI", each.key)
}
}
x509_config {
ca_options {
is_ca = false
}
key_usage {
base_key_usage {
digital_signature = true
}
extended_key_usage {
}
}
}
public_key {
format = "PEM"
key = base64encode(data.google_kms_crypto_key_version.hab_img[each.key].public_key[0].pem)
}
}
}

############################################################
## Terraform state bucket
############################################################

resource "google_kms_key_ring" "terraform_state" {
name = "armored-witness-bucket-tfstate"
location = var.tf_state_location
}

resource "google_kms_crypto_key" "terraform_state_bucket" {
name = "terraform-state-bucket"
key_ring = google_kms_key_ring.terraform_state.id
}

resource "google_storage_bucket" "terraform_state" {
name = "armored-witness-bucket-tfstate"
force_destroy = false
location = var.tf_state_location
storage_class = "STANDARD"
versioning {
enabled = true
}
encryption {
default_kms_key_name = google_kms_crypto_key.terraform_state_bucket.id
}
uniform_bucket_level_access = true
}
5 changes: 5 additions & 0 deletions deployment/hab_pki/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
project_id = "armored-witness"
signing_keyring_location = "global"
tf_state_location = "europe-west2"

hab_ci_revision = 4
Loading
Loading