Skip to content

LanceMcCarthy/akeyless-extension-azdo

Repository files navigation

AKeyless Extension for Azure DevOps

Use this Azure DevOps extension to safely retrieve and use secrets from your AKeyless vault. The task will login to AKeyless using Azure service connection JWT authentication and then fetch static secrets or a dynamic secret producer.

I am 100% committed to maintaining this and update it monthly, however I should mention that Akeyless now has their own, see Akeyless AzDO Extension.

Status

Workflow Status
Main Main - Tests
Publish Publish Release
Proof Pipeline Build Status

Installation

You can add the extension to your Azure DevOps pipeline in one of two ways:

Getting Started

If this is your first time using the extension, please visit the documentation to have the required prerequisites prepared.

Inputs

Name Required Type Value Default
accessId Yes string The access id for your auth method, see Getting Started: Akeyless Setup (step 1.6) null
azureJwt Yes string This is the JWT token to authenticate with Akeyless, see Getting Started: Azure Setup null
staticSecrets No string Static secrets to fetch from AKeyless. This must be a dictionary object, where the 'key' is the secret's path in akeyless and the 'value' is what you want the output variable to be named. See important note below. null
dynamicSecrets No string Dynamic secret to fetch from AKeyless. This must be a dictionary object, where the 'key' is the secret's path in akeyless and the 'value' is what you want the output variable to be named. See important note below. null
apiUrl No string Overrides the URL to the akeyless API server. Warning - Do not set this unless you know what you're doing! https://api.akeyless.io
timeout No Number Overrides the default gateway request timeout of 15 seconds. 15
autogenerate No Boolean Automatically create output variables for dynamic secrets. true

Important

  • When defining the secrets, you need to make sure the input's format is correct. For example, a single secret would be {"/path/to/secret":"my_secret" } or for multiple secrets {"/path/to/first-secret":"first_secret", "/path/to/second-secret":"second_secret" }.
  • To avoid PowerShell JSON parsing errors for dynamic secrets, use an env to pass the task's outputs. See the Processing Plain Output examples.
  • Multiline secret values are handled differently by agent OS. On Windows agents, the requested output keeps the original multiline value. On Linux and macOS agents, Azure DevOps rejects multiline secret variables, so the task stores the requested output as a base64-encoded secret and also emits <outputName>_ENCODING=base64. Decode before use.

Outputs

The task's outputs are determined by the values set in your staticSecrets and dynamicSecrets inputs. In order to access these outputs, first you must set the reference name of the task.

YAML Pipelines

When writing the task in YAML, you set the reference name using the name property:

- task: akeyless-secrets@1
  name: 'MyAkeylessTask'
  displayName: 'Only the task's Display Name'

Classic Pipelines

If you are using classic pipelines, you will find the Reference Name setting under the Output Variables section:

ref name

Now with the reference name, you can access the output(s):

$(MyAkeylessTask.name_of_output)

Static Secrets

For static secrets, you will get an individual secret output variables for each secret. For example:

steps:
# IMPORTANT - This task has a 'name' assigned.
- task: AzureCLI@2
  name: 'AzureCLI'
  displayName: 'Get JWT from Azure'
  inputs:
    azureSubscription: 'My Azure Service Principal'
    scriptType: ps
    scriptLocation: inlineScript
    inlineScript: |
     $JWT=$(az account get-access-token --query accessToken --output tsv)
     echo "##vso[task.setvariable variable=azure_jwt;isoutput=true;issecret=true]$JWT"

- task: akeyless-secrets@1
  name: 'MyAkeylessTask'
  displayName: 'Get Secrets from Akeyless'
  inputs:
    accessid: 'p-123456'
    azureJwt: '$(AzureCLI.azure_jwt)'
    staticSecrets: '{"/path/to/first-secret":"firstSecret", "/path/to/second-secret":"secondSecret" }'

Notice how we are using the azure_jwt output from the AzureCLI task to hold the JWT, then use it in the Akeyless task with $(AzureCLI.azure_jwt).

You will have $(MyAkeylessTask.firstSecret) and $(MyAkeylessTask.secondSecret) available in subsequent tasks of that job.

Multiline Secrets

The task automatically handles secret values that contain newlines (e.g. RSA/PEM private keys, certificates). The behavior differs by agent OS:

Agent OS Behavior
Windows The original multiline value is preserved as-is.
Linux / macOS Azure DevOps rejects multiline secret variables, so the value is stored as a base64-encoded secret. An additional companion variable <outputName>_ENCODING=base64 is emitted when this occurs, so you know to decode it.

This applies to both staticSecrets and dynamicSecrets β€” no extra configuration required.

Example

Using a multiline static secret like an RSA/PEM private key can still be written to a file. On Linux/macOS agents, decode the base64-encoded secret first.

- task: akeyless-secrets@1
  name: 'MyAkeylessTask'
  displayName: 'Get RSA key from Akeyless'
  inputs:
    accessid: 'p-123456'
    azureJwt: '$(AzureCLI.azure_jwt)'
    staticSecrets: '{"/app-secrets/my-private-key":"MY_RSA_KEY"}'

- bash: |
    if [ '$(AkeylessStatic.MY_RSA_KEY_ENCODING)' = "base64" ]; then
      printf 'πŸ”¨+πŸ’Ύ Secret is a base64 string, decoding and saving...'
      printf '%s' '$(AkeylessStatic.MY_RSA_KEY)' | base64 -d > app-private-key.pem
    else
      printf 'πŸ’Ύ Secret is not encoded, saving...'
      cat > app-private-key.pem <<'EOF'
      '$(AkeylessStatic.MY_RSA_KEY)'
      EOF
    fi
    chmod 600 app-private-key.pem
    wc -l app-private-key.pem
    printf 'βœ… RSA key is ready'
  displayName: 'Save multiline RSA key'

Dynamic Secrets

For dynamic secrets, the outputs are available as both individual outputs and the entire value. Multiline values within dynamic secret results are also handled automatically β€” see Multiline Secrets.

Automatic Outputs

By default, the dynamic secret will be parsed into a separate output for every value in the secret. This uses your requested prefix and is recursive, supporting any number of nested objects it needs.

For example, if your secret is {"id": "1","person": { "username": "foo", "password": "bar"},"expiration": "123"}, then the following outputs will automatically generated for you.

  • prefix_ + id
  • prefix_ + person_username
  • prefix_ + person_password
  • prefix_ + expiration

Note

The prefix is the output variable name that you used when for that secret, see the automatic output example below or review the azure-pipelines.yml tester.

Automatic Output Examples

For example, here we are requesting the output variable name to be secret1.

- task: akeyless-secrets@1
  name: 'MyAkeylessTask'
  displayName: 'Get Secrets from Akeyless'
  inputs:
    accessid: 'p-123456'
    azureJwt: '$(AzureCLI.azure_jwt)'
    dynamicSecrets: '{"/first-dynamic-secret":"secret1"}'

As a result, you will have the following outputs available:

Write-Output "Id: $(MyAkeylessTask.secret1_id)"
Write-Output "Person_Username: $(MyAkeylessTask.secret1_person_username)"
Write-Output "Person_Password: $(MyAkeylessTask.secret1_person_password)"
Write-Output "Expires: $(MyAkeylessTask.secret1_expiration)"

Here's a screenshot of multiple dynamic secrets being requested and then accessing the autogenerated outputs.

image

Plain Output

The entire secret's value is produced in the output name you requested. For example, here we are using secret1 as the output name:

- task: akeyless-secrets@1
  name: 'MyAkeylessTask'
  displayName: 'Get Secrets from Akeyless'
  inputs:
    accessid: 'p-123456'
    azureJwt: '$(AzureCLI.azure_jwt)'
    dynamicSecrets: '{"/first-dynamic-secret":"secret1"}'

The complete value name would be in the secret1 output:

Write-Output "COMPLETE JSON RESPONSE: $(MyAkeylessTask.secret1)"

Caution

You need to carefully process this output, as PowerShell may throw errors while trying to convert JSON that has nested objects or quotes. See the exampels below for how to handle this situation using env for the output.

Simple Output Examples

It's important to rememebr when using the Simple Output option that dynamic secrets tend to be complex objects. You will likely need to further process the value to get to an inner value. This topic is outside the scope of this Task, I will share two examples, but GitHub Copilot is great with parsing logic.

Example 1. Using jq

You can use jq to parse out the secret's parts.

- powershell: |
    # TIP: Using the env var to avoid issues with parens in the variable name
    echo $env:DYNAMIC_SECRET_JSON | jq -r 'to_entries|map("SQL_\(.key|ascii_upcase)=\(.value|tostring)")|.[]' >> $SQL
    echo $SQL.id
    echo $SQL.user
    echo $SQL.ttl_in_minutes
    echo $SQL.password
  displayName: 'Check Entra Id JSON output'
  env:
    DYNAMIC_SECRET_JSON: $(MyAkeylessTask.MY_SQL_DYNAMIC_SECRET)
Example 2. Using ConvertFrom-Json

You can try PowerShell's ConvertFrom-Json function, which will create objects you can access through the property name:

- powershell: |
    # TIP: Using the env var to avoid issues with parens in the variable name
    $SQL = $env:DYNAMIC_SECRET_JSON | ConvertFrom-Json
    Write-Output $SQL.id
    Write-Output $SQL.user
    Write-Output $SQL.ttl_in_minutes
    Write-Output $SQL.password
  displayName: 'Check Entra Id JSON output'
  env:
    DYNAMIC_SECRET_JSON: $(MyAkeylessTask.MY_SQL_DYNAMIC_SECRET)

Support

Please open a new issue on GitHub for bug report or feature requests.

About

An Azure DevOps extension to safely retrieve and use secrets from your AKeyless vault.

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors