8

I have a parametrized Jenkins pipeline based on a Jenkinsfile. Some of the parameters contain sensitive passwords that I don't want to appear in the job's build logs.

So my question is: can I somehow register a String within the Jenkinsfile that is then replaced - by let's say ********** - whenever it appears in the log output?

I am aware of the withCredentials step, but I can't use it, since the credentials are not stored in the Jenkins credentials store (but provided as parameters at runtime).

I found this answer here https://stackoverflow.com/a/42372859/1549950 and tried it like this:

def secrets = [
    [password: firstPassword, var: 'SECRET'],
    [password: secondPassword, var: 'SECRET'],
    [password: thirdPassword, var: 'SECRET']
]

node() {
    wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: secrets]) {
        // my stages containing steps...
    }
}

Where firstPassword, secondPassword, thirdPassword are variables containing my passwords. But still I get the content of firstPassword... displayed plain text in the log output.

I have the Mask Password plugin installed on my Jenkins in version 2.12.0.

Basically I am searching for something like this: https://issues.jenkins-ci.org/browse/JENKINS-27486 - ticket is resolved, but no sample snippet of final implementation is given.

Michael Lihs
  • 7,460
  • 17
  • 52
  • 85

5 Answers5

4

Actually I don't know why this didn't work in the first place, but here is the solution to the problem.

Define an array with secrets that you want to hide like this:

def splunkPassword = 'verySecretPa55w0rd'
def basicAuthPassword = 'my8asicAuthPa55w0rd'

def getSecrets() {
    [
            [password: splunkPassword, var: 'SECRET'],
            [password: basicAuthPassword, var: 'SECRET']
    ]
}

Disclaimer: I don't know whether the SECRET value has an important role, copy and pasted it from some snippet and it works as expected :)

Afterwards, you can wrap any calls in your scripted pipeline like this:

node {
    wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: getSecrets()]) {
        stage 'First Stage' { ... }
        stage 'Second Stage' { ... }
    }
}

All passwords provided in the getSecrets() array will then be masked like this in your build output:

SPLUNK_PASSWORD: ********
BASIC_AUTH_ADMIN_PASSWORD: ********
Michael Lihs
  • 7,460
  • 17
  • 52
  • 85
3

I think you are looking for JENKINS-36007?

Jesse Glick
  • 24,539
  • 10
  • 90
  • 112
2

Update 26 May 2020

The workaround below stopped working for me recently. My guess is that something changed in a recent Jenkins update. I was trying to avoid installing another plugin, but I eventually gave up and installed the Mask Passwords plugin.

I used the following syntax for use with parameters:

parameters {
    string(name: 'USERNAME', defaultValue: '', description: 'Username')
    password(name: 'PASSWORD', defaultValue: '', description: 'Password')
}

Then in the build stage:

steps {
    script {
        wrap([$class: 'MaskPasswordsBuildWrapper',
              varPasswordPairs: [
                  [password: "${USERNAME}", var: 'USR'],
                  [password: "${PASSWORD}", var: 'PSW']
              ]
        ]) {
            sh '''
                echo "Username: ${USERNAME}"
                echo "Password: ${PASSWORD}"
            '''
        }
    }
}

The original workaround is below, in case anyone else tries to go down the same path.


I've discovered a workaround that is a bit of a hack, but seems to work well. The trick is to use withCredentials, but override the variable with a parameter.

Here's an example which uses the environment directive's credentials() helper method to populate an environment variable, then overrides the two additional environment variables that are automatically defined (and masked in the logs).

First, create a dummy Username with password Credentials. The Username and Password values don't matter, we just need a Credential to use as a placeholder. Enter an ID such as dummy-credentials.

Then define an environment variable using the dummy credentials, and override the automatically defined variables with the parameters (MYUSERNAME and MYPASSWORD in this example):

environment {
    MY_CREDS = credentials('dummy-credentials')
    MY_CREDS_USR = "${params.MYUSERNAME}"
    MY_CREDS_PSW = "${params.MYPASSWORD}"
}

Use the MY_CREDS_USR and MY_CREDS_PSW environment variables wherever you need to reference the secrets. Their contents will be masked in the console log.

sh '''
    echo "Username: ${MY_CREDS_USR}"
    echo "Password: ${MY_CREDS_PSW}"
'''
Jason Day
  • 8,809
  • 1
  • 41
  • 46
  • 1
    Has this ever worked? I've been applying this, so far haven't managed it to work. It couldn't override the default values. – harshavmb May 25 '20 at 09:49
  • 1
    @harshavmb it worked when I posted it, but it stopped working for me at some point. In my case the parameters override the environment variables, but for some reason they are no longer masked in the logs. I have updated the answer with a new solution using the Mask Passwords plugin. – Jason Day May 26 '20 at 13:35
  • 1
    many thanks. This gave much relief to me. Your latest solution works fine.. – harshavmb May 28 '20 at 11:28
1

You might have a look at https://github.com/jenkinsci/log-file-filter-plugin

This plugin allows filtering Jenkins' console output by means of regular expressions. If some pattern matches the matched string is replaced by a string that can be specified for each pattern in the configuration.

Currently the plugin doesn't support adding filter-patterns from a jenkinsfile but only from the Jenkins global settings.

Pierre.Vriens
  • 2,117
  • 75
  • 29
  • 42
  • This plugin allows filtering Jenkins' console output by means of regular expressions. If some pattern matches the matched string is replaced by a string that can be specified for each pattern in the configuration. – Sascha Retter Sep 29 '18 at 08:08
  • Hm - need to set it in the Jenkinsfile, since it‘s only known „at runtime“ of the pipeline... besides, it would be pretty useless if I specify a regex with a secret credential in it, since every Jenkkns admin could read it then... – Michael Lihs Sep 29 '18 at 19:32
0

Highly brutish workaround.

Write a simple script, e.g. bash, and echo the parameter credentials into some file of arbitrary format, down to your echoing approach.

E.g. basic shell script:

$ cat executor/obfuscate.sh 
#!/bin/bash

echo "PASSWORD: ${AWX_PW}" > ./executor/credential.yml

In your pipeline then:

stages {
    stage('Placing') {
        steps {
            **sh './executor/obfuscate.sh'** }
            [...]
            < something reading credential.yml>
    }
}

Outcome, nothing showing up in console:

enter image description here

cherusk
  • 31
  • 6