Ravindra BagaleCourses & study guides मराठी Track your progress

Create an IAM Role and Policy for EC2 and Lambda Step by Step

Build least-privilege access for S3 read: one customer-managed policy, an EC2 instance role, and a Lambda execution role. Prove both, then clean up.

What you'll learn in this chapter

  • Create a tight S3 read policy
  • EC2 instance profile / role
  • Lambda execution role + basic logs
  • Verify with CLI and a tiny function
  • Cleanup roles and policy

1. Lab: click by click

How to do it (step by step)

Region ap-south-1. Create a private bucket yourname-iam-lab and upload hello.txt with body ok. Replace names/account id.

A. Customer managed policy

  1. IAM → Policies → Create policy → JSON.
  2. Paste (replace BUCKET):
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListBucket",
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::BUCKET"
    },
    {
      "Sid": "ReadObjects",
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": "arn:aws:s3:::BUCKET/*"
    }
  ]
}
  1. Name: lab-s3-read-one-bucket. Create.

B. EC2 role

  1. IAM → Roles → Create role → AWS service → EC2.
  2. Attach lab-s3-read-one-bucket only (not Admin). Role name: lab-ec2-s3-read.
  3. EC2 → instance → Actions → Security → Modify IAM role → lab-ec2-s3-read.
  4. On EC2:
aws sts get-caller-identity
aws s3 cp s3://BUCKET/hello.txt -
# expect: ok
# aws s3 cp s3://SOME-OTHER-BUCKET/x .   # should fail AccessDenied

C. Lambda role

  1. IAM → Roles → Create role → Lambda. Attach lab-s3-read-one-bucket and AWSLambdaBasicExecutionRole. Name: lab-lambda-s3-read.
  2. Lambda → Create function lab-s3-get, Python 3.12, use existing role lab-lambda-s3-read.
  3. Code:
import boto3, os
def lambda_handler(event, context):
    b = os.environ["BUCKET"]
    body = boto3.client("s3").get_object(Bucket=b, Key="hello.txt")["Body"].read().decode()
    return {"ok": True, "body": body}
  1. Env BUCKET=your bucket. Deploy → Test. Expected JSON with "body": "ok".

Cleanup

  1. Delete Lambda function. Remove IAM role from EC2 (or terminate lab instance).
  2. Delete roles lab-ec2-s3-read, lab-lambda-s3-read. Delete policy lab-s3-read-one-bucket.
  3. Empty and delete the lab bucket.

2. Interview angles

Q. Why instance role not access keys?

Keys get stolen from disk; role creds rotate via metadata.

Q. Why two statements List + Get?

ListBucket on bucket ARN; GetObject on object ARN.

Q. Basic execution role?

Writes CloudWatch Logs.

Q. Admin policy on Lambda?

Breaks least privilege — avoid.

Try at home

  1. Add s3:PutObject for a prefix only and test deny outside prefix.
  2. Try the same role pattern for DynamoDB GetItem.

In short

  1. Customer managed policy → attach to roles.
  2. EC2 instance role + Lambda execution role.
  3. Prove allow and deny; then delete lab artifacts.

Practice Tasks

About this scenario

Bavaria Motors is a automobile business in Munich. Lukas Becker looks after its IT and cloud work. They count money in EUR and run their AWS resources in the eu-central-1 Region. In the tasks below you do real jobs for them using what this lesson teaches. All names, account IDs, IP addresses and numbers are made up for practice.

0 / 12

Easy List functions

Why: See which functions exist in this Region.

What to do: List the Lambda functions in eu-central-1.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Trust policy for a Lambda role

Why: The trust policy says WHO may take the role.

What to do: Write a trust policy that lets lambda.amazonaws.com assume the role.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Medium Invoke a function

Why: Invoke runs the function now and saves its answer in a file.

What to do: Invoke bavariamotors-orders-fn and save the response to out.json.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Change timeout and memory

Why: More memory also gives more CPU; timeout stops runaway runs.

What to do: Set bavariamotors-orders-fn to timeout 30 seconds and memory 512 MB.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Let a function write logs

Why: Without these actions, Lambda logs never appear in CloudWatch.

What to do: Allow logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents on arn:aws:logs:*:*:* only.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Medium Trust policy for an EC2 role

Why: The trust policy says WHO may take the role.

What to do: Write a trust policy that lets ec2.amazonaws.com assume the role.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Hard Create a Lambda function

Why: Lambda needs the code zip, a runtime, a handler name and an execution role.

What to do: Create function bavariamotors-orders-fn: runtime python3.12, handler app.handler, role arn:aws:iam::106249807804:role/lambda-basic, code in function.zip.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Set environment variables

Why: Keep settings like table names out of the code.

What to do: Set the environment variable TABLE=bavariamotors-orders on bavariamotors-orders-fn.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Invoke with a JSON payload

Why: In CLI v2, raw JSON needs --cli-binary-format raw-in-base64-out.

What to do: Invoke bavariamotors-orders-fn with payload {"orderId":"o-101"} (raw JSON) and save the reply in out.json.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Lambda GB-seconds

Why: Lambda bills memory × time.

What to do: 1,000,000 invocations, 512 MB memory, 200 ms each. How many GB-seconds?

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Hard Connect an SQS queue to Lambda

Why: An event source mapping makes Lambda poll the queue and process messages in batches.

What to do: Create an event source mapping from queue arn:aws:sqs:eu-central-1:106249807804:bavariamotors-orders to bavariamotors-orders-fn with batch size 10.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Let S3 call your function

Why: A resource-based permission is needed before S3 can invoke the function.

What to do: Add permission statement s3invoke to bavariamotors-orders-fn so s3.amazonaws.com can call lambda:InvokeFunction from bucket arn:aws:s3:::bavariamotors-uploads.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Revision, comparison and interview cards

Revise this lesson in a few minutes. Save the cards on your phone or download them as PNG files. The QR code on each card opens this lesson.

Revision card: Write a least-privilege S3 read policy. AmazonS3FullAccess on a demo role teaches the wrong habit. A customer-managed policy with s3:GetObject (and ListBucket if needed) on one bucket ARN is enough for a read lab. IAM → Policies → Create → JSON with Version 2012-10-17 and Resource arn:aws:s3:::lab-bucket/*. Policy simulator or CLI get-object succeeds; delete-object is denied.
Revision card: Write a least-privilege S3 read policy · Download PNG · Open card page
Revision card: Attach role to EC2. Putting AKIA keys on the instance is how keys leak into GitHub. Create an EC2 instance profile/role with your S3 read policy; attach to the instance; use the instance metadata credentials automatically via AWS CLI. IAM role trusted by ec2.amazonaws.com → attach policy → Modify IAM role on the instance (or launch with it). On the instance: aws s3 cp s3://lab-bucket/hi.txt - works with no keys configured.
Revision card: Attach role to EC2 · Download PNG · Open card page
Revision card: Lambda execution role. Lambda also needs a role — and basic CloudWatch Logs permissions or you see no logs. Create a Lambda execution role trusted by lambda.amazonaws.com; attach AWSLambdaBasicExecutionRole plus your S3 read policy. Function › Configuration › Permissions › use the new role; test an S3 GetObject handler. Test event succeeds; CloudWatch log stream shows START/END without AccessDenied on logs.
Revision card: Lambda execution role · Download PNG · Open card page
Comparison: AWS managed policy vs Customer managed policy. AWS managed policy: AWS maintains broad reusable policies. Customer managed policy: You write/reuse tight JSON for your ARNs.
Comparison: AWS managed policy vs Customer managed policy · Download PNG · Open card page
Interview card: How do you prove least privilege worked?. Try the allowed action and a denied one; use policy simulator or real CLI calls. Evidence beats “we attached AmazonS3FullAccess”. aws s3 cp get succeeds; aws s3 rm returns AccessDenied on the same role.
Interview card: How do you prove least privilege worked? · Download PNG · Open card page
Interview card: Why does Lambda need BasicExecutionRole too?. Without logs permissions the function may run but you cannot debug in CloudWatch. BasicExecutionRole allows creating log streams for the function. Attach AWSLambdaBasicExecutionRole plus your tight S3 policy on the execution role.
Interview card: Why does Lambda need BasicExecutionRole too? · Download PNG · Open card page

More cards: Ravi Sir's Cards.