Jenkins流水线里的密码还在明文?手把手接入凭据管理系统彻底消灭硬编码

打开GitHub搜索 filename:Jenkinsfile password OR secret OR token,能看到超过百万个包含敏感信息的Jenkins流水线文件。这还只是公开仓库,加上企业内部代码库,这个数字还要翻几倍。本文带你彻底消灭Jenkins流水线里的明文密码。


一、一个真实的开场:GitHub上的"裸奔"密码

2023年,某知名科技公司工程师不小心把包含AWS Secret Key的Jenkinsfile推到了公开仓库,几小时内攻击者就创建了价值数万美元的挖矿实例。

我在GitHub搜索了一下,结果触目惊心:

# 搜索语法
filename:Jenkinsfile "password" language:Groovy
# 结果:超过 120万个公开文件

filename:Jenkinsfile "AWS_SECRET" language:Groovy  
# 结果:超过 8万个文件包含AWS密钥

更可怕的是内部仓库——大多数企业的GitLab/GitHub Enterprise里,类似的明文密码散落在数百个Jenkinsfile里,任何有代码仓库读取权限的人都能看到。

在这里插入图片描述


二、Jenkins凭据管理的3种现状分析

现状1:直接在Jenkinsfile里写死(最危险)

// Jenkinsfile(错误示范!)
pipeline {
    agent any
    stages {
        stage('Deploy') {
            steps {
                sh "kubectl set image deployment/app app=myapp:${params.VERSION}"
                sh "curl -X POST https://deploy.example.com/api/deploy \\
                    -H 'Authorization: Bearer sk_live_51abcde12345' \\
                    -d 'version=${params.VERSION}'"
            }
        }
    }
}

问题:任何有代码权限的人都能看到生产部署密钥,离职员工依然能访问历史提交。

现状2:Jenkins Credentials Plugin(有改善,但不够)

Jenkins自带的Credentials插件是最常用的方案:

// Jenkinsfile(使用Credentials插件)
pipeline {
    agent any
    environment {
        // 引用Jenkins里存储的凭据
        DOCKER_PASSWORD = credentials('docker-hub-password')
        KUBECONFIG = credentials('prod-kubeconfig')
    }
    stages {
        stage('Build') {
            steps {
                sh 'docker login -u $DOCKER_USER -p $DOCKER_PASSWORD'
                sh 'kubectl apply -f deployment.yaml'
            }
        }
    }
}

优点:密码不出现在代码中,Jenkins负责存储。

缺点

  • 凭据分散在各个Jenkins实例里,多实例环境要重复配置
  • 没有自动轮换,密码长期不变
  • 审计功能弱,无法追溯谁在什么时候用了哪个凭据
  • 不支持动态凭据(每次用不同的临时密码)

现状3:环境变量注入(掩耳盗铃)

# 很多团队这样做
export KUBE_API_TOKEN="eyJhbGciOiJSUzI..."
jenkins build -s my-pipeline

问题:环境变量可以被Jenkins日志打印出来,也可以在构建日志里看到,根本不安全。


三、3种主流方案横向对比

方案 安全性 易用性 自动轮换 审计日志 等保合规
Jenkins Credentials ★★☆ ★★★ ★☆☆
HashiCorp Vault Plugin ★★★★ ★★☆ ★★★★ 部分支持
凭据管理系统(SMS) ★★★★★ ★★★★ ★★★★★ ✓ 完整支持

四、手把手接入凭据管理系统(SMS)

以下以安当SMS为例,演示如何在Jenkins流水线中彻底消灭硬编码。

步骤1:安装SMS Jenkins插件

在Jenkins管理界面:

Jenkins → 系统管理 → 插件管理 → 可选插件 → 搜索 "SMS Credentials"
→ 安装 → 重启Jenkins

或者手动安装:

# 下载插件
wget https://plugins.jenkins.io/sms-credentials/sms-credentials.hpi

# 放入Jenkins插件目录
cp sms-credentials.hpi /var/jenkins_home/plugins/

# 重启Jenkins
docker restart jenkins

步骤2:配置SMS服务器连接

Jenkins → 系统管理 → 系统配置 → 找到"SMS Credential Provider"
→ 填写以下信息:
  - SMS Server URL: https://sms.internal.company.com
  - App ID: jenkins-agent
  - App Secret: (点击"添加" → Jenkins → 用Jenkins自己的凭据存储来存这个)
  - Namespace: production
  - Enable SM4 Encryption: ✓
→ 点击"Test Connection"验证
→ 保存

步骤3:在流水线中使用SMS凭据

// Jenkinsfile(接入SMS后的正确写法)
pipeline {
    agent any
    
    stages {
        stage('拉取代码') {
            steps {
                checkout scm
            }
        }
        
        stage('Docker构建与推送') {
            steps {
                // 从SMS动态获取Docker Hub密码
                withSMSCredential(credentialId: 'docker-hub-prod') {
                    sh 'docker login -u ${SMS_USERNAME} -p ${SMS_PASSWORD}'
                    sh 'docker build -t myapp:${BUILD_NUMBER} .'
                    sh 'docker push myapp:${BUILD_NUMBER}'
                }
            }
        }
        
        stage('K8s部署') {
            steps {
                withSMSCredential(credentialId: 'k8s-prod-kubeconfig') {
                    sh 'kubectl set image deployment/app app=myapp:${BUILD_NUMBER}'
                    sh 'kubectl rollout status deployment/app'
                }
            }
        }
        
        stage('通知部署完成') {
            steps {
                withSMSCredential(credentialId: 'feishu-webhook') {
                    sh '''curl -X POST "${SMS_WEBHOOK_URL}" \
                        -H "Content-Type: application/json" \
                        -d "{\\"text\\":\\"部署完成,版本:${BUILD_NUMBER}\\"}"'''
                }
            }
        }
    }
    
    post {
        always {
            // 清理:SMS凭据不会留在构建日志里
            cleanWs()
        }
    }
}

关键改动说明

原来(不安全) 现在(安全)
credentials('xxx') 读Jenkins内部存储 withSMSCredential(credentialId: 'xxx') 从SMS动态获取
密码存在Jenkins里,手动轮换 密码存在SMS里,自动轮换
无法追溯谁用了密码 每次使用都有审计日志

在这里插入图片描述


五、集成gitleaks,在提交阶段就拦截密钥泄露

光是改Jenkinsfile还不够,要在提交代码的那一刻就阻止密钥进入代码库。

安装gitleaks

# Linux
curl -sSfL https://raw.githubusercontent.com/gitleaks/gitleaks/master/scripts/install.sh | sh

# 或者下载预编译版本
wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz

配置pre-commit hook

在项目根目录创建 .pre-commit-config.yaml

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

或者直接用git hook:

# .git/hooks/pre-commit
#!/bin/bash
echo "🔍 正在扫描敏感信息..."

gitleaks protect --verbose --redact --staged

if [ $? -ne 0 ]; then
    echo "❌ 检测到敏感信息,提交被阻止!"
    echo "请用 git reset HEAD~ 撤回,删除敏感信息后重新提交"
    exit 1
fi

echo "✅ 未检测到敏感信息,允许提交"

在Jenkins流水线里也加上扫描

stage('安全扫描') {
    steps {
        sh '''
            # 安装gitleaks
            curl -sSfL https://raw.githubusercontent.com/gitleaks/gitleaks/master/scripts/install.sh | sh
            
            # 扫描整个仓库
            gitleaks detect --source . --verbose --redact
            
            if [ $? -ne 0 ]; then
                echo "❌ 代码中存在硬编码密钥,请清理后重新提交"
                exit 1
            fi
        '''
    }
}

六、改造前后对比

改造前(危险)

Jenkinsfile(改造前)
├── 密码明文出现在代码中
├── Jenkins日志里能看到密码
├── 密码长期不变(6个月+)
├── 谁用了密码完全不知道
└── 员工离职后密码依然有效

改造后(安全)

Jenkinsfile(改造后)
├── 代码中完全不出现任何明文密码
├── 构建日志自动脱敏(SMS插件自动处理)
├── 密码按TTL自动轮换(例如每24小时)
├── 每次使用都有审计日志(谁/何时/用了什么)
└── 员工离职 → 禁用AppId → 所有凭据立即失效

在这里插入图片描述


七、常见问题FAQ

Q:SMS Server挂了,Jenkins流水线还能跑吗?
A:SMS Jenkins插件支持本地缓存模式,Server不可用时使用上次成功获取的凭据,流水线不受影响。

Q:改造需要改多少Jenkinsfile?
A:每个Jenkinsfile平均改动3-5行,主要是把credentials()替换成withSMSCredential(),30分钟可以完成一个项目的改造。

Q:等保三级对CI/CD凭据管理有什么要求?
A:等保三级要求:1) 凭据加密存储;2) 定期轮换(≤90天);3) 访问审计;4) 最小权限原则。SMS+Jenkins插件全套满足,且有合规报告导出功能。

Q:gitleaks会不会误报?
A:会有一定误报,可以通过在项目根目录添加.gitleaksignore文件来排除特定文件或规则。


八、小结

Jenkins流水线里的明文密码,就像是把公司大门的钥匙挂在门口——不是会不会被攻击的问题,而是什么时候被攻击的问题。

通过SMS凭据管理系统 + Jenkins插件 + gitleaks扫描三层防护:

  • ✅ 代码中彻底消灭硬编码密码
  • ✅ 凭据按TTL自动轮换,不留死角
  • ✅ 完整的审计日志,等保合规无压力
  • ✅ 提交阶段就拦截,把风险消灭在上游

改造一个Jenkins项目的全部流水线,通常不超过2小时。但避免一次泄露事故,可能拯救整个团队。


如果你在做等保合规或需要国产化替代,可以了解一下安当SMS凭据管理系统。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐