AWS CloudFormation Hooks: Block Unsafe Infra Coding Agents Propose Before It Lands

2 views

Your coding agent just opened a PR that “fixes latency” by attaching AdministratorAccess to a task role and opening 0.0.0.0/0 on a security group. CI might catch it if someone wrote the right cfn-nag rule. Production deploy might not. AWS CloudFormation Hooks run during CREATE/UPDATE/DELETE provisioning and can FAIL the operation when a resource shape violates your policy — before the bucket is public. Use them as the last gate for agent-generated stacks, next to Organizations SCPs, Security Hub aggregation, and GuardDuty for what slips past deploy time.

⚡ TL;DR: Activate AWS-managed Hooks (or publish custom Hook handlers) in every account agents can deploy into. Target high-risk types: IAM roles/policies, S3 buckets, security groups, KMS keys, public-facing load balancers. Configure FAIL mode in prod agent OUs; WARN in sandboxes while you tune. Emit findings to CloudWatch/Logs; page on Hook failures from agent role principals. Related: SCPs, CodeBuild sandboxes, Budgets.

Deploy-time vs org-time vs runtime

Three layers, three jobs:

Layer When Blocks
SCPs API call org-wide Entire services/actions (e.g. no iam:CreateUser)
CloudFormation Hooks CFN resource mutate Bad resource properties in a template
GuardDuty / runtime After resources exist Compromised creds, anomalous API use

Agents love CloudFormation/CDK because it is declarative. Hooks love that too: the proposed resource document is right there to inspect. SCPs will not stop AWS::S3::Bucket with PublicAccessBlockConfiguration missing — Hooks will.

What to Hook first for coding-agent accounts

Start with the blast-radius classics agents hallucinate:

  1. IAM — AWS::IAM::Policy / role policies with Action: * or Resource: *
  2. S3 — public ACL, missing block public access, missing encryption
  3. EC2 SecurityGroup — ingress 0.0.0.0/0 on sensitive ports
  4. RDS / DynamoDB — encryption disabled, overly open SG
  5. Lambda — wild resource-based policies
bash
# ✅ list available Hook types (managed + your private registry)
aws cloudformation list-types \
  --kind HOOK \
  --visibility PUBLIC \
  --filters Category=AWS_TYPES \
  --query 'TypeSummaries[?contains(TypeName, `Hook`)].TypeName' \
  --output text
json
// ✅ example Hook configuration schema mindset (FAIL on noncompliant)
{
  "CloudFormationConfiguration": {
    "HookConfiguration": {
      "TargetStacks": "ALL",
      "FailureMode": "FAIL",
      "Properties": {
        "restrictPublicBuckets": true,
        "denyWildcardIamActions": true,
        "requireS3Encryption": true
      }
    }
  }
}

❌ Relying only on “the agent’s system prompt says never make buckets public” — prompts are not controls.

Custom Hooks for agent-specific policy

Managed rules cover CIS-ish baselines. Agent fleets need shop rules:

  • Deny task roles named coding-agent-* from attaching managed AdministratorAccess
  • Require tags workload=coding-agent + tenant_id on every resource
  • Cap AWS::Lambda::Function memory/timeout in sandbox stacks
  • Block AWS::EC2::Instance outside approved AMIs for tool runners

Custom Hooks are CloudFormation Registry types (Lambda-backed or non-provisioned handlers) invoked with the resource properties.

python
# ✅ sketch: Hook handler rejects wildcard IAM on agent stacks
def hook_handler(event, _ctx):
    props = event.get("requestData", {}).get("targetModel", {}).get("resourceProperties", {})
    policy_doc = props.get("PolicyDocument") or {}
    for stmt in policy_doc.get("Statement", []):
        actions = stmt.get("Action", [])
        if isinstance(actions, str):
            actions = [actions]
        resources = stmt.get("Resource", [])
        if isinstance(resources, str):
            resources = [resources]
        if "*" in actions and "*" in resources and stmt.get("Effect") == "Allow":
            return {
                "hookStatus": "FAILURE",
                "errorCode": "NonCompliant",
                "message": "coding-agent stacks forbid Allow Action:* Resource:*",
                "clientRequestToken": event["clientRequestToken"],
            }
    return {
        "hookStatus": "SUCCESS",
        "message": "ok",
        "clientRequestToken": event["clientRequestToken"],
    }
typescript
// ✅ CDK: ensure agent deploy role can only use Hook-enforced stacks
// (Hooks activate at account/Region level — enforce via pipeline + CFN)
import * as iam from "aws-cdk-lib/aws-iam";

const agentDeployRole = new iam.Role(this, "AgentDeployRole", {
  assumedBy: new iam.ServicePrincipal("codebuild.amazonaws.com"),
  description: "Coding-agent CI deploy — Hooks must be FAIL in this account",
});
// Grant cloudformation:CreateChangeSet / ExecuteChangeSet narrowly;
// ❌ Do not grant iam:PassRole on * — agents will pass Admin

Wire Hooks into the agent deploy path

Agents should deploy through a controlled pipeline (CodeBuild sandboxes, CodePipeline, or internal deployer), never with long-lived admin keys on the laptop.

  1. Agent emits CDK/CFN → PR
  2. Policy-as-code (cfn-guard / Checkov) in CI — fast feedback
  3. Merge → deploy role runs CreateChangeSet / ExecuteChangeSet
  4. Hooks run — FAIL aborts before resources mutate
  5. Failure reason streams back to the agent as a tool error for self-repair
bash
# ✅ activate a Hook type version in the agent OU account
aws cloudformation activate-type \
  --type HOOK \
  --type-name AWS::EarlyValidation::ResourceStronglyTyped \
  --publisher-id <publisher> \
  --type-name-alias MyOrg::Agent::StrictTypes \
  --execution-role-arn arn:aws:iam::111122223333:role/HookExecutionRole

(Use the current AWS-managed / private Hook names available in your Region — aliases and publishers change; pin versions in IaC.)

Observability and agent feedback loops

A Hook failure the agent cannot see is a stuck deploy. Emit:

  • CloudWatch Logs from Hook handlers with stackId, logicalResourceId, rule id
  • Metric filters → alarm when agent deploy role hits FAIL
  • Feed the FAIL message into the agent tool response so it can patch the template
Signal Action
Hook FAIL on IAM wildcard Agent rewrites policy; human review if second FAIL
Hook FAIL on public SG Auto-comment on PR with remediation snippet
Spike in WARN mode Tighten before flipping FAIL in prod
python
# ✅ parse Hook failure into agent-visible tool error
def format_hook_failure(cfn_events: list[dict]) -> str:
    fails = [e for e in cfn_events if "Hook" in e.get("resourceStatusReason", "")
             or e.get("resourceStatus") == "CREATE_FAILED"]
    if not fails:
        return "deploy_failed_unknown"
    reason = fails[0].get("resourceStatusReason", "")[:500]
    return f"HOOK_BLOCKED: {reason}. Fix template properties and retry. Do not widen IAM."

Production checklist

  • [ ] Hooks activated in every account where coding agents can cloudformation:*
  • [ ] Prod FailureMode=FAIL; sandbox may start at WARN with a 14-day tune window
  • [ ] IAM / S3 / SG rules covered first; custom Hook for agent tag requirements
  • [ ] Deploy only via pipeline role — no agent-held AdministratorAccess
  • [ ] Hook FAIL messages returned to agent tool channel + logged for SecOps
  • [ ] SCPs still deny dangerous APIs Hooks cannot see (console clicks, SDK outside CFN)
  • [ ] Quarterly attack-test: agent prompted to create public bucket — must FAIL
  • [ ] Security Hub / Config still on for drift after deploy

FAQ

Q: Do Hooks work with CDK / Terraform?
A: Hooks run on CloudFormation operations. CDK synthesizes to CFN — covered. Terraform AWS provider CFN resources — covered when they go through CFN. Pure Terraform AWS provider resources bypass Hooks; use Sentinel/OPA or SCPs there.

Q: Hooks vs Config rules?
A: Config is often after the fact (or periodic). Hooks are pre-mutation for CFN. You want both.

Q: Will Hooks slow agent deploys?
A: Milliseconds to low seconds per resource evaluation. Far cheaper than a public bucket incident.

Related reading

Prompts suggest safe infra. Hooks enforce it at the CloudFormation boundary — make FAIL the default wherever agents can ship stacks.

Last updated on October 1, 2026

Deep-dive PDF

Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.

Already subscribed? or open the subscribe page.


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a comment

No account needed. Name and email are optional.