在不使用 WithCredentials 的情况下隐藏 Jenkins Pipeline 日志输出中的密码

Hiding passwords in Jenkins Pipeline log output without using WithCredentials

我有一个基于 Jenkinsfile 的参数化 Jenkins 管道。一些参数包含我不想出现在作业的构建日志中的敏感密码。

所以我的问题是:我能否以某种方式在 Jenkinsfile 中注册一个字符串,然后在它出现在日志输出中时替换为 **********

我知道 withCredentials 步骤,但我无法使用它,因为凭证未存储在 Jenkins 凭证存储中(但在运行时作为参数提供)。

我在这里 找到了这个答案并尝试了这个:

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

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

其中 firstPasswordsecondPasswordthirdPassword 是包含我的密码的变量。但我仍然得到 firstPassword 的内容...在日志输出中显示纯文本。

我在我的 Jenkins 2.12.0 版本中安装了 Mask Password plugin

基本上我正在搜索这样的东西:https://issues.jenkins-ci.org/browse/JENKINS-27486 - 票已解决,但没有给出最终实施的示例片段。

我想你在找 JENKINS-36007?

你可以看看https://github.com/jenkinsci/log-file-filter-plugin

此插件允许通过正则表达式过滤 Jenkins 的控制台输出。如果某些模式匹配,则匹配的字符串将替换为可以为配置中的每个模式指定的字符串。

目前该插件不支持从 jenkinsfile 添加过滤模式,只能从 Jenkins 全局设置添加。

实际上我不知道为什么这首先不起作用,但这是问题的解决方案。

定义一个包含要隐藏的秘密的数组:

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

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

免责声明:我不知道 SECRET 值是否有重要作用,从一些片段中复制并粘贴它,它按预期工作:)

之后,您可以像这样在脚本管道中包装任何调用:

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

getSecrets() 数组中提供的所有密码将在您的构建输出中像这样被屏蔽:

SPLUNK_PASSWORD: ********
BASIC_AUTH_ADMIN_PASSWORD: ********

非常残酷的解决方法。

编写一个简单的脚本,例如bash,并将参数凭据回显到某个任意格式的文件中,直至您的回显方法。

例如基本 shell 脚本:

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

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

然后在您的管道中:

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

结果,控制台中没有显示任何内容:

2020 年 5 月 26 日更新

下面的解决方法最近对我不起作用。我的猜测是最近的 Jenkins 更新发生了一些变化。我试图避免安装另一个插件,但我最终放弃并安装了 Mask Passwords plugin.

我使用以下语法与参数一起使用:

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

然后在构建阶段:

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

下面是最初的解决方法,以防其他人尝试走同样的路。


我发现了一个变通方法,它有点麻烦,但似乎运行良好。诀窍是使用 withCredentials,但用参数覆盖变量。

这是一个示例,它使用 environment 指令的 credentials() 辅助方法来填充环境变量,然后覆盖自动定义(并在日志中屏蔽)的两个附加环境变量。

首先,创建一个虚拟 Username with password 凭据。 UsernamePassword 值无关紧要,我们只需要一个 Credential 用作占位符。输入一个 ID,例如 dummy-credentials.

然后使用虚拟凭据定义环境变量,并使用参数覆盖自动定义的变量(本例中为 MYUSERNAMEMYPASSWORD):

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

在需要引用机密的任何地方使用 MY_CREDS_USRMY_CREDS_PSW 环境变量。它们的内容将在控制台日志中被屏蔽。

sh '''
    echo "Username: ${MY_CREDS_USR}"
    echo "Password: ${MY_CREDS_PSW}"
'''