Skip to content

Commit

Permalink
DPC-3767 Add infrastructure for DPC WAF-sync lambda (#127)
Browse files Browse the repository at this point in the history
## 🎫 Ticket

https://jira.cms.gov/browse/DPC-3767

## 🛠 Changes

- Added wav-sync as service
- Added plan and apply wav-sync github actions

## ℹ️ Context

DPC needs to synchronize ip addresses in a database with an AWS WAF IP
Set. We [decided](https://confluence.cms.gov/x/1ZUZQQ) to use a
cron-triggered lambda to manage this. This ticket creates the
infrastructure for automated deployment of the lambda.

The aws_waf_access inline policy seems to be the minimum necessary for
the lambda to run. It may require updating (the lambda has not been
written).

The name of the IP Set was intuited by browsing the WAF IP Sets in AWS
Console.

The terraform scripts and github actions are modified versions of the
opt-out-import service.

## 🧪 Validation

- Comparison of the plan output to opt-out-import plan output show that
the permissions necessary are present.
- Plan applied successfully
  • Loading branch information
jdettmannnava authored Sep 17, 2024
1 parent 0df3c80 commit b42d21d
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 0 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/api-waf-sync-apply.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: api-waf-sync apply terraform

on:
push:
branches:
- main
paths:
- .github/workflows/api-waf-sync-apply.yml
- terraform/modules/bucket/**
- terraform/modules/key/**
- terraform/modules/function/**
- terraform/modules/queue/**
- terraform/modules/subnets/**
- terraform/modules/vpc/**
- terraform/services/api-waf-sync/**
workflow_dispatch: # Allow manual trigger

jobs:
terraform-apply:
permissions:
contents: read
id-token: write
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./terraform/services/api-waf-sync
strategy:
fail-fast: false
matrix:
env: [dev]
env:
TF_VAR_env: ${{ matrix.env }}
steps:
- uses: actions/checkout@v4
- uses: ./actions/setup-tfenv-terraform
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.BCDA_ACCOUNT }}:role/delegatedadmin/developer/dpc-${{ matrix.env }}-github-actions
aws-region: ${{ vars.AWS_REGION }}
- run: terraform init -reconfigure -backend-config=../../backends/dpc-$TF_VAR_env.s3.tfbackend
- run: terraform apply -auto-approve
- uses: slackapi/[email protected]
if: ${{ failure() }}
with:
channel-id: 'C04UG13JF9B'
slack-message: "Terraform apply failure: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

47 changes: 47 additions & 0 deletions .github/workflows/api-waf-sync-plan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: api-waf-sync plan terraform

on:
pull_request:
paths:
- .github/workflows/api-waf-sync-plan.yml
- terraform/modules/bucket/**
- terraform/modules/key/**
- terraform/modules/function/**
- terraform/modules/queue/**
- terraform/modules/subnets/**
- terraform/modules/vpc/**
- terraform/services/api-waf-sync/**
workflow_dispatch: # Allow manual trigger

jobs:
check-terraform-fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./actions/setup-tfenv-terraform
- run: terraform fmt -check -diff -recursive terraform/services/api-waf-sync

terraform-plan:
needs: check-terraform-fmt
permissions:
contents: read
id-token: write
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./terraform/services/api-waf-sync
strategy:
fail-fast: false
matrix:
env: [dev]
env:
TF_VAR_env: ${{ matrix.env }}
steps:
- uses: actions/checkout@v4
- uses: ./actions/setup-tfenv-terraform
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.BCDA_ACCOUNT }}:role/delegatedadmin/developer/dpc-${{ matrix.env }}-github-actions
aws-region: ${{ vars.AWS_REGION }}
- run: terraform init -reconfigure -backend-config=../../backends/dpc-$TF_VAR_env.s3.tfbackend
- run: terraform plan
25 changes: 25 additions & 0 deletions terraform/services/api-waf-sync/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions terraform/services/api-waf-sync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Terraform for api-waf-sync function and associated infra

This service sets up the infrastructure for the api-waf-sync lambda function in dev for dpc.

## Manual deploy

Pass in a backend file when running terraform init. See variables.tf for variables to include. Example:

```bash
export TF_VAR_env=dev
terraform init -backend-config=../../backends/dpc-dev.s3.tfbackend
terraform apply
```

## Automated deploy

This terraform is automatically applied on merge to main by the waf-sync-apply.yml workflow.
60 changes: 60 additions & 0 deletions terraform/services/api-waf-sync/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
locals {
full_name = "dpc-${var.env}-api-waf-sync"
db_sg_name = "dpc-${var.env}-db"
}

module "api_waf_sync_function" {
source = "../../modules/function"

app = "dpc"
env = var.env

name = local.full_name
description = "Synchronizes the IP whitelist in DPC with the WAF IP Set"

handler = "bootstrap"
runtime = "provided.al2"

function_role_inline_policies = {
waf-access = data.aws_iam_policy_document.aws_waf_access.json
}

schedule_expression = "cron(0/10 * * * ? *)"

environment_variables = {
ENV = var.env
APP_NAME = "dpc-${var.env}-api-waf-sync"
WAF_IP_SET_NAME = "DPC_${upper(var.env)}_Implementer_IP_Set"
}
}

# Add a rule to the database security group to allow access from the function

data "aws_security_group" "db" {
name = local.db_sg_name
}

resource "aws_security_group_rule" "function_access" {
type = "ingress"
from_port = 5432
to_port = 5432
protocol = "tcp"
description = "api-waf-sync function access"

security_group_id = data.aws_security_group.db.id
source_security_group_id = module.api_waf_sync_function.security_group_id
}

# Because we inline policies, we cannot just link to aws:policy/AWSWAFFullAccess
data "aws_iam_policy_document" "aws_waf_access" {
statement {
effect = "Allow"
resources = ["*"]

actions = [
"wafv2:GetIpSet",
"wafv2:UpdateIpSet",
]
}
}

7 changes: 7 additions & 0 deletions terraform/services/api-waf-sync/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
output "function_role_arn" {
value = module.api_waf_sync_function.role_arn
}

output "zip_bucket" {
value = module.api_waf_sync_function.zip_bucket
}
18 changes: 18 additions & 0 deletions terraform/services/api-waf-sync/terraform.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
provider "aws" {
default_tags {
tags = {
application = "dpc"
business = "oeda"
code = "https://github.com/CMSgov/ab2d-bcda-dpc-platform/tree/main/terraform/services/api-waf-sync"
component = "api-waf-sync"
environment = var.env
terraform = true
}
}
}

terraform {
backend "s3" {
key = "api-waf-sync/terraform.tfstate"
}
}
8 changes: 8 additions & 0 deletions terraform/services/api-waf-sync/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
variable "env" {
description = "The application environment (dev, test, prod)"
type = string
validation {
condition = contains(["dev", "test", "prod"], var.env)
error_message = "Valid value for env is dev, test, or prod."
}
}

0 comments on commit b42d21d

Please sign in to comment.