Jenkins - CICD 注入环境变量避免明文密码暴露

Jenkins - CICD 注入环境变量避免明文密码暴露

  • [🔧 Jenkins 注入环境变量的方式](#🔧 Jenkins 注入环境变量的方式)
    • [在 Job 配置里直接写环境变量,代码中可通过环境变量访问](#在 Job 配置里直接写环境变量,代码中可通过环境变量访问)
    • [使用 Jenkins Credentials 插件(推荐)](#使用 Jenkins Credentials 插件(推荐))
    • [通过 withEnv 临时注入](#通过 withEnv 临时注入)
    • [✅ 对比总结](#✅ 对比总结)
  • [示例:从 Jenkins Credentials 到 Pipeline 再到代码访问环境变量的全过程](#示例:从 Jenkins Credentials 到 Pipeline 再到代码访问环境变量的全过程)
    • 场景说明
    • [1️⃣ Jenkinsfile 示例](#1️⃣ Jenkinsfile 示例)
    • [2️⃣ Python 代码(app.py)](#2️⃣ Python 代码(app.py))
    • [3️⃣ 工作流程](#3️⃣ 工作流程)

上篇《 Pyhon - 环境变量本地开发方案避免明文密码暴露在代码里》介绍了本地开发方案将明文密码注入环境变量,但实际线上测试和生产环境,CICD 该如何注入明文密码,避免安全问题呢。

🔧 Jenkins 注入环境变量的方式

在 Jenkins 里,环境变量是最常用的方式来传递密码、API Key、数据库连接信息等敏感配置。

在 Job 配置里直接写环境变量,代码中可通过环境变量访问

Freestyle Job GUI 配置

  • 进入 Job → Configure → Build Environment

  • 勾选 Inject environment variables to the build process

  • 手动添加环境变量:

    ini 复制代码
    DB_HOST=127.0.0.1
    DB_USER=myuser
  • 在 Pipeline 脚本里可以直接用:

    groovy 复制代码
    echo "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 文件中配置的变量

    bash 复制代码
    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
      示例:数据库用户名/密码

      groovy 复制代码
      withCredentials([usernamePassword(credentialsId: 'db-creds', usernameVariable: 'DB_USER', passwordVariable: 'DB_PASS')]) {
      		    sh '''
      		        echo "Database user: $DB_USER"
      		        # echo "Password: $DB_PASS"  # 切勿打印密码!
      		    '''
      		}

      示例:Secret Text

      groovy 复制代码
      		withCredentials([string(credentialsId: 'api-key', variable: 'API_KEY')]) {
          sh 'curl -H "Authorization: Bearer $API_KEY" https://api.example.com'
      }

      示例:SSH Key

      groovy 复制代码
      		withCredentials([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
      groovy 复制代码
      	withCredentials([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 格式):

      env 复制代码
      	DEV_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 中,也不会在日志中直接泄露,同时代码可以正常访问环境变量。
相关推荐
meijinmeng6 小时前
EKS 集群 ArgoCD `v3.0.6 → v3.1.x → v3.2.x` 备份,恢复,升级,巡检手册
argocd·cicd
遨游DATA14 小时前
Jenkins 修改 config.xml 后页面仍是旧配置:让 live job 配置真正生效
ci/cd·jenkins·devops·故障排查·config.xml
Dobby_0515 小时前
【CICD】Jenkins Pipeline 快速学习入门
运维·学习·jenkins
Wesleyblue1 天前
Python解释器工作原理解析
命令行·环境变量·工作原理·脚本参数·python解释器
上海安当技术1 天前
统一身份认证平台怎么落地?11 个异构业务系统接入 ASP 的完整实施路径
数据库·servlet·架构·kubernetes·jenkins
回眸不遇2 天前
Elasticsearch嵌套类型nested使用指南
大数据·elasticsearch·jenkins
回眸不遇4 天前
类型的区别和应用场景 nested 每个对象独立存储为隐藏的子文档 适合存储数组 查询的时候有特定的语法 nested查询 且字段要 ...
运维·jenkins
X1A0RAN4 天前
容器化部署 Jenkins 教程
运维·docker·jenkins
BullSmall4 天前
jenkins 全局工具变更后,构建的任务为什么没有刷新过来
运维·jenkins
BullSmall5 天前
报错 libatomic.so.1: No such file or directory
jenkins