Managing Secrets in Github Pipelines

📘

Deeper Dive

For more in-depth information, check out our detailed documentation on the following topics:

Github Actions Community Plugin

Oauth2.0/JWT Auth Method

👍

Something not working?

If something in this tutorial isn't working as expected, feel free to contact our support team via Slack.

Below is a text-only guide for users based on the above video

This is a community plugin that enables you to fetch Static and Dynamic secrets directly from the Akeyless Platform into your Github Actions workflows.

This tutorial will demonstrate running a Github Actions pipeline using OAuth 2.0 / JWT authentication to fetch both a Static and Dynamic secret from Akeyless in order to update a MySQL database table.

Prerequisites

  1. A Github account and project.
  2. A specific job permissions requirement which we will show in the workflow YAML.
  3. For Dynamic Secrets, jq must be installed on the runner host (this is usually installed by default in Github runners).

OAuth 2.0 / JWT

Create Auth Method via Web UI

Go to the console and create your GitLab Auth Method by clicking "Users & Auth Methods" > "New" > "OAuth 2.0 / JWT".

Then add the following information:

Name: Give the Auth Method a name. In this example, we call it GitHubAuth.

JWKs URL: Use the following URL - https://token.actions.githubusercontent.com/.well-known/jwks

Unique Identifier: repository (this will be set in our Access Role's Sub-Claim). Whenever a user logs in with a token, these authentication types issue Sub-Claims that contains details uniquely identifying that user. This sub-claim includes a key containing the ID value you configured and is used to distinguish between users from within the same organization.

JWT TTL: Choose the length of time the token will be available for use (in minutes).

Require Sub Claim on role association: Tick this box to enforce Sub-Claims on role association.

OAuth 2.0 / JWT

Create Auth Method via Web UI

Go to the console and create your GitLab Auth Method by clicking "Users & Auth Methods" > "New" > "OAuth 2.0 / JWT".

Create Auth Method via CLI

In Akeyless, create a new OAuth 2.0 / JWT Authentication Method with the following parameters:

akeyless create-auth-method-oauth2 --name GitHubAuth \
--jwks-uri https://gitlab.com/-/jwks \
--unique-identifier repository
--force-sub-claims

To see how to use the AWS IAM Authentication Method, see the docs.

Access Role

See the video on Role-Based Access Controls to create an Access Role, Associate it with the Auth Method, and provide the proper permissions. In this example, we called the role GithubRole.

Add an appropriate Sub-Claim: repository=/.

🚧

Sub Claims:

It is mandatory to add an appropriate Sub Claim based on the claims available in the Github documentation to prevent access by unauthorized users.

Sub-Claim configuration allows Akeyless to grant access to specific workflows, based on the claims that GitHub provides in the JWT.

Set Read permissions only for Secrets & Keys. You can also specify a specific secret in the path.

📘

Runner Configuration

If you would like to set up a self-hosted runner, check out our [docs](When the job has finished, the VM is automatically decommissioned).

In this demo, we use a Github hosted runner which automatically provisions a new VM for each job which is automatically decommissioned once the job has finished.

Example Usage

In this example, we are updating our Github repo which triggers a workflow that runs a set of commands in order to update a MySQL database. For this to work, you will need to have:

  1. A MySQL database with table as well as the host address
  2. A MySQL Dynamic Secret Producer
  3. Akeyless Gateway
  4. Access ID
  5. Private Key for SSH saved as Static Secret

Open your Github repo and add your ACCESS_ID as a secret under Settings -> Secrets and variables -> Actions.

Next, make sure you have a folder in your repo called .github/workflows along with a yaml file in that directory and update it with the below code.

📘

Important information about this file

In the below file, you should change the following to your own Akeyless secret names:

jeremy-demo is the RSA private key

jeremy-demo.pem is the private key - you can call the file whatever you want, just make sure to update it in both places

mysqlDS is the MySQL Dynamic Secret Producer

<mysql-host> is where you will add your MySQL host address

For the MySQL command, make sure you have your database and table set and change the info to match yours.

name: 'Fetch Static and Dynamic Secrets to Update MySQL DB'
on: push

jobs:
  fetch_static_dynamic_secrets:
    runs-on: 'ubuntu-latest'
    name: Use MySQL Dynamic Secret to Update DB
    
    permissions:
      id-token: write
      contents: read
      
    steps:
    - name: Fetch Private Key Static Secret and MySQL Dynamic Secret from Akeyless
      id: fetch-secrets
      uses: LanceMcCarthy/[email protected]
      with:
        access-id: ${{ secrets.ACCESS_ID }}
        static-secrets: '{"jeremy-demo":"MY_RSA"}'
        dynamic-secrets: '{"mysqlDS":"MYSQL_DYNAMIC_SECRET"}'
        
    - name: Create PEM File & Export Dynamic Secret to Environment
      run: |
        echo ${{ env.MY_RSA }} | base64 -d >> jeremy-demo.pem
        echo '${{ steps.fetch-secrets.outputs.MYSQL_DYNAMIC_SECRET }}' | jq -r 'to_entries|map("JWT_\(.key)=\(.value|tostring)")|.[]' >> $GITHUB_ENV

    - name: Verify Vars
      run: |
        echo "id: ${{ env.JWT_id }}"
        echo "password: ${{ env.JWT_password }}"
        
    - name: SSH into Host and Update Database Table
      run: |
        echo -e '#!/bin/bash' >> employee.sh
        echo -e "mysql -u\$LC_user -p\$LC_pass -e 'USE Employees; INSERT INTO employees (First_Name,Last_Name) VALUES (\"Gwen\",\"Stacy\");'" >> employee.sh
        export LC_user=${{ env.JWT_id }}
        export LC_pass=${{ env.JWT_password }}
        chmod 600 jeremy-demo.pem
        scp -o StrictHostKeyChecking=no -i "jeremy-demo.pem" employee.sh ubuntu@<mysql-host>:~/.
        ssh -o "SendEnv LC_*" -o StrictHostKeyChecking=no -i "jeremy-demo.pem" ubuntu@<mysql-host> -t "bash employee.sh" # SSH into Remote EC2 Host and update DB
        echo "Database Employees updated!"

Here's what is happening in this workflow:

  1. We start a Github runner with the latest Ubuntu image.
  2. Give it the permissions noted earlier.
  3. Use the community project to fetch our Access ID, Static Secret, and Dynamic Secret.
  4. Create our pem file and decode our base64 encoded private key into the file from the Stati Secret.
  5. Add the Dynamic Secret information, parsed into the temp user and temp password, to our Github Env variable.
  6. Check that our variables are giving us valid temporary creds (Optional).
  7. Create our bash script on the fly, which will be used to update the database.
  8. Export the temp user and password.
  9. Give the pem file proper permissions.
  10. Then, we run our SSH copy command to copy the employee.sh file into the remote host which is used to update the database.
  11. Next, SSH into the remote host again sending the values of the username and the password in order to log into the database and then run the `employee.sh` file to log into, and update, the MySQL database.
  12. And we just echo that the database called `employees` was updated.

Once you commit the file, go to the Actions tab and you will see a new workflow with something similar to the following output:

You can head over to your database and login with your admin or temporary credentials to see the update was successful:

Note that the above image shows the previous state of the database and then the updated state with the new row added.