Handling multiple providers/accounts/roles/regions

I am new to TF and even newer to TS so I may be asking a stupid question.
We have a number of separate accounts for our AWS deployment and I cannot seem to see a way to roll the same or different deployment out to multiple accounts other than repeating the configs.
What am I missing?

Terraspace will deploy to whatever AWS account your machine is set up to use. In a multiple AWS account setup, people commonly use a different AWS_PROFILE for each account on their local machine. Here’s an example setup:

~/.aws/config

[profile dev-account]
output=json
region=us-west-2

[profile prod-account]
output=json
region=us-west-2

~/.aws/credentials

[dev-account]
aws_access_key_id=DEV1234567891EXAMPLE
aws_secret_access_key=EXAMPLE12345678912345678912345678EXAMPLE

[prod-account]
aws_access_key_id=PROD123456781EXAMPLE
aws_secret_access_key=EXAMPLE12345678912345678912345678EXAMPLE

Create an example project:

terraspace new infra --examples
cd infra

Deploy to different AWS accounts for dev and prod like so:

AWS_PROFILE=dev-account  TS_ENV=dev  terraspace up demo
AWS_PROFILE=prod-account TS_ENV=prod terraspace up demo

Confirm that the buckets have been created in different accounts:

AWS_PROFILE=dev-account  aws s3 ls | grep ' bucket-'
AWS_PROFILE=dev-account  aws sts get-caller-identity | jq '.Account'
AWS_PROFILE=prod-account aws s3 ls | grep ' bucket-'
AWS_PROFILE=prod-account aws sts get-caller-identity | jq '.Account'

You can use different variables as needed. First, generate some tfvars files with the terraspace seed command.

$ TS_ENV=dev  terraspace seed demo
$ TS_ENV=prod terraspace seed demo
$ ls app/stacks/demo/tfvars/
dev.tfvars  prod.tfvars
$

Put only the environment-specific values in the corresponding env tfvars files to avoid duplication.

For “common variables”, generate a base.tfvars:

$ TS_ENV=base terraspace seed demo
      create  app/stacks/demo/tfvars/base.tfvars

Put the common variables in there, again avoiding duplication.

Layering docs: https://terraspace.cloud/docs/tfvars/layering/


Additionally, if you want not to remember setting the AWS_PROFILE, you can use a boot hook to set AWS_PROFILE.

config/boot/dev.rb

ENV['AWS_PROFILE'] = 'dev-account'

And for prod:

config/env/prod.rb

ENV['AWS_PROFILE'] = 'prod-account'

This now allows you to deploy with just:

TS_ENV=dev  terraspace up demo
TS_ENV=prod terraspace up demo

Note, how it’s no longer necessary to have to remember to set AWS_PROFILE as the terraspace boot hook is automatically switching it for you.

On boot hooks docs: https://terraspace.cloud/docs/config/boot/

Note, think that it’s generally better to set up CI/CD to handle deploying to the separate accounts, though.

How would I for example run
terraspace up demo
that would create 5 different stacks in 5 different AWS_PROFILES?

I see. Don’t think it’s even possible at the terraform level in one-go. And unsure if it belongs at the individual terraspace-level. :face_with_monocle:

Some approaches:

  • Setup CI that handles calling the multiple AWS_PROFILE at a higher level.
  • A wrapper script that calls each of the AWS_PROFILE in a loop.
  • Use tool like make or the like.

:frowning:
Those sound like WET solutions but I get it.
Something like being able to conditionally include different values in the provider.tf config file based on the stack being rendered might work.

You could possibly do things with multiple providers and setting the alias and profile fields in provider.tf Don’t think it’s possible to use different backends in different accounts. AFAIK, the alias field doesn’t exist for a terraform backend config. So, the backend would be shared. So don’t think it’s even possible in one-go with Terraform. It’s also coupled.

Believe it’s cleaner via a wrapper script. At least that’s my 2 cents. The infrastructure code would be the same. The difference would be TS_ENV. Example:

#!/bin/bash
for i in dev prod uat qa stag; do
  TS_ENV=$i terraspace up demo -y
done

Sometimes, folks tend to try to fit everything into one tool to come up with a “god” command. It may be impossible to ever fit the god criteria. As the linux saying goes, “Use the right tool for the right job”. Did an interview with Anton B, he explains it pretty clearly: “We still have makefiles, we still have shell”. Here’s the video at the specific time: https://youtu.be/J_-XPfFlsbU?t=6420 Also see: Customized layering support?

Also think it’s probably better to have different CI jobs on the separate AWS accounts to run terraspace up. It’s nice and secure to separate the machine that handles each environment’s deployment. To keep the CI setup itself DRY, could use terraspace to build the CI jobs themselves. Or could use something like https://cody.run/ to build the CI setup with code. Note, am author of the cody tool also. Cody has similar patterns where you can use the same infrastructure code to build multiple permutations. :+1: