Skip to content

Commit 4bba286

Browse files
committed
new approach to this module to focus on external acct mgmt
1 parent d7772fa commit 4bba286

File tree

8 files changed

+173
-192
lines changed

8 files changed

+173
-192
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
exclude: ".terraform"
22
repos:
33
- repo: https://github.com/antonbabenko/pre-commit-terraform
4-
rev: v1.72.1
4+
rev: v1.74.1
55
hooks:
66
- id: terraform_docs
77
always_run: true

.terraform.lock.hcl

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 31 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,47 @@
11
# terraform-aws-backend
2-
[![](https://github.com/rhythmictech/terraform-aws-backend/workflows/pre-commit-check/badge.svg)](https://github.com/rhythmictech/terraform-aws-backend/actions) <a href="https://twitter.com/intent/follow?screen_name=RhythmicTech"><img src="https://img.shields.io/twitter/follow/RhythmicTech?style=social&logo=RhythmicTech" alt="follow on Twitter"></a>
32

4-
Creates a backend S3 bucket and DynamoDB table for managing Terraform state. Useful for bootstrapping a new
5-
environment. This module supports cross-account state management, using a centralized account that holds the S3 bucket and KMS key.
3+
[![tflint](https://github.com/rhythmictech/terraform-aws-backend/workflows/tflint/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Atflint+event%3Apush+branch%3Amaster)
4+
[![tfsec](https://github.com/rhythmictech/terraform-aws-backend/workflows/tfsec/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Atfsec+event%3Apush+branch%3Amaster)
5+
[![yamllint](https://github.com/rhythmictech/terraform-aws-backend/workflows/yamllint/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Ayamllint+event%3Apush+branch%3Amaster)
6+
[![misspell](https://github.com/rhythmictech/terraform-aws-backend/workflows/misspell/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Amisspell+event%3Apush+branch%3Amaster)
7+
[![pre-commit-check](https://github.com/rhythmictech/terraform-aws-backend/workflows/pre-commit-check/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-backend/actions?query=workflow%3Apre-commit-check+event%3Apush+branch%3Amaster)
8+
<a href="https://twitter.com/intent/follow?screen_name=RhythmicTech"><img src="https://img.shields.io/twitter/follow/RhythmicTech?style=social&logo=twitter" alt="follow on Twitter"></a>
69

7-
_Note: A centralized DynamoDB locking table is not supported because terraform cannot assume more than one IAM role per execution._
10+
Creates a backend 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. 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, which is always preferred.
11+
12+
*Breaking Changes*
13+
14+
Previous 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.
815

916
## Usage
1017
```
1118
module "backend" {
12-
source = "git::ssh://[email protected]/rhythmictech/terraform-aws-backend"
19+
source = "rhythmictech/backend/aws"
20+
1321
bucket = "project-tfstate"
1422
region = "us-east-1"
1523
table = "tf-locktable"
1624
}
17-
1825
```
1926

2027
## Cross Account State Management
21-
Managing state across accounts requires additional configuration to ensure that the S3 bucket is appropriately accessible and the KMS key is usable.
22-
23-
The following module declaration will create an S3 bucket and KMS key that are accessible to the root account (and users with the AdministratorAccess managed role) in the target account:
24-
25-
```yaml
26-
module "backend" {
27-
source = "git::ssh://[email protected]/rhythmictech/terraform-aws-backend"
28-
allowed_account_ids = ["123456789012"]
29-
bucket = "012345678901-us-east-1-tfstate"
30-
region = "us-east-1"
31-
}
32-
```
33-
34-
In the target account, use this declaration to import the module:
28+
To use this bucket to manage the state for other AWS accounts, you must create IAM roles in those accounts and allow the users who run Terraform to assume them.
3529

36-
```yaml
37-
module "backend" {
38-
source = "git::ssh://[email protected]/rhythmictech/terraform-aws-backend"
39-
kms_key_id = "arn:aws:kms:us-east-1:012345678901:key/59381274-af42-8521-04af-ab0acfe3d521"
40-
region = "us-east-1"
41-
remote_bucket = "012345678901-us-east-1-tfstate"
42-
}
43-
```
44-
45-
The module will automatically write to the source account S3 bucket using the KMS key with cross-account access.
46-
47-
Access to the source S3 bucket is done based on a prefix that matches the AWS Account ID. Therefore, target accounts must use a `workspace_key_prefix` that matches the account ID, such as in the following sample backend-config values:
48-
49-
```
50-
bucket = "012345678901-us-east-1-tf-state"
51-
key = "project.tfstate"
52-
workspace_key_prefix = "123456789012"
53-
region = "us-east-1"
54-
```
30+
See [Use AssumeRole to Provision AWS Resources Across Accounts](https://learn.hashicorp.com/tutorials/terraform/aws-assumerole) for more information on this pattern.
5531

5632
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
5733
## Requirements
5834

5935
| Name | Version |
6036
|------|---------|
61-
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.13 |
62-
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 3.15.0 |
37+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.14 |
38+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.0 |
6339

6440
## Providers
6541

6642
| Name | Version |
6743
|------|---------|
68-
| <a name="provider_aws"></a> [aws](#provider\_aws) | ~> 3.15.0 |
44+
| <a name="provider_aws"></a> [aws](#provider\_aws) | 4.28.0 |
6945

7046
## Modules
7147

@@ -79,23 +55,27 @@ No modules.
7955
| [aws_kms_alias.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
8056
| [aws_kms_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
8157
| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
82-
| [aws_s3_bucket_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |
58+
| [aws_s3_bucket_acl.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_acl) | resource |
59+
| [aws_s3_bucket_lifecycle_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |
60+
| [aws_s3_bucket_logging.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |
8361
| [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
62+
| [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 |
63+
| [aws_s3_bucket_versioning.versioning_example](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |
8464
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
65+
| [aws_canonical_user_id.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/canonical_user_id) | data source |
8566
| [aws_iam_policy_document.key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
86-
| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
67+
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
8768

8869
## Inputs
8970

9071
| Name | Description | Type | Default | Required |
9172
|------|-------------|------|---------|:--------:|
92-
| <a name="input_allowed_account_ids"></a> [allowed\_account\_ids](#input\_allowed\_account\_ids) | Account IDs that are allowed to access the bucket/KMS key | `list(string)` | `[]` | no |
93-
| <a name="input_bucket"></a> [bucket](#input\_bucket) | Name of bucket to create (do not provide if using `remote_bucket`) | `string` | `""` | no |
94-
| <a name="input_kms_alias_name"></a> [kms\_alias\_name](#input\_kms\_alias\_name) | Name of KMS Alias | `string` | `""` | no |
95-
| <a name="input_kms_key_id"></a> [kms\_key\_id](#input\_kms\_key\_id) | ARN for KMS key for all encryption operations. | `string` | `""` | no |
96-
| <a name="input_logging_target_bucket"></a> [logging\_target\_bucket](#input\_logging\_target\_bucket) | The name of the bucket that will receive the log objects | `string` | `null` | no |
97-
| <a name="input_logging_target_prefix"></a> [logging\_target\_prefix](#input\_logging\_target\_prefix) | A key prefix for log objects | `string` | `"TFStateLogs/"` | no |
98-
| <a name="input_remote_bucket"></a> [remote\_bucket](#input\_remote\_bucket) | If specified, the remote bucket will be used for the backend. A new bucket will not be created | `string` | `""` | no |
73+
| <a name="input_bucket_name"></a> [bucket\_name](#input\_bucket\_name) | Name of bucket to create | `string` | n/a | yes |
74+
| <a name="input_kms_alias_name"></a> [kms\_alias\_name](#input\_kms\_alias\_name) | Name of KMS Alias | `string` | `null` | no |
75+
| <a name="input_kms_key_id"></a> [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 |
76+
| <a name="input_lifecycle_rules"></a> [lifecycle\_rules](#input\_lifecycle\_rules) | lifecycle rules to apply to the bucket (set to null to skip lifecycle rules) | <pre>list(object(<br> {<br> id = string<br> enabled = bool<br> prefix = string<br> expiration = number<br> noncurrent_version_expiration = number<br> }))</pre> | <pre>[<br> {<br> "enabled": true,<br> "expiration": 90,<br> "id": "tfstate-expire",<br> "noncurrent_version_expiration": 90,<br> "prefix": null<br> }<br>]</pre> | no |
77+
| <a name="input_logging_target_bucket"></a> [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 |
78+
| <a name="input_logging_target_prefix"></a> [logging\_target\_prefix](#input\_logging\_target\_prefix) | A key prefix for log objects | `string` | `null` | no |
9979
| <a name="input_table"></a> [table](#input\_table) | Name of Dynamo Table to create | `string` | `"tf-locktable"` | no |
10080
| <a name="input_tags"></a> [tags](#input\_tags) | Mapping of any extra tags you want added to resources | `map(string)` | `{}` | no |
10181

kms.tf

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,30 @@ data "aws_iam_policy_document" "key" {
33
actions = ["kms:*"]
44
effect = "Allow"
55
resources = ["*"]
6+
67
principals {
78
type = "AWS"
89
identifiers = ["arn:aws:iam::${local.account_id}:root"]
910
}
1011
}
11-
12-
dynamic "statement" {
13-
for_each = var.allowed_account_ids
14-
15-
content {
16-
effect = "Allow"
17-
resources = ["*"]
18-
actions = [
19-
"kms:Encrypt*",
20-
"kms:Decrypt*",
21-
"kms:ReEncrypt*",
22-
"kms:GenerateDataKey*",
23-
"kms:DescribeKey",
24-
]
25-
principals {
26-
type = "AWS"
27-
identifiers = ["arn:aws:iam::${statement.value}:root"]
28-
}
29-
}
30-
}
3112
}
3213

3314
resource "aws_kms_key" "this" {
34-
count = var.kms_key_id == "" ? 1 : 0
15+
count = var.kms_key_id == "" ? 1 : 0
16+
3517
deletion_window_in_days = 7
3618
description = "Terraform State KMS key"
3719
enable_key_rotation = true
3820
policy = data.aws_iam_policy_document.key.json
39-
tags = merge(
40-
{
41-
"Name" = var.kms_alias_name != "" ? var.kms_alias_name : "tf_backend_key"
42-
},
43-
var.tags
44-
)
21+
22+
tags = merge(var.tags, {
23+
"Name" = var.kms_alias_name != null ? var.kms_alias_name : "tf_backend_key"
24+
})
4525
}
4626

4727
resource "aws_kms_alias" "this" {
48-
count = var.kms_key_id == "" ? 1 : 0
28+
count = var.kms_key_id == "" ? 1 : 0
29+
4930
name = "alias/${var.kms_alias_name != "" ? var.kms_alias_name : "tf_backend_key"}"
5031
target_key_id = aws_kms_key.this[0].id
5132
}

0 commit comments

Comments
 (0)