# EKM policy evaluations ======================================================= # Controls: EKM-001 through EKM-008 package controls.aws.ekm import data.common.exemptions as exemptions import data.common.outputs as outputs import data.common.policydoc as policydoc # EKM-001 — Enable Rotation for KMS Customer Managed Keys --------------------- deny contains msg if { policy_id := "ICP-TF-AWS-EKM-001" some _, rc in input.resource_changes rc.type == "aws_kms_key" rc.change.actions[_] in ["create", "update"] rc.change.after.customer_master_key_spec == "SYMMETRIC_DEFAULT" rc.change.after.enable_key_rotation != true meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("KMS key '%s' does not have automatic rotation enabled", [rc.name]), ) } # EKM-002 — Enforce Minimum KMS Key Deletion Window --------------------------- deny contains msg if { policy_id := "ICP-TF-AWS-EKM-002" some _, rc in input.resource_changes rc.type == "aws_kms_key" rc.change.actions[_] in ["create", "update"] window := rc.change.after.deletion_window_in_days window != null window < 30 meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("KMS key '%s' has deletion window of %d days (minimum 30)", [rc.name, window]), ) } # EKM-003 — Prohibit kms:Decrypt on All KMS Keys ------------------------------ deny contains msg if { policy_id := "ICP-TF-AWS-EKM-003" some _, rc in input.resource_changes rc.type in {"aws_iam_policy", "aws_iam_role_policy"} rc.change.actions[_] in ["create", "update"] doc := json.unmarshal(rc.change.after.policy) some stmt in doc.Statement stmt.Effect == "Allow" some action in policydoc.as_list(stmt.Action) _broad_kms_action(action) some resource in policydoc.as_list(stmt.Resource) resource == "*" meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("'%s.%s' grants '%s' on all KMS keys via Resource *", [rc.type, rc.name, action]), ) } _broad_kms_action(a) if a == "kms:*" _broad_kms_action(a) if a == "kms:Decrypt" _broad_kms_action(a) if a == "kms:ReEncryptFrom" # EKM-004 — Require Conditions on KMS Key Policies Granting Full Access to Root # Advisory: emits to warn, not deny warn contains msg if { policy_id := "ICP-TF-AWS-EKM-004" some _, rc in input.resource_changes rc.type in {"aws_kms_key", "aws_kms_key_policy"} rc.change.actions[_] in ["create", "update"] policy_raw := _kms_policy_raw(rc) doc := json.unmarshal(policy_raw) some stmt in doc.Statement stmt.Effect == "Allow" some action in policydoc.as_list(stmt.Action) action == "kms:*" some principal in policydoc.as_list(stmt.Principal.AWS) endswith(principal, ":root") not stmt.Condition meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("KMS key '%s' grants kms:* to root principal without a Condition", [rc.name]), ) } _kms_policy_raw(rc) := rc.change.after.policy if rc.type == "aws_kms_key" _kms_policy_raw(rc) := rc.change.after.policy if rc.type == "aws_kms_key_policy" # EKM-005 — Enforce SSE-KMS on S3 Buckets ------------------------------------- deny contains msg if { policy_id := "ICP-TF-AWS-EKM-005" some _, rc in input.resource_changes rc.type == "aws_s3_bucket_server_side_encryption_configuration" rc.change.actions[_] in ["create", "update"] some rule in rc.change.after.rule some sse in rule.apply_server_side_encryption_by_default not _sse_kms_with_cmk(sse) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("S3 encryption configuration '%s' does not use SSE-KMS with a CMK", [rc.name]), ) } _sse_kms_with_cmk(sse) if { sse.sse_algorithm == "aws:kms" sse.kms_master_key_id != null sse.kms_master_key_id != "" } # EKM-006 — Enable EBS Default Encryption per Region -------------------------- deny contains msg if { some policy_id in {"ICP-TF-AWS-EKM-006", "ICP-TF-AWS-CMP-010", "ICP-TF-AWS-GAC-006"} some _, rc in input.resource_changes rc.type == "aws_ebs_encryption_by_default" rc.change.actions[_] in ["create", "update"] rc.change.after.enabled != true meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("EBS default encryption '%s' is not enabled", [rc.name]), ) } deny contains msg if { policy_id := "ICP-TF-AWS-EKM-006" some _, rc in input.resource_changes rc.type == "aws_ebs_default_kms_key" rc.change.actions[_] in ["create", "update"] not _has_cmk(rc.change.after) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("EBS default KMS key '%s' is not set to a customer-managed key", [rc.name]), ) } _has_cmk(after) if { after.key_arn != null after.key_arn != "" } # EKM-007 — Configure Rotation for Secrets Manager Secrets -------------------- deny contains msg if { policy_id := "ICP-TF-AWS-EKM-007" some _, rc in input.resource_changes rc.type == "aws_secretsmanager_secret" rc.change.actions[_] in ["create", "update"] not _secret_has_rotation(rc) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("Secrets Manager secret '%s' has no rotation configured", [rc.name]), ) } _secret_has_rotation(rc) if { some _, other in input.resource_changes other.type == "aws_secretsmanager_secret_rotation" other.change.actions[_] in ["create", "update"] other.change.after.secret_id == rc.change.after.name other.change.after.rotation_lambda_arn != null other.change.after.rotation_rules[_].automatically_after_days <= 90 } # EKM-008 — Enforce Minimum Key Length for ACM RSA Certificates --------------- deny contains msg if { policy_id := "ICP-TF-AWS-EKM-008" some _, rc in input.resource_changes rc.type == "aws_acm_certificate" rc.change.actions[_] in ["create", "update"] _weak_rsa_key(rc.change.after.key_algorithm) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("ACM certificate '%s' uses weak key algorithm '%s' (minimum RSA_2048)", [rc.name, rc.change.after.key_algorithm]), ) } _weak_rsa_key(algo) if algo == "RSA_1024" _weak_rsa_key(algo) if algo == "RSA_512"