Enforce Resource Tagging in AWS Using IAM Policy Conditions
Tags are very important in a shared cloud environment. They serve many purposes. They let us attribute costs to the right departments. They let us hunt down owners of long-abandoned resources. And so on… In this article, we’ll see how to prevent users from creating resources in AWS unless they’re tagged with a tag key that you want.
Here we take the launching of an EC2 instance as an example but this idea can be applied to any resource. Start by attaching this IAM policy to the IAM user (or their group) who will be launching the instance:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "*",
"Condition": {
"Null": {
"aws:RequestTag/Owner": "true"
}
}
}
}
This policy specifically targets the ec2:RunInstances
action & whenever it happens, it checks whether the instance being launched is lacking the Owner
tag. If it is, the action is denied! Now if the user tries to launch an instance without the Owner tag, they’ll get an error:
Unfortunately, there doesn’t seem to be a way to show a cleaner error to the user. AWS CLI must be used to decode that error:
aws sts decode-authorization-message \
--encoded-message <encoded-message> \
--query DecodedMessage --output text | jq '.'
This returns a huge response, part of it is shown here:
{
"allowed": false,
"explicitDeny": true,
"matchedStatements": {
"items": [
{
"statementId": "",
"effect": "DENY",
"principals": {
"items": [
{
"value": "AIDATDOMLI3YFAYEBFGSO"
}
]
},
"principalGroups": {
"items": []
},
"actions": {
"items": [
{
"value": "ec2:RunInstances"
}
]
},
"resources": {
"items": [
{
"value": "*"
}
]
},
"conditions": {
"items": [
{
"key": "aws:RequestTag/Owner",
"values": {
"items": [
{
"value": "true"
}
]
}
}
]
}
}
]
}
}
It basically says that the instance launch failed because the Owner
tag is missing! Depending on your use case, you can apply this IAM policy to other actions in your account. You can even apply it at an organization level to enforce tagging in all your accounts.
About the Author ✍🏻
Harish KM is a Principal DevOps Engineer at QloudX & a top-ranked AWS Ambassador since 2020. 👨🏻💻
With over a decade of industry experience as everything from a full-stack engineer to a cloud architect, Harish has built many world-class solutions for clients around the world! 👷🏻♂️
With over 20 certifications in cloud (AWS, Azure, GCP), containers (Kubernetes, Docker) & DevOps (Terraform, Ansible, Jenkins), Harish is an expert in a multitude of technologies. 📚
These days, his focus is on the fascinating world of DevOps & how it can transform the way we do things! 🚀
so how do you write this for multiple tags
“aws:RequestTag/Owner”: “true”
“aws:RequestTag/CostCenter”: “true”
“aws:RequestTag/Enviironment”: “true”
“aws:RequestTag/Name”: “true”
[
{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"ForAllValues:StringNotLike": {
"aws:TagKeys": "Owner"
}
}
},
{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"ForAllValues:StringNotLike": {
"aws:TagKeys": "CostCenter"
}
}
},
{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"ForAllValues:StringNotLike": {
"aws:TagKeys": "Environment"
}
}
},
{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"ForAllValues:StringNotLike": {
"aws:TagKeys": "Name"
}
}
}
]