1. Introduction
Jenkins is an excellent tool for automating software builds and deliveries, especially when using git for software configuration management. However, a common problem when using Jenkins is how to handle sensitive data such as passwords or tokens.
In this tutorial, we’ll look at how to securely inject git secrets into Jenkins pipelines and jobs.
2. Git Secrets
To get started, we’ll first look at generating git secrets.
2.1. Create GPG Keys
Because git secrets use GPG keys, we must first ensure we have a valid key to use:
$ gpg --gen-key
This will prompt us for a full name and email, as well as a secret passphrase. Remember this passphrase, as we will need it later when we configure Jenkins.
This will create a public and private key pair in our home directory, which is sufficient to start creating secrets. Later, we’ll see how to export the key for use with Jenkins.
2.2. Initialize Secrets
The git-secret utility is an add-on to git that can store sensitive data inside a git repository. Not only is it a secure way to store credentials, but we also get the benefits of versioning and access control that is native to git.
To get started, we must first install the git-secret utility. Note that this is not a part of most git distributions and must be installed separately.
Once installed, we can initialize secrets inside any git repository:
$ git secret init
This is similar to the git init command. It creates a new .gitsecret directory inside the repository.
As a best practice, we should add all files in the .gitignore directory to source control, except for the random_seed file. The init command above should ensure our .gitignore handles this for us, but it’s worth double-checking.
Next, we need to add a user to the git secret repo keyring:
$ git secret tell [email protected]
We are now ready to store secrets in our repo.
2.3. Storing and Retrieving Secrets
The git secret command works by encrypting specific files in the repo. The files are given a .secret extension, and the original filename is added to .gitignore to prevent it from being committed to the repository.
As an example, let’s say we want to store a password for our database inside a file named dbpassword.txt. We first create the file:
$ echo "Password123" > dbpassword.txt
Now we encrypt the file:
$ git secret add dbpassword.txt
Finally, we must commit the secret using the hide command:
$ git secret hide
At this point, we should commit our changes to ensure the file is securely stored inside our repo. This is done using standard git commands:
$ git add .
$ git commit -m "Add encrypted DB password"
$ git push
Note that the unencrypted file is still available locally. However, it has automatically been ignored by git, so we cannot accidentally check it in.
To confirm this, if we were to do another checkout of the repository, this is what we would see:
$ ls
dbpassword.txt.secret
Note that the contents of the .secret file are encrypted and unreadable. Before we can read them, we have to decrypt the file:
$ git secret reveal -p <PASSPHRASE>
$ git secret cat dbpassword.txt
PASSPHRASE is the GPG passphrase we used when generating our GPG key.
3. Using Git Secrets With Jenkins
We have now seen the steps required for storing and retrieving credentials using git secret. Next, we’ll see how to use encrypted secrets with Jenkins.
3.1. Create Credentials
To get started, we must first export the GPG private key we generated earlier:
$ gpg -a --export-secret-keys [email protected] > gpg-secret.key
$ gpg --export-ownertrust > gpg-ownertrust.txt
It’s important to keep this private key safe. Never share it or save it to a publicly accessible location.
Next, we need to store this private key inside Jenkins. We’ll do this by creating multiple Jenkins credentials to store the GPG private key and trust store we just exported.
First, navigate to Credentials > System > Global Credentials and click Add Credentials. We need to set the following fields:
- Kind: Secret file
- File: Upload the gpg-secret.key we exported above
- ID: gpg-secret
- Description: GPG Secret Key
Save the credential, and create another one for the trust store file:
- Kind: Secret file
- File: Upload the gpg-ownertrust.txt we exported above
- ID: gpg-ownertrust
- Description: GPG Owner Trust
Save the credential and create a final credential for the GPG passphrase:
- Kind: Secret text
- Text:
- ID: gpg-passphrase
- Description: GPG Passphrase
3.2. Use Credentials in Pipeline
Now that we have the GPG key available as credentials, we can create or modify a Jenkins pipeline to use the key. Keep in mind that we must have the git-secret tool installed on the Jenkins agent before this will work.
To access the encrypted data inside our pipeline, we have to add a few pieces to the pipeline script.
First, we add an environment declaration:
environment {
gpg_secret = credentials("gpg-secret")
gpg_trust = credentials("gpg-ownertrust")
gpg_passphrase = credentials("gpg-passphrase")
}
This makes the three credentials we created earlier accessible to subsequent pipeline stages.
Next, we import the GPG key and trust into the local agent environment:
steps {
sh """
gpg --batch --import $gpg_secret
gpg --import-ownertrust $gpg_trust
"""
}
Finally, we can perform git secret commands inside the repo:
steps {
sh """
cd $WORKSPACE
git secret reveal -p '$gpg_passphrase'
git secret cat dbpassword.txt
"""
}
When we execute the pipeline, we should see the database password output at the end:
+ git secret cat dbpassword.txt
Password123
3.3. Jenkins Jobs
We can also use git secrets using traditional Jenkins jobs.
Just like with pipelines, we must configure 3 Jenkins credentials for our GPG key, trust, and passphrase.
The main difference from pipelines is that we inject the GPG credentials using the Jenkins environment configuration panel:
Then we can add the GPG import and git secret commands into shell commands:
As with the pipeline, we should see the database password printed at the end of the job execution:
+ git secret cat dbpassword.txt
Password123
Finished: SUCCESS
4. Conclusion
In this tutorial, we have seen how to use git secrets with both Jenkins pipelines and traditional jobs. This is an easy way to provide access to sensitive data to your CI/CD pipelines.
However, note that, while Git secrets is one option for storing keys, other dedicated security solutions like Hashicorp Vault offer stronger alternatives.