Skip to content

Commit 61b7e2f

Browse files
authored
feat: Refactor infrastrucure to use layered configs rather than a monoconfig. (#10)
- Added foundation layer for infrastructure. - Added networking layer for infrastructure. - Added service layer for infrastructure. - Use SSM to pass parameters between layers. - Removed "development" monoconfig. - Updated plan, deploy, and pull request workflows to supported layered approach.
1 parent 0db3d55 commit 61b7e2f

31 files changed

+458
-84
lines changed

.github/workflows/deploy.yaml

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ name: Deploy infrastructure changes
33
on:
44
workflow_dispatch:
55
inputs:
6+
config:
7+
description: OpenTofu configuration to deploy.
8+
default: service
9+
required: true
10+
type: choice
11+
options:
12+
- foundation
13+
- networking
14+
- service
615
environment:
716
description: Environment to deploy to.
817
default: development
@@ -13,9 +22,6 @@ permissions:
1322
contents: read
1423
id-token: write
1524

16-
env:
17-
CONFIG_PATH: ./tofu/config/development
18-
1925
# TODO: Add an approval step between plan and deploy.
2026
jobs:
2127
plan:
@@ -79,11 +85,11 @@ jobs:
7985
- name: Download plan file
8086
uses: actions/download-artifact@v4
8187
with:
82-
name: tfplan
83-
path: ${{ env.CONFIG_PATH }}
88+
name: ${{ inputs.config }}-tfplan
89+
path: ./tofu/config/${{ inputs.config }}
8490
- name: Initialize OpenTofu
85-
working-directory: ${{ env.CONFIG_PATH }}
91+
working-directory: ./tofu/config/${{ inputs.config }}
8692
run: tofu init
8793
- name: Deploy changes
88-
working-directory: ${{ env.CONFIG_PATH }}
94+
working-directory: ./tofu/config/${{ inputs.config }}
8995
run: tofu apply tfplan

.github/workflows/plan.yaml

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ name: Plan infrastructure changes
33
on:
44
workflow_call:
55
inputs:
6+
config:
7+
description: OpenTofu configuration to plan.
8+
default: service
9+
required: true
10+
type: string
611
environment:
712
description: Environment to plan on.
813
default: development
@@ -22,6 +27,15 @@ on:
2227
TF_VAR_VPC_PUBLIC_SUBNET_CIDRS:
2328
workflow_dispatch:
2429
inputs:
30+
config:
31+
description: OpenTofu configuration to plan.
32+
default: service
33+
required: true
34+
type: choice
35+
options:
36+
- foundation
37+
- networking
38+
- service
2539
environment:
2640
description: Environment to plan on.
2741
default: development
@@ -32,12 +46,9 @@ permissions:
3246
contents: read
3347
id-token: write
3448

35-
env:
36-
CONFIG_PATH: ./tofu/config/development
37-
3849
jobs:
3950
plan:
40-
name: Plan changes to ${{ inputs.environment || 'development' }}
51+
name: Plan changes to ${{ inputs.config }} in ${{ inputs.environment || 'development' }}
4152
runs-on: ubuntu-latest
4253
environment: ${{ inputs.environment || 'development' }}
4354
env:
@@ -77,19 +88,19 @@ jobs:
7788
fi
7889
done
7990
- name: Initialize OpenTofu
80-
working-directory: ${{ env.CONFIG_PATH }}
91+
working-directory: ./tofu/config/${{ inputs.config }}
8192
run: tofu init
8293
- name: Plan changes
83-
working-directory: ${{ env.CONFIG_PATH }}
94+
working-directory: ./tofu/config/${{ inputs.config }}
8495
run: tofu plan -concise -no-color -out tfplan > plan.txt
8596
- name: Display plan
86-
working-directory: ${{ env.CONFIG_PATH }}
97+
working-directory: ./tofu/config/${{ inputs.config }}
8798
run: tofu show -plan tfplan
8899
- name: Upload plan file
89100
uses: actions/upload-artifact@v4
90101
with:
91-
name: tfplan
102+
name: ${{ inputs.config }}-tfplan
92103
path: |
93-
${{ env.CONFIG_PATH }}/plan.txt
94-
${{ env.CONFIG_PATH }}/tfplan
104+
./tofu/config/${{ inputs.config }}/plan.txt
105+
./tofu/config/${{ inputs.config }}/tfplan
95106
retention-days: 5

.github/workflows/pull-request.yaml

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,61 @@ on:
44
pull_request:
55

66
jobs:
7+
configs:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout source code
11+
uses: actions/checkout@v4
12+
- name: Find all configs
13+
id: find
14+
uses: bendrucker/find-terraform-modules@v1
15+
with:
16+
working-directory: tofu/config
17+
- name: Show all matching configs
18+
shell: bash
19+
run: |
20+
mods=(${{ join(fromJSON(steps.find.outputs.modules), ' ') }})
21+
printf "%s\n" "${mods[@]}"
22+
- name: Find all changed files
23+
id: diff
24+
uses: technote-space/get-diff-action@v6
25+
with:
26+
FORMAT: json
27+
- name: Show changed files
28+
run: |
29+
echo "${{ steps.diff.outputs.diff }}"
30+
- name: Get the modified configs
31+
id: modified
32+
uses: actions/github-script@v7
33+
with:
34+
script: |
35+
const configs = ${{ steps.find.outputs.modules }}
36+
const diff = ${{ steps.diff.outputs.diff }}
37+
const modifiedConfigs = configs.filter(
38+
(config) => {
39+
return !!diff.find(file => new RegExp(`^${config}/.+`).test(file))
40+
}
41+
).map(config => config.replace(/^tofu\/config\//, ''))
42+
43+
core.setOutput('configs', modifiedConfigs)
44+
- name: Show modified configs
45+
run: |
46+
echo "${{ steps.modified.outputs.configs }}"
47+
outputs:
48+
configs: ${{ steps.modified.outputs.configs }}
49+
750
plan:
851
uses: ./.github/workflows/plan.yaml
52+
needs: configs
953
permissions:
1054
contents: read
1155
id-token: write
56+
strategy:
57+
matrix:
58+
config: ${{ fromJson(needs.configs.outputs.configs) }}
1259
with:
1360
environment: development
61+
config: ${{ matrix.config }}
1462
secrets:
1563
AWS_REGION: ${{ secrets.AWS_REGION }}
1664
AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }}
@@ -23,17 +71,20 @@ jobs:
2371

2472
comment:
2573
runs-on: ubuntu-latest
26-
needs: plan
74+
needs:
75+
- configs
76+
- plan
2777
permissions:
2878
contents: read
2979
pull-requests: write
30-
env:
31-
CONFIG_PATH: ./tofu/config/development
80+
strategy:
81+
matrix:
82+
config: ${{ fromJson(needs.configs.outputs.configs) }}
3283
steps:
3384
- name: Download plan file
3485
uses: actions/download-artifact@v4
3586
with:
36-
name: tfplan
87+
name: ${{ matrix.config }}-tfplan
3788
- uses: actions/github-script@v7
3889
with:
3990
github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -45,15 +96,15 @@ jobs:
4596
issue_number: context.issue.number,
4697
})
4798
const botComment = comments.find(comment => {
48-
return comment.user.type === 'Bot' && comment.body.includes('## Plan output')
99+
return comment.user.type === 'Bot' && comment.body.includes('## Plan output for ${{ matrix.config }} config')
49100
})
50101
51102
// Read the contents of the plan.
52103
const fs = require('fs');
53104
const plan = fs.readFileSync('./plan.txt', 'utf8');
54105
55106
// Prepare the format of the comment.
56-
const output = `## Plan output\n\n\`\`\`\n${plan}\n\`\`\``
107+
const output = `## Plan output for ${{ matrix.config }} config\n\n\`\`\`\n${plan}\n\`\`\``
57108
58109
// If we have a comment, update it. Otherwise, create a new one.
59110
if (botComment) {

tofu/config/development/.terraform.lock.hcl

Lines changed: 0 additions & 19 deletions
This file was deleted.

tofu/config/foundation/.terraform.lock.hcl

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
terraform {
22
backend "s3" {
33
bucket = "${var.project}-${var.environment}-tfstate"
4-
key = "${var.project}.tfstate"
4+
key = "foundation.tfstate"
55
region = var.region
66
dynamodb_table = "${var.environment}.tfstate"
77
}
@@ -24,37 +24,21 @@ module "backend" {
2424
module "logging" {
2525
source = "github.com/codeforamerica/tofu-modules-aws-logging?ref=2.1.1"
2626

27-
project = var.project
28-
environment = var.environment
29-
cloudwatch_log_retention = 1
30-
key_recovery_period = 7
27+
project = var.project
28+
environment = var.environment
29+
key_recovery_period = var.key_recovery_period
3130

3231
tags = resource.aws_servicecatalogappregistry_application.application.application_tag
3332
}
3433

35-
# TODO: Air gap this VPC from the internet.
36-
module "vpc" {
37-
source = "github.com/codeforamerica/tofu-modules-aws-vpc?ref=1.1.2"
38-
39-
project = var.project
40-
environment = var.environment
41-
cidr = var.vpc_cidr
42-
logging_key_id = module.logging.kms_key_arn
43-
private_subnets = var.vpc_private_subnet_cidrs
44-
45-
# TODO: We don't need public subnets or a NAT gateway for an air gapped VPC.
46-
public_subnets = var.vpc_public_subnet_cidrs
47-
single_nat_gateway = true
48-
49-
tags = resource.aws_servicecatalogappregistry_application.application.application_tag
50-
}
34+
module "outputs" {
35+
source = "../../modules/outputs"
5136

52-
module "system" {
53-
source = "../../modules/system"
37+
prefix = "/${var.project}/${var.environment}"
5438

55-
environment = var.environment
56-
project = var.project
57-
export_expiration = var.export_expiration
58-
key_recovery_period = var.key_recovery_period
59-
logging_bucket = module.logging.bucket
39+
outputs = {
40+
"application/tag" = aws_servicecatalogappregistry_application.application.application_tag["awsApplication"]
41+
"logging/bucket" = module.logging.bucket
42+
"logging/key" = module.logging.kms_key_arn
43+
}
6044
}

tofu/config/foundation/outputs.tf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
output "application_arn" {
2+
description = "ARN of the Service Catalog App Registry application."
3+
value = aws_servicecatalogappregistry_application.application.arn
4+
}
5+
6+
output "logging_bucket" {
7+
value = module.logging.bucket
8+
description = "The name of the S3 bucket for logging."
9+
}
10+
11+
output "logging_key_arn" {
12+
value = module.logging.kms_key_arn
13+
description = "The ARN of the KMS key for logging."
14+
}
15+
16+
output "state_bucket" {
17+
value = module.backend.bucket
18+
description = "The name of the S3 bucket for infrastructure state files."
19+
}
File renamed without changes.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
variable "environment" {
2+
type = string
3+
description = "Environment for the deployment."
4+
default = "development"
5+
}
6+
7+
variable "key_recovery_period" {
8+
type = number
9+
default = 30
10+
description = "Recovery period for deleted KMS keys in days. Must be between 7 and 30."
11+
12+
validation {
13+
condition = var.key_recovery_period > 6 && var.key_recovery_period < 31
14+
error_message = "Recovery period must be between 7 and 30."
15+
}
16+
}
17+
18+
variable "program" {
19+
type = string
20+
description = "Program the project belongs to."
21+
default = null
22+
}
23+
24+
variable "project" {
25+
type = string
26+
description = "Project that these resources are supporting."
27+
default = "sqs-senzing"
28+
}
29+
30+
variable "region" {
31+
type = string
32+
description = "AWS region where resources should be deployed."
33+
default = "us-west-1"
34+
}
File renamed without changes.

0 commit comments

Comments
 (0)