Jenkins - CICD 注入环境变量避免明文密码暴露
- [🔧 Jenkins 注入环境变量的方式](#🔧 Jenkins 注入环境变量的方式)
-
- [在 Job 配置里直接写环境变量,代码中可通过环境变量访问](#在 Job 配置里直接写环境变量,代码中可通过环境变量访问)
- [使用 Jenkins Credentials 插件(推荐)](#使用 Jenkins Credentials 插件(推荐))
- [通过 withEnv 临时注入](#通过 withEnv 临时注入)
- [✅ 对比总结](#✅ 对比总结)
- [示例:从 Jenkins Credentials 到 Pipeline 再到代码访问环境变量的全过程](#示例:从 Jenkins Credentials 到 Pipeline 再到代码访问环境变量的全过程)
上篇《 Pyhon - 环境变量本地开发方案避免明文密码暴露在代码里》介绍了本地开发方案将明文密码注入环境变量,但实际线上测试和生产环境,CICD 该如何注入明文密码,避免安全问题呢。
🔧 Jenkins 注入环境变量的方式
在 Jenkins 里,环境变量是最常用的方式来传递密码、API Key、数据库连接信息等敏感配置。
在 Job 配置里直接写环境变量,代码中可通过环境变量访问
Freestyle Job GUI 配置
-
进入 Job → Configure → Build Environment
-
勾选 Inject environment variables to the build process
-
手动添加环境变量:
iniDB_HOST=127.0.0.1 DB_USER=myuser
-
在 Pipeline 脚本里可以直接用:
groovyecho "DB user is ${env.DB_USER}"
Pipeline Job 里是没有 GUI 勾选的,所有环境变量都要在 Jenkinsfile 里配置
groovy
pipeline {
agent any
environment {
DB_USER = 'myuser'
}
stages {
stage('Show env') {
steps {
sh 'echo "Key: $DB_USER"'
}
}
}
}
⚠️ 缺点:敏感信息容易暴露,不推荐存密码。
使用 Jenkins Credentials 插件(推荐)
👉 如果将敏感信息直接写在代码或 Jenkinsfile 里会有安全隐患,因此推荐通过 Credentials 插件来管理。这是安全管理敏感信息(密码、API Key)的最佳方式。
步骤:
-
添加 Credentials 的位置, 在 Jenkins 界面:
- 进入 Dashboard → Manage Jenkins → Credentials
- 选择 系统(System) → 全局凭据(Global credentials)
- 点击 Add Credentials 添加新的凭据
-
尝见的凭据类型
类型 用途 配置项 Username with password 需要用户名 + 密码的场景(DB、Git、FTP、Docker Registry) 用户名、密码 Secret text 单个敏感值(API Key、Token、Password) Secret SSH Username with private key 通过 SSH 连接服务器、Git 仓库 用户名、私钥 Secret file 整个敏感文件(如 kubeconfig、JSON Key) 上传文件 Certificate SSL 证书、PKCS#12 格式证书 上传证书文件、密码 -
方式一:用 bash command 来加载这些 Credentials,以便 code 中通过环境变量来访问
示例 GUI 上配置 credentia file 绑定,定义变量 API_KEY_FILE
shell 脚本里导出 credentia,以便 app.py 通过环境变量来访问 credential 文件中配置的变量
bashecho "Credential temp file path is: $API_KEY_FILE" export $(grep -v '^#' "$API_KEY_FILE" | xargs) python3 -c "import os; print(os.getenv('DEV_CAAS_DL_API_KEY'))" echo "export credential end" python3 app.py
⚠️ 注意:这种方式注入只在当前会话时有效,也就是说在其他 bash 会话中是无效,需要访问到这些环境变量就加载
-
方式二:在 jenkinsfile 中加载这些 Credentials, 以便 code 中通过环境变量来访问:
-
使用 withCredentials
示例:数据库用户名/密码groovywithCredentials([usernamePassword(credentialsId: 'db-creds', usernameVariable: 'DB_USER', passwordVariable: 'DB_PASS')]) { sh ''' echo "Database user: $DB_USER" # echo "Password: $DB_PASS" # 切勿打印密码! ''' }
示例:Secret Text
groovywithCredentials([string(credentialsId: 'api-key', variable: 'API_KEY')]) { sh 'curl -H "Authorization: Bearer $API_KEY" https://api.example.com' }
示例:SSH Key
groovywithCredentials([sshUserPrivateKey(credentialsId: 'ssh-key', keyFileVariable: 'SSH_KEY_FILE', usernameVariable: 'SSH_USER')]) { sh 'ssh -i $SSH_KEY_FILE $SSH_USER@server.example.com' }
示例:Secret file,创建了一个上传了 .env 文件的 credential id 为 api_key_file
工作机制- withCredentials([file(...)]) → Jenkins 把 .env Secret file 下载到一个临时路径,并写到 $SECRET_FILE 变量里。
- source $SECRET_FILE → 加载 .env 内容到 shell。
- 用 set -o allexport / set +o allexport 确保 .env 文件里的 KEY=value 都会自动 export。
- 这样 .env 配置 DEV_CAAS_DL_API_KEY 就能被后续的 shell、Python 程序读取。
⚠️ 注意: - 如果 jenkins 执行 shell 时默认用的是 /bin/sh,就用 . "$SECRET_FILE"
- 如果 jenkins 执行 shell 时默认用的是 /bin/bash, 就用 source $SECRET_FILE
groovywithCredentials([file(credentialsId: 'api_key_file', variable: 'SECRET_FILE')]) { sh ''' set -o allexport . "$SECRET_FILE" set +o allexport echo "test DEV_API_KEY=$DEV_API_KEY" ''' }
这样,密码不会出现在 Job 配置和日志里,安全性高。
-
通过 withEnv 临时注入
如果需要在某个阶段设置环境变量,可以用 withEnv:
groovy
pipeline {
agent any
stages {
stage('Deploy') {
steps {
withEnv(["APP_ENV=production", "DB_HOST=10.0.0.1"]) {
sh 'echo "Environment: $APP_ENV, Host: $DB_HOST"'
}
}
}
}
}
好处:只在这个 stage 有效,不会污染全局。
✅ 对比总结
方式 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
Job 配置里写变量 | 非敏感配置 | 简单 | 密码不安全 |
Credentials 插件 | 敏感信息(推荐) | 安全、审计 | J需要额外配置 |
withEnv | 临时变量 | 控制作用域 | 只适合少量变量 |
示例:从 Jenkins Credentials 到 Pipeline 再到代码访问环境变量的全过程
场景说明
-
创建 Jenkins Credentials:
-
类型:Secret file
-
ID:api_key_file
-
文件内容(.env 格式):
envDEV_API_KEY=abc123 DEV_API_USER=admin DEV_DB_PASS=super-secret
-
-
目标:
- 在 Jenkinsfile 中安全加载 .env 文件
- 在 Python 代码里通过 os.getenv 访问环境变量
- 不在日志中泄露敏感信息
1️⃣ Jenkinsfile 示例
groovy
pipeline {
agent any
stages {
stage('Load Secret File') {
steps {
// 使用 Jenkins Credentials 拉取 secret file
withCredentials([file(credentialsId: 'api_key_file', variable: 'SECRET_FILE')]) {
sh '''
#!/bin/sh
echo "Loading secret file from $SECRET_FILE"
# 把 .env 文件里的变量导入当前 shell 环境
set -o allexport
. "$SECRET_FILE"
set +o allexport
# 验证(生产环境不要打印敏感信息)
echo "DB_USER=$DEV_DB_USER"
# 运行 Python 程序
python3 app.py
'''
}
}
}
}
}
⚠️ 注意:
- 在 /bin/sh 中没有 source 命令,所以用 . 替代
- set -o allexport 可以确保 .env 文件里的 KEY=value 全部被 export
2️⃣ Python 代码(app.py)
python
import os
api_key = os.getenv("DEV_CAAS_DL_API_KEY")
db_user = os.getenv("DEV_CAAS_DL_DB_USER")
db_pass = os.getenv("DEV_CAAS_DL_DB_PASS")
print("API Key:", api_key)
print("DB User:", db_user)
# 千万不要打印 db_pass
3️⃣ 工作流程
- Jenkins Pipeline 执行 withCredentials([file(...)]),把 .env secret file 下载到临时路径 $SECRET_FILE
- Shell 脚本用 . 和 set -o allexport 把 .env 变量导入环境
- Python 里直接通过 os.getenv 访问环境变量
- Pipeline 结束后,Jenkins 会自动删除临时文件,保证安全
- 这样,你的 敏感信息不会硬编码在代码或 Jenkinsfile 中,也不会在日志中直接泄露,同时代码可以正常访问环境变量。