Installing Terraform for infrastructure development
We’ll need to create and manage remote infrastructure, starting with a remote repository that we will use to develop the app with other developers or to simply backup our code. This remote infrastructure could be created manually, for example, using GitHub’s web interface. However, by using an Infrastructure as a Code tool, we can record all of the changes we make, and then if anything goes wrong, we can rerun our code and restore everything to a known state.
I find Terraform to be the best tool to manage infrastructure, which we can install as follows:
brew install terraform scoop install terraform
With Terraform installed, we can create a folder within our repository for the infrastructure code as follows:
mkdir infrastructure
Our repository should now have the following structure:
tozo ├── backend ├── frontend └── infrastructure
As with the backend and frontend, we’ll need to install tooling to help development. In addition, for the infrastructure, we’ll need tooling to manage secrets.
Managing secrets
To allow Terraform to manage our infrastructure, we will need to provide passwords, keys, and other secrets. These secrets will need to be stored (and used) in a secure fashion – simply storing passwords in plain text in the repository is a common way to be hacked. We will instead encrypt the secrets and store the encrypted file in the repository. This means we’ll have to keep the encryption key secret, which I recommend you do by using a password manager such as BitWarden.
To encrypt the secrets, we can use ansible-vault
, which is installed using the Python package manager, pip
, as follows:
pip install ansible-vault
pip or PDM
pip is a tool for installing packages, whereas PDM is a project management tool. As we don’t have an infrastructure project to manage, it makes more sense to use pip to install ansible-vault
. However, this is the only time we’ll directly use pip.
To configure ansible-vault
, we need to provide the encryption key. To do so, add your encryption key to infrastructure/.ansible-vault and inform Ansible that it is stored there by adding the following to infrastructure/ansible.cfg:
[defaults] vault_password_file = .ansible-vault
We’ll need to encrypt two files: Terraform’s state, terraform.tfstate
, and our collection of secret variables, secrets.auto.tfvars
. The commands to do so are the following:
ansible-vault encrypt secrets.auto.tfvars --output=secrets.auto.tfvars.vault ansible-vault encrypt terraform.tfstate --output=terraform.tfstate.vault
We will also need to decrypt these files, which is done via the following commands:
ansible-vault decrypt secrets.auto.tfvars.vault --output=secrets.auto.tfvars ansible-vault decrypt terraform.tfstate.vault --output=terraform.tfstate
To ensure that the password file, encrypted files, and general Terraform autogenerated files aren’t considered part of the repository, the following should be added to infrastructure/.gitignore:
.ansible-vault secrets.auto.tfvars terraform.tfstate *.backup .terraform.lock.hcl .terraform/
Terraform is now set up and ready to use, which means we can focus on the development tooling.
Formatting, linting, and testing the code
Terraform comes with a built-in formatter, which is invoked via the following command:
terraform fmt
This formatter also supports a check mode to use when linting, as follows:
terraform fmt --check=true
Terraform also comes with a tool to lint your code, as follows:
terraform validate
Testing Terraform code is harder as almost all of the code depends on an interaction with a third-party service. Instead, I find running and checking that the output makes sense to be the only way to test what the code will do. Terraform will provide an output of what it plans to do by running the following command:
terraform plan
This is all we need to install and set up to manage all of the infrastructure we’ll install in this book. We can now focus on the database.