Skip to content

fix(3-security): apply kms_protection_level to keys that set no version_template - #212

Open
scottonix wants to merge 1 commit into
google:mainfrom
scottonix:fix/3-security-kms-protection-level
Open

fix(3-security): apply kms_protection_level to keys that set no version_template#212
scottonix wants to merge 1 commit into
google:mainfrom
scottonix:fix/3-security-kms-protection-level

Conversation

@scottonix

Copy link
Copy Markdown

Description

fast/stages-aw/3-security exposes kms_protection_level, but the value never reaches Cloud KMS. core-prod.tf and core-dev.tf pass it to modules/kms inside the keyring object as keyring.version_template, and that module's keyring variable is typed object({ location = string, name = string }). Terraform drops the extra attribute silently, so every key in kms_keys that does not carry its own version_template is created without one — i.e. at the Cloud KMS default protection level, SOFTWARE — no matter what kms_protection_level says.

On a FedRAMP High / IL5 deployment this is the difference between HSM-backed keys and software keys, and nothing in the plan output makes it obvious unless you read the JSON for each key's version_template.

This change applies the stage-wide protection level per key, which is the only place modules/kms honours it:

  • keys without an explicit version_template get GOOGLE_SYMMETRIC_ENCRYPTION at var.kms_protection_level;
  • keys with their own version_template keep it (per-key override still works);
  • a null kms_protection_level leaves the module default untouched, so existing configurations that never set it plan exactly as before.

The dead version_template inside the keyring object is removed, and the variable description now says what the variable does. No behaviour changes for anyone who already sets version_template on every key (as terraform.tfvars.sample does since #118).

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Deployment & Compliance Impact

  • Applicable Regimes:
    • US Region Restricted (e.g., Access Policy constraint)
    • FedRAMP Moderate
    • FedRAMP High
    • DoD IL4
    • DoD IL5
    • General / All
  • NIST 800-53r5 Controls: SC-12 (cryptographic key establishment and management), SC-13 (cryptographic protection) — the protection level of the stage-3 keys now matches what the deployer configured.

Note for existing deployments: a key's protection level is immutable. A deployment that already applied stage 3 with kms_protection_level = "HSM" and no per-key version_template has SOFTWARE keys today; after this change Terraform will plan to replace those keys (new key, new key material). That is the correct outcome, but it should be done deliberately.

Checklist

Code Quality & Reusability

  • My code adheres to the Maximize Reusability principle. I have not redefined common elements and have reused existing base configurations and modules where possible.
  • I have checked that no existing module or configuration in modules/ or fast/ can be leveraged for this change.
  • My code follows the established naming conventions outlined in documentation/naming-convention.md.

Documentation

  • I have updated the README.md of the modified module or blueprint. (No README change needed beyond the variable description; the README variables table is tfdoc-generated.)
  • I have added/updated documentation for inputs (variables) and outputs.

Security

  • My change adheres to GCP security best practices and the principle of least privilege.
  • I have ensured compliance with the targeted regime (FedRAMP Moderate, FedRAMP High, IL5, etc.).

Testing

  • I have tested my changes locally.
  • I have included details of my testing in this PR.

Testing Performed

Terraform 1.10.5, hashicorp/google from default-versions.tf.

  1. terraform validate on 3-security passes before and after (it also passes before the fix — Terraform does not warn about the discarded attribute, which is why this went unnoticed).

  2. Plan comparison with placeholder inputs (-refresh=false, invalid credentials, so nothing is read from an API), kms_protection_level = "HSM" and two keys in us-east4: inherits with no version_template, explicit with version_template.protection_level = "SOFTWARE". terraform show -json of the plan, google_kms_crypto_key values:

    key main (df47667) this branch
    prod-sec-kms["us-east4"].default["inherits"] version_template = null [{algorithm = GOOGLE_SYMMETRIC_ENCRYPTION, protection_level = HSM}]
    prod-sec-kms["us-east4"].default["explicit"] protection_level = SOFTWARE protection_level = SOFTWARE (per-key override preserved)
    dev-sec-kms[...] same as prod same as prod
  3. The defect was originally found on a live FedRAMP High deployment of this stage: with kms_protection_level = "HSM" and no per-key version_template, the plan JSON showed every key without a version_template, and adding an explicit per-key template was the only way to get HSM keys.

…on_template

core-prod.tf and core-dev.tf passed kms_protection_level to modules/kms inside
the keyring object, but that module's keyring variable is object({location,
name}); Terraform drops the extra attribute silently, so every key in kms_keys
that did not carry its own version_template was created at Cloud KMS's default
protection level (SOFTWARE) regardless of kms_protection_level.

Apply the stage-wide protection level per key instead: keys without an explicit
version_template now get GOOGLE_SYMMETRIC_ENCRYPTION at var.kms_protection_level,
keys with one keep it, and a null kms_protection_level leaves the module default
untouched.

Signed-off-by: Scott McDonald <scott.mcdonald@onixnet.com>
@aghassemlouei aghassemlouei added bug Something isn't working security Something is insecure or can be secured Priority - High Critical issues blocking development or users; urgent bugs or core features for release Level of Effort - Low Quick, well-defined tasks with no unknowns; takes a few hours up to one day to complete labels Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working Level of Effort - Low Quick, well-defined tasks with no unknowns; takes a few hours up to one day to complete Priority - High Critical issues blocking development or users; urgent bugs or core features for release security Something is insecure or can be secured

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants