Jenkins Configuration as Code: Sensitive Data

Written by: Nicolas De Loof

3 min read

This blog post is the second of a six-part Configuration as Code series.

Using Configuration as Code, one can manage the configuration of a Jenkins controller with simple, declarative YAML files, and manage them as code in SCM. But this doesn’t mean you have to commit passwords and other sensitive information in Git.

What about sensitive data?

Managing sensitive data was one of the first requested features for JCasC. We chose to support string substitution so one can write and share YAML configuration samples, without any risk of exposing sensitive information.

credentials:
system:

    # global credentials
    - credentials:
        - certificate:
            scope: SYSTEM
            id:       ssh_private_key
            password: ${SSH_KEY_PASSWORD}
            keyStoreSource:
              fileOnMaster:
                keyStoreFile: /docker/secret/id_rsa

This YAML document can safely be committed to Source Code Management (SCM), or even shared publicly, as it only describes how to set the Secure Shell (SSH) key with a secret passphrase. The passphrase is only available at runtime.

Not just sensitive data

This mechanism has been designed for sensitive data, but we quickly noticed it would also make it easier to customize configurations without the need to edit a YAML document, just like bash environment variables are widely used. So to extend this idea, we also support default values for such parameters, using bash-style syntax: ${PARAMETER:-defaultvalue} .

In doing so, one can design a general purpose set of YAML files to set up Jenkins in a ready-for-service state, relying on reasonable default values. It also gives us an opportunity to customize some values without forking the YAML configuration and then having to merge upstream changes to stay updated.

tool:
git:

  installations:
    - name: git
      home: ${GIT_PATH:-usr/local/bin/git}
 

Sources

String replacement supports multiple sources and can be extended with a simple API to support more in the near future.

We support environment variables, which perfectly match the default-value override scenario, but are a very bad idea for sensitive data -- those would leak in the Jenkins UI and logs.

We also support Hashicorp Vault secret storage , relying on environment variables to configure access to the Vault API with an adequate token.

We also support Docker and Kubernetes secrets. If you’ve never used these, just know there’s no magic here. Both Docker and Kubernetes can manage secrets at the cluster level and inject them into a container at runtime. They use a simple directory with one file per secret, with the file content being the secret’s value. This pattern can be implemented by many other tools if you want to integrate your own system without writing a custom Jenkins plugin for it.

Finally, this API is fully extensible for other use-cases and integrations. If you want integration for your favorite tool and have some Java development skills, developing an adapter plugin would be pretty trivial.

Ok, so what’s next?

You can read more about the Jenkins Configuration as Code plugin on the project’s GitHub repository. To chat with the community and contributors join our gitter channel Or come see us in person at DevOps World | Jenkins World 2018 to discuss the JCasC project and its future!

Also don’t miss next post from the Configuration as Code series, where we’ll go over how to configure specific plugins and show some examples with a few of our favorites.

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.