Use Cases

Claude Code × AWS IAM Complete Guide | Auto-Generate Least-Privilege Policies

Streamline AWS IAM policy design with Claude Code. Auto-generate least-privilege policies, review existing policies for security issues, and implement with CDK—all with real code examples.

IAM policy design is “unglamorous but catastrophic when done wrong.” Policies with wildcard (*) abuse are breeding grounds for security incidents. Yet writing least-privilege policies from scratch takes time.

I operate a serverless architecture combining Lambda, S3, DynamoDB, and CloudWatch in production. By delegating IAM policy design and review to Claude Code, I reduced work time by approximately 70%. This article walks through the practical steps.


IAM Basics in 3 Minutes

Policy Structure

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "StringEquals": {
          "s3:prefix": ["uploads/"]
        }
      }
    }
  ]
}
  • Effect: Allow or Deny
  • Action: The API actions to allow/deny
  • Resource: ARN of the target resource (more specific = more secure)
  • Condition: Additional conditions (IP restrictions, MFA required, etc.)

Principle of Least Privilege

“Permit only the operations needed, on only the resources needed” is the golden rule of IAM.

❌ Dangerous: Wildcard abuse
Action: "*"
Resource: "*"

✅ Safe: Specify concretely
Action: ["s3:GetObject", "s3:PutObject"]
Resource: "arn:aws:s3:::my-uploads-bucket/user-files/*"

Step 1: Describe the Use Case and Auto-Generate a Policy

Generating a Policy for Lambda

claude -p "
Generate the minimum required IAM policy in JSON for the following Lambda function.

[Lambda processing]
- Read images from S3 bucket 'user-uploads-prod'
- Save processed images to 'user-thumbnails-prod'
- Record results in DynamoDB table 'image-metadata'
- Notify SNS topic 'alert-topic' on error
- Write logs to CloudWatch Logs

[Constraints]
- Delete operations are not needed
- Use account ID 123456789012, region ap-northeast-1 for resource ARNs
- No IP restriction via Condition (not needed for Lambda)
"

Generated example:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "S3ReadSourceBucket",
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": "arn:aws:s3:::user-uploads-prod/*"
    },
    {
      "Sid": "S3WriteThumbnailBucket",
      "Effect": "Allow",
      "Action": ["s3:PutObject"],
      "Resource": "arn:aws:s3:::user-thumbnails-prod/*"
    },
    {
      "Sid": "DynamoDBWriteMetadata",
      "Effect": "Allow",
      "Action": ["dynamodb:PutItem", "dynamodb:UpdateItem"],
      "Resource": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/image-metadata"
    },
    {
      "Sid": "SNSPublishAlert",
      "Effect": "Allow",
      "Action": ["sns:Publish"],
      "Resource": "arn:aws:sns:ap-northeast-1:123456789012:alert-topic"
    },
    {
      "Sid": "CloudWatchLogs",
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/lambda/*"
    }
  ]
}

Step 2: Security Review of Existing Policies

Have Claude Code review existing policies for issues.

claude -p "
Review the following IAM policy from a security perspective.
Please identify specific problems and provide concrete remediation suggestions.

$(cat policy.json)
"

Typical issues Claude Code flags:

Issue 1: Resource: "*" grants full S3 access
  → Specify target buckets and prefixes explicitly

Issue 2: s3:DeleteObject is included but not required by the process
  → Remove the delete operation

Issue 3: iam:PassRole is allowed with wildcard resource
  → Restrict PassRole to specific role ARNs only (privilege escalation risk)

Issue 4: CloudTrail enablement cannot be confirmed
  → Recommend enabling logging of IAM operations

Step 3: Automating Role Design

Role Design Spanning Multiple Services

claude -p "
Design all necessary IAM roles for the following architecture:

[Architecture]
- API Gateway → Lambda (authentication)
- Lambda → DynamoDB (user data read/write)
- Lambda → S3 (file storage)
- Lambda → SES (email sending)
- CloudWatch Events → Lambda (batch processing)
- CodePipeline → S3, CodeBuild, Lambda (deployment)

[Output format]
- Name and purpose of each role
- Trust Policy
- Access Policy
- Output as AWS CDK TypeScript code
"

CDK Implementation of Roles

// lib/iam-stack.ts
import * as cdk from "aws-cdk-lib";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";

export class IamStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Lambda execution role (least privilege)
    const lambdaRole = new iam.Role(this, "ApiLambdaRole", {
      assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
      roleName: "api-lambda-role",
      description: "Least-privilege role for API Lambda",
    });

    // DynamoDB read/write permissions (specific table only)
    lambdaRole.addToPolicy(
      new iam.PolicyStatement({
        sid: "DynamoDBAccess",
        effect: iam.Effect.ALLOW,
        actions: [
          "dynamodb:GetItem",
          "dynamodb:PutItem",
          "dynamodb:UpdateItem",
          "dynamodb:Query",
        ],
        resources: [
          `arn:aws:dynamodb:${this.region}:${this.account}:table/users`,
          `arn:aws:dynamodb:${this.region}:${this.account}:table/users/index/*`,
        ],
      })
    );

    // S3 write permissions (specific bucket and prefix only)
    lambdaRole.addToPolicy(
      new iam.PolicyStatement({
        sid: "S3FileUpload",
        effect: iam.Effect.ALLOW,
        actions: ["s3:PutObject", "s3:GetObject"],
        resources: [
          `arn:aws:s3:::user-files-${this.account}/uploads/*`,
        ],
      })
    );

    // SES email send permissions
    lambdaRole.addToPolicy(
      new iam.PolicyStatement({
        sid: "SESSendEmail",
        effect: iam.Effect.ALLOW,
        actions: ["ses:SendEmail", "ses:SendRawEmail"],
        resources: ["*"],
        conditions: {
          StringEquals: {
            "ses:FromAddress": "[email protected]",
          },
        },
      })
    );

    // CloudWatch Logs write permissions
    lambdaRole.addManagedPolicy(
      iam.ManagedPolicy.fromAwsManagedPolicyName(
        "service-role/AWSLambdaBasicExecutionRole"
      )
    );
  }
}

Step 4: Reviewing IAM Access Analyzer Results

Have Claude Code review IAM Access Analyzer output.

# Retrieve Access Analyzer findings
aws accessanalyzer list-findings --analyzer-arn arn:aws:access-analyzer:... \
  --output json > analyzer-findings.json

claude -p "
Read the following IAM Access Analyzer findings and:
1. Classify by severity (HIGH/MEDIUM/LOW)
2. Identify items requiring immediate remediation
3. Provide specific remediation steps for each

$(cat analyzer-findings.json)
"

Step 5: Designing SCPs (Organization-Wide Guardrails)

When using AWS Organizations, use SCPs (Service Control Policies) to establish guardrails for entire accounts.

claude -p "
Design an SCP to apply to production AWS accounts.
It must satisfy the following requirements:

1. Disable all regions except ap-northeast-1 (Tokyo) and us-east-1 (Virginia)
2. Prohibit API operations by the root account
3. Prohibit disabling or deleting CloudTrail
4. Prohibit disabling GuardDuty
5. Prohibit changes to a specific IAM role ('OrganizationAdminRole')
"
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnsupportedRegions",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": ["ap-northeast-1", "us-east-1"]
        },
        "ArnNotLike": {
          "aws:PrincipalARN": [
            "arn:aws:iam::*:role/OrganizationAdminRole"
          ]
        }
      }
    },
    {
      "Sid": "DenyCloudTrailModification",
      "Effect": "Deny",
      "Action": [
        "cloudtrail:DeleteTrail",
        "cloudtrail:StopLogging",
        "cloudtrail:UpdateTrail"
      ],
      "Resource": "*"
    }
  ]
}

4 Common Pitfalls

1. Over-privileged iam:PassRole

// ❌ Dangerous: any role can be passed
{
  "Action": "iam:PassRole",
  "Resource": "*"
}

// ✅ Safe: specific role only
{
  "Action": "iam:PassRole",
  "Resource": "arn:aws:iam::123456789:role/MyLambdaRole",
  "Condition": {
    "StringEquals": {
      "iam:PassedToService": "lambda.amazonaws.com"
    }
  }
}

2. Overusing AWS Managed Policies

Managed policies like AmazonS3FullAccess are convenient but include far more permissions than needed. If Lambda only reads from S3, use a custom policy with only s3:GetObject.

3. Mixing Inline Policies and Custom Managed Policies

Inline policies cannot be reused and are hard to track. Standardize on managed policies and version-control them.

4. Missing MFA Requirement via Conditions

Always enforce MFA when switching to admin roles.

{
  "Condition": {
    "BoolIfExists": {
      "aws:MultiFactorAuthPresent": "true"
    }
  }
}

Summary

TaskClaude Code’s Contribution
Policy generationGenerates least-privilege policies just from a description
Security reviewIdentifies problems and suggests fixes for existing policies
Role designDesigns role structure for the entire architecture
CDK implementationAuto-generates TypeScript IAM code
SCP designGenerates organization-wide guardrail policies

IAM is not “set it and forget it”—regular review is essential. Making a habit of having Claude Code review existing policies monthly is a simple way to continuously reduce security risk.

References

#claude-code #aws #iam #security #typescript #infrastructure

Level up your Claude Code workflow

50 battle-tested prompt templates you can copy-paste into Claude Code right now.

Free

Free PDF: Claude Code Cheatsheet in 5 Minutes

Just enter your email and we'll send you the single-page A4 cheatsheet right away.

We handle your data with care and never send spam.

Masa

About the Author

Masa

Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.