Skip to content

IAM permissions

Every grant the module makes. Checked against main.tf.

Certification primary key policy

Sid Principal Actions
EnableAccountRoot account root kms:*
KeyAdministrators key_administrator_arns see administrator actions
AutomationManageKey automation_role_arn kms:DescribeKey, kms:GetKeyPolicy, kms:GetKeyRotationStatus, kms:ListResourceTags, kms:TagResource, kms:UntagResource, kms:UpdateKeyDescription, kms:PutKeyPolicy
CertifierSign certifier role kms:Sign
PublicKeyRead certifier and reader roles kms:GetPublicKey, kms:DescribeKey
DenySignExceptCertifier everyone except the certifier role (Deny) kms:Sign
DenyPutKeyPolicyExceptAutomation everyone except automation_role_arn (Deny) kms:PutKeyPolicy

Encryption subkey policy

Sid Principal Actions
EnableAccountRoot account root kms:*
KeyAdministrators key_administrator_arns see administrator actions
AutomationManageKey automation_role_arn as above
ReaderDeriveSharedSecret reader role kms:DeriveSharedSecret
PublicKeyRead certifier and reader roles kms:GetPublicKey, kms:DescribeKey
DenyKeyAgreementExceptReader everyone except the reader role (Deny) kms:DeriveSharedSecret, kms:Decrypt
DenyPutKeyPolicyExceptAutomation everyone except automation_role_arn (Deny) kms:PutKeyPolicy

The Deny statements match on aws:PrincipalArn, so they apply to every principal in the account, the account root included, whatever its IAM policies allow.

The two policies are identical except for the sensitive grant: kms:Sign on the primary, kms:DeriveSharedSecret on the subkey.

Administrator actions

Enumerated explicitly rather than by wildcard. Granted unconditionally:

Group Actions
Read kms:DescribeKey, kms:GetKeyPolicy, kms:GetKeyRotationStatus, kms:ListResourceTags, kms:ListKeyPolicies, kms:ListGrants
Lifecycle kms:EnableKey, kms:DisableKey, kms:UpdateKeyDescription
Aliases kms:CreateAlias, kms:UpdateAlias, kms:DeleteAlias
Tags kms:TagResource, kms:UntagResource
Grants kms:RevokeGrant
Protective kms:CancelKeyDeletion

Granted only when allow_administrator_key_deletion = true (default false):

kms:ScheduleKeyDeletion

Notably absent: kms:PutKeyPolicy, kms:Sign, kms:DeriveSharedSecret, kms:GetPublicKey.

[!NOTE] kms:PutKeyPolicy is deliberately not an administrator action. Policy changes flow through the automation role (reviewed plan/apply) and nowhere else, which DenyPutKeyPolicyExceptAutomation enforces.

What no principal is granted

Principal Cannot
automation_role_arn kms:Sign, kms:DeriveSharedSecret: it cannot decrypt or rebind directly, though it can change the key policy, so its compromise reaches as far as a policy change can
key_administrator_arns kms:Sign, kms:DeriveSharedSecret: administering a key is not using it; also kms:PutKeyPolicy, so they cannot widen their own grant
reader role kms:Sign: cannot rebind the certificate
certifier role kms:DeriveSharedSecret: cannot decrypt
any OIDC / federated CI identity anything at all: the module creates no OIDC trust

Trust policies

Both roles use a single statement, AssumeByNamedPrincipals:

Reader Certifier
Action sts:AssumeRole sts:AssumeRole
Principals reader_principal_arns certifier_principal_arns
MFA condition when reader_require_mfa when certifier_require_mfa
Max session max_session_duration (default 3600s) same

The MFA condition is Bool: aws:MultiFactorAuthPresent = true. It appears only in trust policies, never in a key policy (see roles and trust).

Actions used at runtime

Operation Call Role
Decrypt a message kms:GetPublicKey then kms:DeriveSharedSecret (KeyAgreementAlgorithm: ECDH) on the encryption key reader
Emit the primary key packet kms:GetPublicKey certifier
Emit the subkey packet kms:GetPublicKey on the encryption key certifier
Sign the subkey binding kms:Sign certifier
Check the published cert matches KMS kms:GetPublicKey on both either