The right way to pass AWS credentials to Terraform in a CI/CD pipeline
If you need to deploy AWS resources using Terraform, you will typically need to use HashiCorp’s AWS provider. In order for this provider to connect to AWS and provision or manage your resources, you need to make sure it can authenticate to AWS.
There are good ways and bad ways to do this. HashiCorp’s AWS provider has some good documentation explaining the various methods. The one you definitely want to avoid is setting the access_key
and secret_key
in the provider’s declaration, whether directly in the file or as variables in a *.tfvars
file. If you run that in the pipeline, you either have to have those keys in the git repo, which is obviously an enormous and obvious security risk, or you need to put them in environment variables and then you don’t need to set the access_key
and secret_key
variables at all, more on that later. Also, you are running the risk of those keys being leaked in logs. At the very least, declare the variables with sensitive = true
so their values won’t be leaked in the logs, documentation is available here.
In the context of running Terraform locally on one’s computer, the above method is still very risky because there is a high chance that somebody will inadvertently commit those into the git repository and pushing it to the remote repo. In addition, it involves copying these secrets in various places which runs the risk of exposing them through copying to a file or location with security settings that are too permissive.
One good method to use in the context of a CI/CD pipeline is to put the AWS keys in CI/CD secrets (or protected variables). All major CI/CD tools allow this, such as GitHub secrets and GitLab CI masked variables. The variables you need to set are AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
. These are the keys of the IAM user you want Terraform to use when accessing AWS.
Probably the best method is to have a runner inside AWS with an IAM role attached to it, and Terraform will automatically inherit this IAM role and its attached policies. In this case, you don’t have to specify anything, Terraform will just work. The issue is that this method is available only to fairly complex CI/CD setups, and those are typically used only by fairly large businesses because of the added costs.
One final comment is that the AWS provider can switch to a different IAM role based on the initial credentials. This is done using the assume_role
section of the AWS provider configuration. This is very interesting because it can allow Terraform to provision resources in a different AWS account. A well-organised set of AWS accounts could have, for example, one account dedicated to managing IAM users and where those users will have no access except for modifying their own security parameters. Those IAM users can then assume roles in other AWS accounts and perform whatever they need to perform in those accounts.
In conclusion, the most important takeaway is to be careful with the AWS keys. These are secrets which must be protected. Usually, placing these in CI/CD secret variables is a good way to keeping things secure. Ideally, you also want to rotate those keys on a regular basis.