IAM Policy in Practice

Vibe Prompt

“Help me write an AWS IAM Policy that allows a specific service role to read only a particular S3 bucket and write only to a specific DynamoDB table.”

Least‑Privilege Policy Example

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": "arn:aws:s3:::myapp-assets/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:UpdateItem"
      ],
      "Resource": "arn:aws:dynamodb:ap-northeast-1:123456789:table/Visitors"
    },
    {
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": "10.0.0.0/16"
        }
      }
    }
  ]
}

What This Policy Does

  • Read‑only access to objects inside the myapp-assets S3 bucket.
  • Write, read, and update permissions on the Visitors DynamoDB table in the ap-northeast-1 region.
  • Network‑based denial: Any request originating outside‑in protection** – if the request does not come from the 10.0.0.0/16 CIDR block, all actions are denied, adding a defense‑in‑depth layer.

Why Least Privilege Matters

  • Security: Reduces the blast radius if credentials are compromised.
  • Cost Control: Prevents accidental or malicious usage of expensive services (e.g., unlimited S3 GET requests could drive up data transfer fees).
  • Compliance: Aligns with frameworks such as SOC 2, ISO 27001, and PCI‑DSS that require explicit permission scoping.
  • Developer Velocity: Clear, minimal policies make it easier to audit and troubleshoot permission‑related errors.

How to Build This Policy with Vibe Coding

  1. Clarify Intent – Write a concise Vibe Prompt that captures the exact business need (read S3, write DynamoDB, restrict by IP).
  2. Draft Baseline – Start from an AWS managed policy that provides broad access (e.g., AmazonS3ReadOnlyAccess) and then iteratively strip away unnecessary actions.
  3. Scope Resources – Replace wildcard ARNs with specific bucket and table ARNs; use the /* suffix to indicate object‑level access.
  4. Add Conditions – Insert IP‑based condition keys to enforce network boundaries; test with the IAM Policy Simulator.
  5. Review & Refine – Run automated checks (cfn‑lint, cfn‑nag) and peer review; adjust based on feedback.
  6. Commit & Deploy – Store the policy in version control, attach to the appropriate IAM role via CloudFormation, Terraform, or CDK, and promote through your CI/CD pipeline.

Common IAM Roles and Their Typical Use‑Cases

| Role | Purpose | Typical Attached Policies | |------|---------|---------------------------| | EC2 Role | Grants an EC2 instance permission to call AWS APIs on behalf of applications running on the instance. | AmazonS3ReadOnlyAccess, CloudWatchAgentServerPolicy, custom least‑privilege policies for DynamoDB, Secrets Manager, etc. | | Lambda Role | Defines the execution permissions for a Lambda function. | AWSLambdaBasicExecutionRole (managed) + fine‑grained policies for accessing S3, DynamoDB, RDS, etc. | | Cross‑Account Role | Allows a trusted AWS account to assume a role in another account, enabling secure resource sharing. | sts:AssumeRole with external ID, plus scoped policies for the target resources. | | Service‑Linked Role | Predefined role created by an AWS service to integrate with other services; you cannot modify its trust policy. | Managed by the service (e.g., AWSServiceRoleForElasticLoadBalancing). |

Why Choosing the Right Role Type Matters

  • Operational Simplicity: Roles eliminate long‑lived access keys, reducing credential leakage risk.
  • Automation Friendliness: Services like EC2, Lambda, and ECS can automatically retrieve temporary credentials from the instance metadata or task role.
  • Auditability: Role assumption events are logged in CloudTrail, providing a clear trail of who did what and when.
  • Cost Efficiency: By avoiding over‑privileged users, you minimize the chance of runaway resources that inflate your bill.

Vibe Prompt for CDK‑Generated IAM Role + Policy

“Help me use the AWS CDK to create an IAM Role and Policy, then attach them to a Lambda function.”

CDK Implementation (TypeScript)

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';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';

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

    // Existing resources (could be imported or created elsewhere)
    const bucket = s3.Bucket.fromBucketName(this, 'ImportedBucket', 'myapp-assets');
    const table = dynamodb.Table.fromTableName(this, 'ImportedTable', 'Visitors');

    // 1️⃣ Create the IAM Role for Lambda
    const lambdaRole = new iam.Role(this, 'LambdaExecutionRole', {
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
      description: 'Role for Lambda that reads S3 and writes DynamoDB with least privilege',
      managedPolicies: [
        // AWS managed policy for basic Lambda execution (logs, etc.)
        iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')
      ]
    });

    // 2️⃣ Attach least‑privilege inline policies
    lambdaRole.addToPolicy(new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: ['s3:GetObject'],
      resources: [bucket.arnForObjects('*')]
    }));

    lambdaRole.addToPolicy(new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: [
        'dynamodb:PutItem',
        'dynamodb:GetItem',
        'dynamodb:UpdateItem',
        'dynamodb:DeleteItem'
      ],
      resources: [table.tableArn]
    }));

    // 3️⃣ Optional: Deny all actions outside trusted VPC/IP range
    lambdaRole.addToPolicy(new iam.PolicyStatement({
      effect: iam.Effect.DENY,
      actions: ['*'],
      resources: ['*'],
      conditions: {
        NotIpAddress: { 'aws:SourceIp': ['10.0.0.0/16'] }
      }
    }));

    // 4️⃣ Define the Lambda function
    const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
      runtime: lambda.Runtime.PYTHON_3_11,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda'), // assumes a local folder with your code
      role: lambdaRole,
      timeout: cdk.Duration.seconds(30),
      memorySize: 256,
      environment: {
        BUCKET_NAME: bucket.bucketName,
        TABLE_NAME: table.tableName
      }
    });

    // 5️⃣ Grant CDK‑level permissions (optional, adds to role automatically)
    bucket.grantRead(myFunction);
    table.grantReadWriteData(myFunction);
  }
}

What This CDK Code Accomplishes

  • Role Creation: Defines an IAM role that Lambda can assume.
  • Managed Policy: Adds the AWS managed AWSLambdaBasicExecutionRole for CloudWatch Logs.
  • Inline Least‑Privilege Statements: Grants precise S3 GetObject and DynamoDB CRUD actions on specific resources.
  • Network Condition: Adds a deny‑all statement that only allows requests from the trusted 10.0.0.0/16 IP range, reinforcing defense‑in‑depth.
  • Resource Grants: Uses CDK convenience methods (grantRead, grantReadWriteData) to further tighten permissions and avoid manual ARN errors.
  • Environment Variables: Passes bucket and table names to the Lambda runtime for dynamic configuration.

Why Use CDK for IAM?

  • Infrastructure as Code: Policies are version‑controlled, reviewable, and reproducible.
  • Type Safety: TypeScript (or Python/Java) catches ARN typos at compile time.
  • Abstraction: High‑level constructs (grantRead, grantReadWriteData) reduce boilerplate and human error.
  • Change Sets: You can preview how a policy change will affect existing resources before applying.
  • Integration: Seamlessly works with other CDK constructs (API Gateway, Step Functions, etc.) to build full‑stack applications.

Key Takeaways – IAM Four Best Practices

| Principle | What It Means | Why It Matters (Business/Financial) | How to Implement (Vibe Coding Steps) | |-----------|---------------|--------------------------------------|--------------------------------------| | Least Privilege | Grant only the exact actions needed on specific resources. | Lowers risk of data breach; reduces accidental costly API calls (e.g., unlimited S3 GETs can lead to high data transfer fees). | 1. List required actions via stakeholder interviews.
2. Start from AWS managed policies.
3. Use IAM Policy Simulator to validate.
4. Iteratively remove excess permissions.
5. Document rationale in a README.md alongside the policy. | | Use Roles, Not Long‑Lived Users | Prefer IAM roles for EC2, Lambda, ECS, EKS, etc.; avoid creating IAM users with static access keys. | Eliminates credential leakage vectors; temporary credentials auto‑rotate, limiting exposure window. | 1. Identify compute resources needing AWS access.
2. Create a role with trust policy for the service.
3. Attach least‑privilege policies.
4. Remove any IAM user keys associated with those resources.
5. Set up alerts for any attempt to create long‑lived keys. | | Regular Audits | Continuously review who has what permissions and whether they are still needed. | Detects privilege creep before it becomes a security incident; helps maintain compliance and avoid fines. | 1. Enable IAM Access Advisor and AWS Config rules.
2. Schedule monthly reviews (automated Lambda that flags unused permissions).
3. Use AWS IAM Access Analyzer to find overly permissive policies.
4. Remediate findings via pull‑request‑driven policy updates.
5. Report audit results to stakeholders for transparency. | | Permissions Boundaries | Set an upper limit on the permissions that a role or user can have, even if they attach overly permissive policies. | Provides a safety net: even if a developer mistakenly attaches AdministratorAccess, the boundary caps the damage. | 1. Define a boundary policy reflecting your organization’s maximum allowed scope (e.g., PowerUserAccess + specific service limits).
2. Apply the boundary to roles/users via the PermissionsBoundary attribute.
3. Test that attempts to exceed the boundary are denied.
4. Review boundaries quarterly as business needs evolve.
5. Educate teams on why boundaries exist and how to request expansions. |

Policy Structure Deep Dive

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "IpAddress": {"aws:SourceIp": "192.168.1.0/24"}
      }
    }
  ]
}

| Field | Meaning | Typical Values | Best‑Practice Tips | |-------|---------|----------------|--------------------| | Effect | Whether the statement allows or denies the matching actions. | Allow, Deny | Use Deny sparingly; prefer shaping permissions via Allow and rely on explicit deny only for exceptional guardrails (e.g., IP restrictions). | | Action | The AWS API actions the statement applies to. Can use wildcards (s3:*) or list specific actions. | s3:GetObject, dynamodb:PutItem, ec2:StartInstances | List actions explicitly; avoid * unless absolutely necessary and justified. | | Resource | The ARN(s) of the AWS resources the actions apply to. | arn:aws:s3:::my-bucket/*, arn:aws:dynamodb:us-east-1:123456789:table/Orders | Scope to the smallest possible ARN; include both bucket and object ARNs when needed (bucket and bucket/*). | | Condition (optional) | Additional constraints like IP address, time, MFA, VPC endpoint, etc. | { "IpAddress": { "aws:SourceIp": "203.0.113.0/24" } } | Use conditions to enforce network segmentation, time‑of‑day windows, or require MFA for privileged actions. |

Real‑World Business Impact

  • Risk Reduction: A study by the Ponemon Institute found that organizations implementing least‑privilege IAM reduced the average cost of a data breach by $1.2 million.
  • Operational Efficiency: Teams that automated IAM policy reviews via CI/CD saw a 30 % decrease in permission‑related ticket volume.
  • Revenue Protection: Preventing accidental over‑provisioning of services (e.g., runaway EC2 instances) saved one SaaS company ≈ $250 k per year in wasted compute spend.
  • Customer Trust: Demonstrating rigorous IAM controls is often a prerequisite for enterprise contracts and can shorten sales cycles by weeks.

Transition to the Next Chapter: Automated Security Checks with CSPM

Having mastered the art of crafting precise, least‑privilege IAM policies manually, the next logical step is to automate the validation and continuous monitoring of those policies. In the upcoming chapter, we will explore Cloud Security Posture Management (CSPM) tools—such as AWS Security Hub, Azure Policy, and open‑source solutions like ScoutSuite and Prowler—that can:

  1. Scan your entire AWS account for IAM misconfigurations (overly permissive policies, unused credentials, missing MFA, etc.).
  2. Prioritize findings based on risk severity and potential financial impact.
  3. Generate remediation guidance, often in the form of ready‑to‑apply CloudFormation or CDK snippets.
  4. Integrate with your CI/CD pipeline so that every pull request triggering an IAM change is automatically evaluated before deployment.
  5. Provide dashboards and reports that satisfy auditors and demonstrate compliance with frameworks like SOC 2, ISO 27001, and GDPR.

By combining the hands‑on, Vibe‑Coding‑driven policy authoring skills you’ve just learned with automated CSPM checks, you will create a self‑healing security posture: humans define the intent, machines enforce the guardrails, and feedback loops continuously improve both. This synergy not only reduces operational overhead but also translates directly into lower breach risk, reduced cloud spend, and faster time‑to‑market for your applications.

Get ready to dive into the world of automated security scanning, where your meticulously crafted IAM policies become the foundation for a resilient, compliant, and cost‑effective cloud environment. The next chapter will show you how to turn policy authoring from a periodic chore into a continuous, trustworthy process that scales with your organization’s ambitions. Happy building!

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!