Creating infrastructure for AAQ on AWS
Create your own fork or a copy of the AAQ repository to follow along.
1. Install requirements
2. Login to AWS
-
(First time setup) Set up your AWS config file (
~/.aws/config
) to work with the different environments and AWS SSO. Make sure your config file contains the following entries:[profile <Profile Name>] sso_start_url = <your AWS SSO start URL> sso_region = <your AWS SSO region> sso_account_id = <your AWS account ID> sso_role_name = <your AWS SSO role name, e.g. AdministratorAccess> region = <your AWS infratructure region>
-
Log in to AWS
aws sso login --profile <Profile Name>
-
Run the following (Terraform relies on
AWS_PROFILE
environment variable)export AWS_PROFILE=<Profile Name>
3. Create Terraform backend infrastructure
To be able to run the code in a new AWS Account, first you will need to initialize the
code and create an S3 bucket where you will store the terraform state. This code is
housed in deployment/aws/infrastructure/tf_backend
.
- Make sure you've performed the login steps above.
- Review and edit the values in
deployment/aws/infrastructure/tf_backend/tf_backend.auto.tfvars
. -
Navigate to
deployment/aws/infrastructure/tf_backend
. Run the following in order:terraform init terraform plan
-
Review the plan, and apply the changes by running the following.
terraform apply
This will create the S3 bucket that will store the states of terraform.
4. Create AAQ infrastructure
The infractructure code for an example environment demo
is housed in
deployment/aws/infrastructure/demo
.
Create infrastructure for new deployment environments
If you wish to have multiple deployment environments, you can copy the demo
folder as deployment/aws/infrastructure/<environment>/
, for example,
deployment/aws/infrastructure/production/
.
Rename demo.auto.tfvars
file to <environment>.auto.tfvars
. Then, follow the steps
below but replace demo
with your own environment name.
Overview
There are three main modules.
bastion
: The Bastion Host serves as an intermediary server that allows secure access to the DB (an RDS instance). This will allow developers to connect to the DB even outside the VPC that the RDS instance resides in.main
: This is where all the infrastructure code for backend (core_backend
) and frontend (admin-app
) is stored. The application will run on ECS with an EC2 launch type. The load-balancing as well as certificate management is done using Caddy. The docker images will be stored in ECR.network
: This module has the code for the VPC and its components. The other modules will only have Security Groups resources. The rest are placed here.
Creating AAQ infrastructure
-
Navigate to
deployment/aws/infrastructure/demo
folder.cd deployment/aws/infrastructure/demo
-
Configure your deployment environment.
- Update the contents of
backend.conf
to match the resource names created in step 3. - Review and update the contents of the
demo.auto.tfvars
file. This file contains environment-specific variable values, which Terraform automatically loads during resource creation.
- Update the contents of
- Make sure you've performed the login steps above.
-
Initialize the Terraform backend and install the providers.
terraform init -backend-config=backend.conf
-
Run
terraform plan
to view the plan. - Run
terraform apply
to deploy the terraform configuration.
Preparing your infrastructure for deployment
Attach Elastic IP to your domain
When the infrastructure is created, a new Elastic IP is created. If you have your own domain, make sure to associate it with this IP address.
Store API keys in AWS Secrets Manager
For example, if you rely on OpenAI models, you must update the OpenAI API key in AWS AWS Secrets Manager.
5. Deploy on the infrastructure
Your infrastructure is now ready for deployment!
Next, set up CI/CD and deploy AAQ on the infrastructure you created.
Additional guides
Connecting to your DB locally
-
Open a connection to the AAQ database
aws ssm start-session \ --target <Instance ID> \ --profile <Profile Name> \ --region <Region> \ --document-name AWS-StartPortForwardingSession \ --parameters '{"portNumber":["5432"],"localPortNumber":["5432"]}'
<Instance ID>
is the EC2 instance ID of the Bastion Host.If the command hangs at
Starting session with SessionId:...
, make sure port 5432 is available. -
Retrieve the DB connection credentials from AWS Secrets Manager.
-
Connect to the DB via the tunnel created above:
- With pgAdmin: create a connection with the host as
localhost
and enter the credentials -
With docker:
docker pull dpage/pgadmin4 docker run -p 80:80 \ -e 'PGADMIN_DEFAULT_EMAIL=user@domain.com' \ -e 'PGADMIN_DEFAULT_PASSWORD=SuperSecret' \ -d dpage/pgadmin4
When using pgAdmin or docker, the host will be
host.docker.internal
if localhost does not work. - With pgAdmin: create a connection with the host as
Adding a new secret
All secrets stored in AWS Secrets Manager are created and managed using Terraform. The
secrets are defined under deployment/aws/infrastructure/<environment>/main/credentials.tf
.
To add a new secret,
- Create an
aws_secretsmanager_secret
andaws_secretsmanager_secret_version
for your secret.- If this will be a generated secret,
- Increase the value of
random_password.secrets.count
by X depending on how many secrets need to be generated - The value of the
aws_secretsmanager_secret_version.secret_string
is where the generated secret will be stored. To add the value of the generated secret, reference therandom_password.secrets
and the value of the index. If there are 2 secrets to be generated, the index starts from 0. If the secret is the first one, the value will berandom_password.secrets[0].result
. If you are adding to an already existing count, get the last declared index and add 1. So if the last secret wasrandom_password.secrets[4].result
, the new one will berandom_password.secrets[5].result
- Increase the value of
- If you want to create a placeholder secret to be manually set later (e.g. external API key), the
secret_string
should have a placeholder string. Terraform will not allow an empty string. In theaws_secretsmanager_secret_version
, we will also have to ignore changes to the string. This is because when you manually change the string, terraform will detect the change and without ignoring the change, it will overwrite the secret with the placeholder
- If this will be a generated secret,
- Add the secret to the
deployment/aws/infrastructure/<environment>/main/iam.tf
permissions to allow theecs_task_role
to get the value. - If the secret is needed at the backend startup, it also needs to be added to the
deployment/aws/core_backend/bootstrap.sh
file.