{"id":13490605,"url":"https://github.com/env0/terratag","last_synced_at":"2025-05-14T02:08:23.575Z","repository":{"id":37027048,"uuid":"232134221","full_name":"env0/terratag","owner":"env0","description":"Terratag is a CLI tool that enables users of Terraform to automatically create and maintain tags across their entire set of AWS, Azure, and GCP resources","archived":false,"fork":false,"pushed_at":"2025-04-20T12:05:35.000Z","size":633,"stargazers_count":976,"open_issues_count":0,"forks_count":45,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-05-11T15:52:24.321Z","etag":null,"topics":["aws","azure","cloud","cost","devops","env0","gcp","hashicorp-terraform","hcl","iac","infrastructure-as-code","tagging","tags","terraform","terratag"],"latest_commit_sha":null,"homepage":"https://terratag.io","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/env0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-01-06T15:53:12.000Z","updated_at":"2025-05-07T01:42:08.000Z","dependencies_parsed_at":"2024-01-03T02:29:19.072Z","dependency_job_id":"16c321db-0d9a-4886-a325-23043f7b9279","html_url":"https://github.com/env0/terratag","commit_stats":{"total_commits":265,"total_committers":22,"mean_commits":"12.045454545454545","dds":0.6603773584905661,"last_synced_commit":"08fe5ac9f071125cad379a034fdd7e0f2a8d16f3"},"previous_names":[],"tags_count":71,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/env0%2Fterratag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/env0%2Fterratag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/env0%2Fterratag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/env0%2Fterratag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/env0","download_url":"https://codeload.github.com/env0/terratag/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254053155,"owners_count":22006717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","azure","cloud","cost","devops","env0","gcp","hashicorp-terraform","hcl","iac","infrastructure-as-code","tagging","tags","terraform","terratag"],"created_at":"2024-07-31T19:00:49.331Z","updated_at":"2025-05-14T02:08:18.556Z","avatar_url":"https://github.com/env0.png","language":"Go","readme":"# [\u003cimg src=\"ttlogo.png\" width=\"300\" alt=\"Terratag Logo\"\u003e](https://terratag.io)\n\n[![ci](https://github.com/env0/terratag/workflows/ci/badge.svg)](https://github.com/env0/terratag/actions?query=workflow%3Aci+branch%3Amaster) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fenv0%2Fterratag.svg?type=small)](https://app.fossa.com/projects/git%2Bgithub.com%2Fenv0%2Fterratag?ref=badge_small)\n\n\u003e \u003csub\u003eTerratag is brought to you with\u0026nbsp;❤️\u0026nbsp; by\n\u003e [\u003cimg src=\"logo.svg\" width=\"150\"\u003e](https://env0.com)\n\u003e Let your team manage their own environment in AWS, Azure and Google. \u003cbr/\u003e\n\u003e Governed by your policies and with complete visibility and cost management.\n\n## What?\n\nTerratag is a CLI tool allowing for tags or labels to be applied across an entire set of OpenTofu/Terraform files. Terratag will apply tags or labels to any AWS, GCP and Azure resources.\n\n### Terratag in action\n\n![](https://assets.website-files.com/5dc3f52851595b160ba99670/5f62090d2d532ca35e143133_terratag.gif)\n\n## Why?\n\nMaintaining tags across your application is hard, especially when done manually. Terratag enables you to easily add tags to your existing IaC and benefit from some cross-resource tag applications you wish you had thought of when you had just started writing your OpenTofu/Terraform, saving you tons of time and making future updates easy. [Read more](https://d1.awsstatic.com/whitepapers/aws-tagging-best-practices.pdf) on why tagging is important.\n\n## How?\n\n### Prerequisites\n\n- OpenTofu 1.x or Terraform 0.12 through 1.x.\n\n### Usage\n\n1. Install from homebrew:\n\n   ```\n   brew install env0/terratag/terratag\n   ```\n\n   Or download the latest [release binary](https://github.com/env0/terratag/releases) .\n\n1. Initialize Opentofu/Terraform modules to get provider schema and pull child modules:\n\n   ```bash\n    tofu init\n   ```\n\n   ```bash\n    terraform init\n   ```\n\n1. Run Terratag\n\n   ```bash\n    terratag -dir=foo/bar -tags={\\\"environment_id\\\": \\\"prod\\\"}\n   ```\n\n   or\n\n   ```bash\n    terratag -dir=foo/bar -tags=\"environment_id=prod,some-tag=value\"\n   ```\n\n### Example Output\n\n#### Before Terratag\n\n```\n|- aws.tf\n|- gcp.tf\n```\n\n```hcl\n# aws.tf\nprovider \"aws\" {\n  version = \"~\u003e 2.0\"\n  region  = \"us-east-1\"\n}\n\nresource \"aws_s3_bucket\" \"b\" {\n  bucket = \"my-tf-test-bucket\"\n  acl    = \"private\"\n\n  tags {\n    Name        = \"My bucket\"\n  }\n}\n```\n\n```hcl\n#gcp.tf\nresource \"google_storage_bucket\" \"static-site\" {\n  name          = \"image-store.com\"\n  location      = \"EU\"\n  force_destroy = true\n\n  bucket_policy_only = true\n\n  website {\n    main_page_suffix = \"index.html\"\n    not_found_page   = \"404.html\"\n  }\n  cors {\n    origin          = [\"http://image-store.com\"]\n    method          = [\"GET\", \"HEAD\", \"PUT\", \"POST\", \"DELETE\"]\n    response_header = [\"*\"]\n    max_age_seconds = 3600\n  }\n  labels = {\n    \"foo\" = \"bar\"\n  }\n}\n\n```\n\n#### After Terratag\n\nRunning `terratag -tags={\\\"env0_environment_id\\\":\\\"dev\\\",\\\"env0_project_id\\\":\\\"clientA\\\"}` will output:\n\n```\n|- aws.terratag.tf\n|- gcp.terratag.tf\n|- aws.tf.bak\n|- gcp.tf.bak\n```\n\n```hcl\n# aws.terratag.tf\nprovider \"aws\" {\n  version = \"~\u003e 2.0\"\n  region  = \"us-east-1\"\n}\n\nresource \"aws_s3_bucket\" \"b\" {\n  bucket = \"my-tf-test-bucket\"\n  acl    = \"private\"\n\n  tags = merge( map(\"Name\", \"My bucket\" ), local.terratag_added_main)\n}\nlocals {\n  terratag_added_main = {\"env0_environment_id\"=\"dev\",\"env0_project_id\"=\"clientA\"}\n}\n```\n\n```hcl\n# gcp.terratag.tf\nresource \"google_storage_bucket\" \"static-site\" {\n  name          = \"image-store.com\"\n  location      = \"EU\"\n  force_destroy = true\n\n  bucket_policy_only = true\n\n  website {\n    main_page_suffix = \"index.html\"\n    not_found_page   = \"404.html\"\n  }\n  cors {\n    origin          = [\"http://image-store.com\"]\n    method          = [\"GET\", \"HEAD\", \"PUT\", \"POST\", \"DELETE\"]\n    response_header = [\"*\"]\n    max_age_seconds = 3600\n  }\n  labels = merge( map(\"foo\" , \"bar\"), local.terratag_added_main)\n}\nlocals {\n  terratag_added_main = {\"env0_environment_id\"=\"dev\",\"env0_project_id\"=\"clientA\"}\n}\n```\n\n### Optional CLI flags\n\n- `-dir=\u003cpath\u003e` - defaults to `.`. Sets the opentofu/terraform folder to tag `.tf` files in\n- `-skipTerratagFiles=false` - Dont skip processing `*.terratag.tf` files (when running terratag a second time for the same directory)\n- `-rename=false` - Instead of replacing files named `\u003cbasename\u003e.tf` with `\u003cbasename\u003e.terratag.tf`, keep the original filename\n- `-filter=\u003cregular expression\u003e` - defaults to `.*`. Only apply tags to the resource types matched by the regular expression\n- `-type=\u003cterraform, terragrunt, or terragrunt-run-all\u003e` - defaults to `terraform` (and `opentofu`). If `terragrunt` is used, tags the files under `.terragrunt-cache` folder. Note: if Terragrunt does not create a `.terragrunt-cache` folder, use the default or omit.\n- `-verbose` - Turn on verbose logging\n- `-default-to-terraform` By default uses OpenTofu (if installed), if set will use Terraform even when Opentofu is installed\n- `--keep-existing-tags` - When set, existing tags will be preserved when merging tags (by default, new tags override existing ones)\n\nSetting options via enviroment variables is also supported. CLI flags have a precedence over envrionment variables.\n\n```\nTERRATAG_TAGS\nTERRATAG_DIR\nTERRATAG_SKIPTERRATAGFILES\nTERRATAG_FILTER\nTERRATAG_SKIP\nTERRATAG_VERBOSE\nTERRATAG_RENAME\nTERRATAG_TYPE\nTERRATAG_DEFAULT_TO_TERRAFORM\nTERRATAG_KEEP_EXISTING_TAGS\n```\n\n##### See more samples [here](https://github.com/env0/terratag/tree/master/test/fixture)\n\n## Notes\n\n- Resources already having the exact same tag as the one being appended will be overridden\n- Supported providers\n  - `aws`\n  - `google`\n  - `azurerm`\n  - `azurestack`\n  - `azapi`\n\n## Develop\n\nIssues and Pull Requests are very welcome!\n\n### Prerequisites\n\n- Go \u003e 1.23\n\n### Build\n\n```bash\ngit clone https://github.com/env0/terratag\ncd terratag\ngo mod tidy\ngo build ./cmd/terratag\n```\n\n### Test\n\n#### Structure\n\nThe test cases are located under `test/tests`\nEach test case placed there should have the following directory structure:\n\n```\nmy_test\n|+ input\n  ...            // any depth under /input\n     |- main.tf  // this is where we will run all terraform/terratag commands\n|- expected\n```\n\n- `input` is where you should place the terraform files of your test.\n  All commands will be executed wherever down the hierarchy where `main.tf` is located.\n  We do that to allow cases where complex nested submodule resolution may take place, and one would like to test how a directory higher up the hierarchy gets resolved.\n- `expected` is a directory in which all `.terratag.tf` files will be matched with the output directory\n\nEach terraform version has it's own config file containing the list of test suites to run.\nThe config file is under `test/fixtures/terraform_xx/config.yaml` where `xx` is the terraform version.\n\n#### What's being tested?\n\nEach test will run:\n\n- `terraform init`\n- `terratag`\n- `terraform validate`\n\nAnd finally, will compare the results in `out` with the `expected` directory\n\n#### Running Tests\n\nTests can only run on a specific Terraform version -\n\n```\ngo test -run TestTerraformXX\n```\n\nWe use [tfenv](https://github.com/tfutils/tfenv) to switch between versions. The exact versions used in the CI tests can be found under `test/tfenvconf`.\n\n## Release\n\n1. Create and push a tag locally, in semver format - `git tag v0.1.32 \u0026\u0026 git push origin --tags`\n2. Goto [Github Releases](https://github.com/env0/terratag/releases) and edit the draft created by Release Drafter Bot - it should contain the change log for the release (if not press on Auto-generate release notes). Make sure it's pointing at the tag you created in the previous step and publish the release.\n3. Binaries will be automatically generated by the Github action defined in `.github/workflows/release.yml`\n4. NPM will automatically pick up on the new version.\n","funding_links":[],"categories":["Go","Tools","Infrastructure as Code","HCL"],"sub_categories":["Helpers","Terraform Tooling","Community providers"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenv0%2Fterratag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fenv0%2Fterratag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenv0%2Fterratag/lists"}