I'm trying to enforce mandatory tagging for all resources in our AWS accounts to improve cost management and organization. While AWS supports tagging, some resources (especially those created via the AWS Management Console) don’t require tags by default, which makes it easy to overlook them.
I want to block the creation of resources if they don’t include specific tags. Here’s what I’ve explored so far:
Tagging Policies in AWS Organizations: These can flag non-compliant resources but cannot block their creation. Service Control Policies (SCPs): I attempted to use SCPs to enforce this, but I'm unsure if they can directly block resource creation without required tags. AWS Config Rules: Config can detect non-compliance after a resource is created, but remediation is reactive rather than preventive. My Current SCP Configuration Here’s the SCP I’ve tried implementing:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "DenyResourceCreationWithoutAllTags", "Effect": "Deny", "Action": [ "ec2:RunInstances", "rds:CreateDBInstance", "eks:CreateCluster", "lambda:CreateFunction", "dynamodb:CreateTable", "cloudformation:CreateStack", "elasticbeanstalk:CreateEnvironment", "elasticbeanstalk:CreateApplication" ], "Resource": "*", "Condition": { "Null": { "aws:RequestTag/Account": "true", "aws:RequestTag/Division": "true", "aws:RequestTag/Environment": "true" } } }, { "Sid": "DenyResourceCreationWithEmptyTagValues", "Effect": "Deny", "Action": [ "ec2:RunInstances", "rds:CreateDBInstance", "eks:CreateCluster", "lambda:CreateFunction", "dynamodb:CreateTable", "cloudformation:CreateStack", "elasticbeanstalk:CreateEnvironment", "elasticbeanstalk:CreateApplication", "s3:CreateBucket" ], "Resource": "*", "Condition": { "StringEquals": { "aws:RequestTag/Account": "", "aws:RequestTag/Division": "", "aws:RequestTag/Environment": "" } } }, { "Sid": "EnforceSpecificTagValues", "Effect": "Deny", "Action": [ "ec2:RunInstances", "rds:CreateDBInstance", "eks:CreateCluster", "lambda:CreateFunction", "dynamodb:CreateTable", "cloudformation:CreateStack", "elasticbeanstalk:CreateEnvironment", "elasticbeanstalk:CreateApplication", "s3:CreateBucket" ], "Resource": "*", "Condition": { "StringNotEqualsIfExists": { "aws:RequestTag/Account": [ "Audit", "Automation", "Backup", "Delegated", "Egress", "Finops", "Inspection", "Logs-archive", "MFA", "Network", "Sandbox", "Shared-services", "Tekes", "Tekes-dev", "Workspaces", "Cnapp" ], "aws:RequestTag/Division": [ "Information technology communication services", "Applications Development Division", "Cyber Security Technologies Bureau" ], "aws:RequestTag/Environment": [ "production", "development", "test" ] } } } ] }
While this SCP is functional for certain scenarios, I’m still unclear on whether it fully enforces mandatory tagging across all AWS services.
Questions:
Is this SCP the correct approach for blocking resource creation if specific tags are missing or empty? Are there better solutions to enforce mandatory tagging during resource creation (e.g., native AWS features I might have overlooked)? How can I extend this to cover all resource types, not just those explicitly listed? I’m looking for preventive measures to stop non-compliant resources from being created altogether. Any guidance or best practices would be greatly appreciated!
enforcing mandatory tagging in AWS to improve cost management and organisation is definitely a challenge, but you’re on the right way with your SCP way.
SCPs are a solid way to block resource creation without specific tags, making them proactive instead of reactive, but the issue, is that if the service action is not specified the SCP will not be applied, so you need to list all the actions to cover everything, and only it works only on the services which support tagging at creation time.
There's no AWS service which fits to enforce mandatory tagging during resource creation across all the services, but you can use some other services with the SCP, which can enhance this topic:
The best service in this way is AWS Config with which you can use Config rules like required-tags to detect and even auto-remediate non-compliance. This works well for services not covered by SCPs, though it’s reactive.
you can also enhance more your SCP policy with adding more services and actions to the Action list. Use wildcards like ec2:* or s3:* where it makes sense
and use *:TagResource in your SCP. This covers tagging actions directly
.
This is an enhanced version of your Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyResourceCreationWithoutAllTags",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"rds:CreateDBInstance",
"eks:CreateCluster",
"lambda:CreateFunction",
"dynamodb:CreateTable",
"cloudformation:CreateStack",
"elasticbeanstalk:CreateEnvironment",
"elasticbeanstalk:CreateApplication",
"s3:CreateBucket",
"*:TagResource"
],
"Resource": "*",
"Condition": {
"Null": {
"aws:RequestTag/Account": "true",
"aws:RequestTag/Division": "true",
"aws:RequestTag/Environment": "true"
}
}
},
{
"Sid": "DenyResourceCreationWithEmptyTagValues",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"rds:CreateDBInstance",
"eks:CreateCluster",
"lambda:CreateFunction",
"dynamodb:CreateTable",
"cloudformation:CreateStack",
"elasticbeanstalk:CreateEnvironment",
"elasticbeanstalk:CreateApplication",
"s3:CreateBucket"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/Account": "",
"aws:RequestTag/Division": "",
"aws:RequestTag/Environment": ""
}
}
},
{
"Sid": "EnforceSpecificTagValues",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"rds:CreateDBInstance",
"eks:CreateCluster",
"lambda:CreateFunction",
"dynamodb:CreateTable",
"cloudformation:CreateStack",
"elasticbeanstalk:CreateEnvironment",
"elasticbeanstalk:CreateApplication",
"s3:CreateBucket"
],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:RequestTag/Account": [
"Audit", "Automation", "Backup", "Delegated", "Egress",
"Finops", "Inspection", "Logs-archive", "MFA", "Network",
"Sandbox", "Shared-services", "Tekes", "Tekes-dev",
"Workspaces", "Cnapp"
],
"aws:RequestTag/Division": [
"Information technology communication services",
"Applications Development Division",
"Cyber Security Technologies Bureau"
],
"aws:RequestTag/Environment": [
"production", "development", "test"
]
}
}
}
]
}
As a resume, SCP is good tool to enforce the tagging, but will help you a lot when using it with AWS Config
for this topic.