Automating variables and secrets management with Github Actions and AWS SSM Parameter Store

In this article, we will see how to automate the deployment of secrets and variables using AWS SSM (Systems Manager) Parameter Store and Github Actions workflows. This solution relies on the Secrets and Variables configured in the repository settings to serve as the source of truth for secrets and variables. These configurations will be synchronized with AWS SSM Parameter Store through a Github Actions workflow.

Setting Up Secrets and Variables

  1. Navigate to the Secrets and Variables section in the repository settings. You can access repository secrets and variables by clicking on the Secrets or Variables tabs respectively.
  2. Create secrets or variables that have the following format:

Github Secrets

Note: It is crucial to prefix your secret names. You can use any prefix, such as your organization name. This is important because Github has a default set of secrets available for each repository, which you might not be interested in. Using a custom prefix helps to exclude Github’s default secrets from the synchronization process.

Syncing with AWS SSM Parameter Store

The next step is to synchronize your secrets and variables with AWS SSM Parameter Store by creating a Github Actions workflow.

Add a Github Actions workflow file under the .github/workflows folder in your repository. This workflow script runs on commits to the main branch and allows you to trigger the workflow manually.

When executed, it extracts secrets and variables, converts them to JSON and synchronizes them with AWS SSM Parameter Store using jq. All secrets will be added to Parameter Store as secure strings and variables as plain strings. If a parameter already exists, it will be overwritten.

name: Synchronize

on:
  workflow_dispatch:
    branches: 
      - main
  push:
    branches:
      - main

env:
  AWS_REGION : us-east-2
  AWS_DEPLOY_ROLE: arn:aws:iam::111111111111:role/YourAwsDeployRole
  ANCHOR_PREFIX: _YOURPREFIX_

jobs:
  synchronize:
    permissions:
      contents: write
      id-token: write
    name: Synchronize
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup AWS CLI
        uses: actions/setup-python@v4
        with:
          python-version: 3.x
      - run: pip install awscli

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v3
        with:
          role-to-assume: ${{ env.AWS_DEPLOY_ROLE }}
          aws-region: ${{ env.AWS_REGION }}
          role-session-name: ParameterStoreDeploymentSession

      - name: Sync Variables and Secrets
        run: |
          # Loop through all repository secrets
          for SECRET_NAME in $(echo "$SECRETS_JSON" | jq -r 'keys[] | select(. | startswith("${{ env.ANCHOR_PREFIX }}"))'); do
            NEW_SECRET_NAME_LOWERCASE=$(echo "$SECRET_NAME" | tr '[:upper:]' '[:lower:]')  # Convert to lowercase
            SECRET_VALUE=$(echo "$SECRETS_JSON" | jq -r .${SECRET_NAME})
            PARAM_NAME="${NEW_SECRET_NAME_LOWERCASE//_//}"
            aws ssm put-parameter --name "$PARAM_NAME" --value "$SECRET_VALUE" --type SecureString --overwrite
          done

          # Loop through all repository variables
          for VAR_NAME in $(echo "$VARS_JSON" | jq -r 'keys[] | select(. | startswith("${{ env.ANCHOR_PREFIX }}"))'); do
            NEW_VAR_NAME_LOWERCASE=$(echo "$VAR_NAME" | tr '[:upper:]' '[:lower:]')  # Convert to lowercase
            VAR_VALUE=$(echo "$VARS_JSON" | jq -r .${VAR_NAME})
            PARAM_NAME="${NEW_VAR_NAME_LOWERCASE//_//}"
            aws ssm put-parameter --name "$PARAM_NAME" --value "$VAR_VALUE" --type String --overwrite
          done
        env:
          SECRETS_JSON: ${{ toJson(secrets) }}
          VARS_JSON: ${{ toJson(vars) }}

That’s it! With this setup, your secrets and variables will be automatically synchronized with AWS SSM Parameter Store, ensuring secure and efficient management of your application’s configuration.

Security Considerations

GitHub has implemented measures to obfuscate secret printing within workflows. However, it’s important to note that, technically, there are methods to bypass these measures in workflow scripts. This is a crucial consideration when utilizing GitHub repository secrets as the primary source of truth for secret values. It’s recommended to weigh the trade-offs carefully.

Having said that, I believe with proper pull request management and implementation of main branch protection measures, this approach can be effective and secure for many organizations.