Hướng Dẫn Sử Dụng
GitHub Actions 代理:安全存储 Secrets 并配置 CI/CD

目录
当工作流需要访问内部软件包仓库,或通过受控连接端点发送流量时,GitHub Actions 代理就会成为 CI/CD 基础设施的一部分。然而,将密码直接写入 YAML、为诊断问题而打印配置,或在多个项目之间共用账号,都可能导致凭据泄露。
合适的实施方式是将敏感数据存储在 GitHub Actions Secrets 中,仅向需要使用的步骤提供,并控制哪些代码可以与 secret 一同运行。本文介绍如何按照最小权限原则组织、配置和运维代理。
为什么需要保护代理凭据?
代理账号可能允许使用网络服务、访问内部资源,或以组织的名义产生流量。一旦这些信息泄露,风险不仅涉及使用费用,还涉及代理获授的访问范围。
在 CI/CD 中,secret 可能通过错误消息、调试模式、配置文件、缓存或构建产物意外暴露。因此,代理密码安全必须涵盖存储位置、向应用程序传递的方式,以及运行后的数据处理方式。
选择 GitHub Actions Secrets 的存储范围
使用仓库级 secret 保存项目专用配置
当凭据仅供单个仓库使用时,适合使用仓库级 secret。具有管理权限的人员可以访问 Settings → Secrets and variables → Actions 来创建 secret。不要将密码写入工作流文件,也不要提交已填入登录信息的配置文件。
为不同部署环境使用环境级 secret
如果流程包含测试环境和生产环境,应使用独立的代理账号及对应的环境级 secret。作业必须声明相应的环境,才能使用这些 secret。
结合环境保护规则,例如要求审批或限制部署分支,有助于控制何时提供 secret。各项规则是否可用,取决于服务套餐和仓库类型。
使用组织级 secret 满足共享需求
组织级 secret 支持集中管理,但需要限制可以访问它们的仓库。不应在超出实际需求的范围内共享代理账号。为不同工作组设置独立账号,有助于更清晰地撤销权限和调查事件。
存储前整理代理信息
一套配置通常包括服务器地址、端口、用户名、密码,以及不经过代理的目标列表。可以采用以下命名:
- PROXY_HOST: 代理服务器地址。
- PROXY_PORT: 管理方提供的连接端口。
- PROXY_USERNAME: 用于 CI/CD 的账号名称。
- PROXY_PASSWORD: 账号密码。
- NO_PROXY: 需要直接连接的目标列表,前提是网络策略允许。
密码必须以 secret 形式存储。如果主机地址和端口不敏感,可以使用 GitHub Actions Variables;如果它们会暴露内部网络结构,则需要采取相应保护措施。不要使用 Variables 存储凭据。
另一种选择是将完整的认证 URL 存储在 secret PROXY_URL 中。这种方式减少了字符串拼接操作,但会使整个 URL 成为敏感数据。应根据工具要求和凭据轮换流程选择方案。
如何创建 secret 并在工作流中使用
在正确的范围内创建 secret
- 确定需要使用代理的仓库、环境或仓库组。
- 打开相应范围内的 Actions secrets 管理页面。
- 创建名称一致且易于识别的 secret。
- 输入实际值并保存;不要将密码写入描述或说明文档。
- 运行工作流前检查访问策略。
保存后,无法通过常规管理界面再次读取 secret 的值。因此,需要使用经批准的凭据管理来源来支持更新和撤销,而不是依赖个人笔记。
将 secret 映射到步骤的环境变量
在工作流 YAML 中,使用 env 将步骤变量映射到 secret 表达式。例如,变量 PROXY_PASSWORD 的值为 ${{ secrets.PROXY_PASSWORD }}。如果存储的是完整 URL,支持 HTTP_PROXY 或 HTTPS_PROXY 变量的工具可以从 ${{ secrets.PROXY_URL }} 获取值。
优先在步骤级别声明,而不是在整个工作流级别声明。如果只有下载依赖的步骤需要代理,测试或打包步骤就不应获得密码。只有当作业内的各步骤确实需要相同访问权限时,才在作业级别声明。
不要将 secret 表达式直接插入 run 中的 shell 内容。先通过 env 映射,再使用 shell 语法引用变量,有助于避免将秘密值解释为命令的一部分。仍须为变量使用合适的引号,并且不要使用重新求值命令字符串的机制。
根据工具正确配置 CI/CD 代理
并非所有应用程序都读取相同的环境变量
许多工具支持 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY,但对大写、小写变量名的识别方式,以及对排除列表的处理方式可能不同。一些包管理器和构建工具需要专门配置。
因此,CI/CD 代理配置需要以各工具的文档为依据。如果为了兼容性必须同时设置大写和小写变量,应保持值一致,并仅在必要范围内提供。
处理登录信息中的特殊字符
当用户名或密码被放入 URL 时,@、冒号或斜杠等字符可能改变地址的解析方式。需要按照 URL 规则对登录信息部分进行编码,不要随意对整个字符串编码。
编码后的值仍然是秘密。不要为了检查而打印拼接后的 URL,因为 secret 遮蔽机制无法保证识别所有变形后的值。如果工具支持独立的用户名和密码字段,应考虑使用,以减少 URL 处理错误。
保持 TLS 证书验证启用
HTTPS_PROXY 变量通常用于指定处理发往 HTTPS 目标请求的代理;变量名称本身并不保证到代理的连接已加密。需要确认服务器支持的连接协议和认证机制。
如果组织使用内部 CA,请按照工具的说明安装受信任证书。不要为了快速解决连接错误而关闭 TLS 验证。凭据在传输到代理的过程中也需要受到保护,尤其是在使用本身不会加密密码的认证机制时。
防止密码通过日志和输出数据泄露
GitHub Actions 提供日志中的 secret 遮蔽机制,但这并非全面保障。经过编码、拆分或转换的值,可能无法被识别为原始值。
- 不要在包含 secret 的步骤中使用 env 或 printenv 等命令打印全部环境变量。
- 处理凭据时,不要启用 set -x 等 shell 跟踪功能。
- 限制使用可能显示 URL、请求头或连接配置的详细输出模式。
- 不要将密码放入构建产物名称、作业输出或工作流摘要中。
- 不要上传包含带密码代理配置文件的构建产物,也不要将其保存到缓存中。
如果必须在运行期间生成新的敏感值,可以在该值出现在日志之前,使用工作流命令 add-mask 注册遮蔽。主要措施仍应是避免将秘密写入输出,而不是指望事后遮蔽。
控制哪些工作流可以使用 secret
不要向尚不可信的代码提供 secret
来自 fork 的拉取请求通常无法在常规事件中获得 Actions secrets。不应仅为了向不可信来源的测试提供代理密码,就改变执行流程。
对 pull_request_target 尤其需要谨慎:此事件在目标仓库的上下文中运行。在有权访问 secret 的作业中检出并执行拉取请求中的代码,可能导致凭据泄露。应将外部代码检查与需要秘密的工作分开。
审查 action、脚本和可复用工作流
任何接收 secret 的 action 或脚本,都可能读取该值并将其发送到外部。需要评估 action 的来源,按照组织策略固定版本,并限制可以修改工作流的人员。
对于可复用工作流,仅传递必需的 secret。在没有明确需求时,避免继承全部 secret。同时,将 GITHUB_TOKEN 权限设置为最低所需级别;令牌权限和代理密码使用权限是需要分别控制的两个范围。
管理运行器和临时配置文件
环境变量不能替代运行器隔离。子进程可能继承变量,而以相同权限运行的代码可能访问执行过程中的数据。自托管运行器尤其需要注意,因为状态可能在不同作业之间保留。
如果应用程序必须读取配置文件,应在临时目录中创建文件,按照操作系统的方式限制读取权限,并在使用后删除。即使作业失败,清理步骤也应运行。不要将清理视为唯一措施,因为运行器可能中断。
对于 Docker 构建,不要为了下载软件包而通过 ARG 传递密码,或在 Dockerfile 中将密码写入 ENV。优先使用适当的构建 secret 机制,同时检查密码是否被写入镜像层、缓存或最终镜像。
凭据轮换与事件处理
CI/CD 使用的代理账号应与个人账号分离,并且仅具备必要的权限范围。如果服务支持,应限制访问目标、连接来源,或使用适合运行器模式的短期凭据。
更改密码时,应更新正确范围内的 secret,并在可信上下文中运行检查任务。该任务只应报告连接结果或错误类别,不应显示登录信息。按照已约定的流程撤销旧凭据。
如果怀疑发生泄露,应优先撤销或更换凭据。随后检查日志、构建产物、缓存和访问历史。删除日志行不足以保证秘密未被复制。
投入使用前的检查清单
- 将密码存储在 GitHub Actions Secrets 中,而不是源代码中。
- 选择正确的仓库、环境或组织范围。
- 仅向可信的步骤和代码提供 secret。
- 检查工具读取代理变量和处理特殊字符的方式。
- 保持 TLS 验证启用,并管理受信任证书。
- 确保日志、构建产物、缓存和镜像中不包含凭据。
- 准备凭据轮换、撤销和事件调查流程。
安全使用 GitHub Actions 代理,不仅仅是将密码存储在 Secrets 中。保护效果取决于整个使用生命周期:在正确范围内授权、以正确方式传递数据、控制执行代码,以及及时撤销凭据。统一落实这些原则后,CI/CD 代理配置将更易于管理和审查。