AWSIAM

The great AWS Tag standoff

You tried to launch an EC2 instance. Simple task. Routine, even.  

Instead, AWS handed you an AccessDenied error like a parking ticket you didn’t know you’d earned.  

Nobody touched the IAM policy. At least, not that you can prove.  

Yet here you are, staring at a red banner while your coffee goes cold and your standup meeting starts without you.  

Turns out, AWS doesn’t just care what you do; it cares what you call it.  

Welcome to the quiet civil war between two IAM condition keys that look alike, sound alike, and yet refuse to share the same room: ResourceTag and RequestTag.  

The day my EC2 instance got grounded  

It happened on a Tuesday. Not because Tuesdays are cursed, but because Tuesdays are when everyone tries to get ahead before the week collapses into chaos.  

A developer on your team ran `aws ec2 run-instances` with all the right parameters and a hopeful heart. The response? A polite but firm refusal.  

The policy hadn’t changed. The role hadn’t changed. The only thing that had changed was the expectation that tagging was optional.  

In AWS, tags aren’t just metadata. They’re gatekeepers. And if your request doesn’t speak their language, the door stays shut.  

Meet the two Tag twins nobody told you about  

Think of aws:ResourceTag as the librarian who won’t let you check out a book unless it’s already labeled “Fiction” in neat, archival ink. It evaluates tags on existing resources. You’re not creating anything, you’re interacting with something that’s already there. Want to stop an EC2 instance? Fine, but only if it carries the tag `Environment = Production`. No tag? No dice.  

Now meet aws:RequestTag, the nightclub bouncer who won’t let you in unless you show up wearing a wristband that says “VIP,” and you brought the wristband yourself. This condition checks the tags you’re trying to apply when you create a new resource. It’s not about what exists. It’s about what you promise to bring into the world.  

One looks backward. The other looks forward. Confuse them, and your policy becomes a riddle with no answer.  

Why your policy is lying to you  

Here’s the uncomfortable truth: not all AWS services play nice with these conditions.  

Lambda? Mostly shrugs. S3? Cooperates, but only if you ask nicely (and include `s3:PutBucketTagging`). EC2? Oh, EC2 loves a good trap.  

When you run `ec2:RunInstances`, you’re not just creating an instance. You’re also (silently) creating volumes, network interfaces, and possibly a public IP. Each of those needs tagging permissions. And if your policy only allows `ec2:RunInstances` but forgets `ec2:CreateTags`? AccessDenied. Again.  

And don’t assume the AWS Console saves you. Clicking “Add tags” in the UI doesn’t magically bypass IAM. If your role lacks the right conditions, those tags vanish into the void before the resource is born.  

CloudTrail won’t judge you, but it will show you exactly which tags your request claimed to send. Sometimes, the truth hurts less than the guesswork.  

Building a Tag policy that doesn’t backfire  

Let’s build something that works in 2025, not 2018.  
Start with a simple rule: all new S3 buckets must carry `CostCenter` and `Owner`. Your policy might look like this:

{
  "Effect": "Allow",
  "Action": ["s3:CreateBucket", "s3:PutBucketTagging"],
  "Resource": "*",
  "Condition": {
    "StringEquals": {
      "aws:RequestTag/CostCenter": ["Marketing", "Engineering", "Finance"],
      "aws:RequestTag/Owner": ["*"]
    },
    "Null": {
      "aws:RequestTag/CostCenter": "false",
      "aws:RequestTag/Owner": "false"
    }
  }
}

Notice the `Null` condition. It’s the unsung hero that blocks requests missing the required tags entirely.  

For extra credit, layer this with AWS Organizations Service Control Policies (SCPs) to enforce tagging at the account level, and pair it with AWS Tag Policies (via Resource Groups) to standardize tag keys and values across your estate. Defense in depth isn’t paranoia, it’s peace of mind.  

Testing your policy without breaking production  

The IAM Policy Simulator is helpful, sure. But it won’t catch the subtle dance between `RunInstances` and `CreateTags`.  

Better approach: spin up a sandbox account. Write a Terraform module or a Python script that tries to create resources with and without tags. Watch what succeeds, what fails, and, most importantly, why.  

Automate these tests. Run them in CI. Treat IAM policies like code, because they are.  

Remember: in IAM, hope is not a strategy, but a good test plan is.  

The human side of tagging  

Tags aren’t for machines. Machines don’t care.  

Tags are for the human who inherits your account at 2 a.m. during an outage. For the finance team trying to allocate cloud spend. For the auditor who needs to prove compliance without summoning a séance.  

A well-designed tagging policy isn’t about control. It’s about kindness, to your future self, your teammates, and the poor soul who has to clean up after you.  

So next time you write a condition with `ResourceTag` or `RequestTag`, ask yourself: am I building a fence or a welcome mat?  

Because in the cloud, even silence speaks, if you’re listening to the tags.