一、Jenkins流水线日志泄露的常见场景及危害

很多团队用Jenkins做项目的自动打包、部署,流水线跑的时候会输出一大堆日志——比如拉代码的过程、编译的结果、连接服务器的指令、甚至部署时的密钥,这些日志如果没管好,很容易漏出去。

先给大家说个真实的坑:之前有个做电商的小团队,为了方便看部署状态,把Jenkins的流水线日志页面直接挂到了内部测试网,没加权限验证。后来测试网被人扫到,拿到了所有流水线日志,里面有连生产服务器的密码、数据库的账号,最后导致部分用户数据被拖走,损失了几十万。

除了这种直接泄露的,还有两种常见情况:一种是日志存太久,旧的流水线日志没人管,过了半年还能在服务器上找到;另一种是流水线里不小心把敏感信息打出来——比如把数据库密码、云服务器的AKSK(访问密钥)直接写到日志里,哪怕只有几秒钟,也可能被有心人截到。

这些泄露的危害不只是数据丢了,还可能被人拿到权限搞破坏,比如删数据库、改网站内容,甚至把整个服务搞崩,后续排查和修复的成本特别高。

二、规避日志泄露的核心方法

要解决这个问题,得从日志的产生、存储、访问三个环节入手,每个环节都有具体的操作方法,下面给大家说清楚。

2.1 禁止敏感信息写入日志

流水线里的敏感信息,比如密码、密钥、AKSK这些,绝对不能直接写死在脚本里,更不能让它们出现在日志里。很多人会犯的错是把密码当参数传,或者直接在脚本里输出,比如下面这个错误的示例:

# 错误示例:把数据库密码直接写死,还打印出来
DB_PASSWORD="abc123"
echo "正在连接数据库,密码是:${DB_PASSWORD}"
mysql -h 127.0.0.1 -u root -p${DB_PASSWORD}

这样跑的时候,日志里会清清楚楚显示密码“abc123”,谁看谁能拿到。

正确的做法是用Jenkins自带的“凭据”功能,把敏感信息存在Jenkins的凭据管理里,流水线需要用的时候再调用,而且调用的时候不会把明文打出来。具体怎么操作?分两步: 第一步,先把敏感信息存成Jenkins凭据,比如存数据库密码:

  1. 打开Jenkins首页,点左边的“凭据”;
  2. 选“全局凭据”(或者自己建的范围),点“添加凭据”;
  3. 类型选“Secret Text”,然后把密码填到“Secret”里,ID随便起一个,比如叫“db-password”,描述写清楚是啥密码,保存就行。

第二步,流水线里调用这个凭据,正确的示例是这样的:

pipeline {
    agent any
    options {
        timestamps() // 给日志加时间戳,方便排查问题
    }
    environment {
        // 调用Jenkins里的凭据,ID是之前存的db-password
        DB_PASSWORD = credentials('db-password')
    }
    stages {
        stage('连接数据库') {
            steps {
                // 这里调用DB_PASSWORD的时候,不会把明文打出来,日志里只会显示***
                sh 'mysql -h 127.0.0.1 -u root -p${DB_PASSWORD}'
            }
        }
    }
}

跑这个流水线的时候,日志里的密码位置会显示成***,不会泄露明文,这就解决了敏感信息写入日志的问题。

2.2 控制日志的访问权限

很多团队的Jenkins日志页面是公开的,或者内部所有人都能看,这就很危险。比如新入职的开发、外包人员,哪怕没权限操作流水线,只要能看日志,就能拿到敏感信息。

控制访问权限分两步: 第一步,给Jenkins的日志页面加权限验证。Jenkins本身有角色权限管理的功能,默认可能没开,需要装一个叫“Role-based Authorization Strategy”的插件。装完之后,就可以给不同的人分配不同的权限:比如普通开发只能看自己负责的项目的日志,管理员才能看所有项目的日志;甚至可以设置成,只有项目的负责人才能看该项目的流水线日志,其他人连页面都进不去。

举个权限配置的例子:假设我们有一个项目叫“电商后台”,我们想让开发张三只能看这个项目的日志,不能看其他项目的,也不能修改流水线。具体配置:

  1. 先建一个角色,叫“电商后台日志查看者”;
  2. 给这个角色分配权限:只能看“电商后台”项目的“Read”权限,不能分配“Configure”(修改流水线)、“Build”(触发流水线)这些权限;
  3. 再把张三的Jenkins账号和这个角色绑定,这样张三登录后,只能看到“电商后台”的项目,只能看它的日志,其他项目根本看不到。

第二步,禁止把日志页面直接挂到公网。如果是内部用的Jenkins,一定要放在内部网,不能直接让公网访问;如果需要远程访问,得加VPN,或者用Jenkins的反向代理加身份验证,比如用Nginx给Jenkins页面加密码验证,只有输入正确的账号密码才能进。

2.3 定期清理旧日志

流水线跑一次就会生成一次日志,时间长了,旧日志会越积越多,占空间不说,还会增加泄露的风险。比如半年前的流水线日志,里面可能有当时的测试密码、临时的密钥,现在已经不用了,但如果被人拿到,还是可能造成麻烦。

定期清理旧日志有两种方法,一种是手动清理,一种是自动清理。手动清理适合小团队,比如每个月找一次超过6个月的旧日志,直接删掉就行。但手动容易忘,所以推荐用自动清理的方法。

自动清理可以在Jenkins的项目配置里设置,每个项目都能单独配,不用改全局设置。具体操作:

  1. 打开要配置的项目,点“配置”;
  2. 找到“构建后操作”,或者直接找“丢弃旧的构建”这个选项(不同版本的Jenkins位置可能不一样,有的在“常规”里);
  3. 勾选“丢弃旧的构建”,然后设置保留的天数,比如只保留最近30天的日志,超过30天的自动删掉;也可以设置保留的构建次数,比如只保留最近10次的流水线日志,超过的自动清理。

举个自动清理的配置示例,用Jenkins的流水线脚本写的话,就是在options里加一个参数:

pipeline {
    agent any
    options {
        // 丢弃旧的构建,保留最近30天的日志,最多保留10次构建
        buildDiscarder(logRotator(numToKeepStr: '10', daysToKeepStr: '30'))
    }
    stages {
        stage('测试阶段') {
            steps {
                echo '正在测试...'
            }
        }
    }
}

这样配置后,每次流水线跑完,Jenkins都会自动检查旧的日志,超过30天或者超过10次的就会被删掉,不用手动管。

三、日志泄露后的应急处理方案

哪怕做了上面的防护,也可能因为操作失误或者漏洞导致日志泄露,所以得有应急处理的办法,万一出问题能快速止损。

应急处理分四步: 第一步,立刻停止泄露源。如果发现日志里有敏感信息,比如刚跑的流水线把密码打出来了,立刻把那个流水线暂停,防止后续的流水线继续泄露;如果是日志页面被人访问到,立刻把Jenkins的访问权限收回来,比如临时关闭公网访问,或者把相关人员的权限先停掉。

第二步,排查泄露范围。要搞清楚两个问题:一是泄露的日志里有哪些敏感信息,比如是数据库密码还是云服务器的密钥;二是这些日志被谁看到了,比如是内部人员还是外部的黑客。如果是内部人员不小心看到,只要没外传,风险就小;如果是外部黑客拿到,就得立刻处理。

第三步,重置所有敏感信息。如果泄露的是密码、密钥,不管有没有被外传,都要立刻重置。比如数据库密码,要立刻改,还要检查数据库的访问日志,看有没有异常的登录;如果是云服务器的AKSK,要立刻在云厂商的控制台删掉旧的密钥,重新生成新的,还要检查云服务器的日志,看有没有异常的操作。

第四步,复盘和加固。等问题解决后,要复盘这次泄露的原因,比如是流水线脚本写错了,还是权限配置有问题,然后针对性地加固。比如如果是脚本写错了,就要给团队做培训,禁止把敏感信息直接写在脚本里;如果是权限配置有问题,就要重新调整Jenkins的权限,把每个项目的日志权限都收严。

四、Jenkins日志安全的整体加固方案

除了上面的规避方法,还要做整体的加固,从系统层面防止日志泄露,形成一套完整的防护体系。

4.1 对日志进行脱敏处理

除了不让敏感信息写入日志,还可以对已经产生的日志做脱敏处理,哪怕日志被拿到,也看不到敏感信息。脱敏的意思就是把日志里的敏感内容替换成固定的字符串,比如把密码替换成“***”,把AKSK替换成“”。

Jenkins有专门的插件可以做日志脱敏,叫“Mask Passwords Plugin”。装完这个插件后,只要在流水线里配置要脱敏的内容,Jenkins就会自动把日志里的这些内容替换掉。

举个脱敏的配置示例,用流水线脚本写的话,就是在environment里加要脱敏的变量:

pipeline {
    agent any
    environment {
        // 要脱敏的变量,比如云服务器的AKSK
        AWS_ACCESS_KEY_ID = credentials('aws-access-key')
        AWS_SECRET_ACCESS_KEY = credentials('aws-secret-key')
    }
    options {
        // 启用密码脱敏,把上面两个变量的内容在日志里替换成***
        maskPasswords('AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY')
    }
    stages {
        stage('部署到云服务器') {
            steps {
                sh 'aws s3 cp test.txt s3://my-bucket/'
            }
        }
    }
}

跑这个流水线的时候,日志里的AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY都会被替换成***,哪怕有人拿到日志,也看不到具体的密钥。

4.2 监控日志的访问情况

要知道有没有人在看你的日志,就得加监控,比如监控Jenkins日志页面的访问情况,一旦发现异常访问,立刻报警。

监控的方法有两种:一种是用Jenkins自带的日志功能,Jenkins会记录所有用户的操作,包括谁访问了哪个项目的日志,什么时候访问的。可以定期看这个操作日志,比如每周查一次,有没有陌生的IP或者账号访问日志。

另一种是用第三方的监控工具,比如Prometheus加Grafana,或者用ELK(Elasticsearch、Logstash、Kibana)来收集和分析Jenkins的日志。比如可以设置规则,当有一个账号在短时间内访问了超过10个项目的日志,就触发报警,因为正常情况下,一个开发只会看自己负责的几个项目的日志,不会看那么多。

举个ELK监控的简单示例,把Jenkins的操作日志导入到ELK后,可以在Kibana里做一个仪表盘,显示最近24小时的日志访问情况,一旦有异常,比如陌生IP访问,仪表盘就会变红,同时给团队发邮件或者企业微信报警。

4.3 定期做安全扫描

Jenkins本身也可能有漏洞,比如旧版本的Jenkins可能有日志泄露的漏洞,所以要定期对Jenkins做安全扫描,及时打补丁,升级版本。

扫描的方法可以用专门的漏洞扫描工具,比如Nessus、OpenVAS,这些工具可以扫描Jenkins的版本,有没有已知的漏洞,比如CVE-2022-34170(这个漏洞就是Jenkins的日志页面存在未授权访问的问题),如果扫描到有漏洞,就立刻升级Jenkins的版本,或者打对应的补丁。

除了扫描Jenkins本身,还要定期检查流水线的配置,比如检查每个项目的流水线脚本有没有把敏感信息写死,检查权限配置有没有漏洞,比如有没有人有超出需要的权限,检查旧日志有没有定期清理。

五、应用场景、技术优缺点及注意事项

5.1 应用场景

这套方法适合所有用Jenkins做持续集成/持续部署(CI/CD)的团队,不管是小团队还是大公司,不管是做前端项目、后端项目还是移动端项目,都能用。特别是以下几种场景更需要注意:

  1. 涉及敏感信息的项目,比如电商项目、金融项目,这些项目的流水线日志里可能有数据库密码、支付密钥等敏感信息;
  2. 有外包人员或者临时员工的团队,这些人员的权限需要严格控制,不能让他们随便看日志;
  3. 有多个项目的团队,需要给不同的项目分配不同的权限,防止一个项目的日志泄露影响其他项目。

5.2 技术优缺点

这套方案的优点很明显:

  1. 防护全面,从日志的产生、存储、访问到应急处理,覆盖了整个生命周期;
  2. 操作简单,大部分功能都是Jenkins自带的,不需要额外开发,只要配置就行;
  3. 成本低,用到的插件都是免费的,监控工具也有开源的,不需要花太多钱。

当然也有一些缺点:

  1. 配置比较繁琐,比如权限管理、脱敏配置,需要花时间去设置,尤其是项目多的团队,每个项目都要单独配;
  2. 依赖插件,很多功能都是靠插件实现的,如果插件出问题,比如Mask Passwords Plugin更新后不兼容,可能会导致脱敏失效;
  3. 不能完全避免人为失误,比如如果开发不小心把敏感信息直接写到脚本里,没有用Jenkins的凭据功能,还是会导致泄露。

5.3 注意事项

在实施这套方案的时候,有几个注意事项要记住:

  1. 不要把敏感信息存到代码仓库里,哪怕是私有仓库也不行,代码仓库的权限可能会被突破,最好还是存在Jenkins的凭据管理里;
  2. 定期更新Jenkins和插件,旧版本的Jenkins和插件可能有安全漏洞,及时更新能防止被攻击;
  3. 不要把Jenkins的管理员账号给太多人,管理员账号有最高权限,能看所有日志,所以管理员账号要少,最好只有一两个人有;
  4. 应急处理要快,一旦发现日志泄露,要立刻采取措施,不能拖,拖的时间越长,风险越大。

六、文章总结

Jenkins流水线日志泄露是很多团队容易忽略的安全问题,但它的危害却很大,小到项目代码泄露,大到数据被拖走、服务被破坏。要规避这个风险,核心是从三个环节入手:一是不让敏感信息写入日志,用Jenkins的凭据功能代替硬编码;二是控制日志的访问权限,给不同的人分配不同的权限;三是定期清理旧日志,减少泄露的可能性。

除了这些基础的规避方法,还要做整体的加固,比如对日志做脱敏处理、监控日志的访问情况、定期做安全扫描,形成一套完整的防护体系。同时,还要有应急处理方案,万一出问题能快速止损。

最后要记住,安全不是一劳永逸的,要定期检查和优化防护措施,不能一次配置完就不管了,只有持续关注,才能保证Jenkins流水线日志的安全。