Cursor Rules for AWS CDK: Stop AI From Inventing IAM Wildcards

Cursor Rules for AWS CDK: Stop AI From Inventing IAM Wildcards

AI pair programmers love Action: "*" and Resource: "*" because demos work on the first try. Production does not forgive that. Encode CDK least-privilege as Cursor rules so generated stacks fail locally before they ever reach cdk diff on main.

⚡ TL;DR: Ship .cursor/rules that ban IAM wildcards, 0.0.0.0/0 ingress, public S3, and overly broad managed policies; add a CDK-nag / custom aspect gate in CI; teach the agent to use grant helpers and specific ARNs from constructs. Pair with Cursor Rules for TypeScript Monorepos and AI Code Review Bots.

Project rules that name the sins

# AWS CDK IAM law
- Never emit IAM `Action: "*"` or `Resource: "*"` unless the file is under `/stacks/break-glass/` and labeled BREAK_GLASS.
- Prefer `table.grantReadData(fn)` / `bucket.grantRead(fn)` over hand-written PolicyStatements.
- SecurityGroup ingress: no `Peer.anyIpv4()` on prod stacks; use prefix lists or VPC CIDR.
- S3: `BlockPublicAccess.BLOCK_ALL`, encryption mandatory, no `BUCKET_OWNER_PREFERRED` without reason.
- When unsure of ARN, add a TODO + narrow placeholder — do not widen to `*`.
// .cursor/rules encoded as a lintable constant the agent must import
export const CDK_AGENT_LAW = {
  forbidActionWildcard: true,
  forbidResourceWildcard: true,
  forbidAnyIpv4Ingress: true,
  requireBucketBlockPublic: true,
} as const;

Aspects that fail the synth

// lib/aspects/no-wildcards.ts
import * as cdk from "aws-cdk-lib";
import { IConstruct } from "constructs";
import * as iam from "aws-cdk-lib/aws-iam";

export class NoIamWildcards implements cdk.IAspect {
  visit(node: IConstruct) {
    if (!(node instanceof iam.CfnPolicy) && !(node instanceof iam.CfnManagedPolicy)) return;
    const doc = (node as any).policyDocument ?? (node as any).policyDocument;
    // Normalize to JSON
    const raw = JSON.stringify(node);
    // ✅ Cheap static deny — refine with PolicyDocument parsing in real packs
    if (/"Action"\s*:\s*"\*"/i.test(raw) || /"Action"\s*:\s*\[\s*"\*"/i.test(raw)) {
      cdk.Annotations.of(node).addError("IAM Action wildcard forbidden by aspect");
    }
    if (/"Resource"\s*:\s*"\*"/i.test(raw)) {
      cdk.Annotations.of(node).addError("IAM Resource wildcard forbidden by aspect");
    }
  }
}

// app.ts
const app = new cdk.App();
const stack = new CheckoutStack(app, "CheckoutProd");
cdk.Aspects.of(app).add(new NoIamWildcards());

Add cdk-nag AwsSolutions checks in the same synth. CI should run cdk synth and fail on errors — not warnings the agent can ignore.

Teach grant helpers, not PolicyStatement novels

// ✅ Agent-friendly pattern
import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
import * as lambda from "aws-cdk-lib/aws-lambda";

declare const table: dynamodb.Table;
declare const fn: lambda.Function;
table.grantReadData(fn); // precise actions + table ARN + indexes

// ❌ What models invent
fn.addToRolePolicy(new iam.PolicyStatement({
  actions: ["dynamodb:*"],
  resources: ["*"],
}));
// When you must hand-write, pin ARNs from constructs
fn.addToRolePolicy(new iam.PolicyStatement({
  actions: ["dynamodb:GetItem", "dynamodb:Query"],
  resources: [table.tableArn, `${table.tableArn}/index/*`],
}));

Security groups and buckets the agent must not “simplify”

// ❌ Prod anti-pattern the rule must ban
sg.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(443), "temp open");

// ✅
sg.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(443));

// S3
new s3.Bucket(this, "Assets", {
  blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
  encryption: s3.BucketEncryption.S3_MANAGED,
  enforceSSL: true,
});

Review bots should flag wildcards the same way — see AI Code Review Bots: IAM, Secrets, and Least-Privilege Pipelines.

CI gate snippet

# .github/workflows/cdk.yml
- name: Synth with nag
  run: |
    npx cdk synth -q
    # Annotations.addError fails synth when --strict / app throws via Aspects
- name: Diff attach policy wildcards
  run: |
    ! git diff origin/main...HEAD | grep -E 'Action:\s*"\*"|"Action"\s*:\s*"\*"'

Closing checklist

✅ Dos
– ✅ Encode wildcard bans in Cursor rules + CDK Aspects
– ✅ Prefer grant* helpers from L2 constructs
– ✅ Run cdk-nag / custom aspects on every PR
– ✅ Block public buckets and anyIpv4 in prod stacks
– ✅ Keep a labeled break-glass path with expiry

❌ Don’ts
– ❌ Don’t accept dynamodb:* / s3:* “just for now”
– ❌ Don’t open 0.0.0.0/0 for “debugging ALB”
– ❌ Don’t silence cdk-nag with blanket suppressions
– ❌ Don’t let the agent edit IAM in the same PR as business logic without a label
– ❌ Don’t copy AWS managed AdministratorAccess into task roles

Related reading

Last updated on September 11, 2026


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

1 Comment

Leave a Reply