mirror of
https://github.com/GSA/notifications-api.git
synced 2026-05-27 17:38:17 -04:00
Merge pull request #115 from GSA/main
Deploy restricted egress configuration to demo
This commit is contained in:
42
.github/actions/deploy-proxy/action.yml
vendored
Normal file
42
.github/actions/deploy-proxy/action.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Deploy egress proxy
|
||||
description: Set egress space security groups and deploy proxy
|
||||
inputs:
|
||||
cf_space:
|
||||
description: The space the target app exists in.
|
||||
required: true
|
||||
app:
|
||||
description: application name to be proxied.
|
||||
required: true
|
||||
proxy_repo:
|
||||
description: git repo for cg-egress-proxy
|
||||
default: https://github.com/rahearn/cg-egress-proxy.git
|
||||
proxy_version:
|
||||
description: git ref to be deployed
|
||||
default: main
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Set restricted space egress
|
||||
shell: bash
|
||||
run: ./terraform/set_space_egress.sh -t -s ${{ inputs.cf_space }}
|
||||
- name: Set public space egress
|
||||
shell: bash
|
||||
run: ./terraform/set_space_egress.sh -p -s ${{ inputs.cf_space }}-egress
|
||||
- name: Create temp directory
|
||||
shell: bash
|
||||
id: create-temp-dir
|
||||
run: echo "path=$(mktemp -d -t egress-XXXXXXXXXX --tmpdir=$RUNNER_TEMP)" >> $GITHUB_OUTPUT
|
||||
- name: Clone cg-egress-proxy
|
||||
shell: bash
|
||||
run: git clone ${{ inputs.proxy_repo }} ${{ steps.create-temp-dir.outputs.path }}
|
||||
- name: Switch to deploy ref
|
||||
shell: bash
|
||||
working-directory: ${{ steps.create-temp-dir.outputs.path }}
|
||||
run: git checkout ${{ inputs.proxy_version }}
|
||||
- name: Copy config files
|
||||
shell: bash
|
||||
run: cp ./deploy-config/egress_proxy/${{ inputs.app }}.*.acl ${{ steps.create-temp-dir.outputs.path }}
|
||||
- name: Build and deploy proxy
|
||||
shell: bash
|
||||
working-directory: ${{ steps.create-temp-dir.outputs.path }}
|
||||
run: make && ./bin/cf-deployproxy -a ${{ inputs.app }} -p egress-proxy -e egress_proxy
|
||||
17
.github/workflows/deploy-demo.yml
vendored
17
.github/workflows/deploy-demo.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
- name: Check for changes to Terraform
|
||||
id: changed-terraform-files
|
||||
uses: tj-actions/changed-files@v1.1.2
|
||||
uses: tj-actions/changed-files@v34
|
||||
with:
|
||||
files: terraform/demo
|
||||
- name: Terraform init
|
||||
@@ -65,3 +65,18 @@ jobs:
|
||||
--var ADMIN_CLIENT_SECRET="$ADMIN_CLIENT_SECRET"
|
||||
--var AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID"
|
||||
--var AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY"
|
||||
|
||||
- name: Check for changes to egress config
|
||||
id: changed-egress-config
|
||||
uses: tj-actions/changed-files@v34
|
||||
with:
|
||||
files: |
|
||||
deploy-config/egress_proxy/notify-api-demo.*.acl
|
||||
.github/actions/deploy-proxy/action.yml
|
||||
.github/workflows/deploy-demo.yml
|
||||
- name: Deploy egress proxy
|
||||
if: steps.changed-egress-config.outputs.any_changed == 'true'
|
||||
uses: ./.github/actions/deploy-proxy
|
||||
with:
|
||||
cf_space: notify-demo
|
||||
app: notify-api-demo
|
||||
|
||||
17
.github/workflows/deploy.yml
vendored
17
.github/workflows/deploy.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
- name: Check for changes to Terraform
|
||||
id: changed-terraform-files
|
||||
uses: tj-actions/changed-files@v1.1.2
|
||||
uses: tj-actions/changed-files@v34
|
||||
with:
|
||||
files: terraform/staging
|
||||
- name: Terraform init
|
||||
@@ -71,6 +71,21 @@ jobs:
|
||||
--var AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID"
|
||||
--var AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY"
|
||||
|
||||
- name: Check for changes to egress config
|
||||
id: changed-egress-config
|
||||
uses: tj-actions/changed-files@v34
|
||||
with:
|
||||
files: |
|
||||
deploy-config/egress_proxy/notify-api-staging.*.acl
|
||||
.github/actions/deploy-proxy/action.yml
|
||||
.github/workflows/deploy.yml
|
||||
- name: Deploy egress proxy
|
||||
if: steps.changed-egress-config.outputs.any_changed == 'true'
|
||||
uses: ./.github/actions/deploy-proxy
|
||||
with:
|
||||
cf_space: notify-staging
|
||||
app: notify-api-staging
|
||||
|
||||
bail:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
|
||||
|
||||
6
.profile
Normal file
6
.profile
Normal file
@@ -0,0 +1,6 @@
|
||||
##
|
||||
# Cloud Foundry app initialization script
|
||||
# https://docs.cloudfoundry.org/devguide/deploy-apps/deploy-app.html#profile
|
||||
##
|
||||
|
||||
export https_proxy=$egress_proxy
|
||||
@@ -425,5 +425,6 @@ configs = {
|
||||
'test': Test,
|
||||
'staging': Staging,
|
||||
'demo': Demo,
|
||||
'sandbox': Staging,
|
||||
'production': Production
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@ web_instances: 1
|
||||
web_memory: 1G
|
||||
worker_instances: 1
|
||||
worker_memory: 512M
|
||||
scheduler_memory: 256M
|
||||
public_api_route: notify-api-demo.app.cloud.gov
|
||||
admin_base_url: https://notify-demo.app.cloud.gov
|
||||
|
||||
3
deploy-config/egress_proxy/notify-api-demo.allow.acl
Normal file
3
deploy-config/egress_proxy/notify-api-demo.allow.acl
Normal file
@@ -0,0 +1,3 @@
|
||||
email.us-west-2.amazonaws.com
|
||||
sns.us-west-2.amazonaws.com
|
||||
logs.us-west-2.amazonaws.com
|
||||
0
deploy-config/egress_proxy/notify-api-demo.deny.acl
Normal file
0
deploy-config/egress_proxy/notify-api-demo.deny.acl
Normal file
3
deploy-config/egress_proxy/notify-api-staging.allow.acl
Normal file
3
deploy-config/egress_proxy/notify-api-staging.allow.acl
Normal file
@@ -0,0 +1,3 @@
|
||||
email.us-west-2.amazonaws.com
|
||||
sns.us-west-2.amazonaws.com
|
||||
logs.us-west-2.amazonaws.com
|
||||
1
deploy-config/egress_proxy/notify-api-staging.deploy.acl
Normal file
1
deploy-config/egress_proxy/notify-api-staging.deploy.acl
Normal file
@@ -0,0 +1 @@
|
||||
Update this file to force a re-deploy of the egress proxy even when notify-api-staging.<allow|deny>.acl haven't changed
|
||||
@@ -3,5 +3,6 @@ web_instances: 2
|
||||
web_memory: 1G
|
||||
worker_instances: 1
|
||||
worker_memory: 512M
|
||||
scheduler_memory: 256M
|
||||
public_api_route: notify-api.app.cloud.gov
|
||||
admin_base_url: https://notify.app.cloud.gov
|
||||
|
||||
10
deploy-config/sandbox.yml
Normal file
10
deploy-config/sandbox.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
env: sandbox
|
||||
web_instances: 1
|
||||
web_memory: 1G
|
||||
worker_instances: 1
|
||||
worker_memory: 512M
|
||||
public_api_route: notify-api-sandbox.app.cloud.gov
|
||||
admin_base_url: https://notify-sandbox.app.cloud.gov
|
||||
ADMIN_CLIENT_SECRET: dev-notify-secret-key
|
||||
DANGEROUS_SALT: dev-notify-salt
|
||||
SECRET_KEY: dev-notify-secret-key
|
||||
@@ -3,5 +3,6 @@ web_instances: 1
|
||||
web_memory: 1G
|
||||
worker_instances: 1
|
||||
worker_memory: 512M
|
||||
scheduler_memory: 256M
|
||||
public_api_route: notify-api-staging.app.cloud.gov
|
||||
admin_base_url: https://notify-staging.app.cloud.gov
|
||||
|
||||
@@ -20,3 +20,42 @@ Configurations for these are located in [the `deploy-config` folder](../deploy-c
|
||||
In the event that a deployment includes a Terraform change, that change will run before any code is deployed to the environment. Each environment has its own Terraform GitHub Action to handle that change.
|
||||
|
||||
Failures in any of these GitHub workflows will be surfaced in the Pull Request related to the code change, and in the case of `checks.yml` actively prevent the PR from being merged. Failure in the Terraform workflow will not actively prevent the PR from being merged, but reviewers should not approve a PR with a failing terraform plan.
|
||||
|
||||
## Egress Proxy
|
||||
|
||||
The API app runs in a [restricted egress space](https://cloud.gov/docs/management/space-egress/).
|
||||
This allows direct communication to cloud.gov-brokered services, but
|
||||
not to other APIs that we require.
|
||||
|
||||
As part of the deploy, we create an
|
||||
[egress proxy application](https://github.com/GSA/cg-egress-proxy) that allows traffic out of our
|
||||
application to a select list of allowed domains.
|
||||
|
||||
Update the allowed domains by updating `deploy-config/egress_proxy/notify-api-<env>.allow.acl`
|
||||
and deploying an updated version of the application throught he normal deploy process.
|
||||
|
||||
## Sandbox environment
|
||||
|
||||
There is a sandbox space, complete with terraform and `deploy-config/sandbox.yml` file available
|
||||
for experimenting with infrastructure changes without going through the full CI/CD cycle each time.
|
||||
|
||||
Rules for use:
|
||||
|
||||
1. Ensure that no other developer is using the environment, as there is nothing stopping changes from overwriting each other.
|
||||
1. Clean up services you create when you are done. `terraform destroy` from within the `terraform/sandbox` directory should do it.
|
||||
|
||||
### Deploying to the sandbox
|
||||
|
||||
1. Set up services:
|
||||
```
|
||||
$ cd terraform/sandbox
|
||||
$ ../create_service_account.sh -s notify-sandbox -u <your-name>-terraform -m > secrets.auto.tfvars
|
||||
$ terraform init
|
||||
$ terraform plan
|
||||
$ terraform apply
|
||||
```
|
||||
1. start a pipenv shell as a shortcut to load `.env` file variables: `$ pipenv shell`
|
||||
1. Deploy the application:
|
||||
```
|
||||
cf push --vars-file deploy-config/sandbox.yml --var AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID --var AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
|
||||
```
|
||||
|
||||
@@ -23,6 +23,10 @@ applications:
|
||||
instances: ((worker_instances))
|
||||
memory: ((worker_memory))
|
||||
command: ./scripts/run_app_paas.sh celery -A run_celery.notify_celery worker --loglevel=INFO --concurrency=4
|
||||
- type: scheduler
|
||||
instances: 1
|
||||
memory: ((scheduler_memory))
|
||||
command: ./scripts/run_app_paas.sh celery -A run_celery.notify_celery beat --loglevel=INFO
|
||||
|
||||
env:
|
||||
NOTIFY_APP_NAME: api
|
||||
@@ -43,3 +47,5 @@ applications:
|
||||
AWS_REGION: us-west-2
|
||||
AWS_PINPOINT_REGION: us-west-2
|
||||
AWS_US_TOLL_FREE_NUMBER: +18446120782
|
||||
|
||||
REQUESTS_CA_BUNDLE: "/etc/ssl/certs/ca-certificates.crt"
|
||||
|
||||
@@ -7,14 +7,18 @@ $0: Create a Service User Account for a given space
|
||||
|
||||
Usage:
|
||||
$0 -h
|
||||
$0 -s <SPACE NAME> -u <USER NAME> [-r <ROLE NAME>] [-o <ORG NAME>]
|
||||
$0 -s <SPACE NAME> -u <USER NAME> [-r <ROLE NAME>] [-o <ORG NAME>] [-m]
|
||||
|
||||
Options:
|
||||
-h: show help and exit
|
||||
-s <SPACE NAME>: configure the space to act on. Required
|
||||
-u <USER NAME>: set the service user name. Required
|
||||
-r <ROLE NAME>: set the service user's role to either space-deployer or space-auditor. Default: space-deployer
|
||||
-m: If provided, make the service user an OrgManager
|
||||
-o <ORG NAME>: configure the organization to act on. Default: $org
|
||||
|
||||
Notes:
|
||||
OrgManager is required for terraform to create <env>-egress spaces
|
||||
"
|
||||
|
||||
set -e
|
||||
@@ -23,8 +27,9 @@ set -o pipefail
|
||||
space=""
|
||||
service=""
|
||||
role="space-deployer"
|
||||
org_manager="false"
|
||||
|
||||
while getopts ":hs:u:r:o:" opt; do
|
||||
while getopts ":hms:u:r:o:" opt; do
|
||||
case "$opt" in
|
||||
s)
|
||||
space=${OPTARG}
|
||||
@@ -38,6 +43,9 @@ while getopts ":hs:u:r:o:" opt; do
|
||||
o)
|
||||
org=${OPTARG}
|
||||
;;
|
||||
m)
|
||||
org_manager="true"
|
||||
;;
|
||||
h)
|
||||
echo "$usage"
|
||||
exit 0
|
||||
@@ -60,13 +68,17 @@ cf create-service-key $service service-account-key 1>&2
|
||||
|
||||
# output service key to stdout in secrets.auto.tfvars format
|
||||
creds=`cf service-key $service service-account-key | tail -n 4`
|
||||
username=`echo $creds | jq '.username'`
|
||||
password=`echo $creds | jq '.password'`
|
||||
username=`echo $creds | jq -r '.username'`
|
||||
password=`echo $creds | jq -r '.password'`
|
||||
|
||||
if [[ $org_manager = "true" ]]; then
|
||||
cf set-org-role $username $org OrgManager 1>&2
|
||||
fi
|
||||
|
||||
cat << EOF
|
||||
# generated with $0 -s $space -u $service -r $role -o $org
|
||||
# revoke with $(dirname $0)/destroy_service_account.sh -s $space -u $service -o $org
|
||||
|
||||
cf_user = $username
|
||||
cf_password = $password
|
||||
cf_user = "$username"
|
||||
cf_password = "$password"
|
||||
EOF
|
||||
|
||||
@@ -53,3 +53,17 @@ module "contact_list_bucket" {
|
||||
recursive_delete = local.recursive_delete
|
||||
s3_service_name = "${local.app_name}-contact-list-bucket-${local.env}"
|
||||
}
|
||||
|
||||
module "egress-space" {
|
||||
source = "../shared/egress_space"
|
||||
|
||||
cf_user = var.cf_user
|
||||
cf_password = var.cf_password
|
||||
cf_org_name = local.cf_org_name
|
||||
cf_restricted_space_name = local.cf_space_name
|
||||
deployers = [
|
||||
var.cf_user,
|
||||
"ryan.ahearn@gsa.gov",
|
||||
"steven.reilly@gsa.gov"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -54,6 +54,18 @@ module "contact_list_bucket" {
|
||||
s3_service_name = "${local.app_name}-contact-list-bucket-${local.env}"
|
||||
}
|
||||
|
||||
module "egress-space" {
|
||||
source = "../shared/egress_space"
|
||||
|
||||
cf_user = var.cf_user
|
||||
cf_password = var.cf_password
|
||||
cf_org_name = local.cf_org_name
|
||||
cf_restricted_space_name = local.cf_space_name
|
||||
deployers = [
|
||||
var.cf_user
|
||||
]
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# The following lines need to be commented out for the initial `terraform apply`
|
||||
# It can be re-enabled after:
|
||||
|
||||
69
terraform/sandbox/main.tf
Normal file
69
terraform/sandbox/main.tf
Normal file
@@ -0,0 +1,69 @@
|
||||
locals {
|
||||
cf_org_name = "gsa-tts-benefits-studio-prototyping"
|
||||
cf_space_name = "notify-sandbox"
|
||||
env = "sandbox"
|
||||
app_name = "notify-api"
|
||||
recursive_delete = true
|
||||
}
|
||||
|
||||
module "database" {
|
||||
source = "github.com/18f/terraform-cloudgov//database"
|
||||
|
||||
cf_user = var.cf_user
|
||||
cf_password = var.cf_password
|
||||
cf_org_name = local.cf_org_name
|
||||
cf_space_name = local.cf_space_name
|
||||
env = local.env
|
||||
app_name = local.app_name
|
||||
recursive_delete = local.recursive_delete
|
||||
rds_plan_name = "micro-psql"
|
||||
}
|
||||
|
||||
module "redis" {
|
||||
source = "github.com/18f/terraform-cloudgov//redis"
|
||||
|
||||
cf_user = var.cf_user
|
||||
cf_password = var.cf_password
|
||||
cf_org_name = local.cf_org_name
|
||||
cf_space_name = local.cf_space_name
|
||||
env = local.env
|
||||
app_name = local.app_name
|
||||
recursive_delete = local.recursive_delete
|
||||
redis_plan_name = "redis-dev"
|
||||
}
|
||||
|
||||
module "csv_upload_bucket" {
|
||||
source = "github.com/18f/terraform-cloudgov//s3"
|
||||
|
||||
cf_user = var.cf_user
|
||||
cf_password = var.cf_password
|
||||
cf_org_name = local.cf_org_name
|
||||
cf_space_name = local.cf_space_name
|
||||
recursive_delete = local.recursive_delete
|
||||
s3_service_name = "${local.app_name}-csv-upload-bucket-${local.env}"
|
||||
}
|
||||
|
||||
module "contact_list_bucket" {
|
||||
source = "github.com/18f/terraform-cloudgov//s3"
|
||||
|
||||
cf_user = var.cf_user
|
||||
cf_password = var.cf_password
|
||||
cf_org_name = local.cf_org_name
|
||||
cf_space_name = local.cf_space_name
|
||||
recursive_delete = local.recursive_delete
|
||||
s3_service_name = "${local.app_name}-contact-list-bucket-${local.env}"
|
||||
}
|
||||
|
||||
module "egress-space" {
|
||||
source = "../shared/egress_space"
|
||||
|
||||
cf_user = var.cf_user
|
||||
cf_password = var.cf_password
|
||||
cf_org_name = local.cf_org_name
|
||||
cf_restricted_space_name = local.cf_space_name
|
||||
deployers = [
|
||||
var.cf_user,
|
||||
"ryan.ahearn@gsa.gov",
|
||||
"steven.reilly@gsa.gov"
|
||||
]
|
||||
}
|
||||
17
terraform/sandbox/providers.tf
Normal file
17
terraform/sandbox/providers.tf
Normal file
@@ -0,0 +1,17 @@
|
||||
terraform {
|
||||
required_version = "~> 1.0"
|
||||
required_providers {
|
||||
cloudfoundry = {
|
||||
source = "cloudfoundry-community/cloudfoundry"
|
||||
version = "0.15.5"
|
||||
}
|
||||
}
|
||||
|
||||
backend "s3" {
|
||||
bucket = "cg-6b759c13-6253-4a64-9bda-dd1f620185b0"
|
||||
key = "api.tfstate.sandbox"
|
||||
encrypt = "true"
|
||||
region = "us-gov-west-1"
|
||||
profile = "notify-terraform-backend"
|
||||
}
|
||||
}
|
||||
4
terraform/sandbox/variables.tf
Normal file
4
terraform/sandbox/variables.tf
Normal file
@@ -0,0 +1,4 @@
|
||||
variable "cf_password" {
|
||||
sensitive = true
|
||||
}
|
||||
variable "cf_user" {}
|
||||
36
terraform/shared/egress_space/main.tf
Normal file
36
terraform/shared/egress_space/main.tf
Normal file
@@ -0,0 +1,36 @@
|
||||
###
|
||||
# Target space/org
|
||||
###
|
||||
|
||||
data "cloudfoundry_org" "org" {
|
||||
name = var.cf_org_name
|
||||
}
|
||||
|
||||
###
|
||||
# Egress Space
|
||||
###
|
||||
|
||||
resource "cloudfoundry_space" "public_egress" {
|
||||
name = "${var.cf_restricted_space_name}-egress"
|
||||
org = data.cloudfoundry_org.org.id
|
||||
}
|
||||
|
||||
###
|
||||
# User roles
|
||||
###
|
||||
|
||||
data "cloudfoundry_user" "users" {
|
||||
for_each = var.deployers
|
||||
name = each.key
|
||||
org_id = data.cloudfoundry_org.org.id
|
||||
}
|
||||
|
||||
locals {
|
||||
user_ids = [for user in data.cloudfoundry_user.users : user.id]
|
||||
}
|
||||
|
||||
resource "cloudfoundry_space_users" "deployers" {
|
||||
space = cloudfoundry_space.public_egress.id
|
||||
managers = local.user_ids
|
||||
developers = local.user_ids
|
||||
}
|
||||
16
terraform/shared/egress_space/providers.tf
Normal file
16
terraform/shared/egress_space/providers.tf
Normal file
@@ -0,0 +1,16 @@
|
||||
terraform {
|
||||
required_version = "~> 1.0"
|
||||
required_providers {
|
||||
cloudfoundry = {
|
||||
source = "cloudfoundry-community/cloudfoundry"
|
||||
version = "~> 0.15"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "cloudfoundry" {
|
||||
api_url = "https://api.fr.cloud.gov"
|
||||
user = var.cf_user
|
||||
password = var.cf_password
|
||||
app_logs_max = 30
|
||||
}
|
||||
10
terraform/shared/egress_space/variables.tf
Normal file
10
terraform/shared/egress_space/variables.tf
Normal file
@@ -0,0 +1,10 @@
|
||||
variable "cf_password" {
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
variable "cf_user" {}
|
||||
variable "cf_org_name" {}
|
||||
variable "cf_restricted_space_name" {}
|
||||
variable "deployers" {
|
||||
type = set(string)
|
||||
}
|
||||
@@ -53,3 +53,17 @@ module "contact_list_bucket" {
|
||||
recursive_delete = local.recursive_delete
|
||||
s3_service_name = "${local.app_name}-contact-list-bucket-${local.env}"
|
||||
}
|
||||
|
||||
module "egress-space" {
|
||||
source = "../shared/egress_space"
|
||||
|
||||
cf_user = var.cf_user
|
||||
cf_password = var.cf_password
|
||||
cf_org_name = local.cf_org_name
|
||||
cf_restricted_space_name = local.cf_space_name
|
||||
deployers = [
|
||||
var.cf_user,
|
||||
"ryan.ahearn@gsa.gov",
|
||||
"steven.reilly@gsa.gov"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user