DEV Community

Camille He
Camille He

Posted on

Deploy Github Secrets to AWS Secrets Manager using Terraform and Github Actions

In this article, I'm going to guide you how to save the project secure tokens in Github Secrets and deploy them into AWS Secrets Manager using Terraform and Github Actions workflow.

Using sensitive information, such as api key, password, secure tokens in a real project is very common. For example, you are working on a backend web server that needs to interacts with database. You must have database user/password configured programmatically no matter which programming language you select. These secure tokens are normally persisted in a secret management tool, and injected into environment variables when the server is up.

Secrets management tools help companies securely store, transmit, and manage sensitive digital authentication credentials such as passwords, SSH keys, API keys, database passwords, certificates like TLS/SSL certificates or private certificates, tokens, encryption keys, privileged credentials, and other secrets.

Some companies use third-party tools, such as AWS Secrets Manager, Azure Key Vault, and HashiCorp Vault, etc. Some CICD tools also provide secret management features to allow your pipeline retrieves these secrets easily before deployment. Jenkins has Credentials and Github Actions has Secrets.

What I implemented:

  1. Create a Terraform project that defines a aws_secretsmanager_secret resource using AWS official provider.
  2. Create an Environment named dev and add secrets and variables in the environment.
  3. Create a Github Actions workflow to deploy Terraform resources to AWS account.

Find the demo source code from https://github.com/camillehe1992/aws-terraform-examples/tree/main/secret-manager

Project Structure

The project source code structure as follows.



.
├── Makefile                    # a markfile for terraform commands 
├── README.md
├── main.tf                     # define the specs of secretsmanager module
├── modules
│   └── secretsmanager          # secretsmanager module
│       ├── locals.tf
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── outputs.tf                  # outputs of terraform
├── terraform.tfvars            # variables of terraform
├── variables.tf                # variables definition of terraform
└── versions.tf                 # terraform backend configuration and provider versions


Enter fullscreen mode Exit fullscreen mode

Define a variable named database_password in variables.tf.



variable "database_password" {
  type        = string
  description = "The password of database"
}


Enter fullscreen mode Exit fullscreen mode

Define a Terraform module named secretsmanager and create a bucket of secrets.

Modules are containers for multiple resources that are used together.



module "secrets" {
source = "./modules/secretsmanager"

env = var.env
nickname = var.nickname
tags = var.tags

secret_specs = {
database_password = {
description = "A sample secure. e.g password"
secret_string = var.database_password
}
}
}

Enter fullscreen mode Exit fullscreen mode




Create Environment and Secrets

Create an environment named dev in Github Settings, and add secrets and variables in it as follows.

Github Actions Secrets

Github Actions Workflow

Define an environment variable name DATABASE_PASSWORD in env block in Github Actions workflow file and inject the environment variable DATABASE_PASSWORD dynamically when running command terraform plan via parameter -var.



env:
# Secret tokens injected into Terraform infra
DATABASE_PASSWORD: "${{ secrets.TF_VAR_DATABASE_PASSWORD }}"

...

  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Terraform Plan</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">${{ inputs.destroy }} == </span><span class="kc">false</span>
    <span class="na">id</span><span class="pi">:</span> <span class="s">tf-plan</span>
    <span class="na">working-directory</span><span class="pi">:</span> <span class="s">${{ env.WORKING_DIRECTORY }}</span>
    <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
      <span class="s">export exitcode=0</span>
      <span class="s">terraform plan -var-file $(pwd)/tf_$ENVIRONMENT.tfvars \</span>
      <span class="s">-var="database_password=$DATABASE_PASSWORD" \</span>
      <span class="s">-detailed-exitcode -no-color -out tfplan || export exitcode=$?</span>
Enter fullscreen mode Exit fullscreen mode
Enter fullscreen mode Exit fullscreen mode




Trigger Deployment Manually

Github Actions workflow

  • Choose the target environment to deploy. Currently only dev is available.
  • Check True to destroy checkbox if you want to destory the resources.
  • Check True to force checkbox if you want to apply refresh the secure tokens. Useful when there is no change in Terraform infra, but there is a variables or secrets update in Github Settings.

Done. I'm always appreciating your comments and advice.

Top comments (1)

Collapse
 
navjot profile image
Navjot Singh

Hi @camillehe1992

I have setup everything like above in my .NET 8 application.
Below is my variable declaration in my tf:
variable "param_Api_Service_Password" {
type = string
description = "Parameter write API Service Password"
sensitive = true
default = "********"
}

I have set default value as "********".
In my AWS secrets manager, Git secret values are not getting picked up and this default value is stored in the secret. Could you please suggest what could be wrong?