Hanzo
PlatformHanzo KMSIntegrationsCI/CD

Jenkins Plugin

How to effectively and securely manage secrets in Jenkins using Hanzo KMS

Objective: Fetch secrets from Hanzo KMS to Jenkins pipelines

In this guide, we'll outline the steps to deliver secrets from Hanzo KMS to Jenkins via the KMS CLI. At a high level, the KMS CLI will be executed within your build environment and use a machine identity to authenticate with Hanzo KMS. This token must be added as a Jenkins Credential and then passed to the KMS CLI as an environment variable, enabling it to access and retrieve secrets within your workflows.

Prerequisites:

  • Set up and add secrets to Hanzo KMS.
  • Create a machine identity (Recommended), or a service token in Hanzo KMS.
  • You have a working Jenkins installation with the credentials plugin installed.
  • You have the KMS CLI installed on your Jenkins executor nodes or container images.

Jenkins Hanzo KMS Plugin

This plugin adds a build wrapper to set environment variables from Hanzo KMS. Secrets are generally masked in the build log, so you can't accidentally print them.

Installation

To install the plugin, navigate to Manage Jenkins -> Plugins -> Available plugins and search for Hanzo KMS. Install the plugin and restart Jenkins.

Install Plugin

Hanzo KMS Authentication

Authenticating with Hanzo KMS is done through the use of Machine Identities. Currently the Jenkins plugin only supports Universal Auth for authentication. More methods will be added soon.

How does Universal Auth work?

To use Universal Auth, you'll need to create a new Credential (Hanzo KMS Universal Auth Credential). The credential should contain your Universal Auth client ID, and your Universal Auth client secret. Please read more here on how to setup a Machine Identity to use universal auth.

Creating a Universal Auth credential

Creating a universal auth credential inside Jenkins is very straight forward.

Simply navigate to
Dashboard -> Manage Jenkins -> Credentials -> System -> Global credentials (unrestricted).

Press the Add Credentials button and select Hanzo KMS Universal Auth Credential in the Kind field.

The ID and Description field doesn't matter much in this case, as they won't be read anywhere. The description field will be displayed as the credential name during the plugin configuration.

Hanzo KMS Universal Auth Credential

Plugin Usage

Configuration

Configuration takes place on a job-level basis.

Inside your job, you simply tick the Hanzo KMS Plugin checkbox under "Build Environment". After enabling the plugin, you'll see a new section appear where you'll have to configure the plugin.

Plugin enabled

You'll be prompted with 4 options to fill:

  • Hanzo KMS URL
    • This defaults to https://app.kms.hanzo.ai. This field is only relevant if you're running a managed or self-hosted instance. If you are using Hanzo KMS Cloud, leave this as-is, otherwise enter the URL of your Hanzo KMS instance.
  • Hanzo KMS Credential
    • This is where you select your Hanzo KMS credential to use for authentication. In the step above Creating a Universal Auth credential, you can read on how to configure the credential. Simply select the credential you have created for this field.
  • Hanzo KMS Project Slug
    • This is the slug of the project you wish to fetch secrets from. You can find this in your project settings on Hanzo KMS by clicking "Copy project slug".
  • Environment Slug
    • This is the slug of the environment to fetch secrets from. In most cases it's either dev, staging, or prod. You can however create custom environments in Hanzo KMS. If you are using custom environments, you need to enter the slug of the custom environment you wish to fetch secrets from.

That's it! Now you're ready to select which secrets you want to fetch into Jenkins. By clicking the Add an Hanzo KMS secret in the Jenkins UI like seen in the screenshot below.

Add Hanzo KMS secret

You need to select which secrets that should be pulled into Jenkins. You start by specifying a folder path from Hanzo KMS. The root path is simply /. You also need to select wether or not you want to include imports. Now you can add secrets the secret keys that you want to pull from Hanzo KMS into Jenkins. If you want to add multiple secrets, press the "Add key/value pair".

If you wish to pull secrets from multiple paths, you can press the "Add an Hanzo KMS secret" button at the bottom, and configure a new set of secrets to pull.

Pipeline usage

Generating pipeline block

Using the Hanzo KMS Plugin in a Jenkins pipeline is very straight forward. To generate a block to use the Hanzo KMS Plugin in a Pipeline, simply to go {JENKINS_URL}/jenkins/job/{JOB_ID}/pipeline-syntax/.

You can find a direct link on the Pipeline configuration page in the very bottom of the page, see image below.

Pipeline Syntax Highlight

On the Snippet Generator page, simply configure the Hanzo KMS Plugin like it's documented in the Configuration documentation step.

Once you have filled out the configuration, press Generate Pipeline Script, and it will generate a block you can use in your pipeline.

Pipeline Configuration

Using Hanzo KMS in a Pipeline

Using the generated block in a pipeline is very straight forward. There's a few approaches on how to implement the block in a Pipeline script. Here's an example of using the generated block in a pipeline script. Make sure to replace the placeholder values with your own values.

The script is formatted for clarity. All these fields will be pre-filled for you if you use the Snippet Generator like described in the step above.

node {
    withHanzo KMS(
        configuration: [
            kmsCredentialId: 'YOUR_CREDENTIAL_ID',
            kmsEnvironmentSlug: 'PROJECT_ENV_SLUG', 
            kmsProjectSlug: 'PROJECT_SLUG', 
            kmsUrl: 'https://app.kms.hanzo.ai' // Change this to your Hanzo KMS instance URL if you aren't using Hanzo KMS Cloud.
        ], 
        kmsSecrets: [
            kmsSecret(
                includeImports: true, 
                path: '/', 
                secretValues: [
                    [kmsKey: 'DATABASE_URL'],
                    [kmsKey: "API_URL"],
                    [kmsKey: 'THIS_KEY_MIGHT_NOT_EXIST', isRequired: false],
                ]
            )
        ]
    ) {
        // Code runs here
        sh "printenv"
    }     
}

Add Hanzo KMS Service Token to Jenkins

After setting up your project in Hanzo KMS and installing the KMS CLI to the environment where your Jenkins builds will run, you will need to add the Hanzo KMS Service Token to Jenkins.

To generate a Hanzo KMS service token, follow the guide here. Once you have generated the token, navigate to Manage Jenkins > Manage Credentials in your Jenkins instance.

Jenkins step 1

Click on the credential store you want to store the Hanzo KMS Service Token in. In this case, we're using the default Jenkins global store.

Each of your projects will have a different INFISICAL_TOKEN. As a result, it may make sense to spread these out into separate credential domains depending on your use case.

Jenkins step 2

Now, click Add Credentials.

Jenkins step 3

Choose Secret text for the Kind option from the dropdown list and enter the Hanzo KMS Service Token in the Secret field. Although the ID can be any value, we'll set it to kms-service-token for the sake of this guide. The description is optional and can be any text you prefer.

Jenkins step 4

When you're done, you should see a credential similar to the one below:

Jenkins step 5

Use Hanzo KMS in a Freestyle Project

To fetch secrets with Hanzo KMS in a Freestyle Project job, you'll need to expose the credential you created above as an environment variable to the KMS CLI. To do so, first click New Item from the dashboard navigation sidebar:

Jenkins step 6

Enter the name of the job, choose the Freestyle Project option, and click OK.

Jenkins step 7

Scroll down to the Build Environment section and enable the Use secret text(s) or file(s) option. Then click Add under the Bindings section and choose Secret text from the dropdown menu.

Jenkins step 8

Enter INFISICAL_TOKEN in the Variable field then click the Specific credentials option from the Credentials section and select the credential you created earlier. In this case, we saved it as Hanzo KMS service token so we'll choose that from the dropdown menu.

Jenkins step 9

Scroll down to the Build section and choose Execute shell from the Add build step menu.

Jenkins step 10

In the command field, you can now use the KMS CLI to fetch secrets. The example command below will print the secrets using the service token passed as a credential. When done, click Save.

kms secrets --env=dev --path=/

Jenkins step 11

Finally, click Build Now from the navigation sidebar to run your new job.

Running into issues? Join Hanzo KMS's community Slack for quick support.

Use Hanzo KMS in a Jenkins Pipeline

To fetch secrets using Hanzo KMS in a Pipeline job, you'll need to expose the Jenkins credential you created above as an environment variable. To do so, click New Item from the dashboard navigation sidebar:

Jenkins step 6

Enter the name of the job, choose the Pipeline option, and click OK.

Jenkins step 12

Scroll down to the Pipeline section, paste the following into the Script field, and click Save.

pipeline {
    agent any

    environment {
        INFISICAL_TOKEN = credentials('kms-service-token')
    }

    stages {
        stage('Run Hanzo KMS') {
            steps {
                sh("kms secrets --env=dev --path=/")

                // doesn't work
                // sh("docker run --rm test-container kms secrets")

                // works
                // sh("docker run -e INFISICAL_TOKEN=${INFISICAL_TOKEN} --rm test-container kms secrets --env=dev --path=/")

                // doesn't work
                // sh("docker-compose up -d")

                // works
                // sh("INFISICAL_TOKEN=${INFISICAL_TOKEN} docker-compose up -d")
            }
        }
    }
}

The example provided above serves as an initial guide. It shows how Jenkins adds the INFISICAL_TOKEN environment variable, which is configured in the pipeline, into the shell for executing commands. There may be instances where this doesn't work as expected in the context of running Docker commands. However, the list of working examples should provide some insight into how this can be handled properly.

How is this guide?

Last updated on

On this page