{"id":19508817,"url":"https://github.com/rhythmictech/terraform-aws-backend","last_synced_at":"2025-07-24T06:07:12.989Z","repository":{"id":34992595,"uuid":"184105443","full_name":"rhythmictech/terraform-aws-backend","owner":"rhythmictech","description":"Creates a backend S3 bucket and DynamoDB table for managing Terraform state in external accounts","archived":false,"fork":false,"pushed_at":"2024-03-04T19:07:06.000Z","size":139,"stargazers_count":7,"open_issues_count":1,"forks_count":6,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-26T03:44:01.630Z","etag":null,"topics":["aws","aws-backend-terraform","dynamodb-table","terraform","terraform-module","terraform-modules"],"latest_commit_sha":null,"homepage":"https://registry.terraform.io/modules/rhythmictech/backend/aws","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rhythmictech.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":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-04-29T16:23:22.000Z","updated_at":"2023-07-07T01:48:55.000Z","dependencies_parsed_at":"2024-03-04T20:31:06.027Z","dependency_job_id":"501ac026-1845-4f4a-9f36-52396b0c1329","html_url":"https://github.com/rhythmictech/terraform-aws-backend","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/rhythmictech/terraform-aws-backend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhythmictech%2Fterraform-aws-backend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhythmictech%2Fterraform-aws-backend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhythmictech%2Fterraform-aws-backend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhythmictech%2Fterraform-aws-backend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rhythmictech","download_url":"https://codeload.github.com/rhythmictech/terraform-aws-backend/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhythmictech%2Fterraform-aws-backend/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266801550,"owners_count":23986372,"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","status":"online","status_checked_at":"2025-07-24T02:00:09.469Z","response_time":99,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","aws-backend-terraform","dynamodb-table","terraform","terraform-module","terraform-modules"],"created_at":"2024-11-10T23:09:56.761Z","updated_at":"2025-07-24T06:07:12.959Z","avatar_url":"https://github.com/rhythmictech.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# terraform-aws-backend\n\n[![tflint](https://github.com/rhythmictech/terraform-aws-backend/workflows/tflint/badge.svg?branch=master\u0026event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Atflint+event%3Apush+branch%3Amaster)\n[![tfsec](https://github.com/rhythmictech/terraform-aws-backend/workflows/tfsec/badge.svg?branch=master\u0026event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Atfsec+event%3Apush+branch%3Amaster)\n[![yamllint](https://github.com/rhythmictech/terraform-aws-backend/workflows/yamllint/badge.svg?branch=master\u0026event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Ayamllint+event%3Apush+branch%3Amaster)\n[![misspell](https://github.com/rhythmictech/terraform-aws-backend/workflows/misspell/badge.svg?branch=master\u0026event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Amisspell+event%3Apush+branch%3Amaster)\n[![pre-commit-check](https://github.com/rhythmictech/terraform-aws-backend/workflows/pre-commit-check/badge.svg?branch=master\u0026event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Apre-commit-check+event%3Apush+branch%3Amaster)\n\u003ca href=\"https://twitter.com/intent/follow?screen_name=RhythmicTech\"\u003e\u003cimg src=\"https://img.shields.io/twitter/follow/RhythmicTech?style=social\u0026logo=twitter\" alt=\"follow on Twitter\"\u003e\u003c/a\u003e\n\nCreates an S3 bucket and DynamoDB table for managing Terraform state. Note that when bootstrapping a new environment, it is typically easier to use a separate method for creating the bucket and lock table, like [a CloudFormation Stack](https://github.com/rhythmictech/AWS-CFN-Terraform-Bootstrap). This module is intended to create a backend in an AWS account that is already Terraform-managed. This is useful to store the state for other accounts externally.\n\nThis module will create a CloudFormation stack and an optional wrapper script to deploy it. This stack is suitable to run in any account that will store its Terraform state in the bucket created by this module. It creates an IAM role with the AdministratorAccess policy attached and with an External ID which can then be assumed by terraform to create resources in the child account(s).\n\n![visualization](.github/terraform-backend.drawio.png)\n\n*Breaking Changes*\n\nPrevious versions of this module had support for cross-account management in a way that proved awkward for many uses cases and made it more difficult than it should've to fully secure the tfstate between accounts. Version 4.x and later eliminates support for this and refocuses the module on using centralized tfstate buckets with cross-account role assumption for execution of terraform. As a result, many variable names have changed and functionality has been dropped. Upgrade to this version at your own peril.\n\n## Multi-Account Usage\nThese instructions assume two AWS accounts; a \"Parent\" account which holds the terraform state and IAM users, and a \"Child\" account.\n\n1) In the parent account create this module. The below code is a serving suggestion. \n```\nmodule \"backend\" {\n  source  = \"rhythmictech/backend/aws\"\n  version = \"4.1.0\"\n\n  bucket_name                = \"${local.account_id}-${var.region}-terraform-state\"\n  create_assumerole_template = true\n  logging_target_bucket      = module.s3logging-bucket.s3_bucket_name\n  logging_target_prefix      = \"${local.account_id}-${var.region}-tf-state\"\n  tags                       = module.tags.tags_no_name\n}\n```\n\nIt will create a folder with a shell script and a CloudFormation stack in it. \n\n2) Log into the child account and run the shell script, `assumerole/addrole.sh`. This will create a CloudFormation stack in that child account.\n\n3) In the terraform code for the child account create the provider and backend sections like below, substituting `PARENT_ACCT_ID` and `PARENT_REGION`, `CHILD_ACCT_ID`, AND `EXTERNAL_ID`.  \n\nterraform backend config:\n```\nbucket         = \"PARENT_ACCT_ID-PARENT_REGION-terraform-state\"\ndynamodb_table = \"tf-locktable\"\nkey            = \"account.tfstate\"\nregion         = \"PARENT_REGION\"\n```\n\nprovider config:\n```\nprovider \"aws\" {\n  assume_role {\n    role_arn     = \"arn:aws:iam::CHILD_ACCT_ID:role/Terraform\"\n    session_name = \"terraform-network\"\n    external_id  = \"EXTERNAL_ID\"\n  }\n}\n```\n\n4) Log in to the master account and run terraform using this backend and provider config. The state will be stored in the parent account but terraform will assume the child account role.\n\n## Cross Account State Management\n\nSee [Use AssumeRole to Provision AWS Resources Across Accounts](https://learn.hashicorp.com/tutorials/terraform/aws-assumerole) for more information on this pattern.\n\nThis module is not intended to hold the state for the account in which it is created. If the account itself is also Terraform managed, it is recommended to create a separate bucket for its own state manually or via a different IaC method (e.g., CloudFormation) to avoid the chicken-and-egg problem. See [this CloudFormation template](https://github.com/rhythmictech/AWS-CFN-Terraform-Bootstrap) to create terraform backend for this or any other single account. \n\nYou can test the ability to assume a role in the child account by logging in with the parent account and running this \n```\n\nexport $(printf \"AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s\" \\\n$(aws sts assume-role \\\n--external-id EXTERNAL_ID \\\n--role-arn arn:aws:iam::CHILD_ACCT_ID:role/Terraform \\\n--role-session-name testme \\\n--query \"Credentials.[AccessKeyId,SecretAccessKey,SessionToken]\" \\\n--output text))%  \n\nAWS_SECURITY_TOKEN=\n```\nThen `aws sts get-caller-identity` should reveal you to be in the child account. \n\n\n\u003c!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK --\u003e\n## Requirements\n\n| Name | Version |\n|------|---------|\n| \u003ca name=\"requirement_terraform\"\u003e\u003c/a\u003e [terraform](#requirement\\_terraform) | \u003e= 0.14 |\n| \u003ca name=\"requirement_aws\"\u003e\u003c/a\u003e [aws](#requirement\\_aws) | \u003e= 4.0 |\n| \u003ca name=\"requirement_local\"\u003e\u003c/a\u003e [local](#requirement\\_local) | \u003e= 2.0 |\n| \u003ca name=\"requirement_random\"\u003e\u003c/a\u003e [random](#requirement\\_random) | \u003e= 3.0 |\n\n## Providers\n\n| Name | Version |\n|------|---------|\n| \u003ca name=\"provider_aws\"\u003e\u003c/a\u003e [aws](#provider\\_aws) | 4.28.0 |\n| \u003ca name=\"provider_local\"\u003e\u003c/a\u003e [local](#provider\\_local) | 2.2.3 |\n| \u003ca name=\"provider_random\"\u003e\u003c/a\u003e [random](#provider\\_random) | 3.4.1 |\n\n## Modules\n\nNo modules.\n\n## Resources\n\n| Name | Type |\n|------|------|\n| [aws_dynamodb_table.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/dynamodb_table) | resource |\n| [aws_kms_alias.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |\n| [aws_kms_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |\n| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket_lifecycle_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |\n| [aws_s3_bucket_logging.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_ownership_controls.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource |\n| [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_versioning.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [local_file.assumerole_addrole](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |\n| [local_sensitive_file.assumerole_tfassumerole](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/sensitive_file) | resource |\n| [random_password.external_id](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |\n| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |\n| [aws_iam_policy_document.key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |\n| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |\n| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |\n\n## Inputs\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| \u003ca name=\"input_assumerole_role_attach_policies\"\u003e\u003c/a\u003e [assumerole\\_role\\_attach\\_policies](#input\\_assumerole\\_role\\_attach\\_policies) | Policy ARNs to attach to role (can be managed or custom but must exist) | `list(string)` | \u003cpre\u003e[\u003cbr\u003e  \"arn:aws:iam::aws:policy/AdministratorAccess\"\u003cbr\u003e]\u003c/pre\u003e | no |\n| \u003ca name=\"input_assumerole_role_external_id\"\u003e\u003c/a\u003e [assumerole\\_role\\_external\\_id](#input\\_assumerole\\_role\\_external\\_id) | External ID to attach to role (this is required, a random ID will be generated if not specified here) | `string` | `null` | no |\n| \u003ca name=\"input_assumerole_role_name\"\u003e\u003c/a\u003e [assumerole\\_role\\_name](#input\\_assumerole\\_role\\_name) | Name of role to create in assumerole template | `string` | `\"Terraform\"` | no |\n| \u003ca name=\"input_assumerole_stack_name\"\u003e\u003c/a\u003e [assumerole\\_stack\\_name](#input\\_assumerole\\_stack\\_name) | Name of CloudFormation stack | `string` | `\"tf-assumerole\"` | no |\n| \u003ca name=\"input_assumerole_template_name\"\u003e\u003c/a\u003e [assumerole\\_template\\_name](#input\\_assumerole\\_template\\_name) | File name of assumerole cloudformation template | `string` | `\"assumerole/tfassumerole.cfn.yml\"` | no |\n| \u003ca name=\"input_bucket_name\"\u003e\u003c/a\u003e [bucket\\_name](#input\\_bucket\\_name) | Name of bucket to hold tf state | `string` | n/a | yes |\n| \u003ca name=\"input_create_assumerole_template\"\u003e\u003c/a\u003e [create\\_assumerole\\_template](#input\\_create\\_assumerole\\_template) | If true, create a CloudFormation template that can be run against accounts to create an assumable role | `bool` | `false` | no |\n| \u003ca name=\"input_dynamo_locktable_name\"\u003e\u003c/a\u003e [dynamo\\_locktable\\_name](#input\\_dynamo\\_locktable\\_name) | Name of lock table for terraform | `string` | `\"tf-locktable\"` | no |\n| \u003ca name=\"input_dynamodb_kms_key_arn\"\u003e\u003c/a\u003e [dynamodb\\_kms\\_key\\_arn](#input\\_dynamodb\\_kms\\_key\\_arn) | KMS key arn to enable encryption on dynamodb table. Defaults to `alias/aws/dynamodb` | `string` | `null` | no |\n| \u003ca name=\"input_dynamodb_point_in_time_recovery\"\u003e\u003c/a\u003e [dynamodb\\_point\\_in\\_time\\_recovery](#input\\_dynamodb\\_point\\_in\\_time\\_recovery) | DynamoDB point-in-time recovery. | `bool` | `true` | no |\n| \u003ca name=\"input_dynamodb_server_side_encryption\"\u003e\u003c/a\u003e [dynamodb\\_server\\_side\\_encryption](#input\\_dynamodb\\_server\\_side\\_encryption) | Bool to enable encryption on dynamodb table | `bool` | `true` | no |\n| \u003ca name=\"input_kms_alias_name\"\u003e\u003c/a\u003e [kms\\_alias\\_name](#input\\_kms\\_alias\\_name) | Name of KMS Alias | `string` | `null` | no |\n| \u003ca name=\"input_kms_key_id\"\u003e\u003c/a\u003e [kms\\_key\\_id](#input\\_kms\\_key\\_id) | ARN for KMS key for all encryption operations (a key will be created if this is not provided) | `string` | `null` | no |\n| \u003ca name=\"input_lifecycle_rules\"\u003e\u003c/a\u003e [lifecycle\\_rules](#input\\_lifecycle\\_rules) | lifecycle rules to apply to the bucket (set to null to skip lifecycle rules) | \u003cpre\u003elist(object(\u003cbr\u003e    {\u003cbr\u003e      id                            = string\u003cbr\u003e      enabled                       = bool\u003cbr\u003e      prefix                        = string\u003cbr\u003e      expiration                    = number\u003cbr\u003e      noncurrent_version_expiration = number\u003cbr\u003e  }))\u003c/pre\u003e | `null` | no |\n| \u003ca name=\"input_logging_target_bucket\"\u003e\u003c/a\u003e [logging\\_target\\_bucket](#input\\_logging\\_target\\_bucket) | The name of the bucket that will receive the log objects (logging will be disabled if null) | `string` | `null` | no |\n| \u003ca name=\"input_logging_target_prefix\"\u003e\u003c/a\u003e [logging\\_target\\_prefix](#input\\_logging\\_target\\_prefix) | A key prefix for log objects | `string` | `null` | no |\n| \u003ca name=\"input_tags\"\u003e\u003c/a\u003e [tags](#input\\_tags) | Mapping of any extra tags you want added to resources | `map(string)` | `{}` | no |\n\n## Outputs\n\n| Name | Description |\n|------|-------------|\n| \u003ca name=\"output_backend_config_stub\"\u003e\u003c/a\u003e [backend\\_config\\_stub](#output\\_backend\\_config\\_stub) | Backend config stub to be used in child account(s) |\n| \u003ca name=\"output_external_id\"\u003e\u003c/a\u003e [external\\_id](#output\\_external\\_id) | External ID attached to IAM role in managed accounts |\n| \u003ca name=\"output_kms_key_arn\"\u003e\u003c/a\u003e [kms\\_key\\_arn](#output\\_kms\\_key\\_arn) | ARN of KMS Key for S3 bucket |\n| \u003ca name=\"output_provider_config_stub\"\u003e\u003c/a\u003e [provider\\_config\\_stub](#output\\_provider\\_config\\_stub) | Provider config stub to be used in child account(s) |\n| \u003ca name=\"output_s3_bucket_backend\"\u003e\u003c/a\u003e [s3\\_bucket\\_backend](#output\\_s3\\_bucket\\_backend) | S3 bucket used to store TF state |\n\u003c!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhythmictech%2Fterraform-aws-backend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhythmictech%2Fterraform-aws-backend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhythmictech%2Fterraform-aws-backend/lists"}