The most secure way to manage infrastructure in AWS is to use multiple AWS accounts. You define all your IAM users in one account (e.g., the “security” account) and deploy all of your infrastructure into a number of other accounts (e.g., the “dev”, “stage”, and “prod” accounts). To access those accounts, you login to the security account and assume an IAM role in the other accounts.
There are a few ways to assume IAM roles when using AWS CLI tools, such as Terraform:
One option is to create a named profile, each with a different role_arn parameter. You then tell Terraform which profile to use via the
AWS_PROFILE environment variable. The downside to using profiles is that you have to store your AWS credentials in plaintext on your hard drive.
Another option is to use environment variables and the AWS CLI. You first set the credentials for the security account (the one where your IAM users are defined) as the environment variables
AWS_SECRET_ACCESS_KEY and run
aws sts assume-role --role-arn <ROLE>. This gives you back a blob of JSON that contains new
AWS_SECRET_ACCESS_KEY values you can set as environment variables to allow Terraform to use that role. The advantage of this approach is that you can store your AWS credentials in a secret store and never write them to disk in plaintext. The disadvantage is that assuming an IAM role requires several tedious steps. Worse yet, the credentials you get back from the
assume-role command are only good for up to 1 hour, so you have to repeat this process often.
A final option is to modify your AWS provider with the assume_role configuration and your S3 backend with the role_arn parameter. You can then set the credentials for the security account (the one where your IAM users are defined) as the environment variables
AWS_SECRET_ACCESS_KEY and when you run
terraform apply or
terragrunt apply, Terraform/Terragrunt will assume the IAM role you specify automatically. The advantage of this approach is that you can store your AWS credentials in a secret store and never write them to disk in plaintext, and you get fresh credentials on every run of
apply, without the complexity of calling
assume-role. The disadvantage is that you have to modify all your Terraform / Terragrunt code to set the
role_arn param and your Terraform backend configuration will change (and prompt you to manually confirm the update!) every time you change the IAM role you’re using.
To avoid these frustrating trade-offs, you can configure Terragrunt to assume an IAM role for you, as described next.
To tell Terragrunt to assume an IAM role, just set the
--terragrunt-iam-role command line argument:
terragrunt apply --terragrunt-iam-role "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME"
Alternatively, you can set the
TERRAGRUNT_IAM_ROLE environment variable:
export TERRAGRUNT_IAM_ROLE="arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" terragrunt apply
Additionally, you can specify an
iam_role property in the terragrunt config:
iam_role = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME"
Terragrunt will resolve the value of the option by first looking for the cli argument, then looking for the environment variable, then defaulting to the value specified in the config file.
Terragrunt will call the
sts assume-role API on your behalf and expose the credentials it gets back as environment variables when running Terraform. The advantage of this approach is that you can store your AWS credentials in a secret store and never write them to disk in plaintext, you get fresh credentials on every run of Terragrunt, without the complexity of calling
assume-role yourself, and you don’t have to modify your Terraform code or backend configuration at all.