Deploy Github Secrets to AWS Secrets Manager using Terraform and Github Actions
Tags: aws, githubactions, cicd
Published: 2023-09-21 09:49:54

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](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret).
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.

```bash
.
├── 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
```
Define a variable named `database_password` in `variables.tf`.

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

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

> Modules are containers for multiple resources that are used together.

```terraform
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
    }
  }
}
```
## Create Environment and Secrets
Create an environment named `dev` in Github Settings, and add secrets and variables in it as follows.

![Github Actions Secrets](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jeym6hkthd98fbmnm08g.png)

## 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`.

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

...

      - name: Terraform Plan
        if: ${{ inputs.destroy }} == false
        id: tf-plan
        working-directory: ${{ env.WORKING_DIRECTORY }}
        run: |
          export exitcode=0
          terraform plan -var-file $(pwd)/tf_$ENVIRONMENT.tfvars \
          -var="database_password=$DATABASE_PASSWORD" \
          -detailed-exitcode -no-color -out tfplan || export exitcode=$?

```
## Trigger Deployment Manually

![Github Actions workflow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2cu30qzg87owqn7b8c3i.png)

- 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.