diff --git a/terraform/backends/cdap-insights-mgmt.s3.hcl b/terraform/backends/cdap-insights-mgmt.s3.hcl
new file mode 100644
index 00000000..61b08ed7
--- /dev/null
+++ b/terraform/backends/cdap-insights-mgmt.s3.hcl
@@ -0,0 +1,2 @@
+bucket = "cdap-mgmt-tfstate-20250930180004007700000001"
+use_lockfile = true
diff --git a/terraform/modules/bucket/main.tf b/terraform/modules/bucket/main.tf
index 777937b4..179ba54f 100644
--- a/terraform/modules/bucket/main.tf
+++ b/terraform/modules/bucket/main.tf
@@ -1,8 +1,9 @@
-module "bucket_key" {
- source = "../key"
- name = "${var.name}-bucket"
- description = "For ${var.name} S3 bucket and its access logs"
- user_roles = var.cross_account_read_roles
+locals {
+ cdap_ssm = zipmap(
+ data.aws_ssm_parameters_by_path.cdap.names,
+ data.aws_ssm_parameters_by_path.cdap.values
+ )
+ access_logs_bucket = lookup(local.cdap_ssm, "/cdap/bucket-access-logs-bucket", null)
}
resource "aws_s3_bucket" "this" {
@@ -99,19 +100,24 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
}
}
-data "aws_iam_account_alias" "current" {}
+data "aws_ssm_parameters_by_path" "cdap" {
+ path = "/cdap"
+ recursive = true
+}
data "aws_s3_bucket" "bucket_access_logs" {
- bucket = (data.aws_iam_account_alias.current.account_alias == "aws-cms-oeda-bcda-prod"
- ? "bucket-access-logs-20250411172631068600000001"
- : "bucket-access-logs-20250409172631068600000001"
- )
+ count = local.access_logs_bucket == null ? 0 : 1
+
+ bucket = local.access_logs_bucket
}
+
resource "aws_s3_bucket_logging" "this" {
+ count = local.access_logs_bucket == null ? 0 : 1
+
bucket = aws_s3_bucket.this.id
- target_bucket = data.aws_s3_bucket.bucket_access_logs.id
+ target_bucket = data.aws_s3_bucket.bucket_access_logs[0].id
target_prefix = "${aws_s3_bucket.this.id}/"
}
diff --git a/terraform/modules/bucket/outputs.tf b/terraform/modules/bucket/outputs.tf
index 0e72aae4..7be085a8 100644
--- a/terraform/modules/bucket/outputs.tf
+++ b/terraform/modules/bucket/outputs.tf
@@ -12,18 +12,3 @@ output "id" {
description = "ID for the S3 bucket"
value = aws_s3_bucket.this.id
}
-
-output "key_alias" {
- description = "Key Alias for this bucket"
- value = module.bucket_key.alias
-}
-
-output "key_arn" {
- description = "KEY ARN for this bucket"
- value = module.bucket_key.arn
-}
-
-output "key_id" {
- description = "KEY identifier for this bucket"
- value = module.bucket_key.id
-}
diff --git a/terraform/modules/platform/README.md b/terraform/modules/platform/README.md
index 1cb5714b..dce08063 100644
--- a/terraform/modules/platform/README.md
+++ b/terraform/modules/platform/README.md
@@ -152,7 +152,6 @@ No modules.
| [primary\_region](#output\_primary\_region) | The primary data.aws\_region object from the current caller identity |
| [private\_subnets](#output\_private\_subnets) | Map of current VPC **private** [aws\_subnet data sources](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet), keyed by `subnet_id` |
| [public\_subnets](#output\_public\_subnets) | Map of current VPC **public** [aws\_subnet data sources](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet), keyed by `id` |
-| [region\_name](#output\_region\_name) | **Deprecated**. Use `primary_region.name`. The region name associated with the current caller identity |
| [sdlc\_env](#output\_sdlc\_env) | The SDLC (production vs non-production) environment. |
| [secondary\_region](#output\_secondary\_region) | The secondary data.aws\_region object associated with the secondary region. |
| [security\_groups](#output\_security\_groups) | Map of current VPC's common [aws\_security\_group data sources](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/security_group#attribute-reference), keyed by `name` |
diff --git a/terraform/modules/platform/outputs.tf b/terraform/modules/platform/outputs.tf
index 246e7621..514b0898 100644
--- a/terraform/modules/platform/outputs.tf
+++ b/terraform/modules/platform/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.primary.name
-}
-
output "primary_region" {
description = "The primary data.aws_region object from the current caller identity"
sensitive = false
diff --git a/terraform/modules/standards/README.md b/terraform/modules/standards/README.md
index 59082826..1f38539c 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.14.1 |
+| [aws.secondary](#provider\_aws.secondary) | 6.14.1 |
diff --git a/terraform/modules/standards/main.tf b/terraform/modules/standards/main.tf
index 26bd2c62..53022807 100644
--- a/terraform/modules/standards/main.tf
+++ b/terraform/modules/standards/main.tf
@@ -4,10 +4,14 @@ locals {
root_module = var.root_module
service = var.service
+ established_envs = ["test", "dev", "sandbox", "prod", "mgmt"]
+ parent_env = one([for x in local.established_envs : x if can(regex("${x}$$", local.env))])
+
static_tags = {
application = local.app
business = "oeda"
environment = local.env
+ parent_env = local.parent_env
service = local.service
terraform = true
tf_root_module = local.root_module
diff --git a/terraform/modules/standards/outputs.tf b/terraform/modules/standards/outputs.tf
index 299499aa..79fdd0ba 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
@@ -29,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
@@ -51,3 +51,15 @@ output "default_permissions_boundary" {
sensitive = false
value = data.aws_iam_policy.permissions_boundary
}
+
+output "is_ephemeral_env" {
+ description = "Returns true when environment is _ephemeral_, false when _established_"
+ sensitive = false
+ value = local.env != local.parent_env
+}
+
+output "parent_env" {
+ description = "The solution's source environment. For established environments this is equal to the environment's name"
+ sensitive = false
+ value = local.parent_env
+}
diff --git a/terraform/modules/standards/terraform.tf b/terraform/modules/standards/terraform.tf
index bd633a74..0885f73d 100644
--- a/terraform/modules/standards/terraform.tf
+++ b/terraform/modules/standards/terraform.tf
@@ -2,7 +2,7 @@ terraform {
required_providers {
aws = {
source = "hashicorp/aws"
- version = "~>5"
+ version = "~>6"
configuration_aliases = [aws.secondary]
}
}
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
diff --git a/terraform/services/kms-keys/main.tf b/terraform/services/kms-keys/main.tf
index ef97ef5e..c6e64262 100644
--- a/terraform/services/kms-keys/main.tf
+++ b/terraform/services/kms-keys/main.tf
@@ -1,9 +1,11 @@
module "standards" {
- source = "github.com/CMSgov/cdap//terraform/modules/standards?ref=0bd3eeae6b03cc8883b7dbdee5f04deb33468260"
+ source = "../../modules/standards" #TODO: Update with appropriate reference
+
app = var.app
env = var.env
root_module = "https://github.com/CMSgov/cdap/tree/main/terraform/services/kms-keys"
service = "kms-keys"
+ providers = { aws = aws, aws.secondary = aws.secondary }
}
locals {
diff --git a/terraform/services/tfstate/main.tf b/terraform/services/tfstate/main.tf
index 748f77e8..71169e4d 100644
--- a/terraform/services/tfstate/main.tf
+++ b/terraform/services/tfstate/main.tf
@@ -1,11 +1,23 @@
locals {
- name = "${var.app}-${var.env}-tfstate"
+ app = var.app
+ env = var.env
+ name = "${local.app}-${local.env}-tfstate"
+}
+
+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/tfstate"
+ service = "tfstate"
+ providers = { aws = aws, aws.secondary = aws.secondary }
}
module "tfstate_bucket" {
- source = "../../modules/bucket"
+ source = "../../modules/bucket" #TODO: Update with appropriate reference
name = local.name
- app = var.app
- env = var.env
+ app = local.app
+ env = local.env
}
diff --git a/terraform/services/tfstate/terraform.tf b/terraform/services/tfstate/terraform.tf
index 6479a5f5..d2d58983 100644
--- a/terraform/services/tfstate/terraform.tf
+++ b/terraform/services/tfstate/terraform.tf
@@ -1,16 +1,19 @@
+terraform {
+ backend "s3" {
+ key = "tfstate/terraform.tfstate"
+ }
+}
+
provider "aws" {
default_tags {
- tags = {
- Terraform = true
- business = "oeda"
- code = "https://github.com/CMSgov/cdap/tree/main/terraform/services/tfstate"
- }
+ tags = module.standards.default_tags
}
}
-terraform {
- # Comment out backend block and init without -backend-config for initial creation of resources
- backend "s3" {
- key = "tfstate/terraform.tfstate"
+provider "aws" {
+ alias = "secondary"
+ region = "us-west-2"
+ default_tags {
+ tags = module.standards.default_tags
}
}