Jenkins - CICD 注入环境变量避免明文密码暴露
Jenkins - CICD 注入环境变量避免明文密码暴露
- 🔧 Jenkins 注入环境变量的方式
- 在 Job 配置里直接写环境变量,代码中可通过环境变量访问
- 使用 Jenkins Credentials 插件(推荐)
- 通过 withEnv 临时注入
- ✅ 对比总结
- 示例:从 Jenkins Credentials 到 Pipeline 再到代码访问环境变量的全过程
- 场景说明
- 1️⃣ Jenkinsfile 示例
- 2️⃣ Python 代码(app.py)
- 3️⃣ 工作流程
上篇《 Pyhon - 环境变量本地开发方案避免明文密码暴露在代码里》介绍了本地开发方案将明文密码注入环境变量,但实际线上测试和生产环境,CICD 该如何注入明文密码,避免安全问题呢。
🔧 Jenkins 注入环境变量的方式
在 Jenkins 里,环境变量是最常用的方式来传递密码、API Key、数据库连接信息等敏感配置。
在 Job 配置里直接写环境变量,代码中可通过环境变量访问
Freestyle Job GUI 配置
-
进入 Job → Configure → Build Environment
-
勾选 Inject environment variables to the build process
-
手动添加环境变量:
DB_HOST=127.0.0.1 DB_USER=myuser
-
在 Pipeline 脚本里可以直接用:
echo "DB user is ${env.DB_USER}"
Pipeline Job 里是没有 GUI 勾选的,所有环境变量都要在 Jenkinsfile 里配置
pipeline {agent anyenvironment {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 文件中配置的变量echo "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
示例:数据库用户名/密码
示例:Secret TextwithCredentials([usernamePassword(credentialsId: 'db-creds', usernameVariable: 'DB_USER', passwordVariable: 'DB_PASS')]) {sh '''echo "Database user: $DB_USER"# echo "Password: $DB_PASS" # 切勿打印密码!'''}
示例:SSH KeywithCredentials([string(credentialsId: 'api-key', variable: 'API_KEY')]) {sh 'curl -H "Authorization: Bearer $API_KEY" https://api.example.com' }
示例:Secret file,创建了一个上传了 .env 文件的 credential id 为 api_key_filewithCredentials([sshUserPrivateKey(credentialsId: 'ssh-key', keyFileVariable: 'SSH_KEY_FILE', usernameVariable: 'SSH_USER')]) {sh 'ssh -i $SSH_KEY_FILE $SSH_USER@server.example.com' }
工作机制- 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
withCredentials([file(credentialsId: 'api_key_file', variable: 'SECRET_FILE')]) {sh '''set -o allexport. "$SECRET_FILE"set +o allexportecho "test DEV_API_KEY=$DEV_API_KEY"''' }
这样,密码不会出现在 Job 配置和日志里,安全性高。
- 使用 withCredentials
通过 withEnv 临时注入
如果需要在某个阶段设置环境变量,可以用 withEnv:
pipeline {agent anystages {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 格式):
DEV_API_KEY=abc123DEV_API_USER=adminDEV_DB_PASS=super-secret
- 目标:
- 在 Jenkinsfile 中安全加载 .env 文件
- 在 Python 代码里通过 os.getenv 访问环境变量
- 不在日志中泄露敏感信息
1️⃣ Jenkinsfile 示例
pipeline {agent anystages {stage('Load Secret File') {steps {// 使用 Jenkins Credentials 拉取 secret filewithCredentials([file(credentialsId: 'api_key_file', variable: 'SECRET_FILE')]) {sh '''#!/bin/shecho "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)
import osapi_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 中,也不会在日志中直接泄露,同时代码可以正常访问环境变量。