From 1aa51c8a19bbbb31171df87d5c0d481e57bc9b4b Mon Sep 17 00:00:00 2001 From: Michael J Burling Date: Tue, 30 Sep 2025 08:59:04 -0500 Subject: [PATCH 01/10] Update standards for ephemeral support --- terraform/modules/standards/README.md | 7 ++++--- terraform/modules/standards/main.tf | 4 ++++ terraform/modules/standards/outputs.tf | 6 ++++++ terraform/modules/standards/terraform.tf | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/terraform/modules/standards/README.md b/terraform/modules/standards/README.md index 59082826..644416a4 100644 --- a/terraform/modules/standards/README.md +++ b/terraform/modules/standards/README.md @@ -56,8 +56,8 @@ locals { | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~>5 | -| [aws.secondary](#provider\_aws.secondary) | ~>5 | +| [aws](#provider\_aws) | ~>6 | +| [aws.secondary](#provider\_aws.secondary) | ~>6 | diff --git a/terraform/modules/standards/outputs.tf b/terraform/modules/standards/outputs.tf index e69fbf1c..fccf8e0c 100644 --- a/terraform/modules/standards/outputs.tf +++ b/terraform/modules/standards/outputs.tf @@ -10,12 +10,6 @@ output "service" { value = local.service } -output "region_name" { - description = "**Deprecated**. Use `primary_region.name`. The region name associated with the current caller identity" - sensitive = false - value = data.aws_region.this.name -} - output "primary_region" { description = "The primary data.aws_region object from the current caller identity" sensitive = false From a5a12a514c13c691a6d652ee7d373204b43bb733 Mon Sep 17 00:00:00 2001 From: Michael J Burling Date: Tue, 30 Sep 2025 11:18:58 -0500 Subject: [PATCH 03/10] Deprecate account_id, use aws_caller_identity --- terraform/modules/standards/README.md | 3 ++- terraform/modules/standards/outputs.tf | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/terraform/modules/standards/README.md b/terraform/modules/standards/README.md index d8af21a9..55e7e6ca 100644 --- a/terraform/modules/standards/README.md +++ b/terraform/modules/standards/README.md @@ -117,8 +117,9 @@ No modules. | Name | Description | |------|-------------| -| [account\_id](#output\_account\_id) | The AWS account ID associated with the current caller identity | +| [account\_id](#output\_account\_id) | Deprecated. Use `aws_caller_identity.account_id`. The AWS account ID associated with the current caller identity | | [app](#output\_app) | The short name for the delivery team or ADO. | +| [aws\_caller\_identity](#output\_aws\_caller\_identity) | The current data.aws\_caller\_identity object. | | [default\_permissions\_boundary](#output\_default\_permissions\_boundary) | Default permissions boundary [aws\_iam\_policy data source](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy#attribute-reference) | | [default\_tags](#output\_default\_tags) | Map of tags for use in AWS provider block `default_tags`. Merges collection of standard tags with optional, user-specificed `additional_tags` | | [env](#output\_env) | The solution's application environment name. | diff --git a/terraform/modules/standards/outputs.tf b/terraform/modules/standards/outputs.tf index fccf8e0c..5574d6b6 100644 --- a/terraform/modules/standards/outputs.tf +++ b/terraform/modules/standards/outputs.tf @@ -23,11 +23,17 @@ output "secondary_region" { } output "account_id" { - description = "The AWS account ID associated with the current caller identity" + description = "Deprecated. Use `aws_caller_identity.account_id`. The AWS account ID associated with the current caller identity" sensitive = true value = data.aws_caller_identity.this.account_id } +output "aws_caller_identity" { + description = "The current data.aws_caller_identity object." + sensitive = true + value = data.aws_caller_identity.this +} + output "env" { description = "The solution's application environment name." sensitive = false From b35e0db37e0fb821fb5e8189f5a61c91e63be0e2 Mon Sep 17 00:00:00 2001 From: Michael J Burling Date: Tue, 30 Sep 2025 15:22:29 -0500 Subject: [PATCH 04/10] PLT-1224: Initial Management of DASG Insights --- terraform/services/insights/mgmt/README.md | 85 +++++++++++++++++++ terraform/services/insights/mgmt/iam.tf | 32 +++++++ terraform/services/insights/mgmt/main.tf | 50 +++++++++++ .../services/insights/mgmt/quicksight.tf | 15 ++++ terraform/services/insights/mgmt/terraform.tf | 20 +++++ .../insights/mgmt/values/mgmt.sopsw.yaml | 17 ++++ 6 files changed, 219 insertions(+) create mode 100644 terraform/services/insights/mgmt/README.md create mode 100644 terraform/services/insights/mgmt/iam.tf create mode 100644 terraform/services/insights/mgmt/main.tf create mode 100644 terraform/services/insights/mgmt/quicksight.tf create mode 100644 terraform/services/insights/mgmt/terraform.tf create mode 100644 terraform/services/insights/mgmt/values/mgmt.sopsw.yaml diff --git a/terraform/services/insights/mgmt/README.md b/terraform/services/insights/mgmt/README.md new file mode 100644 index 00000000..2cde4a1c --- /dev/null +++ b/terraform/services/insights/mgmt/README.md @@ -0,0 +1,85 @@ +# CDAP Insights Management Environment + +This root module configures the fundamental platform resources in the AWS DASG Insights account, including IAM, QuickSight, and SSM Parameters. + +## Dependencies +- `services/kms-keys` +- `services/bucket-access-logging` +- `services/tfstate` + +## Bootstrapping + +This module is intended to serve the single `mgmt` environment. Initialization is done through the following: + +```sh +tofu init -backend-config="../../../backends/cdap-insights-mgmt.s3.hcl" +``` + + + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | 6.14.1 | +| [aws.secondary](#provider\_aws.secondary) | 6.14.1 | + + +## Requirements + +No requirements. + + +## Inputs + +No inputs. + + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [sops](#module\_sops) | ../../../modules/sops | n/a | +| [standards](#module\_standards) | ../../../modules/standards | n/a | + + +## Resources + +| Name | Type | +|------|------| +| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_quicksight_account_settings.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/quicksight_account_settings) | resource | +| [aws_quicksight_ip_restriction.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/quicksight_ip_restriction) | resource | +| [aws_kms_alias.primary](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_kms_alias.secondary](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | + + +## Outputs + +No outputs. + diff --git a/terraform/services/insights/mgmt/iam.tf b/terraform/services/insights/mgmt/iam.tf new file mode 100644 index 00000000..8972d67d --- /dev/null +++ b/terraform/services/insights/mgmt/iam.tf @@ -0,0 +1,32 @@ +resource "aws_iam_role" "this" { + assume_role_policy = jsonencode( + { + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "quicksight.amazonaws.com" + } + }, + ] + Version = "2012-10-17" + } + ) + force_detach_policies = true + max_session_duration = 3600 + name = "${local.service_prefix}-quicksight-service" + path = "/service-role/" +} + +# Basic Policy Attachments, Further Attachments Necessary +resource "aws_iam_role_policy_attachment" "this" { + for_each = toset([ + "arn:aws:iam::aws:policy/service-role/AmazonSageMakerQuickSightVPCPolicy", #AWS-managed, allowing CRUD on ENIs, Limited VPC Resources + "arn:aws:iam::aws:policy/service-role/AWSQuickSightListIAM", #AWS-managed, allows `iam:List*` + "arn:aws:iam::aws:policy/service-role/AWSQuicksightAthenaAccess", #AWS-managed, allows access to glue, athena, and athena-related s3 resources + ]) + + role = aws_iam_role.this.name + policy_arn = each.value +} diff --git a/terraform/services/insights/mgmt/main.tf b/terraform/services/insights/mgmt/main.tf new file mode 100644 index 00000000..bdd1058e --- /dev/null +++ b/terraform/services/insights/mgmt/main.tf @@ -0,0 +1,50 @@ +locals { + app = "cdap" + env = "mgmt" + service = "insights" + service_prefix = "${local.app}-${local.env}-${local.service}" + account_id = module.standards.aws_caller_identity.id + + kms_key_aliases = { + kms_alias_primary = data.aws_kms_alias.primary, + kms_alias_secondary = data.aws_kms_alias.secondary + } + + cdap_ssm = zipmap( + data.aws_ssm_parameters_by_path.cdap.names, + data.aws_ssm_parameters_by_path.cdap.values + ) + + ip_restrictions = jsondecode(lookup(nonsensitive(local.cdap_ssm), "/cdap/mgmt/insights/sensitive/ip-restrictions", "{}")) +} + +module "standards" { + source = "../../../modules/standards" #TODO: Update with appropriate reference + + app = local.app + env = local.env + root_module = "https://github.com/CMSgov/cdap/tree/main/terraform/services/insights/mgmt" + service = local.service + providers = { aws = aws, aws.secondary = aws.secondary } +} + +data "aws_kms_alias" "primary" { + name = "alias/${local.app}-${local.env}" +} + +data "aws_kms_alias" "secondary" { + provider = aws.secondary + name = "alias/${local.app}-${local.env}" +} + +module "sops" { + source = "../../../modules/sops" #TODO: Update with appropriate reference + + platform = merge(module.standards, local.kms_key_aliases) +} + +data "aws_ssm_parameters_by_path" "cdap" { + path = "/cdap" + recursive = true + with_decryption = true +} diff --git a/terraform/services/insights/mgmt/quicksight.tf b/terraform/services/insights/mgmt/quicksight.tf new file mode 100644 index 00000000..25df1bac --- /dev/null +++ b/terraform/services/insights/mgmt/quicksight.tf @@ -0,0 +1,15 @@ +resource "aws_quicksight_account_settings" "this" { + aws_account_id = local.account_id + default_namespace = "default" + termination_protection_enabled = true +} + +resource "aws_quicksight_ip_restriction" "this" { + enabled = length(local.ip_restrictions) > 0 + + ip_restriction_rule_map = local.ip_restrictions + + depends_on = [ + module.sops + ] +} diff --git a/terraform/services/insights/mgmt/terraform.tf b/terraform/services/insights/mgmt/terraform.tf new file mode 100644 index 00000000..7c93cf58 --- /dev/null +++ b/terraform/services/insights/mgmt/terraform.tf @@ -0,0 +1,20 @@ +terraform { + backend "s3" { + key = "insights/mgmt/terraform.tfstate" + } +} + +provider "aws" { + region = "us-east-1" + default_tags { + tags = module.standards.default_tags + } +} + +provider "aws" { + alias = "secondary" + region = "us-west-2" + default_tags { + tags = module.standards.default_tags + } +} diff --git a/terraform/services/insights/mgmt/values/mgmt.sopsw.yaml b/terraform/services/insights/mgmt/values/mgmt.sopsw.yaml new file mode 100644 index 00000000..a8a0f5b5 --- /dev/null +++ b/terraform/services/insights/mgmt/values/mgmt.sopsw.yaml @@ -0,0 +1,17 @@ +/cdap/mgmt/insights/sensitive/production-account: ENC[AES256_GCM,data:Q4IQ10q1U9Z9LHsV,iv:msDZEXCE1nDfDiT5OCwSy6P6Ux2+rg88MlPgBotKEGA=,tag:Ux+aJ1iwcf8dVu4v4gStXA==,type:int] +/cdap/mgmt/insights/sensitive/ip-restrictions: ENC[AES256_GCM,data:TH/Wefc/8xxF9qB+q/rp9iqhCBewzvz5K0o=,iv:0zj/O2MYd2hrbAZjpf/19f6ux/BVbEFawA6PujTVrn8=,tag:EoYOTqJjTS5eOM7RQHWC6w==,type:str] +/bb2/mgmt/insights/sensitive/production-account: ENC[AES256_GCM,data:DcCO+t2uT1KbBvLG,iv:ExMspQ9CN5hq8bPLFL5KKWiDuI6yXpTnLSf6kZQ4fQM=,tag:XmksqLTyohSNBxS6J6p38A==,type:int] +/bfd/mgmt/insights/sensitive/production-account: ENC[AES256_GCM,data:7+mpZZm1qvASmcTs,iv:mh1lrbiSGpT+yR+6QrlcHWlnWd3oFZr9wm40Y0RBEhQ=,tag:5do/BZFSoOrLIKcch78/Ug==,type:int] +sops: + kms: + - arn: arn:aws:kms:us-east-1:${ACCOUNT_ID}:alias/cdap-mgmt + created_at: "2025-09-30T19:13:00Z" + enc: AQICAHiKQjEEYvJPdywF5tXeCz/FMh8ciiBXHJWYytbH1uw6WAHXW/jBPCgfFFvNAduurTWAAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMYzrROySfTwxycQu4AgEQgDuf5uH3iGb0blD2+r43vtd6R77A+/Zk77BfVhHGC03I0Qm7EqgdymL6cntCAeMxbybefBN3BKWFVWYD+w== + aws_profile: "" + - arn: arn:aws:kms:us-west-2:${ACCOUNT_ID}:alias/cdap-mgmt + created_at: "2025-09-30T19:13:00Z" + enc: AQICAHgWPUweNgOZBy54eQNTANw37AMcHppSZnWTksh1eOtc+wGh8N9L+gMCpKxWGdj0ob8ZAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMJT/PBEbyPHJ4h8cgAgEQgDuOyZxSH2R8GQiz8eqcDM2X8xuWxvpC0pYAaH+KJ64dWv6DEGJ7i0luLQ+dqFTGV6/aAeG5d+ybjzNFFg== + aws_profile: "" + unencrypted_regex: /nonsensitive/ + mac_only_encrypted: true + version: 3.10.2 From dd80885da897017fdfc0ff6aae2df7e819c22761 Mon Sep 17 00:00:00 2001 From: Michael J Burling Date: Wed, 1 Oct 2025 09:44:09 -0500 Subject: [PATCH 05/10] Add parent_env to standards output --- terraform/modules/standards/README.md | 5 +++-- terraform/modules/standards/outputs.tf | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/terraform/modules/standards/README.md b/terraform/modules/standards/README.md index 55e7e6ca..1f38539c 100644 --- a/terraform/modules/standards/README.md +++ b/terraform/modules/standards/README.md @@ -56,8 +56,8 @@ locals { | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~>6 | -| [aws.secondary](#provider\_aws.secondary) | ~>6 | +| [aws](#provider\_aws) | 6.14.1 | +| [aws.secondary](#provider\_aws.secondary) | 6.14.1 |