Skip to content

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 to false for Identity Center principals, or the role is unassumable (how-to).
  • prevent_destroy — defaults to true and 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 deletion
of either key. Defaults to false — the deliberately awkward default.

With this false, kms:ScheduleKeyDeletion is withheld from
administrators and the broad kms:Delete* is narrowed to
kms:DeleteAlias. kms:CancelKeyDeletion is always granted, because
cancelling 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 administrator
cannot 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 never
become 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-glass
principal. 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), while
certification — 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 a
second, signing-capable key is structurally required.

Defaults to RSA_4096 because that is the combination this estate
has actually driven OpenPGP signing with from KMS — see the sibling
terraform-aws-signing-kms, whose key_spec notes that go-crypto's
OpenPGP Ed25519 branch requires a concrete private key and offers no
crypto.Signer fall-through, so it cannot be driven by an opaque KMS
signer. ECC_NIST_EDWARDS25519 is therefore NOT accepted here: it
would 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 end
to end before choosing one.

WARNING: ForceNew, as with encryption_key_spec. Recreating the
primary 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_4096cannot work at all for
OpenPGP. 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 and
RSAES_OAEP_SHA_256 for RSA key specs — there is no PKCS#1 v1.5
decryption path. An ENCRYPT_DECRYPT RSA key provisions cleanly
and 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 and
verification only". It cannot derive a shared secret.
- ECC_SECG_P256K1 — signing and verification only; AWS explicitly
excludes 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 are
ForceNew — 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 hold
this 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 trust
policy — 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.