Jenkins如何不通过字符串插值解析凭据?
先看你提到的官方示例代码:
pipeline { agent any environment { EXAMPLE_CREDS = credentials('example-credentials-id') } stages { stage('Example') { steps { /* CORRECT */ sh('curl -u $EXAMPLE_CREDS_USR:$EXAMPLE_CREDS_PSW https://example.com/') } } } }
官方文档提示:
若Groovy执行插值操作,敏感值会直接注入sh步骤的参数中,导致该值会在代理节点的操作系统进程列表中暴露。引用这些敏感环境变量时使用单引号可避免此类泄露。
你的疑问核心是:Groovy单引号不会展开变量,为什么curl还能拿到正确的凭据?答案很简单——变量解析的主体不是Groovy,而是代理节点的shell,具体逻辑如下:
Groovy层面:单引号字符串在Groovy中确实不会做变量插值,所以
sh('curl -u $EXAMPLE_CREDS_USR:$EXAMPLE_CREDS_PSW ...')会把整个命令原封不动地传递给代理节点的shell进程,不会把$EXAMPLE_CREDS_USR替换成明文密码。Jenkins环境变量传递:当你在pipeline的
environment块中定义了凭据变量后,Jenkins会自动把EXAMPLE_CREDS_USR和EXAMPLE_CREDS_PSW这两个衍生变量注入到代理节点执行sh步骤的shell进程的环境变量里。也就是说,shell进程启动时,已经能读取到这两个变量的实际值。Shell层面解析:shell拿到命令后,会自己解析其中的
$EXAMPLE_CREDS_USR和$EXAMPLE_CREDS_PSW,从当前环境变量中取出对应的值替换,然后执行curl命令。
这样做的好处就是避免敏感值泄露:如果用双引号让Groovy提前插值,那么传递给shell的命令会是curl -u 明文用户名:明文密码 ...,这个明文会出现在操作系统的进程列表(比如ps命令的输出)中;而单引号的方式下,进程列表里只会显示变量名,不会暴露实际敏感值。
内容的提问来源于stack exchange,提问作者Matheus

