From 4e45e182751d7f103d09e81c25510de16d47af62 Mon Sep 17 00:00:00 2001 From: badra001 Date: Mon, 14 Jul 2025 14:23:04 -0400 Subject: [PATCH] add files for example application tfstate --- .../data.tfstate-policy.tf | 26 ++++++ .../remote_state.tf.txt | 16 ++++ .../remote_state.yml.txt | 12 +++ .../tfstate-policy.tf | 89 +++++++++++++++++++ .../variables.tfstate-policy.tf | 49 ++++++++++ 5 files changed, 192 insertions(+) create mode 100644 examples/application-terraform-state/data.tfstate-policy.tf create mode 100644 examples/application-terraform-state/remote_state.tf.txt create mode 100644 examples/application-terraform-state/remote_state.yml.txt create mode 100644 examples/application-terraform-state/tfstate-policy.tf create mode 100644 examples/application-terraform-state/variables.tfstate-policy.tf diff --git a/examples/application-terraform-state/data.tfstate-policy.tf b/examples/application-terraform-state/data.tfstate-policy.tf new file mode 100644 index 0000000..135f628 --- /dev/null +++ b/examples/application-terraform-state/data.tfstate-policy.tf @@ -0,0 +1,26 @@ +data "aws_caller_identity" "tfstate" {} + +data "aws_arn" "tfstate" { + arn = data.aws_caller_identity.tfstate.arn +} + +data "aws_region" "tfstate" {} + +data "aws_iam_account_alias" "tfstate" {} + + +# output "caller_account_id" { +# value = data.aws_caller_identity.tfstate.account_id +# } +# +# output "account_caller_arn" { +# value = data.aws_caller_identity.tfstate.arn +# } +# +# output "account_caller_arn_partition" { +# value = data.aws_arn.tfstate.partition +# } +# +# output "account_alias" { +# value = data.aws_iam_account_alias.tfstate.account_alias +# } diff --git a/examples/application-terraform-state/remote_state.tf.txt b/examples/application-terraform-state/remote_state.tf.txt new file mode 100644 index 0000000..de4c7bd --- /dev/null +++ b/examples/application-terraform-state/remote_state.tf.txt @@ -0,0 +1,16 @@ +# example for ma25-gov, application ditd-dso + +# all files start in the main tfstate bucket, in a prefix with the alias, followed by +# applications, the app name (from the business label from NTS), followed by custom. +# next would be any subdirectory. + +# base custom terraform state +terraform { + backend "s3" { + profile = "272733779579-ma25-gov" + bucket = "inf-tfstate-272733779579" + key = "ma25-gov/applications/ditd-dso/custom/terraform.tfstate" + region = "us-gov-east-1" + dynamodb_table = "tf_remote_state" + } +} diff --git a/examples/application-terraform-state/remote_state.yml.txt b/examples/application-terraform-state/remote_state.yml.txt new file mode 100644 index 0000000..e5f301e --- /dev/null +++ b/examples/application-terraform-state/remote_state.yml.txt @@ -0,0 +1,12 @@ +# example for ma25-gov, application ditd-dso, "top" level directory of the TF structure for the application + +bucket: "inf-tfstate-272733779579" +bucket_region: "us-gov-east-1" +directory: "applications/ditd-dso/custom" +profile: "272733779579-ma25-gov" +region: "us-gov-east-1" +regions: ["us-gov-east-1"] +account_id: "272733779579" +account_alias: "ma25-gov" +aws_environment: "govcloud" + diff --git a/examples/application-terraform-state/tfstate-policy.tf b/examples/application-terraform-state/tfstate-policy.tf new file mode 100644 index 0000000..ca88bdd --- /dev/null +++ b/examples/application-terraform-state/tfstate-policy.tf @@ -0,0 +1,89 @@ +locals { + tfstate_bucket = var.tfstate_bucket != null ? var.tfstate_bucket : format("inf-terraform-%v", data.aws_caller_identity.tfstate.account_id) + tfstate_key_prefix = var.tfstate_key_prefix != null ? var.tfstate_key_prefix : data.aws_iam_account_alias.tfstate.account_alias +} + +data "aws_s3_bucket" "tfstate" { + bucket = var.tfstate_bucket +} + +data "aws_dynamodb_table" "tfstate" { + name = var.tfstate_table +} + +data "aws_kms_key" "tfstate" { + key_id = format("alias/%v", var.kms_tfstate_key) +} + +resource "aws_iam_policy" "tfstate" { + name = format("p-%v-tfstate", var.tfstate_app_name) + path = "/" + description = format("Access to tfstate resources (write) for %v", var.tfstate_app_name) + policy = data.aws_iam_policy_document.tfstate.json +} + +data "aws_iam_policy_document" "tfstate" { + statement { + sid = "TFRemoteStateList" + effect = "Allow" + resources = [data.aws_s3_bucket.tfstate.arn] + actions = ["s3:ListBucket"] + } + statement { + sid = "TFRemoteState" + effect = "Allow" + resources = [ + format("%v/%v/applications/%v/custom", data.aws_s3_bucket.tfstate.arn, var.tfstate_key_prefix, var.tfstate_app_name), + format("%v/%v/applications/%v/custom/*", data.aws_s3_bucket.tfstate.arn, var.tfstate_key_prefix, var.tfstate_app_name), + ] + actions = [ + "s3:List*", + "s3:GetObject", + "s3:PutObject", + ] + } + statement { + sid = "TFRemoteStateDDB" + effect = "Allow" + resources = [data.aws_dynamodb_table.tfstate.arn] + actions = [ + "dynamodb:GetItem", + "dynamodb:PutItem", + "dynamodb:DeleteItem", + ] + condition { + test = "ForAllValues:StringLike" + variable = "dynamodb:LeadingKeys" + values = [ + format("%v/%v/applications/%v/custom/*", var.tfstate_bucket, var.tfstate_key_prefix, var.tfstate_app_name), + format("%v/%v/applications/%v/custom", var.tfstate_bucket, var.tfstate_key_prefix, var.tfstate_app_name), + ] + } + } + statement { + sid = "TFStateKMSUse" + effect = "Allow" + actions = [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey", + ] + resources = [data.aws_kms_key.tfstate.arn] + } +} + + +## ddb item format +## { +## "Item": { +## "Digest": { +## "S": "4cdf3505508cd5c99462ea4d3060cac5" +## }, +## "LockID": { +## "S": "inf-tfstate-107742151971/do2-govcloud/common/apps/ditd-gups/terraform.tfstate-md5" +## } +## } +## } +## diff --git a/examples/application-terraform-state/variables.tfstate-policy.tf b/examples/application-terraform-state/variables.tfstate-policy.tf new file mode 100644 index 0000000..7d1c2d1 --- /dev/null +++ b/examples/application-terraform-state/variables.tfstate-policy.tf @@ -0,0 +1,49 @@ +#--- +# tfstate-policy +#--- +variable "kms_tfstate_key" { + description = "Terraform remote state KMS key alias" + type = string + default = "k-kms-inf-tfstate" +} + +variable "tfstate_table" { + description = "Terraform remote state table" + type = string + default = "tf_remote_state" +} + +variable "tfstate_bucket" { + description = "Terraform remote state S3 bucket" + type = string + # default = "inf-tfstate-107742151971" + default = null +} + +variable "tfstate_key_prefix" { + description = "Terraform remote state S3 bucket prefix" + type = string + # default = "do2-govcloud" + default = null +} + +variable "tfstate_key_suffix" { + description = "Terraform remote state S3 bucket suffix" + type = string + default = "terraform.tfstate" +} + +# this is needed when we do multi-region stuff +variable "tfstate_region" { + description = "Terraform remote state S3 bucket region" + type = string + default = "us-gov-east-1" +} + +#--- +# application stuff +#--- +variable "tfstate_app_name" { + description = "Application Name {org}-{app}[-{env}] (env is optional) from the base label format of NTS" + type = string +}