34

I'm trying to mask a password in my Jenkins build.

I have been trying the mask-passwords plugin.

However, this doesn't seem to work with my Jenkins pipeline script, because if I define the password PASSWD1 and then I use it in the script like this ${PASSWD1}, I am getting:

No such DSL method '$' found among steps [addToClasspath, ansiColor, ansiblePlaybook, ....]

If I use env.PASSWD1, then its value will be resolved to null.

So how should I mask a password in a Jenkins pipeline script?

bsky
  • 19,326
  • 49
  • 155
  • 270
  • Can you show more of your Pipeline script? The `${PASSWD1}` syntax only works within a double-quoted string. Or you should likely be using the `PASSWD1` `env.PASSWD1`. Though that's unrelated to the Mask Passwords Plugin. Though this issue sounds relevant: https://issues.jenkins-ci.org/browse/JENKINS-41955 – Christopher Orr Feb 21 '17 at 16:30
  • I also tried using `env.PASSWD1`. I updated my question. – bsky Feb 21 '17 at 16:38

2 Answers2

53

The simplest way would be to use the Credentials Plugin.

There you can define different types of credential, whether it's a single password ("secret text"), or a file, or a username/password combination. Plus other plugins can contribute other types of credentials.

When you create a credential (via the Credentials link on the main Jenkins page), make sure you set an "ID". In the example below, I've called it my-pass. If you don't set it, it will still work, Jenkins will allocate an opaque UUID for you instead.

In any case, you can easily generate the required syntax with the snippet generator.

withCredentials([string(credentialsId: 'my-pass', variable: 'PW1')]) {
    echo "My password is '${PW1}'!"
}

This will make the password available in the given variable only within this block. If you attempt to print the password, like I do here, it will be masked.

mkobit
  • 43,979
  • 12
  • 156
  • 150
Christopher Orr
  • 110,418
  • 27
  • 198
  • 193
  • Thank you! This works if I just try to print the password. However, I also make an API call: `httpRequest myUrl`. This prints ```HttpMode: GET URL: myUrl```, and this time, in `myUrl`, the password is in plain text. Any idea how I could prevent this as well? – bsky Feb 22 '17 at 18:23
  • 1
    @octavian are you using [HTTP Request Plugin](https://wiki.jenkins-ci.org/display/JENKINS/HTTP+Request+Plugin)?. You can pass credentials in "Authorization" header (which get masked in the logs) inestead of URL. – amarruedo Jun 19 '17 at 10:00
  • So what if you want to pass multiple variables to the same stage? – David Essien Sep 09 '19 at 22:22
21

Looking at this issue, https://issues.jenkins-ci.org/browse/JENKINS-27392, you should be able to do the following:

node {
    wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: '123ADS', var: 'SECRET']]]) {
        echo env['SECRET'];
    }
}

However, if you look at the last comments in that issue it doesn't work, seems like a bug. However, if you know the secret and accidentally print int in the logs, the it is hidden, like this:

node {
        wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: '123ADS', var: 'SECRET']]]) {
        echo "123ADS";
    }
}

This produces:

[Pipeline] node
Running on master in workspace/pl
[Pipeline] {
[Pipeline] wrap
[Pipeline] {
[Pipeline] echo
********
[Pipeline] }
[Pipeline] // wrap
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Regarding the error you are getting, No such DSL method '$' found among steps ..., I'm just guessing but you are probably using ${VAR} directly in the pipeline script, ${...} is only relevant inside strings in groovy.

EDIT: Or you can use the Credentails Plugin and pipeline step withCredentials:

// Credential d389273c-03a0-45af-a847-166092b77bda is set to a string secret in Jenkins config.
node {
    withCredentials([string(credentialsId: 'd389273c-03a0-45af-a847-166092b77bda', variable: 'SECRET')]) {
        bat """
if ["${SECRET}"] == ["123ASD"] echo "Equal!"
""";
    }
}

This results in:

[Pipeline] node
Running on master in workspace/pl
[Pipeline] {
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] bat
[pl] Running batch script

workspace/pl>if ["****"] == ["****"] echo "Equal!" 
"Equal!"
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Note that this plugin binds the variable directly to the closure and not the environment as the other, e.g. I can use the variable SECRET directly.

Jon S
  • 15,846
  • 4
  • 44
  • 45
  • 1
    You are showing the password: `password: '123ADS'` in the script in the plain text as well, right?. I wouldn't want it in the script either. It should be stored somewhere in Jenkins, in some Credentials field, encrypted. – bsky Feb 21 '17 at 16:34
  • 1
    I think you can set system wide password with `Mask Passwords Plugin`, I just used it locally here for a single complete example – Jon S Feb 21 '17 at 16:42
  • Since `env.PASSWD1` is resolved to `null`, wrapping my code with ```wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: '123ADS', var: 'SECRET']]]) {``` wouldn't work, right? I mean it still wouldn't be resolve, no? – bsky Feb 21 '17 at 16:46
  • Doh, right, my bad, you, might be able to use the `withCredentials` step. I'll see if I can fix an example. – Jon S Feb 21 '17 at 16:55
  • 4
    Consider the situation where you have a password and need to send it via curl as base64. Then Jenkins won't consider the base64 as a password and won't hide its value. Or the situation where the build agent has a password injected into it via env variable. Perhaps its on a rotation and gets changed every 30 min. You don't want that one to appear either in the log. There needs to be a way to tell Jenkins that some random string is a password that needs to be hidden in the logs. – Lee Meador May 20 '21 at 18:30