GitHub Actions enables you to automate workflows for your GitHub-hosted repositories. With the Github Actions plugin, you can fetch secrets directly from Akeyless into your workflows. This guide describes how to use our various Authentication Methods to fetch Static, Dynamic, and Rotated secrets, as well as SSH and PKI certificates, from Akeyless.
⚠️ Important: Setting
ACTIONS_RUNNER_DEBUG
totrue
can expose sensitive information in your error logs. Use with caution.
Name | Required | Type | Value |
---|---|---|---|
access-id | No | string |
The access id for your auth method. If token is not provided this field is required. |
access-type | No | string |
Default: jwt . The login method to use. Valid options are jwt /access_key /universal_identity /aws_iam /azure_ad /gcp /k8s . |
token | No | string |
A valid Akeyless token. |
api-url | No | string |
Default: https://api.akeyless.io . The API endpoint to use. |
static-secrets | No | string |
A YAML list representing static secrets to fetch. |
dynamic-secrets | No | string |
A YAML list representing dynamic secrets to fetch. |
rotated-secrets | No | string |
A YAML list representing rotated secrets to fetch. |
ssh-certificates | No | string |
A YAML list representing ssh certificates to fetch. |
pki-certificates | No | string |
A YAML list representing pki certificates to fetch. |
export-secrets-to-outputs | No | boolean |
Default: true . True/False to denote if secrets should be exported as environment variables. |
export-secrets-to-environment | No | boolean |
Default: true . True/False to denote if secrets should be exported as action outputs. |
access-key | No | string |
Access key (relevant only for access-type=access_key ). |
gcp-audience | No | string |
GCP audience to use in signed JWT (relevant only for access-type=gcp ). |
gateway-url | No | string |
Gateway URL for the K8s authenticated (relevant only for access-type=k8s /oauth2 ). |
k8s-auth-config-name | No | string |
The K8s Auth config name (relevant only for access-type=k8s ). |
uid_token | No | string |
The Universal Identity token (relevant only for access-type=universal_identity). |
The job outputs are determined by the values set in your static-secrets
/dynamic-secrets
/rotated-secrets
/ssh-certificates
/pki-certificates
inputs.
The default behavior will create a single output/env variable that uses the name you set for the output.
Name | Value |
---|---|
outputs | use ${{ steps.JOB_NAME.outputs.SECRET_NAME }} |
environment variables | use ${{ env.SECRET_NAME }} |
For each Akeyless secret you can extract a specific field out of the JSON by adding the field key name.
For example, for the following static secret value name "github-static-secret-json":
{
"imp": "needed",
"no": "no_need"
}
We can use:
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
and in "steps.output.my_first_secret" the value will be "needed".
There is an option to get more detailed logs from the Akeyless Github Action by setting the ACTIONS_RUNNER_DEBUG
secret or variable to true
in the repository that contains the workflow.
⚠️ Important: Setting
ACTIONS_RUNNER_DEBUG
totrue
can expose sensitive information in your error logs. Use with caution.
Although this repository's workflows use placeholder values, it is still a real Akeyless account and real providers. The approaches demonstrated are still valid as-is for real implementations. Use these to your advantage!
Static secrets are the easiest to use. Just define the secret's path and the secret's output.
jobs:
fetch_secrets:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Fetch static secrets from Akeyless
uses: akeyless-community/akeyless-github-action@v1.0.1
id: fetch-secrets
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: jwt
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
- name: "/akeyless-github-action/github-static-secret"
output-name: "my_second_secret"
- name: Use Akeyless secret
run: |
echo "Step Outputs"
echo "my_first_secret: ${{ steps.fetch-secrets.outputs.my_first_secret }}" >> secrets.txt
echo "my_second_secret: ${{ steps.fetch-secrets.outputs.my_second_secret }}" >> secrets.txt
echo "Environment Variables"
echo "my_first_secret: ${{ env.my_first_secret }}" >> secrets.txt
echo "my_second_secret: ${{ env.my_second_secret }}" >> secrets.txt
This example demonstrates fetching an AWS Dynamic Secret from Akeyless.
fetch_aws_dynamic_secrets:
runs-on: ubuntu-latest
name: Fetch AWS dynamic secrets
permissions:
id-token: write
contents: read
steps:
- name: Fetch dynamic secrets from Akeyless
id: fetch-dynamic-secrets
uses: akeyless-community/akeyless-github-action@v1.0.1
with:
access-id: ${{vars.AKEYLESS_ACCESS_ID}}
dynamic-secrets: |
- name: "/path/to/dynamic/aws/secret"
output-name: "aws_dynamic_secrets"
access-type: jwt
# ********* KEY TAKEAWAY ********* #
# STEP 1 - Export Dynamic Secret's keys to env vars
- name: Export Secrets to Environment
run: |
echo '${{ steps.fetch-dynamic-secrets.outputs.aws_dynamic_secrets }}' | jq -r 'to_entries|map("AWS_\(.key|ascii_upcase)=\(.value|tostring)")|.[]' >> $GITHUB_ENV
# STEP 2 - You can now access each secret separately as environment variables
- name: Verify Vars
run: |
echo "access_key_id: ${{ env.AWS_ACCESS_KEY_ID }}" >> secrets.txt
echo "id: ${{ env.AWS_ID }}" >> secrets.txt
echo "secret_access_key: ${{ env.AWS_SECRET_ACCESS_KEY }}" >> secrets.txt
echo "security_token: ${{ env.AWS_SECURITY_TOKEN }}" >> secrets.txt
echo "ttl_in_minutes: ${{ env.AWS_TTL_IN_MINUTES }}" >> secrets.txt
echo "type: ${{ env.AWS_TYPE }}" >> secrets.txt
echo "user: ${{ env.AWS_USER }}" >> secrets.txt
This example demonstrates fetching an AWS Rotated Secret from Akeyless.
fetch_aws_rotated_secrets:
runs-on: ubuntu-latest
name: Fetch AWS rotated secrets
permissions:
id-token: write
contents: read
steps:
- name: Fetch rotated secrets from Akeyless
id: fetch-rotated-secrets
uses: akeyless-community/akeyless-github-action@v1.0.1
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: jwt
rotated-secrets: |
- name: "/path/to/rotated/aws/secret"
output-name: "aws_rotated_secrets"
fetch_ssh_secrets:
runs-on: ubuntu-latest
name: Fetch ssh certificate
permissions:
id-token: write
contents: read
steps:
- name: Fetch ssh certificates from Akeyless
id: fetch-ssh-certificate
uses: akeyless-community/akeyless-github-action@v1.0.1
with:
access-type: jwt
ssh-certificate-secrets: |
- name: "/path/to/ssh/secret1"
output-name: "ssh_secret"
cert-username: "ubuntu",
public-key-data: "public_key_data",
- name: "/path/to/ssh/secret2"
output-name: "ssh_secret2"
cert-username: "ubuntu",
public-key-data: "public_key_data",
fetch_pki_secrets:
runs-on: ubuntu-latest
name: Fetch pki certificate
permissions:
id-token: write
contents: read
steps:
- name: Fetch pki certificates from Akeyless
id: fetch-pki-certificates
uses: akeyless-community/akeyless-github-action@v1.0.1
with:
access-type: jwt
pki-certificate-secrets: |
- name: "/path/to/pki/secret1"
output-name: "pki_secret"
csr-data-base64: "csr_data_base64"
- name: "/path/to/pki/secret2"
output-name: "pki_secret2"
csr-data-base64: "csr_data_base64"
By default, the action sets the environment variable value to the entire JSON string in the secret value. Set parse-json-secrets
to true
to create environment variables for each key/value pair in the secret JSON.
parse-json-secrets
to false and parse the JSON secret value separately.key
and output-name
for extracting a specific key with a specific name./dev/test
, the default name will be env.DEV_TEST_{key}
.For example, for a secret with JSON values:
{
"key1":"val1",
"key2":"val2"
}
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: jwt
static-secrets: |
- name: "/path/to-secret"
- name: "/path/to-secret"
key: "key1"
output-name: "SECRET"
parse-json-secrets: true
- name: Use Akeyless secret
run: |
echo "key1: ${{ env.PATH_TO-SECRET_KEY1 }} >> secrets.txt
echo "key2: ${{ env.PATH_TO-SECRET_KEY2 }}" >> secrets.txt
echo "key1: ${{ env.SECRET }}" >> secrets.txt
If you don't want the prefix to be the secret name you can add prefix-json-secrets
with the prefix you would like:
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: jwt
static-secrets: |
- name: "/path/to-secret"
prefix-json-secrets: "Mysql"
parse-json-secrets: true
- name: Use Akeyless secret
run: |
echo "val1 == ${{ env.MYSQL_KEY1 }}" >> secrets.txt
echo "val2 == ${{ env.MYSQL_KEY2 }}" >> secrets.txt
This action supports the following authentication methods. Pay close attention as for some authentication methods there are extra inputs needed aside from the access-type
.
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: jwt
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
The default usage relies on using the GitHub JWT to login to Akeyless. To make this available, you have to configure it in your job workflow:
jobs:
my_job:
#---------Required---------#
permissions:
id-token: write
contents: read
#--------------------------#
⚠️ If this is not present, the akeyless-action step will fail with the following error:
Failed to login to Akeyless: Error: Failed to fetch Github JWT: Error message: Unable to get ACTIONS\_ID\_TOKEN\_REQUEST\_URL env variable
.
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: aws_iam
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: azure_ad
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: gcp
gcp-audience: "gcp-audience"
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: k8s
k8s-auth-config-name: "k8s-auth-config-name"
gateway-url: "gateway-url"
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: universal_identity
uid_token: "uid_token"
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-key: ${{ secrets.AKEYLESS_ACCESS_KEY }}
access-type: access_key
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
with:
token: ${{ steps.JOB_NAME.outputs.token }}
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
When TLS is configured on the Akeyless Gateway, you need to also pass the CA certificate (the CA certificate should be in PEM format):
with:
access-id: ${{ vars.AKEYLESS_ACCESS_ID }}
access-type: universal_identity
uid_token: "uid_token"
ca-certificate: ${{ secrets.AKEYLESS_CA_CERTIFICATE }}
static-secrets: |
- name: "/akeyless-github-action/github-static-secret-json"
output-name: "my_first_secret"
key: "imp"
To configure Akeyless and grant your repositories the necessary permissions to execute this action:
https://token.actions.githubusercontent.com/.well-known/jwks
repository
. See note (1) below for more details.read
access to any static or dynamic secrets you will fetch from your pipeline.After following these steps, you'll be ready to use JWT Auth from your GitHub runners!
(1) Note: The unique identifier is mainly used for auditing/billing purposes, so there isn't one correct answer here. repository
is a sensible default but if you are uncertain, contact support for more details.
(2) Note: Sub-claim checks allow Akeyless to grant access to specific workflows based on the claims that GitHub provides in the JWT. Using the example JWT from the documentation, you could set a sub-claim check in Akeyless, using the example below, to limit access to workflows that were triggered from the main branch in the octo-org/octo-repo
repository:
repository=octo-org/octo-repo
ref=refs/heads/main