一.简介

众所周知,在Jenkinsfile或部署脚本中使用明文密码会造成安全隐患。但是为什么还频繁出现明文密码被上传到GitHub上的情况呢?笔者认为有两个主要原因(当然,现实的原因可能更多)∶

1.程序员或运维人员不知道如何保护密码。

2.管理者没有足够重视,否则会给更多的时间让程序员或运维人员想办法隐藏明文密码。

凭证( cridential )是Jenkins进行受限操作时的凭据。比如使用SSH登录远程机器时,用户名和密码或SSH key就是凭证。而这些凭证不可能以明文写在Jenkinsfile中。Jenkins凭证管理指的就是对这些凭证进行管理。

为了最大限度地提高安全性,在Jenkins master节点上对凭证进行加密存储(通过Jenkins实例ID加密),只有通过它们的凭证ID才能在pipeline中使用,并且限制了将证书从一个Jenkins实例复制到另一个Jenkins实例的能力。

也因为所有的凭证都被存储在Jenkins master上,所以在Jenkins master上最好不要执行任务,以免被pipeline非法读取出来,应该分配到Jenkis agent上执行

二.管理凭证

创建凭证,要先确保当前账号有这个权限,Jenkins首页-》凭据-》系统-》全局凭据-》添加凭据

选项:

  • Kind:选择凭证类型
  • Scope 凭证的作用域
  • Global,全局作用域。凭证用于pipeline,则使用此种作用域
  • System,如果凭证用于Jenkins本身的系统管理,例如电子邮件身份验证、代理连接等等,则使用此种作用域
  • ID 在pipeline使用凭证的唯一标识

Jenkins默认支持以下凭证类型:Secret text、Username with password、Secret file、SSH Username with private key、Certificate:PKCS#12、Docker Host Certificate Authentication credentials。

添加凭证后,安装Credentials Binding Plugin插件。通过其提供的withCredentials步骤就可以在pipeline中使用凭证了。

三.常用凭证

保密文本

是一串需要保密的文本,比如GitLab的API token。添加方法:

withCredentials([[string(credentialsId:'secretText', variable:'varName')]) {
    echo "${varName}"
}

账号密码

Username with password指用户和密码凭证。

withCredentials([usernamePassword(credentialsId:'gitlab-user', usernameVariable:'username', passwordVariable:'passwd')]) {
    echo "${username}, ${password}"
}

保密文件

Secret file指需要保密的文本文件。使用Secret file时,Jenkins会将文件复制到一个临时目录中,再将文件路径设置到一个变量中。构建结束后,所复制的secret file会被删除

withCredentials([file(credentialsId:'ansible-pass', variable:'vault')]){
    sh "ansible -i hosts playbook.yml --vault-password-file=${vault}"
}

账号秘钥

ssh Usermame with private key指一对ssh用户名和秘钥

在使用此类凭证时,Jenkins会将ssh key复制到一个临时目录中,再将文件路径设置到一个变量中

withCredentials([sshUserPrivatekey(KeyFileVariable:"key",credentialsId:"private-key")]){
    echo "${key}"
}

sshUserPrivateKey函数还支持以下参数

  • usernameVariable:ssh用户名的变量名
  • passphraseVariable ssh key密码的变量名

四.优雅使用凭证

上面写法比较啰嗦,为了解决这个问题,声明式pipeline提供了credentials helper方法(只能在environment中使用)来简化凭证的使用。

通过credentials helper方法,我们可以像使用环境变量一样使用凭证。

但遗憾的是,credentials helper方法只支持Secret text、Username with password、Secret file三种凭证。

保密文本

environment {
    AWS_ACCESS_KEY_ID = credentials('aws-secret-key-id')
    AWS_SECRET_ACCESS_KEY = credentials('aws-secret-access-key')
}

AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY使我们预先定义的凭证ID。creden-tials方法将凭证赋值给变量后,就可以正常使用了。如 echo "${AWS_ACCESS_KEY_ID}"

账号密码

environment {
    BITBUCKET_CREDS = credentials('jenkins-bitbucket-creds')
}

与Secret text不同的是,我们需要通过BITBUCKET CREDS USR拿到用户名的值,通过BITBUCKET CREDS PSW拿到密码的值。而变量BITBUCKET CREDS的值则是一个字符串,格式为:<用户名>:<密码>

保密文件

environment {
    KNOWN_HOSTS = credentials('known_hosts')
}

五.凭证插件

如果觉得Jenkins的凭证管理功能太弱,无法满足你的需求,则可以考虑使用HashiCorp Vault。

HashiCorp Vault是一款对敏感信息进行存储,并进行访问控制的工具。敏感信息指的是密码、token、秘钥等。它不仅可以存储敏感信息,还具有滚动更新、审计等功能。

集成HashiCorp Vault

1.安装HashiCorp Vault插件

2.添加Vault Token凭证

3.配置插件

pipeline

HashiCorp Vault插件并没有提供pipeline步骤,提供此步骤的是Hashicorp Vault Pipeline插件。但是它依赖的是2.138.1或以上的版本

如果你的Jenkins版本较低,但又想用这个插件。可以将该插件的源码下载到本地,将pom.xml的Jenkins。version值改成你的Jenkins版本。然后运行mvn clean package进行编译打包。若没有报错,则找到target/hashicorp-vault-pipeline.hpi进行手动安装

首先我们使用vault命令向vault服务写入私密数据以方便测试:vault write secret/hello value=word

pipeline {
    agent any
    environment {
        SECRET = vault path: 'secret/hello', key:'value'
    }
    stages {
        stage("read vault key") {
            steps {
                script{
                    def x = vault path: 'secret/hello', key:'value'
                    echo "${x}"
                    echo "${SECRET}"
                }
            }
        }
    }
}

我们可以在environment和steps中使用vault步骤。推荐在environment中使用

  • path 存储键值对的路径
  • key 存储内容的键
  • vaultUrl(可选),vault服务地址
  • credentialsld(可选),vault服务认证的凭证。

如果不填vaultUrl与credentialsld参数,则使用系统级别的配置

六.在Jenkins日志中隐藏敏感信息

如果使用的是credentials helper方法或者withCredentials步骤为变量赋值的,那么这个变量的值是不会被明文打印到Jenkins日志中的。除非使用以下方法:

steps {
    script{
        def hack = 'hack it'
        withCredentials([string(credentialsId:'abc', variable:'secretText')]) {
            echo "${secretText}" //打印****
            hack = "${secretText}"
        }
        echo "${hack}" //打印出明文:test
    }
}

在没有使用credential的场景下,我们又该如何在日志中隐藏变量呢?可以使用Masked Pass-word插件。通过改插件提供的包装器,可以隐藏我们指定的敏感信息

pipeline {
    agent any
    environment {
        SECRET1 = "secret1"
        SECRET2 = "secret2"
        NOT_SECRET = "no secret"
    }
    stages {
        stage("read vault key") {
            steps {
                wrap([$class:'MaskPasswordsBuildWrapper', varPasswordPairs:[
                    [password:env['SECRET1'], var:'s1'],
                    [password:env['SECRET2'], var:'s2']]]
                ) {
                    echo "被隐藏的密文:${SECRET1} 和 ${SECRET2}"
                    echo "secret1" //这也会被隐藏,打印出**
                    echo "明文打印:${NOT_SECRET}"
                }
            }
        }
    }
}

初次使用Masked Password插件很容易以为是使用s1和s2作为变量的,如echo"被隐藏的密文:${s1}和${s2}"。

实际上,var参数只是用于方便在自由风格的Jenkins项目中区分不同的需要隐藏的密文。在pipeline中使用,它就没有意义了。即使这样也不能省略它,必须传一个值。password参数传的是真正要隐藏的密文。

那么,为什么echo "secret1"这条语句中并没有使用预定义的变量,secret1也会被隐藏呢?这是由Masked Passord插件的实现方式决定的。

Jenkins提供了ConsoleLogFilter接口,可以在日志打印阶段实现我们自己的业务逻辑。Masked Password插件实现了ConsoleLogFilter接口,然后利用正则表达式将匹配到的文本replaceAll成***

MaskPasswordsBuildWrapper包装器除了支持varPasswordPairs参数,还支持varMask Regexes参数,使用自定义的正则表达式匹配需要隐藏的文本

steps {
    wrap([$class: 'MaskPasswordsBuildWrapper', varMaskRegexes:[[regex:'abc-.*']]]
    ) {
        echo "abc-xxxx"
    }
}

通过Masked Password插件还可以设置全局级别的密文隐藏,在Manage Jenkins-》Configure System页中可以找到。

Jenkins凭证管理的更多相关文章

  1. Jenkins 凭证管理 - 看这一篇就够了~

    目录 Credential 类型 Credential 安全 Credential 创建 Credential ID 定义 Credential 使用 Credential 相关插件 最佳实践 许多三 ...

  2. Jenkins的凭证管理

    Jenkins的凭证管理 什么是凭证? 凭证(cridential)是Jenkins进行受限操作时的凭据.比如使用SSH登录远程机器时,用户名和密码或SSH key就是凭证.而这些凭证不可能以明文写在 ...

  3. 有手就行2——持续集成环境—Jenkins安装、插件、用户权限及凭证管理

    有手就行2--持续集成环境-Jenkins安装.插件.权限及凭证管理 持续集成环境(1)-Jenkins安装 持续集成环境(2)-Jenkins插件管理 持续集成环境(3)-Jenkins用户权限管理 ...

  4. Jenkins凭证及任务演示-pipeline(二)--技术流ken

    Jenkins前言 在上一篇博客<Jenkins持续集成介绍及插件安装版本更新演示(一)--技术流ken>中已经详细介绍了jenkins的插件安装以版本更新等,本篇博客将再深入探究jenk ...

  5. Jenkins 凭证 Devops 的粘合剂

    大家好,我是小猿来也,一个热衷于搞 Devops 自动化的 Java 程序猿. 万事具备,只欠东风.当我决定大搞特搞 Devops 的时候,Jenkins 凭证却傻傻分不清. 玩 Devops 的小伙 ...

  6. [转]Jenkins使用 管理节点

    现在我们已经搭建好了基本的Jenkins环境,在这一集里,我们说一说如何管理节点. 进入“系统管理”中的“管理节点”. 创建Windos系统的奴隶节点 先创建一台安装了Win7系统的虚拟机,作为Jen ...

  7. Jenkins用户组管理

    Jenkins用户组管理 转载2015-06-10 21:44:24 标签:jenkinsrolestrategypluginusergroupcitools 一.安装插件 安装RoleStrateg ...

  8. 用XCA(X Certificate and key management)可视化程序管理SSL 证书(3)--创建自己定义的凭证管理中心(Certificate Authority)

    在第"用XCA(X Certificate and key management)可视化程序管理SSL 证书(2)---创建证书请求"章节中,我们介绍了怎样用XCA创建SSL证书请 ...

  9. 【Devops】【docker】【CI/CD】Jenkins源代码管理 添加gitlab项目地址,报错Failed to connect to repository : Error performing command: ls-remote -h git@192.168.92.130:8090/root/swapping.git HEAD

    Jenkins源代码管理 添加gitlab项目地址 报错如下: Failed to connect to repository : Error performing command: ls-remot ...

随机推荐

  1. Django 小实例S1 简易学生选课管理系统 12 CSS样式完善

    Django 小实例S1 简易学生选课管理系统 第12节--CSS样式完善 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 课程模块的逻辑代码到这里 ...

  2. Spring Cloud Gateway实战之四:内置predicate小结

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  3. [cf1217F]Forced Online Queries Problem

    可以用并查集维护连通性,删除可以用按置合并并查集,但删掉一条边后无法再维护两点的联通性了(因为产生环的边是不加入的)暴力思路是, 考虑前i个操作后边的集合,暴力加入即可,但复杂度是$o(n^2)$的用 ...

  4. springboot启动流程1

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.res ...

  5. [USACO07NOV]Cow Relays G

    题目大意 给出一张无向连通图(点数小于1000),求S到E经过k条边的最短路. 算法 这是之前国庆模拟赛的题 因为懒 所以就只挑一些题写博客 在考场上写了个dp 然后水到了50分 出考场和神仙们一问才 ...

  6. LOJ 3066 - 「ROI 2016 Day2」快递(线段树合并+set 启发式合并)

    LOJ 题面传送门 人傻常数大,需要狠命卡--/wq/wq 画个图可以发现两条路径相交无非以下两种情况(其中红色部分为两路径的重叠部分,粉色.绿色的部分分别表示两条路径): 考虑如何计算它们的贡献,对 ...

  7. perl 获取目录信息

    1 #!/usr/bin/perl -w 2 use strict; 3 use FindBin qw($Bin $Script); 4 5 my $rp=$Bin; 6 print "th ...

  8. js变量作为数组对象的键值方法

    js变量作为数组对象的键值方法,变量键值获取数组值 js也可以像php的数组一样用下标获取数组的值,方法是: var arr = {'key':'abc'}; var key = 'key'; con ...

  9. java9 模块化 jigsaw

    java9并没有在语言层面做出很多改变,而是致力于一些新特性,如模块化,其核心就是解决历史遗留问题,为以后的jar包森林理清道路.模块化是一个很大的命题,就不讲那么细致了,关于java9的特性也有很多 ...

  10. flink---实时项目----day03---1.练习讲解(全局参数,数据以parquet格式写入hdfs中) 2 异步查询 3 BroadcastState

    1 练习讲解(此处自己没跑通,以后debug) 题目见flink---实时项目---day02 kafka中的数据,见day02的文档 GeoUtils package cn._51doit.flin ...