Skip to content
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1aa51c8
Update standards for ephemeral support
mjburling Sep 30, 2025
b264343
Remove deprecated region_name output
mjburling Sep 30, 2025
a5a12a5
Deprecate account_id, use aws_caller_identity
mjburling Sep 30, 2025
b35e0db
PLT-1224: Initial Management of DASG Insights
mjburling Sep 30, 2025
dd80885
Add parent_env to standards output
mjburling Oct 1, 2025
2b23d9b
Remove bucket_key module declaration, outputs
mjburling Oct 1, 2025
05383e7
Lookup access bucket logging via SSM
mjburling Oct 1, 2025
b128ca0
Add backend for cdap's insights mgmt environment
mjburling Oct 1, 2025
cecd277
Use path relative standards reference, temporarily
mjburling Oct 1, 2025
852b37f
Use temporary standards module; tidy
mjburling Oct 1, 2025
0b71d36
Merge branch 'main' into burling/plt-1224
gsf Dec 2, 2025
8d0ed4e
Move tf to root of insights service
gsf Dec 5, 2025
726e8f7
Add dasg-insights-prod environment to tofu-plan and tofu-apply
gsf Dec 12, 2025
ba35ce1
Correct module refs from move
gsf Dec 12, 2025
1a01ed3
Disable IP restriction
gsf Dec 12, 2025
3d3e682
Add conf.sh for dasg-insights
gsf Dec 12, 2025
a4a6f23
Move insights service to dasg-insights
gsf Dec 12, 2025
14e35b8
Add dasg-insights to account target env
gsf Dec 12, 2025
c461304
Merge branch 'main' into burling/plt-1224
gsf Jan 13, 2026
39e44d0
Switch app name from dasg-insights to insights
gsf Jan 13, 2026
997191e
Switch to INSIGHTS_ACCOUNT for account ID secret
gsf Jan 13, 2026
ce0b25c
Move service from dasg-insights to insights
gsf Feb 13, 2026
77fd022
Switch environment to insights-mgmt
gsf Feb 13, 2026
069dd40
Switch app references to dasg-insights
gsf Feb 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions terraform/backends/cdap-insights-mgmt.s3.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bucket = "cdap-mgmt-tfstate-20250930180004007700000001"
use_lockfile = true
28 changes: 17 additions & 11 deletions terraform/modules/bucket/main.tf
Original file line number Diff line number Diff line change
@@ -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
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change probably shouldn't be accepted until other module declaration sources of the modules/bucket child are pinned to existing references.

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" {
Expand Down Expand Up @@ -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
}
Comment on lines +104 to +107
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the aws_ssm_parameters_by_path data source allows for empty results. Paired with the call to the zipmap() in local.cdap_ssm and the lookup() on the same for local.access_logs_bucket, this helps us avoid failures on missing configuration and obviates the need for hard-coding bucket-access-logs buckets.


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}/"
}

Expand Down
15 changes: 0 additions & 15 deletions terraform/modules/bucket/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
1 change: 0 additions & 1 deletion terraform/modules/platform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ No modules.
| <a name="output_primary_region"></a> [primary\_region](#output\_primary\_region) | The primary data.aws\_region object from the current caller identity |
| <a name="output_private_subnets"></a> [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` |
| <a name="output_public_subnets"></a> [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` |
| <a name="output_region_name"></a> [region\_name](#output\_region\_name) | **Deprecated**. Use `primary_region.name`. The region name associated with the current caller identity |
| <a name="output_sdlc_env"></a> [sdlc\_env](#output\_sdlc\_env) | The SDLC (production vs non-production) environment. |
| <a name="output_secondary_region"></a> [secondary\_region](#output\_secondary\_region) | The secondary data.aws\_region object associated with the secondary region. |
| <a name="output_security_groups"></a> [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` |
Expand Down
6 changes: 0 additions & 6 deletions terraform/modules/platform/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 7 additions & 5 deletions terraform/modules/standards/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ locals {

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | ~>5 |
| <a name="provider_aws.secondary"></a> [aws.secondary](#provider\_aws.secondary) | ~>5 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | 6.14.1 |
| <a name="provider_aws.secondary"></a> [aws.secondary](#provider\_aws.secondary) | 6.14.1 |

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Expand All @@ -68,7 +68,7 @@ locals {

| Name | Version |
|------|---------|
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~>5 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~>6 |

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Expand Down Expand Up @@ -117,13 +117,15 @@ No modules.

| Name | Description |
|------|-------------|
| <a name="output_account_id"></a> [account\_id](#output\_account\_id) | The AWS account ID associated with the current caller identity |
| <a name="output_account_id"></a> [account\_id](#output\_account\_id) | Deprecated. Use `aws_caller_identity.account_id`. The AWS account ID associated with the current caller identity |
| <a name="output_app"></a> [app](#output\_app) | The short name for the delivery team or ADO. |
| <a name="output_aws_caller_identity"></a> [aws\_caller\_identity](#output\_aws\_caller\_identity) | The current data.aws\_caller\_identity object. |
| <a name="output_default_permissions_boundary"></a> [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) |
| <a name="output_default_tags"></a> [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` |
| <a name="output_env"></a> [env](#output\_env) | The solution's application environment name. |
| <a name="output_is_ephemeral_env"></a> [is\_ephemeral\_env](#output\_is\_ephemeral\_env) | Returns true when environment is \_ephemeral\_, false when \_established\_ |
| <a name="output_parent_env"></a> [parent\_env](#output\_parent\_env) | The solution's source environment. For established environments this is equal to the environment's name |
| <a name="output_primary_region"></a> [primary\_region](#output\_primary\_region) | The primary data.aws\_region object from the current caller identity |
| <a name="output_region_name"></a> [region\_name](#output\_region\_name) | **Deprecated**. Use `primary_region.name`. The region name associated with the current caller identity |
| <a name="output_secondary_region"></a> [secondary\_region](#output\_secondary\_region) | The secondary data.aws\_region object associated with the secondary region. |
| <a name="output_service"></a> [service](#output\_service) | The name of the current service or terraservice. |
<!-- END_TF_DOCS -->
4 changes: 4 additions & 0 deletions terraform/modules/standards/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 19 additions & 7 deletions terraform/modules/standards/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Comment on lines -13 to -18
Copy link
Copy Markdown
Member Author

@mjburling mjburling Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change.

As noted, this was already deprecated in favor of the primary_region output. With updates to aws provider version 6, data.aws_region has a deprecated name and an attribute, in favor of region, so... references like this would be most correct as data.aws_region.this.region. ¯\_(ツ)_/¯

output "primary_region" {
description = "The primary data.aws_region object from the current caller identity"
sensitive = false
Expand All @@ -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
}
Comment on lines 25 to 29
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecating account_id to match how the platform module surfaces this. It might be interesting to start using the opentofu-specific deprecation fields once we're confident that all terraform is executed under opentofu....


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
Expand All @@ -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
}
2 changes: 1 addition & 1 deletion terraform/modules/standards/terraform.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~>5"
version = "~>6"
configuration_aliases = [aws.secondary]
}
}
Expand Down
85 changes: 85 additions & 0 deletions terraform/services/insights/mgmt/README.md
Original file line number Diff line number Diff line change
@@ -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"
```

<!-- BEGIN_TF_DOCS -->
<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 6.14.1 |
| <a name="provider_aws.secondary"></a> [aws.secondary](#provider\_aws.secondary) | 6.14.1 |

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Requirements

No requirements.

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Inputs

No inputs.

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_sops"></a> [sops](#module\_sops) | ../../../modules/sops | n/a |
| <a name="module_standards"></a> [standards](#module\_standards) | ../../../modules/standards | n/a |

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## 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 |

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Outputs

No outputs.
<!-- END_TF_DOCS -->
32 changes: 32 additions & 0 deletions terraform/services/insights/mgmt/iam.tf
Original file line number Diff line number Diff line change
@@ -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
}
50 changes: 50 additions & 0 deletions terraform/services/insights/mgmt/main.tf
Original file line number Diff line number Diff line change
@@ -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
}
15 changes: 15 additions & 0 deletions terraform/services/insights/mgmt/quicksight.tf
Original file line number Diff line number Diff line change
@@ -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
]
}
Loading