

Discover more from CoderCo
How to securely pass secret values in Terraform to CICD pipelines (GitHub Actions)
I recently faced issues trying to pass secrets securely using CICD with Terraform. Here is a simple solution that works.
In the realm of cloud infrastructure management and automation, there often arises a need to configure secret values for various resources. For instance, you might have to integrate an API key into a deployed application or connect to a MongoDB Server using traditional username and password authentication. In this article, we will delve into a secure approach for passing these secret values to an Infrastructure as Code (IaC) pipeline using GitHub Actions and Terraform.
Securing Secrets in Terraform: When dealing with secret values in Terraform, the first step is to declare them as variables and ensure they remain hidden in logs and console outputs. The typical approach of declaring variables exposes their values, which is a major security concern. To prevent this, you can define variables with the "sensitive" attribute set to true, like so:
variable "mongodbatlas_public_key" {
type = string
description = "MongoDB Atlas public API key used to authenticate with MongoDB provider"
sensitive = true
}
variable "mongodbatlas_private_key" {
type = string
description = "MongoDB Atlas private API key used to authenticate with MongoDB provider"
sensitive = true
}
This "sensitive = true" declaration instructs Terraform to treat the variable as a secret, ensuring its value remains concealed in logs and outputs. You can then use this variable to create resources that require these secrets, such as setting up a MongoDB cluster:
module "mongodb_atlas_cluster" {
source = "../../terraform/modules/mongodb2.0"
atlas_org_id = var.org_id
cloud_provider = "AWS"
mongodb_version = "6.0"
mongodbatlas_public_key = var.mongodbatlas_public_key
mongodbatlas_private_key = var.mongodbatlas_private_key
ip_address = var.ip_address
Inputting Secret Values into Terraform
Now that Terraform understands the sensitive nature of the variable, the challenge is to input the secret value securely. The common approach of using a .tfvars file is not suitable because it exposes secrets in a file managed by Git. Another option is to have a .tfvars file in .gitignore, but this makes it challenging to use in a pipeline as it must be stored securely and authenticated to access.
An effective solution is to leverage environment variables to provide secret values. These environment variables must adhere to the syntax TF_VAR_{var-name}
, where var-name matches the variable name in the Terraform files. For example, for the "mssql_login_pwd" variable, you'd set an environment variable named TF_VAR_mongodbatlas_private_key
. Terraform will then use this value to populate the variable.
To implement this solution, we need to inform the pipeline runner about its environment variables.
Setting Up in a GitHub Actions Workflow
GitHub Actions should always have a way to securely store and pass secret values to runners. In GitHub, you can establish environments in your repository, ideally creating separate environments for production and development, each linked to specific branches (e.g., master and develop). This setup allows you to test deployments in a development environment before promoting changes to production.
Once environments are set up, you can add secret values to them. GitHub Actions workflows can automatically access the appropriate secrets based on the environment. For instance, you can add the public and private keys for connecting to a mongoDB cluster as secrets within the GitHub UI portal.
With secrets securely stored in GitHub environments, you can reference them in your workflows like this:
jobs:
tf_deploy:
name: TF deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TF_ACTION_WORKING_DIR: './examples/basic-2'
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
TF_VAR_mongodbatlas_public_key: ${{ secrets.MONGODBATLAS_PUBLIC_KEY }}
TF_VAR_mongodbatlas_private_key: ${{ secrets.MONGODBATLAS_PRIVATE_KEY }}
TF_VAR_ip_address: ${{ secrets.IP_ADDRESS }}
Now, the Ubuntu runner will have these environment variables populated directly from GitHub secrets. When Terraform executes on this runner, it will use these values to fill the "mongodbatlas_public_key
" and "mongodbatlas_private_key
" variables.
Conclusion
By following this method, you can establish a robust and secure way to transmit static secrets to GitHub Actions workflows responsible for deploying your infrastructure. These values remain secret both in GitHub and Terraform. Furthermore, since pipeline runners are ephemeral, the secrets exist in environment variables only for the duration of the job, enhancing overall security.
Future
Look for other ways to make this smoother and even more secure.