Skip to content

This is intended to be used by an organization for all of their own accounts. This does not protect access to DynamoDB locking of other accounts, it only restricts access S3 paths for each account. This restriction is put in place by creating a unique role for each account, then creating an assumerole policy that trusts the corresponding account…

License

Notifications You must be signed in to change notification settings

StratusGrid/terraform-aws-terraform-state-s3-bucket-centralized-with-roles

Repository files navigation

Contact Us | Stratusphere FinOps | StratusGrid Home | Blog

terraform-state-s3-bucket-centralized-with-roles

GitHub: StratusGrid/terraform-state-s3-bucket-centralized-with-roles

This is intended to be used by an organization for all of their own accounts. This does not protect access to DynamoDB locking of other accounts, it only restricts access S3 paths for each account.

This restriction is put in place by creating a unique role for each account, then attaching an assumerole policy that trusts the corresponding account to assume it. You will still need to give permission to assume roles to your users/roles that are used to apply terraform in other accounts, and configure your state appropriately to use this.

As of v3.0, all public access is blocked by default. There are individual parameters which can be set to "false" if public bucket/state access is desired:

  • block_public_acls
  • block_public_policy
  • ignore_public_acls
  • restrict_public_buckets

Example Config:

module "terraform_state_backend" {
  source  = "StratusGrid/terraform-state-s3-bucket-centralized-with-roles/aws"
  version = "~> 4.1"

  name_prefix   = "mycompany"
  log_bucket_id = module.s3_bucket_logging.bucket_id
  account_arns = [
    "arn:aws:iam::123456789012:root",
    "arn:aws:iam::098765432109:root"
  ]
  global_account_arns = ["arn:aws:iam::123456789012:root"]
  input_tags          = local.common_tags
}

output "terraform_state_kms_key_alias_arns" {
  value = module.terraform_state.kms_key_alias_arns
}

output "terraform_state_kms_key_arns" {
  value = module.terraform_state.kms_key_arns
}

output "terraform_state_iam_role_arns" {
  value = module.terraform_state.iam_role_arns
}

Example Backend Config:

terraform {
  backend "s3" {
    role_arn       = "arn:aws:iam::123456789012:role/123456789012-terraform-state"
    acl            = "bucket-owner-full-control"
    bucket         = "mycompany-remote-state-backend-anm1587s49"
    dynamodb_table = "mycompany-remote-state-backend"
    encrypt        = true
    key            = "123456789012/mycompany-account-organization-master/terraform.tfstate"
    kms_key_id     = "arn:aws:kms:us-east-1:123456789012:key/4ryh7htp-FAKE-ARNS-DUDE-777d88512345"
    region         = "us-east-1"
  }
}

Example to Initialize the backend:

terraform init -backend-config="access_key=ABCDEFGHIJKLMNOPQR" -backend-config="secret_key=AbcDeFgHIJKlmnOPqRStUVwxyZ"

NOTE: The access and secret keys used must have rights to assume the role created by the module

  • This is usually automatically the case for any keys that have full admin rights in the account whose state is to be stored, or in one of the global accounts specified.
  • Otherwise, this will need to be assigned manually. You can use this module to help with mapping those trusts: https://registry.terraform.io/modules/StratusGrid/iam-cross-account-trust-maps/aws
  • Use trusting_arn to map a single trust (like for a standard account assumption policy)
  • Use trusting_arns to map multiple trusts (like for a global account assumption policy)

Example Configuration on Global Users Account:

# This should have each terraform state role if you want a user to be able to apply terraform manually
locals {
  mycompany_organization_terraform_state_account_roles = [
    "arn:aws:iam::123456789012:role/210987654321-terraform-state",
    "arn:aws:iam::123456789012:role/123456789012-terraform-state"
  ]
}

# When require_mfa is set to true, terraform init and terraform apply would need to be run with your STS acquired temporary token
module "mycompany_organization_terraform_state_trust_maps" {
  source              = "StratusGrid/iam-role-cross-account-trusting/aws"
  version             = "~> 2.1"
  trusting_role_arns  = local.mycompany_organization_terraform_state_account_roles
  trusted_policy_name = "mycompany-organization-terraform-states"
  trusted_group_names = [
    "${aws_iam_group.mycompany_internal_admins.name}"
  ]
  trusted_role_names = []
  require_mfa        = false
  input_tags         = local.common_tags
}

Example config without trusting any other accounts

In this case, you just don't specific other accounts. Then, you use the default kms key along with the dynamodb table.

module "terraform_state" {
  source  = "StratusGrid/terraform-state-s3-bucket-centralized-with-roles/aws"
  version = "~> 5.1"

  name_prefix = var.name_prefix
  name_suffix = local.name_suffix

  log_bucket_id                       = module.s3_bucket_logging.bucket_id
  log_bucket_target_prefix            = "s3/"
  log_bucket_target_object_key_format = {
    partitioned_prefix = {
      partition_date_source = "EventTime"
    }
  }

  account_arns        = []
  global_account_arns = []

  dynamodb_table_billing_type   = "PROVISIONED"
  dynamodb_table_read_capacity  = 1
  dynamodb_table_write_capacity = 1

  input_tags = merge(local.common_tags, {})
}

output "terraform_state_kms_key_alias_arn" {
  value = module.terraform_state.kms_default_key_alias_arn
}

output "terraform_state_kms_key_arn" {
  value = module.terraform_state.kms_default_key_arn
}

Resources

Name Type
aws_dynamodb_table.remote_state_backend resource
aws_iam_policy.account_state_policy resource
aws_iam_role.account_state_role resource
aws_iam_role_policy_attachment.account_state_role resource
aws_kms_alias.remote_state_backend resource
aws_kms_alias.specific_state_backend resource
aws_kms_key.remote_state_backend resource
aws_kms_key.specific_remote_state_backend resource
aws_s3_bucket.remote_state_backend resource
aws_s3_bucket_logging.remote_state_backend resource
aws_s3_bucket_policy.remote_state_backend resource
aws_s3_bucket_public_access_block.this resource
aws_s3_bucket_server_side_encryption_configuration.remote_state_backend resource
aws_s3_bucket_versioning.remote_state_backend resource

Inputs

Name Description Type Default Required
account_arns Arns for accounts / roles in accounts which are given a role they are able to assume to access their state. list(string) [] no
aws_s3_bucket_server_side_encryption_type Selection of the bucket encryption type string "SSE_KMS" no
block_public_acls Blocks public ACLs on the bucket. bool true no
block_public_policy Whether Amazon S3 should block public bucket policies for this bucket. bool true no
dynamodb_table_billing_type Defines whether the DynamoDB table used for state locking and consistency checking should use on-demand or provisioned capacity mode. string "PAY_PER_REQUEST" no
dynamodb_table_read_capacity Defines the number of read units for the state locking and consistency table. If the dynamodb_table_billing_type is PROVISIONED, this field is required. number 0 no
dynamodb_table_write_capacity Defines the number of write units for the state locking and consistency table. If the dynamodb_table_billing_type is PROVISIONED, this field is required. number 0 no
global_account_arns Arns for a account(s) / roles in account(s) that would be allowed access to all account states, for instance a global users account. Restrictions of which of that accounts users were able to access a given state would need to be further restricted inside of the global account(s) themselves. list(string) [] no
ignore_public_acls Whether Amazon S3 should ignore public ACLs for this bucket. Causes Amazon S3 to ignore public ACLs on this bucket and any objects that it contains. bool true no
input_tags Map of tags to apply to resources map(string) {} no
log_bucket_id ID of logging bucket to be targeted for S3 bucket logs string n/a yes
log_bucket_target_object_key_format Map containing logging bucket target object key format configuration. any {} no
log_bucket_target_prefix The prefix for all log object keys. Define this varible to override the default. string "" no
name_prefix String to use as prefix on object names string n/a yes
name_suffix String to append to object names. This is optional, so start with dash if using string "" no
restrict_public_buckets Whether Amazon S3 should restrict public bucket policies for this bucket. Enabling this setting does not affect the previously stored bucket policy, except that public and cross-account access within the public bucket policy, including non-public delegation to specific accounts, is blocked. bool true no

Outputs

Name Description
bucket bucket friendly name
dynamodb_table dynamodb friendly name
iam_role_arns arns for each IAM role that can be assumend for the corresponding account's terraform state
kms_default_key_alias_arn kms key arn that is created by default. Use this when just using this for a state bucket and not from other accounts.
kms_default_key_arn kms key alias arn that is created by default. Use this when just using this for a state bucket and not from other accounts.
kms_key_alias_arns kms key alias arns for each specific account
kms_key_arns kms key arns for each specific account

Contributors

Note: Manual changes to the README will be overwritten when the documentation is updated. To update the documentation, run terraform-docs -c .config/.terraform-docs.yml .

About

This is intended to be used by an organization for all of their own accounts. This does not protect access to DynamoDB locking of other accounts, it only restricts access S3 paths for each account. This restriction is put in place by creating a unique role for each account, then creating an assumerole policy that trusts the corresponding account…

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages