Skip to content

Fix ineffective SCP, silent SNS delivery failures, and Lambda edge cases - #13

Merged
DustyStudy merged 1 commit into
mainfrom
fix/security-accuracy-review
Sep 18, 2026
Merged

DustyStudy merged 1 commit into
mainfrom
fix/security-accuracy-review

Conversation

@DustyStudy

@DustyStudy DustyStudy commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

Summary

Full accuracy / professionalism / security review. Existing lint, terraform validate and Checkov were already clean, so these are issues the tooling can't see. Verified after the changes: cfn-lint, terraform fmt/validate (all 18 modules) and Checkov (CFN 400 passed / 0 failed; TF 644 / 0) are clean, and each Lambda change was unit-tested with mocked AWS clients. Nothing was deployed to AWS.

Security / correctness

  • S3 Block Public Access SCP was a no-op. It used condition keys (s3:PutAccountPublicAccessBlock:*) that S3 doesn't define (confirmed against AWS's service reference), so the deny never matched. Replaced with an unconditional deny of PutAccountPublicAccessBlock / PutBucketPublicAccessBlock in the JSON, CFN and Terraform copies.
  • SNS topics couldn't receive from service principals. root-activity-alarm, bedrock-cost-guardrails and organization-trail used the AWS-managed aws/sns key, whose policy can't grant EventBridge / Budgets / Cost Anomaly Detection / CloudTrail access, so alerts would silently never arrive. Now customer-managed keys.
  • Org trail confused-deputy gap. Bucket and topic policies had no aws:SourceArn; added it, plus a TLS-only deny on the trail bucket.
  • Bedrock model allow-list denied inference-profile ARNs (e.g. us.anthropic.*), breaking this repo's own claude-apps-gateway. Inference-profile ARNs are now allowed; the model allow-list still applies via the underlying foundation-model ARN.
  • claude-apps-gateway: CorporateCidr now rejects 0.0.0.0/0 (the description already said never to use it); documented that the latest tag default conflicts with the IMMUTABLE ECR repo.

Lambda fixes (CFN and Terraform copies kept identical)

  • remediate_open_ssh_rdp: all-traffic (-1) rules produced a revoke call with FromPort/ToPort=None, failing boto3 validation and crashing.
  • wiz_webhook_bridge: secrets compared as bytes (a non-ASCII path segment raised TypeError -> 500), SNS subject sanitized, base64 bodies handled.
  • deactivate_stale_iam_keys: fails safe (skips the user) if the exemption-tag lookup errors.
  • audit_ai_agent_iam_roles / audit_identity_center_access: handle a single-object Statement (previously skipped or crashed), flag Allow + NotAction on Resource: "*", and stop swallowing API errors (an AccessDenied looked like "no findings").
  • remediate_sagemaker_notebook_exposure: reports a failed update instead of erroring out.
  • enforce_bedrock_logging: detects drift in image/embedding delivery flags, not only text.

Docs / CI

  • Corrected wiz-finding-bridge docs: this repo's remediators don't accept the bridge payload, so an adapter Lambda is required.
  • Added caveats: SCPs don't apply to the management account, S3 PAB behaviour, root-alarm regional coverage, EC2 isolation (primary ENI only, established connections persist).
  • CI: lint the Terraform-side StackSet template, compile Python, validate policy JSON, and fail if a CFN/Terraform Lambda copy drifts.

Test plan

  • CI passes (new python-and-policies job included)
  • Deploy root-activity-alarm to a sandbox account in us-east-1 and trigger a root event to confirm delivery through the CMK-encrypted topic (SNS/KMS behaviour follows AWS docs; not exercised end to end here)
  • Optionally attach deny-disable-s3-public-access-block to a test OU and confirm put-public-access-block is denied

Not changed, for your call: deny-disable-security-services doesn't cover guardduty:UpdateDetector, which can also disable GuardDuty; adding it would block legitimate tuning.

Security / correctness
- deny-disable-s3-public-access-block: the SCP used condition keys
  (s3:PutAccountPublicAccessBlock:*) that S3 does not define, so the deny
  could never match. Replace with an unconditional deny of
  PutAccountPublicAccessBlock/PutBucketPublicAccessBlock in the JSON, CFN
  and Terraform copies.
- restrict-bedrock-foundation-models: also allow inference-profile ARNs,
  otherwise enabling the allow-list blocks cross-region profile calls
  (including this repo's own claude-apps-gateway).
- root-activity-alarm, bedrock-cost-guardrails, organization-trail: SNS
  topics were encrypted with the AWS-managed aws/sns key, which cannot be
  used by service-principal publishers (EventBridge, Budgets, Cost
  Anomaly Detection, CloudTrail), so alerts would never be delivered. Use
  customer-managed keys.
- organization-trail: scope the bucket and topic policies to this trail
  with aws:SourceArn (confused-deputy) and deny non-TLS access to the
  trail bucket.
- claude-apps-gateway: reject 0.0.0.0/0 for CorporateCidr, and warn that
  the IMMUTABLE ECR repo makes the "latest" tag default a trap.

Lambda fixes (CFN and Terraform copies kept identical)
- remediate_open_ssh_rdp: all-traffic (-1) rules produced a revoke call
  with FromPort/ToPort=None, which fails boto3 validation and crashed.
- wiz_webhook_bridge: compare secrets as bytes (non-ASCII path segment
  raised TypeError -> 500), sanitize the SNS subject, handle
  base64-encoded bodies.
- deactivate_stale_iam_keys: fail safe (skip user) when the exemption-tag
  lookup fails instead of deactivating a possibly-exempt user's keys.
- ai-agent / identity-center auditors: handle a single-object Statement
  (previously skipped or crashed), flag Allow+NotAction on Resource "*",
  and stop swallowing API errors (an AccessDenied produced a false
  "no findings").
- sagemaker remediation: report a failed update instead of erroring out.
- bedrock logging enforcement: detect drift in image/embedding delivery
  flags, not just text.

Docs / CI
- Correct the wiz-finding-bridge docs: this repo's remediators do not
  accept the bridge payload; an adapter is required.
- Document SCP limitations (management account exempt, S3 PAB behavior),
  root-alarm regional coverage, and EC2 isolation caveats.
- CI: lint the Terraform-side StackSet template, compile Python, validate
  policy JSON, and check the CFN/Terraform Lambda copies stay identical.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@DustyStudy
DustyStudy merged commit 9f7924d into main Sep 18, 2026
3 checks passed
@DustyStudy
DustyStudy deleted the fix/security-accuracy-review branch September 18, 2026 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant