Terratags is a tool for validating tags on AWS and Azure resources in Terraform configurations.
- Validates required tags on AWS and Azure resources
- Advanced pattern matching with regex validation for tag values
- Module resource validation - validates resources created by external modules via Terraform plan analysis
- Supports AWS provider default_tags
- Supports AWSCC provider tag format (see AWSCC exclusion list for resources with non-compliant tag schemas)
- Supports Azure providers (azurerm and azapi)
- Supports azapi provider default_tags
- Supports module-level tags with tag inheritance
- Supports exemptions for specific resources
- Generates HTML reports of tag compliance
- Provides auto-remediation suggestions
- Integrates with Terraform plan output
- Tracks tag inheritance from provider default_tags
- Exemption tracking and reporting
- Excluded resources tracking for AWSCC resources with non-compliant tag schemas
Open issues for other providers:
- Google provider
- Azure providers : Keeping this open as there are additional Azure providers.
- The behavior with provider aliases is not tested and so the evaluation cannot be guaranteed.
brew install terratags/tap/terratags
go install github.com/terratags/terratags@latest
Download the appropriate binary from the GitHub Releases page.
See installation docs for more options.
terratags -config config.yaml -dir ./infra
-config
,-c
: Path to the config file (JSON/YAML) containing required tag keys (required)-dir
,-d
: Path to the Terraform directory to analyze (default: current directory)-verbose
,-v
: Enable verbose output-log-level
,-l
: Set logging level: DEBUG, INFO, WARN, ERROR (default: ERROR)-plan
,-p
: Path to Terraform plan JSON file to analyze (includes module resource validation)-report
,-r
: Path to output HTML report file-remediate
,-re
: Show auto-remediation suggestions for non-compliant resources-exemptions
,-e
: Path to exemptions file (JSON/YAML)-ignore-case
,-i
: Ignore case when comparing required tag keys-help
,-h
: Show help message-version
,-V
: Show version information
Note: Pattern validation was introduced in version 0.3.0 and provides advanced regex-based tag value validation.
Terratags supports advanced pattern validation using regular expressions to validate tag values. This allows you to enforce specific formats, naming conventions, and business rules for your tags.
- Regex Support: Use any valid Go regex pattern for tag value validation
- Case Sensitivity: Patterns are case-sensitive by default (use
--ignore-case
for case-insensitive tag name matching) - Flexible Configuration: Mix pattern validation with simple presence validation
- Clear Error Messages: Detailed feedback when patterns don't match
- Backward Compatibility: Existing simple configurations continue to work
Pattern validation uses an object format instead of the simple array format:
required_tags:
TagName:
pattern: "regex_pattern_here"
# Tag without pattern (just presence validation)
SimpleTag: {}
Environment:
pattern: "^(dev|test|staging|prod)$"
- âś… Matches:
dev
,test
,staging
,prod
- ❌ Rejects:
development
,production
,DEV
,Test
Owner:
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
- âś… Matches:
devops@company.com
,team.lead@company.com
- ❌ Rejects:
username
,user@domain
,@company.com
Project:
pattern: "^[A-Z]{2,4}-[0-9]{3,6}$"
- âś… Matches:
WEB-123456
,DATA-567890
,INFRA-890123
- ❌ Rejects:
web-123
,PROJECT
,ABC-12
,TOOLONG-1234567
CostCenter:
pattern: "^CC-[0-9]{4}$"
- âś… Matches:
CC-1234
,CC-5678
,CC-9012
- ❌ Rejects:
CC123
,CC-12345
,cc-1234
,CostCenter-1234
Name:
pattern: "^\\S+$"
- âś… Matches:
web-server-01
,data-bucket
,main-vpc
- ❌ Rejects:
web server
,database 01
,api gateway
Version:
pattern: "^v?[0-9]+\\.[0-9]+\\.[0-9]+$"
- âś… Matches:
1.0.0
,v2.1.3
,10.15.2
- ❌ Rejects:
1.0
,v1
,1.0.0-beta
,latest
ResourceName:
pattern: "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$"
- âś… Matches:
web-server
,api-gateway-v2
,database01
- ❌ Rejects:
-web-server
,api-gateway-
,web--server
required_tags:
# Strict environment values
Environment:
pattern: "^(dev|test|staging|prod)$"
# Valid email for ownership
Owner:
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
# Project code format
Project:
pattern: "^[A-Z]{2,4}-[0-9]{3,6}$"
# Cost center format
CostCenter:
pattern: "^CC-[0-9]{4}$"
# No whitespace in names
Name:
pattern: "^\\S+$"
# Simple presence validation (no pattern)
Team: {}
required_tags:
# Pattern validation for critical tags
Environment:
pattern: "^(dev|test|staging|prod)$"
Owner:
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
# Simple validation for others
Name: {}
Project: {}
Team: {}
When pattern validation fails, Terratags provides clear error messages:
Resource aws_instance 'web_server' has tag pattern violations:
- Tag 'Environment': value 'Production' does not match required pattern '^(dev|test|staging|prod)$'
- Tag 'Owner': value 'DevOps Team' does not match required pattern '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
- Tag 'Project': value 'website' does not match required pattern '^[A-Z]{2,4}-[0-9]{3,6}$'
Use the provided examples to test pattern validation:
# Test passing patterns
terratags -config examples/config-patterns.yaml -dir examples/pattern_validation_passing
# Test failing patterns
terratags -config examples/config-patterns.yaml -dir examples/pattern_validation_failing
# Generate detailed report
terratags -config examples/config-patterns.yaml -dir examples/pattern_validation_failing -report pattern-report.html
- Start Simple: Begin with basic patterns and refine as needed
- Test Thoroughly: Use both passing and failing examples to validate patterns
- Escape Special Characters: Remember to escape backslashes in YAML/JSON (
\\
instead of\
) - Case Sensitivity: Patterns are case-sensitive unless using
--ignore-case
flag - Anchor Patterns: Use
^
and$
to match the entire string - Test Online: Use regex testing tools to validate patterns before deployment
Common regex elements used in tag patterns:
Element | Description | Example |
---|---|---|
^ |
Start of string | ^dev matches strings starting with "dev" |
$ |
End of string | prod$ matches strings ending with "prod" |
\S |
Non-whitespace character | ^\S+$ matches strings without spaces |
[a-z] |
Character class | [a-zA-Z] matches any letter |
[0-9] |
Digit class | [0-9]{4} matches exactly 4 digits |
{n,m} |
Quantifier | {2,4} matches 2 to 4 occurrences |
+ |
One or more | [a-z]+ matches one or more letters |
* |
Zero or more | [a-z]* matches zero or more letters |
| |
Alternation | (dev|test|prod) matches any of the three |
\. |
Literal dot | \.com matches ".com" literally |
\\ |
Escape character | \\S in YAML becomes \S in regex |
Existing simple configurations work unchanged:
# This continues to work
required_tags:
- Name
- Environment
- Owner
To add pattern validation, convert to object format:
# Enhanced with patterns
required_tags:
Name: {} # Just presence validation
Environment:
pattern: "^(dev|test|staging|prod)$"
Owner:
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
Use Case | Pattern | Example Values |
---|---|---|
Environment | ^(dev|test|staging|prod)$ |
dev , test , staging , prod |
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$ |
devops@company.com , team.lead@company.com |
|
Project Code | ^[A-Z]{2,4}-[0-9]{3,6}$ |
WEB-123456 , DATA-567890 , SEC-123456 |
Cost Center | ^CC-[0-9]{4}$ |
CC-1234 , CC-5678 , CC-9012 |
No Whitespace | ^\\S+$ |
web-server-01 , data-bucket , main-vpc |
Version | ^v?[0-9]+\\.[0-9]+\\.[0-9]+$ |
1.0.0 , v2.1.3 , 10.15.2 |
For comprehensive pattern matching documentation, including advanced techniques, common patterns library, and troubleshooting guide, see Pattern Matching Guide.
Terratags supports two configuration formats for specifying required tags: a simple format for basic tag presence validation, and an advanced format with regex pattern validation for tag values.
The simple format validates that required tags are present but doesn't validate their values:
YAML Format:
required_tags:
- Name
- Environment
- Owner
- Project
JSON Format:
{
"required_tags": [
"Name",
"Environment",
"Owner",
"Project"
]
}
The advanced format allows you to specify regex patterns to validate tag values:
YAML Format:
required_tags:
Name:
pattern: "^\\S+$"
Environment:
pattern: "^(dev|test|staging|prod)$"
Owner:
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
Project:
pattern: "^[A-Z]{2,4}-[0-9]{3,6}$"
# Tag required but no pattern validation
Team: {}
JSON Format:
{
"required_tags": {
"Name": {
"pattern": "^\\S+$"
},
"Environment": {
"pattern": "^(dev|test|staging|prod)$"
},
"Owner": {
"pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
},
"Project": {
"pattern": "^[A-Z]{2,4}-[0-9]{3,6}$"
},
"Team": {}
}
}
You can mix both simple and advanced formats in the same configuration:
required_tags:
# Simple tags (just check presence)
Name: {}
Project: {}
# Advanced tags with pattern validation
Environment:
pattern: "^(dev|test|staging|prod)$"
Owner:
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
- Regex Support: Use any valid Go regex pattern
- Case Sensitivity: Respects the
--ignore-case
flag for tag name matching - Backward Compatibility: Existing simple configurations continue to work unchanged
Here are some commonly used patterns:
required_tags:
# Environment validation
Environment:
pattern: "^(dev|test|staging|prod|production)$"
# Email validation
Owner:
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
# Cost center format
CostCenter:
pattern: "^CC-[0-9]{4}$"
# Semantic version
Version:
pattern: "^v?[0-9]+\\.[0-9]+\\.[0-9]+$"
# No whitespace
Name:
pattern: "^\\S+$"
# Alphanumeric with dashes
Project:
pattern: "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$"
Exemptions allow you to exclude specific resources or resource types from certain tag requirements. Create a YAML or JSON file with your exemptions.
resource_type
: The AWS resource type (e.g., aws_s3_bucket, aws_instance)resource_name
: The name of the specific resource to exempt. Use "*" to exempt all resources of the specified typeexempt_tags
: List of tags that are not required for this resourcereason
: A description explaining why this exemption exists
exemptions:
- resource_type: aws_s3_bucket
resource_name: logs_bucket
exempt_tags: [Owner, Project]
reason: "Legacy bucket used for system logs only"
- resource_type: aws_dynamodb_table
resource_name: "*"
exempt_tags: [Environment]
reason: "DynamoDB tables use environment from provider default_tags"
Terratags supports the AWS Cloud Control (AWSCC) provider's tag format, which differs from the standard AWS provider tag format.
AWS Provider uses a map of key/value pairs:
tags = {
Environment = "test"
Project = "demo"
}
AWSCC Provider uses a list of maps with key
and value
fields:
tags = [{
key = "Environment"
value = "test"
}, {
key = "Project"
value = "demo"
}]
Note: AWSCC provider does not support the default_tags
feature. Some AWSCC resources have non-compliant tag schemas and are excluded from validation.
See AWSCC Support for more details.
Terratags integrates with AWS provider's default_tags
feature. When you define default tags in your AWS provider configuration, Terratags will recognize these tags and consider them when validating resources.
- Tags defined in the AWS provider's
default_tags
block are automatically applied to all resources created by that provider - Terratags tracks tag inheritance from provider default_tags to individual resources
- Resources only need to specify tags not covered by default_tags
- Default tags can be overridden at the resource level if needed
provider "aws" {
region = "us-west-2"
default_tags {
tags = {
Environment = "dev"
Owner = "team-a"
Project = "demo"
}
}
}
resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t2.micro"
# Only need to specify Name tag, as other required tags come from default_tags
tags = {
Name = "example-instance"
}
}
In this example, the AWS instance will have all four required tags: Name
from the resource-level tags, and Environment
, Owner
, and Project
from the provider's default_tags.
Terratags also supports the AWSCC provider's tag format, which differs from the standard AWS provider format.
The AWSCC provider uses a list of maps with key/value pairs for tags:
resource "awscc_apigateway_rest_api" "example" {
name = "example-api"
description = "Example API"
tags = [{
key = "Environment"
value = "Production"
}, {
key = "Project"
value = "Terratags"
}]
}
Note: AWSCC provider does not support default_tags
, so all required tags must be specified at the resource level.
See AWSCC Support documentation for more details.
Terratags supports both the Azurerm and azapi providers for Azure resources.
The Azurerm provider uses a map of key/value pairs for tags, similar to the AWS provider:
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "West Europe"
tags = {
Environment = "Production"
Project = "Terratags"
}
}
Note: Azurerm provider does not support default_tags
, so all required tags must be specified at the resource level.
The azapi provider supports tags at both the provider level (via default_tags
) and at the resource level:
provider "azapi" {
default_tags = {
Environment = "Production"
Project = "Terratags"
}
}
resource "azapi_resource" "example" {
type = "Microsoft.Storage/storageAccounts@2022-05-01"
name = "examplestorageaccount"
parent_id = azurerm_resource_group.example.id
location = azurerm_resource_group.example.location
tags = {
Name = "example-storage"
}
}
See Azure Support documentation for more details.
terratags -config config.yaml -dir ./infra
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
terratags -config config.yaml -plan plan.json
terratags -config config.yaml -dir ./infra -report report.html
terratags -config config.yaml -dir ./infra -remediate
terratags -config config.yaml -dir ./infra -exemptions exemptions.yaml
Terratags can be integrated with pre-commit to automatically validate tags before commits are made to your repository.
-
Install pre-commit:
pip install pre-commit
-
Add to your
.pre-commit-config.yaml
:repos: - repo: https://github.com/terratags/terratags rev: v0.3.0 # Use the latest version (available from v0.3.0+) hooks: - id: terratags
-
Install the hook:
pre-commit install
-
Ensure you have a
terratags.yaml
configuration file in your repository root
You can customize the hook with additional arguments:
repos:
- repo: https://github.com/terratags/terratags
rev: v0.3.0
hooks:
- id: terratags
args: [
--config=custom-config.yaml,
--exemptions=exemptions.yaml,
--remediate
]
Define different hooks for different purposes:
repos:
- repo: https://github.com/terratags/terratags
rev: v0.3.0
hooks:
# Basic validation on every commit
- id: terratags
name: terratags-validate
args: [--config=terratags.yaml]
# Generate report (run manually)
- id: terratags
name: terratags-report
args: [--config=terratags.yaml, --report=tag-report.html]
stages: [manual]
See Pre-commit Documentation for detailed setup instructions and advanced configurations.
Add Terratags to your CI/CD pipeline to enforce tag compliance:
# GitHub Actions example - Directory validation
name: Validate Tags
on:
pull_request:
paths:
- '**.tf'
jobs:
validate-tags:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: Install Terratags
run: go install github.com/terratags/terratags@latest
- name: Validate Tags (Direct Resources)
run: terratags -config config.yaml -dir ./infra
For comprehensive validation including module resources, use plan-based validation. See CI/CD documentation for detailed examples.
Terratags provides enhanced HTML reports with detailed information about tag compliance:
- Visual indicators for compliant, non-compliant, and exempt resources
- Detailed breakdown of tag status for each resource
- Separate sections for direct resources and module-created resources
- Module path and source information for module resources
- Tracking of tag sources (resource-level vs provider default_tags vs module inheritance)
- Exemption details including reasons for exemptions
- Summary statistics including exempt resources
- Tag violation counts by tag name
The HTML report provides a visual representation of tag compliance across your Terraform resources, making it easy to identify which resources need attention and track compliance metrics. When using plan validation, the report clearly distinguishes between direct resources and those created by modules. You can view the generated HTML report in any web browser.