Ravindra BagaleCourses & study guides मराठी

Chapter 40: Terraform Real AWS Labs VPC EC2 nginx S3 and IAM Role

40.4 Lab part 4 — IAM role and instance profile

Story. An Infosys client application needed to read from S3, and the old server had an access key in a config file that leaked in a backup. An IAM role gives the instance short-lived credentials that rotate automatically. The trust policy says EC2 may assume the role, the permissions say what it may do, and the instance profile attaches it to the server. Adding the SSM managed policy also lets you open a shell with Session Manager, with no SSH port.

trust policy ec2 IAM role policies S3 + SSM instance profile EC2 no keys
Trust policy, role, permissions, instance profile, then the server gets temporary credentials.
data "aws_iam_policy_document" "ec2_trust" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

resource "aws_iam_role" "web" {
  name               = "badge-lab-web-role"
  assume_role_policy = data.aws_iam_policy_document.ec2_trust.json
}

resource "aws_iam_role_policy_attachment" "ssm" {
  role       = aws_iam_role.web.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

data "aws_iam_policy_document" "read_assets" {
  statement {
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.assets.arn}/*"]
  }
}

resource "aws_iam_role_policy" "read_assets" {
  role   = aws_iam_role.web.id
  policy = data.aws_iam_policy_document.read_assets.json
}

resource "aws_iam_instance_profile" "web" {
  name = "badge-lab-web-profile"
  role = aws_iam_role.web.name
}

What each line does

  • data "aws_iam_policy_document" "ec2_trust" { — Builds the trust policy JSON in HCL.
  • actions = ["sts:AssumeRole"] — The action being allowed is assuming the role.
  • identifiers = ["ec2.amazonaws.com"] — Only the EC2 service may assume it.
  • assume_role_policy = ...ec2_trust.json — Attaches the trust policy to the new role.
  • policy_arn = ".../AmazonSSMManagedInstanceCore" — Allows Session Manager shell access with no SSH.
  • actions = ["s3:GetObject"] — Read objects only; no write, no delete.
  • resources = ["${aws_s3_bucket.assets.arn}/*"] — Only objects in the lab bucket from part 5.
  • resource "aws_iam_role_policy" "read_assets" { — Adds that least-privilege policy inline to the role.
  • resource "aws_iam_instance_profile" "web" { — The wrapper EC2 needs in order to use a role.

When it is green.

aws_iam_role.web: Creation complete after 1s [id=badge-lab-web-role]
aws_iam_instance_profile.web: Creation complete after 7s
Plan: 4 to add, 0 to change, 0 to destroy.

When it is red.

Error: creating EC2 Instance: InvalidParameterValue: Value (badge-lab-web-profile) for parameter
iamInstanceProfile.name is invalid. Invalid IAM Instance Profile name

Fix. IAM is eventually consistent; the profile was not visible yet. Run terraform apply again; it usually succeeds on the second run.

What: every term in plain English

  • IAM role — An identity with permissions but no password or long-term key. Something trusted assumes it.
  • trust policy — The part of a role that says who may assume it. Here: the EC2 service.
  • permissions policy — The part that says what the role may do, such as s3:GetObject on one bucket.
  • instance profile — A small wrapper that attaches a role to an EC2 instance.
  • temporary credentials — Keys from STS that expire in hours and rotate by themselves.
  • least privilege — Give only the actions and resources the job needs, nothing more.
  • aws_iam_policy_document — A data source that writes policy JSON from HCL, so you never hand-write JSON.

Example 1: See the JSON Terraform builds

Reviewers at a Deloitte client wanted to read the final policy JSON, not HCL. Print it from the plan.

  1. Run terraform console.
  2. Print the trust policy JSON.
  3. Print the read policy JSON.
terraform console
> jsondecode(data.aws_iam_policy_document.ec2_trust.json)

Output

{
  "Statement" = [
    {
      "Action" = "sts:AssumeRole"
      "Effect" = "Allow"
      "Principal" = {
        "Service" = "ec2.amazonaws.com"
      }
    },
  ]
  "Version" = "2012-10-17"
}

What it shows: Only the EC2 service can assume this role. No user, no other account.

Example 2: Check from inside the server who it is

The first command an SRE at PhonePe runs on a server with a role: get-caller-identity. It proves the role is attached.

  1. Open Session Manager.
  2. Run get-caller-identity.
  3. Look for the role name in the ARN.
aws ssm start-session --target $ID
aws sts get-caller-identity --query Arn --output text
ls ~/.aws 2>/dev/null || echo "no key files"

Output

arn:aws:sts::123456789012:assumed-role/badge-lab-web-role/i-0a1b2c3d4e5f60718
no key files

What it shows: The server has credentials but no files. They come from the metadata service and rotate on their own.

Example 3: Prove least privilege by trying a forbidden action

Good roles fail loudly when used for the wrong job. Try to list buckets, which the role does not allow.

  1. From the server, read an object you uploaded.
  2. Try to list all buckets.
  3. Try to delete the object.
aws s3 cp s3://badge-lab-assets-123456789012/hello.txt -
aws s3 ls
aws s3 rm s3://badge-lab-assets-123456789012/hello.txt

Output

Hello from the badge lab
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
delete failed: An error occurred (AccessDenied) when calling the DeleteObject operation

What it shows: Read works, everything else fails. That is exactly the job and no more.

Example 4: Use the IAM policy simulator from the CLI

Before a release at an Amdocs project, the team proved the role could not delete objects, without touching real data.

  1. Get the role ARN.
  2. Simulate GetObject and DeleteObject.
ROLE=$(aws iam get-role --role-name badge-lab-web-role --query Role.Arn --output text)
aws iam simulate-principal-policy --policy-source-arn $ROLE \
  --action-names s3:GetObject s3:DeleteObject \
  --resource-arns arn:aws:s3:::badge-lab-assets-123456789012/hello.txt \
  --query "EvaluationResults[].[EvalActionName,EvalDecision]" --output text

Output

s3:GetObject    allowed
s3:DeleteObject implicitDeny

What it shows: implicitDeny means no statement allows it. The simulator answers without making real calls.

Command cheat sheet

Command What it does When to use it
aws sts get-​caller-​identity Shows who you are First check on any server
aws iam get-​role --​role-​name R Shows the role and trust policy Review trust
aws iam list-​attached-​role-​policies --​role-​name R Lists managed policies Check SSM is attached
aws iam simulate-​principal-​policy Tests actions without calling them Prove least privilege
terraform console Prints policy JSON Review before apply
aws ec2 describe-​iam-​instance-​profile-​associations Shows profile on instances Debug attachment

Verify: did it work?

  1. Profile attached

    aws ec2 describe-iam-instance-profile-associations --filters Name=instance-id,Values=$ID --query "IamInstanceProfileAssociations[0].State" --output text
    

    Output

    associated
    
  2. SSM policy present

    aws iam list-attached-role-policies --role-name badge-lab-web-role --query "AttachedPolicies[].PolicyName" --output text
    

    Output

    AmazonSSMManagedInstanceCore
    

When it is red 1

Unable to locate credentials. You can configure credentials by running "aws configure".

Cause. No instance profile on the server.

Fix, step by step

  1. Check iam_instance_profile in aws_instance.
  2. Apply.
  3. Wait a minute and try again.

When it is red 2

Error: creating IAM Role: EntityAlreadyExists: Role with name badge-lab-web-role already exists.

Cause. A role from an old lab was left behind.

Fix, step by step

  1. Import it with an import block, or delete the old role in the console.
  2. Plan again.

When it is red 3

AccessDenied when calling the GetObject operation

Cause. The resource ARN lacks the /* at the end, so it matches the bucket, not the objects.

Fix, step by step

  1. Use "${aws_s3_bucket.assets.arn}/*".
  2. Apply and retry.

Cleanup

terraform destroy -auto-approve

Ravindra Bagale's Tip

If you ever see an access key in a server config file, replace it with a role the same day.

Practice tasks

Easy Who am I

Why: Prove the role.

What to do: Run get-caller-identity on the server.

How:
  1. Use Session Manager.

Check: assumed-role ARN.

Easy Read JSON

Why: Review policy.

What to do: Print the read policy JSON in console.

How:
  1. Use jsondecode.

Check: s3:GetObject only.

Medium Forbidden action

Why: Prove least privilege.

What to do: Try aws s3 ls on the server.

How:
  1. Expect failure.

Check: AccessDenied.

Medium Simulator

Why: Test without risk.

What to do: Simulate GetObject and DeleteObject.

How:
  1. Use simulate-principal-policy.

Check: allowed and implicitDeny.

Easy Say it in two lines

Why: If you can say it simply, you understand it.

What to do: Write two short lines about this lesson for a fresher.

How:
  1. Write the problem it solves.
  2. Write the one command or file you use.
  3. Read it aloud.

Check: A fresher understands it without a question.

Easy Start a safe lab folder

Why: Practice needs a throwaway place.

What to do: Make a new folder with versions.tf and a random_pet resource, so no AWS cost.

How:
  1. mkdir tf-lab and cd into it.
  2. Add the hashicorp/random provider and one random_pet.
  3. Run terraform init and terraform apply.

Check: Apply complete! with 1 added.

Medium Break it on purpose

Why: You must know the red output by face.

What to do: Cause one error from the red part of this lesson and fix it.

How:
  1. Follow one red section.
  2. Copy the exact message to your notes.
  3. Write the fix in one line.

Check: You fixed it without searching the web.

Medium Run it twice

Why: A second run must be quiet.

What to do: Run the same plan two times with no edits.

How:
  1. Run terraform plan.
  2. Run it again.
  3. Explain any change it still shows.

Check: The second plan says No changes, or you can explain each line.

Medium Write a runbook page

Why: At 2 a.m. nobody remembers flags.

What to do: Write a one-page runbook for this lesson.

How:
  1. Title, when to use, exact commands, how to check, how to undo.

Check: A teammate can follow it alone.

Medium Run it from a pipeline

Why: Real teams run Terraform from CI, not from laptops.

What to do: Run the main command of this lesson inside a GitHub Actions or Jenkins job.

How:
  1. Add a job with hashicorp/setup-terraform or a Terraform Docker image.
  2. Give it AWS access through an IAM role, never a key in the file.
  3. Run init, then the command from this lesson.

Check: The job log shows the same output you saw on your laptop.

Medium Check the cost

Why: Labs left running cost real money.

What to do: Find what this lesson would cost per day if you forgot to destroy it.

How:
  1. Open the AWS Pricing Calculator.
  2. Add each resource from your plan.
  3. Write the daily cost in your notes.

Check: You know the daily cost and you ran terraform destroy.

Hard Draw the flow top to bottom

Why: A drawing shows the order of work.

What to do: Draw this lesson as boxes from top to bottom.

How:
  1. Start at your code, go through plan and state, end at AWS.
  2. Mark where each command reads or writes.

Check: Each box matches a real step you ran.

Hard Explain it like an interview

Why: Interviewers want real stories.

What to do: Record a 60 second answer about this lesson.

How:
  1. Say the problem, the command, and one error you hit.

Check: Your answer has a real command and a real error message.

Homework: try at home

Try at home

Write a role policy for a server that must write logs to one prefix, logs/, in one bucket, and nothing else.

Recap

  • Roles replace keys on servers.
  • Trust says who; permissions say what.
  • The instance profile attaches the role to EC2.
  • Build policy JSON with aws_iam_policy_document.
  • Prove least privilege with real failures or the simulator.

FAQ

Why both a role and an instance profile?

EC2 attaches profiles, and a profile holds one role. Terraform makes both.

How long do the credentials last?

A few hours, and they refresh automatically before expiry.

Can the role be used from my laptop?

No. The trust policy allows only EC2.

Why the SSM managed policy?

It lets the SSM agent register so Session Manager works.

Can I change permissions without a restart?

Yes. Policy changes apply within seconds.

Interview questions

  1. How do you give an EC2 instance access to S3 without keys?

    Role with a trust policy for EC2, a permissions policy, and an instance profile.

  2. Trust policy versus permissions policy?

    Trust says who may assume the role; permissions say what it may do.

  3. Why aws_iam_policy_document?

    HCL validation and references instead of hand-written JSON.

  4. How do you test a policy safely?

    IAM policy simulator or a deliberate forbidden call.

  5. What does implicitDeny mean?

    No statement allowed the action.

Quick quiz

Q1. Service in the trust policy?

ec2.amazonaws.com

Q2. Object that attaches a role to EC2?

Instance profile

Q3. Command to see the current identity?

aws sts get-caller-identity

Q4. Policy for Session Manager?

AmazonSSMManagedInstanceCore

Q5. Suffix needed for object ARNs?

/*

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards