Skip to content

Security: Pulumi state, Config, and central-logging buckets use SSE-S3 (AES256) not a CMK, and the encryption guardrail accepts any sseAlgorithm (A02:2021 / CKV_AWS_145 — Low) #187

Description

@Kravalg

Severity

Reported: Low. Adjusted: Low (confirmed). A clear deviation from a hardening standard the repo itself follows for its CloudTrail sink, but defense-in-depth: the attack requires a principal that already holds s3:GetObject on the bucket. Correctly self-rated.

OWASP / standard

A02:2021 (Cryptographic Failures); Checkov CKV_AWS_145 (S3 encrypted with KMS CMK).

Attack scenario

The Pulumi state buckets hold serialized stack state (resource outputs, ARNs, non-secret config), the Config bucket holds full resource-configuration snapshots, and the central logging bucket holds server-access logs. All three are encrypted with SSE-S3 (AES256), which is transparent to anyone holding s3:GetObject: there is no second kms:Decrypt authorization layer and no per-decryption CloudTrail data event tied to a dedicated key. A principal that gains only s3:GetObject reads plaintext directly, whereas a customer-managed KMS key would require a separate grant and would surface each decrypt in CloudTrail. The policy pack's encryption check treats this as compliant because it only verifies that some sseAlgorithm string is present, so it cannot flag SSE-S3 (or a downgrade) on a sensitive store.

Evidence

  • pulumi/infra/pulumi_state.py:228-240_state_bucket_encryption_rules uses sse_algorithm="AES256" (SSE-S3) for primary and replica state buckets
  • pulumi/infra/security_account_controls.py:240-252 — Config delivery bucket sse_algorithm="AES256"
  • pulumi/infra/logging_bucket.py:307-320 — central logging bucket sse_algorithm="AES256" (contrast operations_monitoring.py:499-502, where the CloudTrail bucket correctly uses aws:kms with a CMK)
  • policy/guardrails.py:286-294_has_default_s3_encryption_rule returns True as soon as any applyServerSideEncryptionByDefault.sseAlgorithm string exists, with no CMK/kmsMasterKeyId requirement (grep of policy/ for kmsMasterKeyId/aws:kms/CKV_AWS_145 returns zero matches)

Impact

A single-permission (s3:GetObject) compromise on a state/config/log bucket yields plaintext with no second authorization layer and no dedicated-key decrypt audit trail — a missing defense-in-depth layer on the repo's most sensitive stores, inconsistent with the CMK pattern already applied to CloudTrail.

Remediation

  • Encrypt the Pulumi-state, Config, and central-logging buckets with dedicated customer-managed KMS keys (sse_algorithm="aws:kms" + kms_master_key_id, with enable_key_rotation), matching the CloudTrail bucket pattern.
  • Tighten the CrossGuard encryption rule so audit/state buckets require aws:kms with a CMK rather than accepting SSE-S3.

Acceptance criteria (5/5)

  • State, Config, and central-logging buckets use aws:kms with a customer-managed key and key rotation; unit tests assert the CMK encryption config on each.
  • The CrossGuard/policy encryption rule fails audit/state/log buckets that use SSE-S3 or lack a kmsMasterKeyId; a policy test covers an AES256 bucket → fail.
  • A downgrade from aws:kms to AES256 on these buckets is rejected by CI.
  • KMS key policies scope kms:Decrypt to the intended principals.
  • Documentation records the CMK-encryption requirement for sensitive stores.

Verification notes

All four citations verified across passes: the three buckets use AES256 while CloudTrail uses aws:kms + CMK (proving the pattern exists and was applied to only one of four sensitive stores). _has_default_s3_encryption_rule returns True on any sseAlgorithm string with no CMK check. Public-access blocks and SSE-C blocking are present but add neither the second kms:Decrypt layer nor the per-decrypt data event. Defense-in-depth requiring prior s3:GetObject access; the report does not overclaim secret exposure (Pulumi encrypts secret config separately). Low is appropriate.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions