Inputs and outputs¶
Generated from the module source with terraform-docs; regenerated by CI and
by Renovate, so it does not drift from the code.
Four inputs carry consequences worth reading before you set them:
encryption_key_spec— ForceNew, and RSA is rejected at plan time (why).certify_key_spec— ForceNew; recreating the primary invalidates the subkey binding and forces a reissue.reader_require_mfa— set tofalsefor Identity Center principals, or the role is unassumable (how-to).prevent_destroy— defaults totrueand also blocks ForceNew replacement (why).
Requirements¶
| Name | Version |
|---|---|
| terraform | ~> 1.12.5 |
| aws | ~> 6.0 |
Providers¶
| Name | Version |
|---|---|
| aws | ~> 6.0 |
Resources¶
| Name | Type |
|---|---|
| aws_iam_role.certifier | resource |
| aws_iam_role.reader | resource |
| aws_kms_alias.certify | resource |
| aws_kms_alias.encrypt | resource |
| aws_kms_key.certify | resource |
| aws_kms_key.encrypt | resource |
Inputs¶
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| allow_administrator_key_deletion | Whether the principals in key_administrator_arns may schedule deletionof either key. Defaults to false — the deliberately awkward default. With this false, kms:ScheduleKeyDeletion is withheld fromadministrators and the broad kms:Delete* is narrowed tokms:DeleteAlias. kms:CancelKeyDeletion is always granted, becausecancelling a deletion is protective rather than destructive. Be clear about what this does and does not buy. Administrator actions are enumerated explicitly and exclude kms:PutKeyPolicy, so an administratorcannot rewrite this policy to grant themselves deletion — which a kms:Put* wildcard would have allowed. The control is still not absolute:the account root retains kms:* as break-glass (so the key can neverbecome undeletable), and the automation role can change the policy, through a reviewed plan/apply. Set true when genuinely decommissioning an identity, then apply, then schedule the deletion. |
bool |
false |
no |
| automation_role_arn | ARN of the IAM role the infra apply pipeline assumes. Granted the KMS permissions needed to manage both keys as Terraform resources. Deliberately NOT granted kms:Sign or kms:DeriveSharedSecret — a full compromise of the apply runner must not yield the ability to decrypt messages or to rebind the certificate. |
string |
n/a | yes |
| certifier_principal_arns | Principal ARNs permitted to assume the certifier role — the role that can call kms:Sign with the primary key.This is the higher-privilege of the two roles and should be a strict subset of reader_principal_arns, or a dedicated break-glassprincipal. Signing with the primary can mint a new subkey binding signature, which rebinds the published certificate to a different encryption key. An attacker who can do that redirects all future encrypted messages to a key they hold, without ever touching the encryption key itself. Certification is a rare operation — initial cert assembly, subkey rotation, revocation. It is not part of reading a message. |
list(string) |
n/a | yes |
| certifier_require_mfa | As reader_require_mfa, but for the certifier role.Separate from the reader's flag deliberately. The intended shape for an Identity Center estate is asymmetric: routine reading arrives through SSO ( reader_require_mfa = false, MFA enforced at sign-in), whilecertification — which can rebind the published certificate — is held by a dedicated, rarely-used IAM principal that can carry a hard IAM-level MFA condition ( certifier_require_mfa = true).A single module-wide flag would have forced both roles onto whichever trust model the weaker one needed, which is exactly the wrong direction for the higher-privileged role. |
bool |
true |
no |
| certifier_role_name | Explicit name for the certifier IAM role. Defaults to <name>-certifier. |
string |
null |
no |
| certify_key_alias | Explicit KMS alias for the certification primary key, including the alias/ prefix. Defaults to alias/<name>-certify. |
string |
null |
no |
| certify_key_spec | KMS key spec for the certification primary key. Must be a SIGN_VERIFY-capable spec. An OpenPGP encryption key cannot stand alone: a publishable certificate needs a certification-capable primary key, and the ECDH key must be an encryption subkey bound to it by a binding signature. A KEY_AGREEMENT key cannot sign its own binding, so asecond, signing-capable key is structurally required. Defaults to RSA_4096 because that is the combination this estatehas actually driven OpenPGP signing with from KMS — see the sibling terraform-aws-signing-kms, whose key_spec notes that go-crypto'sOpenPGP Ed25519 branch requires a concrete private key and offers no crypto.Signer fall-through, so it cannot be driven by an opaque KMSsigner. ECC_NIST_EDWARDS25519 is therefore NOT accepted here: itwould provision cleanly and then be unusable for cert assembly. The NIST P-curve specs are accepted for callers whose OpenPGP implementation drives ECDSA through crypto.Signer. Verify that endto end before choosing one. WARNING: ForceNew, as with encryption_key_spec. Recreating theprimary invalidates every signature it made, including the subkey binding — the published certificate would have to be reissued. |
string |
"RSA_4096" |
no |
| component_tag | Value of the Component tag merged into var.tags on every taggable resource. Defaults to encryption-kms. Set to null to omit the tag entirely if your estate does not use it. |
string |
"encryption-kms" |
no |
| deletion_window_in_days | Number of days AWS KMS waits between schedule-deletion and actual deletion. Range 7-30. Defaults to the maximum (30) — losing this key means losing the ability to read everything ever encrypted to it, so the longest recovery window is the only sensible default. | number |
30 |
no |
| description | Human-readable description applied to both KMS keys (suffixed per key with its role). Shown in the AWS console and in CloudTrail events; useful for auditors. Override it to say what this identity is actually for. | string |
"KMS-backed OpenPGP encryption identity" |
no |
| encryption_key_alias | Explicit KMS alias for the encryption subkey, including the alias/ prefix. Defaults to alias/<name>-encrypt. |
string |
null |
no |
| encryption_key_spec | KMS key spec for the encryption subkey. Must be a NIST-standard elliptic curve spec that supports KEY_AGREEMENT.This is the input where getting it wrong is unrecoverable, so the validation below is deliberately narrow. Only three specs can ever work, and the reasons the others cannot are not arbitrary: - RSA_2048 / RSA_3072 / RSA_4096 — cannot work at all forOpenPGP. OpenPGP encrypts the session key in a PKESK packet using PKCS#1 v1.5 padding (RFC 9580, Public-Key Encrypted Session Key Packet). AWS KMS supports only RSAES_OAEP_SHA_1 andRSAES_OAEP_SHA_256 for RSA key specs — there is no PKCS#1 v1.5decryption path. An ENCRYPT_DECRYPT RSA key provisions cleanlyand is then unable to decrypt any OpenPGP message. Excluding RSA here is the whole point of this validation: it makes that dead end unrepresentable rather than discoverable at 2am. - ECC_NIST_EDWARDS25519 — AWS documents it "signing andverification only". It cannot derive a shared secret. - ECC_SECG_P256K1 — signing and verification only; AWS explicitlyexcludes it from the key-agreement specs. The supported specs work because OpenPGP ECDH is key derivation, not padding: DeriveSharedSecret returns the raw ECDH shared secret(the shared point's x-coordinate), which is exactly the input OpenPGP's KDF consumes before AES-key-wrapping the session key. NIST P-curves have cofactor h=1, so the cofactor ECDH primitive KMS implements is plain ECDH. WARNING: this value is ForceNew. Changing it on an existing key destroys and recreates the key, losing the private half and with it the ability to decrypt anything already encrypted to the published public key. Rotate by minting a new identity, never by editing this. |
string |
"ECC_NIST_P256" |
no |
| key_administrator_arns | Principal ARNs that may administer both keys — schedule deletion, rotate policy, tag. Typically the operator role from terraform-aws-security-baseline plus the account root. Administrators can NOT decrypt and can NOT sign; those are reserved for the reader and certifier roles respectively. |
list(string) |
n/a | yes |
| max_session_duration | Maximum session duration, in seconds, for the reader and certifier roles. Range 3600-43200. Defaults to the one-hour minimum — these roles hold the estate's most sensitive read capability, so short sessions are the right trade against re-assume friction. | number |
3600 |
no |
| name | Short kebab-case identifier for this encryption identity. Used to derive the IAM role names (<name>-reader, <name>-certifier) and the KMS aliases (alias/<name>-encrypt, alias/<name>-certify) unless those are overridden individually. Pick something that survives rotation — e.g. security-contact-v1 rather than security-contact, since an OpenPGP identity is superseded by minting a new one. |
string |
n/a | yes |
| prevent_destroy | Whether OpenTofu refuses to destroy or replace either KMS key. Defaults to true, and should stay true anywhere a certificate has been published. This guards two distinct accidents, both of which end the same way: - a tofu destroy (or a removed module block) taking the keys with it;- a change to certify_key_spec / encryption_key_spec, which areForceNew — the plan would quietly destroy and recreate the key, losing the private half. Why it matters more here than for a signing key: AWS documents that scheduling deletion of an asymmetric KMS key has no effect on public keys already outside KMS. Senders holding the published certificate keep encrypting to it, receive no warning or error, and their messages become permanently unreadable. AWS also notes that alarms and logs cannot detect use of the public key outside KMS, so this failure is silent on both sides. > [!NOTE] > Driving prevent_destroy from a variable is an OpenTofu> capability; Terraform rejects a non-literal here. This module is > OpenTofu-only in that respect. Verified against OpenTofu 1.12.5. Set to false only for a throwaway or sandbox deployment whose certificate was never published. |
bool |
true |
no |
| reader_principal_arns | Principal ARNs permitted to assume the reader role — the role that can call kms:DeriveSharedSecret and therefore decrypt inbound messages.Keep this list as short as the job allows. Every principal here can read everything ever encrypted to this identity — the exposure is retroactive, covering archived messages as well as future ones. Deliberately IAM principals only: there is no OIDC trust anywhere in this module. See the main.tf header for why no CI pipeline may holdthis capability. |
list(string) |
n/a | yes |
| reader_require_mfa | Whether assuming the reader role requires an IAM-observable MFA session. Adds aws:MultiFactorAuthPresent to the role's trustpolicy — never to a key policy, for the reason below. Set this false when the reader principals are IAM Identity Center permission-set roles. That is not a weakening. Identity Center enforces MFA at sign-in, but AWS documents this condition key as "not present for federated identities", so it can never match a federated session however the user authenticated. Leaving it true there yields a role no human can assume. Passing the authentication method as a session tag is AWS's suggested alternative, but that depends on an external identity provider supplying it; Identity Center's own directory exposes no MFA attribute. Under Identity Center, MFA is enforced upstream and is simply not expressible as an IAM condition — an observability gap, not a weaker control. Leave it true when the principals are ordinary IAM roles or users, for whom the key is present. |
bool |
true |
no |
| reader_role_name | Explicit name for the reader IAM role. Defaults to <name>-reader. Set this when your estate imposes a naming convention the derived form does not satisfy. |
string |
null |
no |
| tags | Tags to apply to every taggable resource. Merged with Component = "encryption-kms" per the module-repo convention. Cross-cutting tags (Project, ManagedBy, Repository) come from the consuming stack's provider default_tags. |
map(string) |
{} |
no |
Outputs¶
| Name | Description |
|---|---|
| certifier_role_arn | ARN of the certifier role. Assume this only for certificate assembly, subkey rotation, or revocation — it can rebind the published certificate to a different encryption key. |
| certifier_role_name | Bare name of the certifier IAM role. Useful for diagnostic CLI calls; production wiring should use certifier_role_arn. |
| certify_key_alias_arn | ARN of the certification primary key's alias resource. Rarely needed directly; useful for IAM policies that allow alias-based access (a pattern this module does not adopt but callers might). |
| certify_key_alias_name | Full KMS alias of the certification primary key (e.g. alias/<name>-certify). Pass to aws kms sign --key-id when producing the User ID self-certification, the subkey binding signature, or a revocation. |
| certify_key_arn | Full ARN of the certification primary key. Use in IAM policy Resource blocks that need to reference this specific key. |
| certify_key_id | Bare KMS key ID of the certification primary key. Prefer certify_key_alias_name for run-time references. |
| certify_key_spec | The KMS key spec the certification primary key was created with. Echoed so a caller can assert on it, and because the value is ForceNew — a plan that changes it is destroying the identity. |
| encryption_key_alias_arn | ARN of the encryption subkey's alias resource. |
| encryption_key_alias_name | Full KMS alias of the encryption subkey (e.g. alias/<name>-encrypt). Pass to aws kms derive-shared-secret --key-id when decrypting a report. |
| encryption_key_arn | Full ARN of the encryption subkey. Use in IAM policy Resource blocks that need to reference this specific key. |
| encryption_key_id | Bare KMS key ID of the encryption subkey. Prefer encryption_key_alias_name for run-time references. |
| encryption_key_spec | The KMS key spec the encryption subkey was created with — determines the curve the published OpenPGP subkey must declare. ForceNew, as with certify_key_spec. |
| reader_role_arn | ARN of the reader role. Assume this (with MFA, unless require_mfa is false) to decrypt an inbound report. This role can read every report ever encrypted to the published certificate. |
| reader_role_name | Bare name of the reader IAM role. Useful for diagnostic CLI calls (aws iam get-role --role-name ...); production wiring should use reader_role_arn. |