The persistent AWS infrastructure is deployed as Cloud.gov assets via Terraform. For a description of persistent infrastructure and how it differs from ephemeral infrastructure see the root README.md.
These docs are verbose because this is technology with which developers will rarely interact. I suggest you settle in for a nice long read with your favorite drink of choice.
-
Install Terraform
- On MacOS:
brew install terraform
- On other platforms: Download and install terraform
- On MacOS:
-
Use githook for formatting
Terraform has a specific whitespace formatting style that is difficult to maintain. Terraform includes a formatting command,
terraform fmt
, to help developers maintain the correct style. This repository contains a pre-commit hook that runsterraform fmt
on all staged files so you don't have to remember to run this command.If you are not using your own custom pre-commit hooks:
# start from repo root directory # make the pre-commit file executable chmod 755 .githooks/pre-commit # change your default hooks directory to `.githooks`. git config core.hooksPath .githooks
If you are already using git hooks, add the
.githooks/pre-commit
contents to your hooks directory or current pre-commit hook. Remember to make the file executable. -
Install Version 7 of the Cloud Foundry CLI tool
- On MacOS:
brew install cloudfoundry/tap/cf-cli@7
- On other platforms: Download and install cf. Be sure to get version 7.x
- On MacOS:
-
Add target environment credentials
We are using Terraform to create Cloud Foundry resources in a Cloud.gov account. Creating infrastructure on the Cloud.gov platform requires a Cloud.gov service account username and password. These keys are specific to each cloud.gov organization/space, i.e. each deployment environment, and can be generated by developers who have proper Cloud.gov permissions at any time.
Follow the steps below to generate a new set of credentials. If you need more information, check out the service account docs.
# login cf login -a api.fr.cloud.gov --sso # follow temporary authorization code prompts # select org "hhs-acf-ohs-tta", and the space (env) within which you want to build infrastructure # sandbox = ttahub-sandbox # dev = ttahub-dev # staging = ttahub-staging # prod = ttahub-prod # create a service instance that can provision service accounts # the value for < YOUR-NAME > can be any version of your name, it isn't significant cf create-service cloud-gov-service-account space-deployer < YOUR-NAME > # bind a service key to the service instance cf create-service-key < YOUR-NAME > space-deployer-key # return a username/password pair for the service instance cf service-key < YOUR-NAME > space-deployer-key
Add the username and password output from the last command to a
secrets.auto.tfvars
file in each environment directory. Terraform automatically loads this variable definition file. You can also provide variable values via environment variables. For more on this, check out terraform variable definitions.For example, your
terraform/dev/secrets.auto.tfvars
file should look something like this:cf_user = "some-dev-user" cf_password = "some-dev-password"
Additionally, for environments other than dev and production, we need to grant the space deployer credentials access to the dev space to enable setting up network policies to the dev ClamAV server.
# Grant some-dev-user from previous step SpaceDeveloper access to ttahub-dev cf set-space-role <some-dev-user from previous step> hhs-acf-ohs-tta ttahub-dev SpaceDeveloper
-
Create S3 bucket credentials
We are using an S3 bucket created by Cloud Foundry in Cloud.gov as our remote backend for Terraform. The backend maintains the "state" of Terraform and makes it possible for multiple developers to implement changes in a linear fashion.
Follow these directions to create a new service account and generate credentials. If you need more information check out the services docs.
# login cf login -a api.fr.cloud.gov --sso # follow temporary authorization code prompts # select org "hhs-acf-ohs-tta", space "infrastructure-config" # create a service instance # the value for < YOUR-NAME > can be any version of your name # it can be the same or different from the name you used for environment credentials in the previous step cf create-service-key ohs-ttahub-iac-state < YOUR-NAME > # return a username/password pair for the service instance cf service-key ohs-ttahub-iac-state < YOUR-NAME >
These credentials are for an S3 bucket that is used for holding the state of the dev, staging, and prod terraform environments; you only need to create one set of these
ohs-ttahub-iac-state
S3 bucket credentials. If you're already using AWS CLI you may simply add your newly generatedaccess_key_id
,secret_access_key
values to~/.aws/credentials
, and yourregion
value to~/.aws/config
. If this is your first time using AWS CLI install the tool and then follow the Quick Configuration with aws configure guide.Your
~/.aws/credentials
file should look something like this:[default] aws_access_key_id = foo aws_secret_access_key = bar
Your
~/.aws/config
file should look something like this:[default] region = us-gov-west-1
Tip: You run terraform files from the directory in which they are stored. For example, to instantiate a database described in terraform/dev/main.tf
you would run all the commands below from terraform/dev
.
-
Initialize your working directory
The first time you are working in a new environment, for example, after cloning this repository, you will need to initialize a working directory containing Terraform configuration files using the
init
command. It is safe to run this command multiple times.terraform init
-
Check that your state is clean
Terraform configuration files committed to the
main
branch should describe the infrastructure that is currently in use. This is described as a "clean state". Use theplan
command to display a list of infrastructure that Terraform will need to update, delete or create to match what is in your local Terraform configuration files.- If state is clean,
plan
will not display any changes. - If state is not clean and you are working on a feature branch try merging in the main branch; your local terraform files might be behind the current/applied state. If
plan
still shows an unclean state, reach out to your fellow developers for clarification and advice on how to proceed. It is very likely that changes were accidentally applied and a developer is currently working on a fix.
terraform plan
- If state is clean,
-
Make changes and get feedback
Make any needed changes to your local Terraform configuration files. Open a PR for those changes. In your PR include the output from
terraform plan
so reviewers can see what resources will be updated, created and destroyed. -
Merge and apply changes immediately
Tip: Before you merge your PR ensure you have enough time to sit and work through any unexpected problems that could arise. Database changes can take upwards of ten minutes to apply.
Merge your PR into
main
and then immediately apply your changes. Always merge and apply in one sitting.terraform apply
-
Bind the infrastructure to the application
CloudFoundry/cloud.gov requires that some "services" (e.g. AWS infrastructure) be "bound" to the application instance. S3, and Redis are all services that require this "binding" step. See the cloud.gov documentation for more direction on this. Also, check out PR#71 for an example of how this was done for the RDS instances.