diff --git a/.github/workflows/tf-config.yml b/.github/workflows/tf-config.yml
new file mode 100644
index 00000000..85c18e14
--- /dev/null
+++ b/.github/workflows/tf-config.yml
@@ -0,0 +1,64 @@
+name: tf-config
+run-name: tf-config ${{ (inputs.apply || (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'schedule') && 'apply' || 'plan' }}
+
+on:
+ push:
+ paths:
+ - .github/workflows/tf-config.yml
+ - terraform/services/config/**
+ schedule:
+ - cron: "12 14 * * 1-5"
+ workflow_dispatch:
+ inputs:
+ apply:
+ required: false
+ type: boolean
+ description: "Apply the terraform?"
+
+env:
+ TENV_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+defaults:
+ run:
+ working-directory: ./terraform/services/config
+
+jobs:
+ check-fmt:
+ runs-on: codebuild-cdap-${{github.run_id}}-${{github.run_attempt}}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2
+ - uses: cmsgov/cdap/actions/setup-tenv@8343fb96563ce4b74c4dececee9b268f42bd4a40
+ - run: tofu fmt -check -diff -recursive .
+
+ plan-apply:
+ needs: check-fmt
+ permissions:
+ contents: read
+ id-token: write
+ runs-on: codebuild-cdap-${{github.run_id}}-${{github.run_attempt}}
+ strategy:
+ fail-fast: false
+ matrix:
+ app: [cdap]
+ env: [test, prod]
+ include:
+ - app: cdap
+ env: mgmt
+ steps:
+ - uses: actions/checkout@v4
+ - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2
+ - uses: cmsgov/cdap/actions/setup-tenv@8343fb96563ce4b74c4dececee9b268f42bd4a40
+ with:
+ role-to-assume: arn:aws:iam::${{ contains(fromJSON('["dev", "test"]'), matrix.env) && secrets.NON_PROD_ACCOUNT || secrets.PROD_ACCOUNT }}:role/delegatedadmin/developer/${{ matrix.app }}-${{ matrix.env }}-github-actions
+ aws-region: ${{ vars.AWS_REGION }}
+ - uses: nhedger/setup-sops@v2
+ with:
+ version: "latest"
+ - run: tofu init -backend-config=../../backends/${{ matrix.app }}-${{ matrix.env }}.s3.tfbackend
+ - run: tofu plan -out=tf.plan
+ env:
+ TF_VAR_app: ${{ matrix.app }}
+ TF_VAR_env: ${{ matrix.env }}
+ - if: inputs.apply || (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'schedule'
+ run: tofu apply -auto-approve tf.plan
\ No newline at end of file
diff --git a/terraform/modules/platform/main.tf b/terraform/modules/platform/main.tf
index 2a8432b2..acb03df7 100644
--- a/terraform/modules/platform/main.tf
+++ b/terraform/modules/platform/main.tf
@@ -1,7 +1,7 @@
locals {
app = var.app
env = var.env
- established_envs = ["test", "dev", "sandbox", "prod"]
+ established_envs = ["test", "dev", "sandbox", "prod", "mgmt"]
root_module = var.root_module
parent_env = one([for x in local.established_envs : x if can(regex("${x}$$", local.env))])
sdlc_env = contains(["sandbox", "prod"], local.parent_env) ? "production" : "non-production"
@@ -22,6 +22,7 @@ locals {
"test" = "bucket-access-logs-20250409172631068600000001"
"sandbox" = "bucket-access-logs-20250411172631068600000001"
"prod" = "bucket-access-logs-20250411172631068600000001"
+ "mgmt" = "bucket-access-logs-20250411172631068600000001"
}
aws_iam_role_names = [
diff --git a/terraform/modules/platform/variables.tf b/terraform/modules/platform/variables.tf
index c1acd7f2..41088478 100644
--- a/terraform/modules/platform/variables.tf
+++ b/terraform/modules/platform/variables.tf
@@ -2,8 +2,8 @@ variable "app" {
description = "The short name for the delivery team or ADO."
type = string
validation {
- condition = contains(["ab2d", "bcda", "dpc"], var.app)
- error_message = "Invalid short var.app (application). Must be one of ab2d, bcda, or dpc."
+ condition = contains(["ab2d", "bcda", "dpc", "cdap"], var.app)
+ error_message = "Invalid short var.app (application). Must be one of ab2d, bcda, dpc or cdap."
}
}
@@ -11,8 +11,8 @@ variable "env" {
description = "The solution's environment name."
type = string
validation {
- condition = one([for x in ["test", "dev", "sandbox", "prod"] : x if can(regex("^${x}$$|^([a-z0-9]+[a-z0-9-])+([^--])-${x}$$", var.env))]) != null
- error_message = "Invalid environment/workspace name. Must end in one of test, dev, sandbox, or prod."
+ condition = one([for x in ["test", "dev", "sandbox", "prod", "mgmt"] : x if can(regex("^${x}$$|^([a-z0-9]+[a-z0-9-])+([^--])-${x}$$", var.env))]) != null
+ error_message = "Invalid environment/workspace name. Must end in one of test, dev, sandbox, prod or mgmt."
}
}
diff --git a/terraform/modules/sops/main.tf b/terraform/modules/sops/main.tf
index b21afcb8..6876ee6c 100644
--- a/terraform/modules/sops/main.tf
+++ b/terraform/modules/sops/main.tf
@@ -3,7 +3,7 @@ locals {
is_ephemeral_env = var.platform.is_ephemeral_env
env = var.platform.env
parent_env = var.platform.parent_env
- env_key_arn = var.platform.kms_alias_primary.id
+ env_key_arn = var.platform.kms_alias_primary.target_key_arn
# Local Variables with Input Variable Overrides
sopsw_values_dir = coalesce(var.sopsw_values_dir, "${path.root}/values")
diff --git a/terraform/modules/sops/variables.tf b/terraform/modules/sops/variables.tf
index 78604425..6cecbace 100644
--- a/terraform/modules/sops/variables.tf
+++ b/terraform/modules/sops/variables.tf
@@ -1,6 +1,14 @@
variable "platform" {
description = "Object that describes standardized platform values."
- type = any
+ type = object({
+ app = string,
+ parent_env = string,env = string,
+ kms_alias_primary = object({
+ target_key_arn = string,
+ }),
+ service = string,
+ is_ephemeral_env = string
+ })
}
variable "sopsw_values_file_extension" {
diff --git a/terraform/services/config/README.md b/terraform/services/config/README.md
new file mode 100644
index 00000000..6a29fd18
--- /dev/null
+++ b/terraform/services/config/README.md
@@ -0,0 +1,63 @@
+# CDAP Config Root Module
+
+This root module is responsible for configuring the sops-enabled strategy for storing sensitive and nonsensitive configuration in AWS SSM Parameter Store.
+The _parent environment_ specific configuration values are located in the `values` directory.
+
+Usage:
+```hcl
+# declare the `db` module, defining the desired input variables
+module "db" {
+ source = "github.com/CMSgov/cdap//terraform/modules/aurora"
+
+ backup_retention_period = module.platform.is_ephemeral_env ? 1 : 7
+ deletion_protection = !module.platform.is_ephemeral_env
+ password = module.platform.ssm.core.database_password.value
+ username = module.platform.ssm.core.database_user.value
+ platform = module.platform
+
+}
+
+# use the `db` module's output to write parameter to SSM parameter store:
+resource "aws_ssm_parameter" "writer_endpoint" {
+ name = "/cdap/writer_endpoint"
+ value = "${module.db.aurora_cluster.endpoint}:${module.db.aurora_cluster.port}"
+type = "String"
+}
+```
+
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [aws](#requirement\_aws) | ~> 5 |
+
+## Providers
+
+No providers.
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [platform](#module\_platform) | github.com/CMSgov/cdap//terraform/modules/platform | ff2ef539fb06f2c98f0e3ce0c8f922bdacb96d66 |
+| [sops](#module\_sops) | github.com/CMSgov/cdap//terraform/modules/sops | ff2ef539fb06f2c98f0e3ce0c8f922bdacb96d66 |
+
+## Resources
+
+No resources.
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [region](#input\_region) | n/a | `string` | `"us-east-1"` | no |
+| [secondary\_region](#input\_secondary\_region) | n/a | `string` | `"us-west-2"` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [edit](#output\_edit) | n/a |
+
diff --git a/terraform/services/config/main.tf b/terraform/services/config/main.tf
new file mode 100644
index 00000000..68d4cbb2
--- /dev/null
+++ b/terraform/services/config/main.tf
@@ -0,0 +1,32 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 5"
+ }
+ }
+}
+
+module "platform" {
+ source = "github.com/CMSgov/cdap//terraform/modules/platform?ref=plt-1358_sops"
+ providers = { aws = aws, aws.secondary = aws.secondary }
+
+ app = local.app
+ env = var.env
+ root_module = "https://github.com/CMSgov/cdap/tree/terraform/services/config"
+ service = local.service
+}
+
+locals {
+ default_tags = module.platform.default_tags
+ service = "config"
+}
+
+module "sops" {
+ source = "github.com/CMSgov/cdap//terraform/modules/sops?ref=ff2ef539fb06f2c98f0e3ce0c8f922bdacb96d66"
+ platform = module.platform
+}
+
+output "edit" {
+ value = module.sops.sopsw
+}
diff --git a/terraform/services/config/tofu.tf b/terraform/services/config/tofu.tf
new file mode 100644
index 00000000..998dde33
--- /dev/null
+++ b/terraform/services/config/tofu.tf
@@ -0,0 +1,37 @@
+locals {
+ app = "cdap"
+}
+
+variable "region" {
+ default = "us-east-1"
+ nullable = false
+ type = string
+}
+
+variable "secondary_region" {
+ default = "us-west-2"
+ nullable = false
+ type = string
+}
+
+provider "aws" {
+ region = var.region
+ default_tags {
+ tags = local.default_tags
+ }
+}
+
+provider "aws" {
+ alias = "secondary"
+
+ region = var.secondary_region
+ default_tags {
+ tags = local.default_tags
+ }
+}
+
+terraform {
+ backend "s3" {
+ key = "config/terraform.tfstate"
+ }
+}
diff --git a/terraform/services/config/values/mgmt.sopsw.yaml b/terraform/services/config/values/mgmt.sopsw.yaml
new file mode 100644
index 00000000..aa3f4b26
--- /dev/null
+++ b/terraform/services/config/values/mgmt.sopsw.yaml
@@ -0,0 +1,17 @@
+/cdap/account/security_events_slack_renotify_after_days: 30
+/cdap/account/security_events_slack_severity_list: CRITICAL,HIGH,MEDIUM
+/cdap/sensitive/account/security_events_slack_webhook_url: ENC[AES256_GCM,data:z9MLEAlb76u6MZ+GWcWcfnRtax1J677k47tabDmwCqAGN7H2BrmTnkIs1fAhl9dShaL5qZrq78s0sY9b2hCAGIWWaUenVbGGpWBuZvh7rw==,iv:kbgCH76ryIbnU40SWd/Wgg+hULSgGsTO4LLWIPoDE68=,tag:NmwrTB/oVI0WEhL9R5eV2g==,type:str]
+/cdap/sensitive/bucket-access-logs-bucket: ENC[AES256_GCM,data:TjwtktvWlh7Gt7JrTuxZganUT3AotzmEAeYKkpn5GutLcIT1/KSpTV1kjMxV,iv:fSMld0pXjqKabcq+8CK7kG018tspwVAS30ngYFepJKw=,tag:dMsUtxHVSpiHb9U+ebUbNg==,type:str]
+/cdap/sensitive/mgmt-vpc/cidr: ENC[AES256_GCM,data:uNKE6Nckt24ZWHDHEWjU,iv:yVvl1HbK7ljy6lgZdGUkfi0CeIHPnd2uof9tVB1z008=,tag:9tQ1atj1Vwkgw6j1FQ8p5w==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-a: ENC[AES256_GCM,data:FlVrW4HMpGxShfezY7k=,iv:5pZNFGbdfyrGCti7cL/7pfm4S3i5VpnESEO5Rglqw7E=,tag:NZIPNuaSZD/NSD6Q2sE2PQ==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-b: ENC[AES256_GCM,data:N1zEW1bym0cRrT5b,iv:+i6TbqeQLVdZRGUb/O0FUDSEXHsuxxW8hEJbQJYy8gU=,tag:dypP4NS1W0h0c+SeMmuI+g==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-c: ENC[AES256_GCM,data:dE2gJAAstO0VcCol,iv:C5g6vtQbu6AQUmtobCrnZmFcBc4Pn6EZmex1YhQqXA8=,tag:gsAznB9ygxhNdpK73HbAwQ==,type:str]
+sops:
+ kms:
+ - arn: arn:aws:kms:us-east-1:${ACCOUNT_ID}:key/e32dffdb-97e7-4b64-b5cb-f6dc4e6fabca
+ created_at: "2025-10-03T17:27:53Z"
+ enc: AQICAHiXhc+HhELIyRKOpc5vBWQJB9/2XFW+CxWFIfUyci0r/wGkXSt3AG0b8bCJ0pVuEmyuAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM+S5DlWnhTDkMvmOxAgEQgDvMXlly/I5Vb2ah1KX2fSbY3mMOxA92rK4MU/rsyUN2oR8WXebzzW+ooNY1pEdGE4FMUmLUrU5qbcUoPg==
+ aws_profile: ""
+ encrypted_regex: sensitive
+ mac_only_encrypted: true
+ version: 3.11.0
diff --git a/terraform/services/config/values/prod.sopsw.yaml b/terraform/services/config/values/prod.sopsw.yaml
new file mode 100644
index 00000000..aa3f4b26
--- /dev/null
+++ b/terraform/services/config/values/prod.sopsw.yaml
@@ -0,0 +1,17 @@
+/cdap/account/security_events_slack_renotify_after_days: 30
+/cdap/account/security_events_slack_severity_list: CRITICAL,HIGH,MEDIUM
+/cdap/sensitive/account/security_events_slack_webhook_url: ENC[AES256_GCM,data:z9MLEAlb76u6MZ+GWcWcfnRtax1J677k47tabDmwCqAGN7H2BrmTnkIs1fAhl9dShaL5qZrq78s0sY9b2hCAGIWWaUenVbGGpWBuZvh7rw==,iv:kbgCH76ryIbnU40SWd/Wgg+hULSgGsTO4LLWIPoDE68=,tag:NmwrTB/oVI0WEhL9R5eV2g==,type:str]
+/cdap/sensitive/bucket-access-logs-bucket: ENC[AES256_GCM,data:TjwtktvWlh7Gt7JrTuxZganUT3AotzmEAeYKkpn5GutLcIT1/KSpTV1kjMxV,iv:fSMld0pXjqKabcq+8CK7kG018tspwVAS30ngYFepJKw=,tag:dMsUtxHVSpiHb9U+ebUbNg==,type:str]
+/cdap/sensitive/mgmt-vpc/cidr: ENC[AES256_GCM,data:uNKE6Nckt24ZWHDHEWjU,iv:yVvl1HbK7ljy6lgZdGUkfi0CeIHPnd2uof9tVB1z008=,tag:9tQ1atj1Vwkgw6j1FQ8p5w==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-a: ENC[AES256_GCM,data:FlVrW4HMpGxShfezY7k=,iv:5pZNFGbdfyrGCti7cL/7pfm4S3i5VpnESEO5Rglqw7E=,tag:NZIPNuaSZD/NSD6Q2sE2PQ==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-b: ENC[AES256_GCM,data:N1zEW1bym0cRrT5b,iv:+i6TbqeQLVdZRGUb/O0FUDSEXHsuxxW8hEJbQJYy8gU=,tag:dypP4NS1W0h0c+SeMmuI+g==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-c: ENC[AES256_GCM,data:dE2gJAAstO0VcCol,iv:C5g6vtQbu6AQUmtobCrnZmFcBc4Pn6EZmex1YhQqXA8=,tag:gsAznB9ygxhNdpK73HbAwQ==,type:str]
+sops:
+ kms:
+ - arn: arn:aws:kms:us-east-1:${ACCOUNT_ID}:key/e32dffdb-97e7-4b64-b5cb-f6dc4e6fabca
+ created_at: "2025-10-03T17:27:53Z"
+ enc: AQICAHiXhc+HhELIyRKOpc5vBWQJB9/2XFW+CxWFIfUyci0r/wGkXSt3AG0b8bCJ0pVuEmyuAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM+S5DlWnhTDkMvmOxAgEQgDvMXlly/I5Vb2ah1KX2fSbY3mMOxA92rK4MU/rsyUN2oR8WXebzzW+ooNY1pEdGE4FMUmLUrU5qbcUoPg==
+ aws_profile: ""
+ encrypted_regex: sensitive
+ mac_only_encrypted: true
+ version: 3.11.0
diff --git a/terraform/services/config/values/test.sopsw.yaml b/terraform/services/config/values/test.sopsw.yaml
new file mode 100644
index 00000000..6fbc46f2
--- /dev/null
+++ b/terraform/services/config/values/test.sopsw.yaml
@@ -0,0 +1,16 @@
+/cdap/account/security_events_slack_renotify_after_days: 30
+/cdap/account/security_events_slack_severity_list: CRITICAL,HIGH,MEDIUM
+/cdap/sensitive/account/security_events_slack_webhook_url: ENC[AES256_GCM,data:J70QSI23I0d1OnvD+n2ncd/ii0XiZ3NRcQqVwCLCBd7UxRIKgJ1YWqCZ9xV2Y8s/4fy+hi8iVvIkd0WdnC1Q9Adwh2rvRKKWM6lS59EYlA==,iv:/ZIY4WGOsxo2pR/t2FYADYcUeEq5eutP43KkNeTa3q0=,tag:HYuxPAStpJZ0t39j/xHLYg==,type:str]
+/cdap/sensitive/bucket-access-logs-bucket: ENC[AES256_GCM,data:I8m2zMO44IB1FnAuK08G99390eF5NjLcKTVvY4T5oD2O6/Apt3oSV3GAUldn,iv:DQUyoHG1Gplx4YuogWcG9kZnK3XTZXC+N5Ayzyb6LDM=,tag:wQpSTHVaItOGb3PC6tHw/w==,type:str]
+/cdap/sensitive/mgmt-vpc/cidr: ENC[AES256_GCM,data:bKqvpJcIqTqG9DkzO1/T,iv:ul/XIzIZ3BnERohYmuM7fWXWTYI0b45T4F2lUFHkvIw=,tag:LEpy1QiHUoGlTg+mKUaQtg==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-a: ENC[AES256_GCM,data:dAMCs1t1aqfpzibaswE=,iv:g6q2MfSpDZeaSSkpkdwZhGD0ZCdlvrJpHoGVTD1+FfU=,tag:7Z5gSQuDlI0wjBiafCJmDA==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-b: ENC[AES256_GCM,data:tfr8BWh6eKGNsUkx,iv:oAHGGbq9ttxnJ99I70Z7IXIgKRSPkvqIkAmVOyBzWus=,tag:iZ1A8L7mUQLJvJ6uWsoF6A==,type:str]
+/cdap/mgmt/public_nat_ipv4/sensitive/cdap-east-mgmt-c: ENC[AES256_GCM,data:nIVBfKDdYIzOObjj,iv:5E2wwUCOtBtmjpAnWOBZxUJVIqci3o2ncBNQmzEOEPM=,tag:bygAmJUYfbP4tLcFRu94XQ==,type:str]
+sops:
+ kms:
+ - arn: arn:aws:kms:us-east-1:${ACCOUNT_ID}:key/e32dffdb-97e7-4b64-b5cb-f6dc4e6fabca
+ created_at: "2025-10-03T17:38:55Z"
+ enc: AQICAHiXhc+HhELIyRKOpc5vBWQJB9/2XFW+CxWFIfUyci0r/wGgF/ZOMV/LMrvJSRhtedM1AAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM8xXrZN9mTFGkvKjtAgEQgDsOpxt5mGlXEpdiTlnAjnt/AcOMpA8coSH4NHWfC2Tsw/VES55XVAaWQYXuOOdKnIJznMlUqzqBVrfvTw==
+ aws_profile: ""
+ encrypted_regex: sensitive
+ version: 3.11.0
diff --git a/terraform/services/config/variables.tf b/terraform/services/config/variables.tf
new file mode 100644
index 00000000..1d0d9afc
--- /dev/null
+++ b/terraform/services/config/variables.tf
@@ -0,0 +1,8 @@
+variable "env" {
+ description = "The application environment (test, prod, mgmt)"
+ type = string
+ validation {
+ condition = contains(["test", "prod", "mgmt"], var.env)
+ error_message = "Valid value for env is test, prod, or mgmt."
+ }
+}