How to Inject Environment Variables in Jenkins Pipeline

Jenkins provides multiple ways to parameterize your pipelines. One of the ways that most of the CI/CD tools enable that is via the environment variables. Unfortunately, Jenkins does not provide a robust out of the box solution for injecting environment variables out of the box.

There is an Environment Injector plugin that can be used for this purpose. However, this does not work for Multibranch Pipeline. The Multibranch Pipeline support in Jenkins gives us a convenient way to automatically manage separate pipelines for individual branches in your project.

One of the easiest ways to do this is to use configFileProvider to add a groovy configuration file to your job and then define the environment variables in that file. You can then load that groovy file at the beginning of your pipeline, which would execute the groovy file, thus injecting the environment variables into your pipeline.

Although the examples below are for declarative pipeline, but the method is equally valid for scripted pipelines as well.

Inject Common Variables Across the Job

Let’s start with a simple case where you would want to inject common variables for all the branches in your Multibranch Pipeline. Start with adding a new config from Jenkins  Your Job  Config Files  Add a new Config. Choose Groovy File as type.

You can declare the environment variables here like this:

config.env
env.DEPLOYMENT_SERVER="10.2.12.44"
env.DEPLOYMENT_PATH="/srv/www"

Note the ID of the file (config.env in this case).

Back to your Jenkinsfile, you can use configFileProvider to save this configuration as a groovy file in your workspace. Once it’s available, you can load this file using load. This essentially executes the groovy file, thus injecting the environment variables defined in the file.

Given that load will load and execute any arbitrary script in the groovy file, you will have to be very careful about what goes into your config file.
Jenkinsfile
pipeline {
    agent {
        // Define agent details here
    }
  stages {
    stage('Prepare') {
      steps {
        // Load the configuration file as 'env.groovy'
        configFileProvider([configFile(fileId: "config.env", targetLocation: 'env.groovy', variable: 'ENV_CONFIG')]) {
          load "env.groovy"; (1)
        }
      }
    }
  }
}
1Note that the targetLocation in configFileProvider was env.groovy.

Inject Individual Config for Each Branch

It is also possible to inject individual configuration for each branch. This is useful for Multibranch Pipelines where you might want separate parameters for each branch. E.g., maybe you want to deploy development branch on one server and master branch on another server.

This can be achieved by configuring separate config files for each branch and name the config files after the branch names. E.g., if you have two branches, master and develop, then you can have two config files named like:

  • master.env

  • develop.env

You can then go ahead declare the environment variables in these files as we did in the previous section.

Once we have a different configuration for each branch, all we have to do is to use the BRANCH_NAME environment variable in the fileId parameter in configFileProvider.

configFileProvider([configFile(fileId: "$BRANCH_NAME.env", targetLocation: 'env.groovy', variable: 'ENV_CONFIG')]) {
  load "env.groovy";
}

API Keys and Other Secrets

Once we a way of injecting arbitrary environment variables into our pipeline, it becomes very tempting to use this method to inject API Keys and other secrets via config files. Even though this is much better than hard coding these in your Jenkinsfile, you should never add API Keys and secrets to your config files.

Not only this allows anyone with access to the config files to steal these, but it also becomes clearly visible in the logs if your pipeline spits these values out to the console.

It is very much recommended to use the built-in Credentials Manager for this purpose. You can add Secret Text for API Keys and secrets.

Again, if you want to have different credentials for individual branches, you can use the branch name in the IDs of the credentials. E.g., you can add a credential with ID API_KEY_ID to be used across the branches and one with ID master_KEY_ID for master branch.

Once you have the credentials, you can use the credentials() helper method to load the credentials into the environment.

Jenkinsfile
pipeline {
    agent {
        // Define agent details here
    }
    environment {
        API_KEY = credentials('API_KEY_ID')
        BRANCH_KEY = credentials("$BRANCH_KEY_ID")
    }
    stages {
        stage('Test API') {
            steps {
              echo "Loaded keys $API_KEY and $BRANCH_KEY" (1)
              sh "curl -H 'api-key: $API_KEY' -H 'branch-key: $BRANCH_KEY' https://example.com"
            }
        }
    }
}
1Trying to print the secrets to the console

The echo statement in the above pipeline will give you the following output. Note that now even if you try to print the secrets to console, Jenkins will mask the values in the output for you. [1]

[Pipeline] withCredentials
Masking supported pattern matches of $API_KEY or $BRANCH_KEY
[Pipeline] {
  ...
[Pipeline] echo
Loaded keys **** and ****

1. Just masking the credentials in output does not guarantee that your secrets cannot be recovered in any way. Read more about limitations of credentials masking.
Load Comments?