尧图精选

Woodpecker Secret Extension 完全指南:用外部 HTTP 服务集中管理 CI/CD 密钥

🕒 发布时间:2026/9/28 2:16:23 📁 来源:尧图网络
CI/CDDevOps【免费下载链接】woodpeckerWoodpecker is a simple, yet powerful CI/CD engine with great extensibility.项目地址https://gitcode.com/gh_mirrors/wo/woodpecker点击查看免费下载Woodpecker CI 的 Secret Extension 允许你通过一个外部 HTTP 服务为流水线动态提供密钥secrets从而把密钥管理从 Woodpecker 实例中剥离出来实现集中化管理例如接入 HashiCorp Vault、AWS Secrets Manager或按流水线动态生成密钥。读完本文你将掌握 Secret Extension 的全局与仓库级配置方式、请求/响应协议细节、签名校验机制以及如何基于仓库源码实现一个符合规范的扩展服务。什么是 Secret Extension在 Woodpecker 中Secret Extension 是一种用于从外部服务获取密钥的扩展机制。你可以在仓库设置Repository Settings的 Extensions 标签页中配置一个 HTTP 端点Woodpecker 会在流水线触发时向该端点发起请求拉取流水线所需的密钥。使用这类扩展主要解决两类问题集中化密钥管理将密钥统一存放在 Vault、AWS Secrets Manager 等外部系统避免在 Woodpecker 数据库中重复维护多份密钥按流水线动态生成密钥根据当前流水线的仓库、提交、事件等信息在运行时实时生成或轮换密钥而不是使用静态存储的固定值。需要说明的是Secret Extension 与 Configuration Extension、Registry Extension 一样都是 Woodpecker 通过预定义 HTTP 端点替换内部逻辑的扩展机制之一详见 Extensions 总览。安全模型为什么必须信任并验证扩展:::warning Woodpecker 会向扩展传递令牌等私密信息并且会执行扩展返回的配置内容因此保护外部扩展的安全至关重要。 :::Woodpecker 会对每一个发往扩展的请求进行签名。从源码看这一机制实现在 server/services/utils/http.goWoodpecker 使用ed25519 公私钥对通过httpsign库对请求进行 HTTP 签名签名名称signature name固定为woodpecker-ci-extensions签名覆盖request-target与content-digest两个头部Content-Digest会自动生成扩展服务端必须使用Woodpecker 的签名公钥验证每个请求的签名后才可处理。获取公钥的方式有两种访问http://my-woodpecker.tld/api/signature/public-key接口对应 server/api/signature_public_key.go打开 Woodpecker UI进入仓库设置中的 Extensions 页面查看。此外为了防止扩展被用来调用内网服务SSRF 风险Woodpecker 默认只允许扩展访问外部主机。可通过WOODPECKER_EXTENSIONS_ALLOWED_HOSTS环境变量调整白名单逗号分隔支持以下取值取值类型说明内置网络loopback127.0.0.0/8IPv4与 ::1/128IPv6包含 localhost内置网络privateRFC 191810.0.0.0/8、172.16.0.0/12、192.168.0.0/16与 RFC 4193FC00::/7即局域网/内网内置网络external合法的非私有公网单播 IP可访问公网所有主机内置网络*允许所有主机CIDR 列表如1.2.3.0/8IPv4、2001:db8::/32IPv6通配主机名如example.com、*.example.com、192.168.100.*该白名单在客户端层面通过hostmatcher.NewDialContext强制生效见 server/services/utils/http.go即使用户配置的扩展端点指向被禁主机连接也会被拒绝。全局配置Server 端除了在仓库设置中按仓库配置扩展端点你还可以在Woodpecker Server 配置中设置一个全局端点让该扩展对所有仓库生效WOODPECKER_SECRET_EXTENSION_ENDPOINThttps://example.com/secrets WOODPECKER_SECRET_EXTENSION_NETRCfalse对应的两个参数在 cmd/server/flags.go 中定义WOODPECKER_SECRET_EXTENSION_ENDPOINT对应secret-extension-endpoint外部密钥服务端点 URLWOODPECKER_SECRET_EXTENSION_NETRC对应secret-extension-netrc默认false是否在请求中携带 netrc 凭据。:::warning 如果你与他人共享同一台 Woodpecker Server请谨慎使用全局扩展——所有仓库都会使用你配置的密钥扩展这可能泄露你不想公开的密钥获取渠道。 :::优先级规则当全局端点与仓库级端点都返回了同名密钥时以仓库级扩展返回的密钥为准详见下文合并与优先级。仓库级配置在仓库设置 → Extensions 标签页中你可以为该仓库单独配置Secret Extension 端点URLSend netrc credentials发送 netrc 凭据开关。仓库级配置存储在仓库模型的secret_extension_endpoint与secret_extension_netrc字段中见 server/model/repo.go。从 server/services/manager.go 的SecretServiceFromRepo实现可以看到只要仓库配置了SecretExtensionEndpointWoodpecker 就会用secret.NewCombined(全局服务, 仓库级扩展)组合出一个叠加了全局与仓库级两层密钥来源的服务func (m *manager) SecretServiceFromRepo(repo *model.Repo) secret.Service { if repo.SecretExtensionEndpoint ! { return secret.NewCombined(m.secret, secret.NewHTTP(strings.TrimRight(repo.SecretExtensionEndpoint, /), m.client, repo.SecretExtensionNetrc)) } return m.SecretService() }注意这里strings.TrimRight(repo.SecretExtensionEndpoint, /)——尾部斜杠会被自动去除配置端点时不必也不建议以/结尾。工作原理与密钥合并逻辑当一条流水线被触发时Woodpecker 会从本地数据库读取仓库、组织、全局层级直接配置的密钥调用 Secret Extension全局端点与/或仓库级端点拉取扩展密钥将两者合并扩展返回的密钥在同名时优先如果扩展不可用回退到本地配置的密钥流水线不会被阻塞。这一逻辑的核心实现在 server/services/secret/combined.go 的combined.SecretListPipeline中它先调用基础服务拿到baseSecrets再调用扩展拿到extensionSecrets若扩展调用失败仅记录一条zerolog警告日志failed to fetch secrets from extension并直接返回基础密钥合并时以扩展密钥的 name 建立exists集合扩展密钥在前、基础密钥去重追加在后从而保证同名时扩展密钥胜出、且不产生重复项。调用扩展的 HTTP 客户端实现在 server/services/secret/http.gotype secretRequestStructure struct { Repo *model.Repo json:repo Pipeline *model.Pipeline json:pipeline Netrc *model.Netrc json:netrc,omitempty } type secretResponseStructure struct { Secrets []*model.Secret json:secrets }其SecretListPipeline方法向端点发送POST请求把repo、pipeline以及按需的netrc编码为 JSON当includeNetrc为真时才把Netrc写入请求体对应json:netrc,omitempty。请求使用 server/services/utils/http.go 中带签名的utils.Client.Send发送该客户端具备以下行为均为源码可证实的事实HTTP 超时 10 秒指数退避重试最多3 次对 5xx服务端错误与网络类瞬时错误连接被拒、连接重置、DNS 解析失败、TLS 握手超时等自动重试对 4xx 客户端错误不做重试直接返回错误请求携带User-Agent: server-extensions与 ed25519 HTTP 签名。请求协议扩展接收一个HTTP POST 请求JSON 载荷结构如下class Request { repo: Repo; pipeline: Pipeline; netrc?: Netrc; // 仅当 netrc 发送启用时包含见上文全局与仓库级开关 }:::infonetrc字段只在以下情况出现在请求中全局WOODPECKER_SECRET_EXTENSION_NETRC设置为true默认false或仓库设置中勾选了 Send netrc credentials。 :::各模型的详细字段可参考当前仓库中的定义repo 模型pipeline 模型netrc 模型:::tipnetrc数据非常强大——它包含访问仓库所需的凭据。扩展可以利用它克隆仓库甚至调用 ForgeGitHub、GitLab 等的 API 获取更多仓库信息例如根据分支、PR 上下文动态签发短期令牌。 :::一个请求示例注意请以上述模型的最新结构为准此示例可能已过时{ repo: { id: 100, uid: , user_id: 0, namespace: , name: woodpecker-test-pipeline, slug: , scm: git, git_http_url: , git_ssh_url: , link: , default_branch: , private: true, visibility: private, active: true, config: , trusted: false, protected: false, ignore_forks: false, ignore_pulls: false, cancel_pulls: false, timeout: 60, counter: 0, synced: 0, created: 0, updated: 0, version: 0 }, pipeline: { author: myUser, author_avatar: https://myforge.com/avatars/d6b3f7787a685fcdf2a44e2c685c7e03, author_email: myemail.com, branch: main, changed_files: [some-filename.txt], commit: 2fff90f8d288a4640e90f05049fe30e61a14fd50, created_at: 0, deploy_to: , enqueued_at: 0, error: , event: push, finished_at: 0, id: 0, link_url: https://myforge.com/myUser/woodpecker-testpipe/commit/2fff90f8d288a4640e90f05049fe30e61a14fd50, message: test old config\n, number: 0, parent: 0, ref: refs/heads/main, refspec: , clone_url: , reviewed_at: 0, reviewed_by: , sender: myUser, signed: false, started_at: 0, status: , timestamp: 1645962783, title: , updated_at: 0, verified: false }, netrc: { machine: myforge.com, login: myUser, password: forge-access-token } }注未启用 netrc 发送时netrc字段不会出现在请求中。响应协议扩展应返回一个包含secrets数组的 JSON 对象如果扩展希望保持现有密钥不变、不新增任何密钥可以返回 HTTP 状态码204 No Content——从 server/services/secret/http.go 的实现看收到 204 时 Woodpecker 会将其视为无额外密钥返回nil而不报错。class Response { secrets: { name: string; // 密钥名称与流水线配置中的 from_secret 对应 value: string; // 密钥值 images?: string[]; // 可选限定仅对指定插件可见 events?: string[]; // 可选限定仅对指定流水线事件生效 }[]; }字段说明name密钥名流水线 YAML 中通过from_secret引用value密钥值images可选白名单限制该密钥只能被列出的插件镜像使用对应 server/model/secret.go 中Secret的Images字段events可选白名单限制该密钥只在特定流水线事件如push、tag下可用对应同一模型中的Events字段。响应示例{ secrets: [ { name: docker_password, value: your-secret-password-123 }, { name: deploy_token, value: super-secret-token, events: [push, tag] } ] }实现一个最小可用的 Secret Extension基于上面的协议一个最简单的扩展服务伪代码大致如下import { verifySignature, getWoodpeckerPublicKey } from ./httpsig-utils; async function handleSecretsRequest(req) { // 1. 用 Woodpecker 公钥校验 HTTP 签名ed25519签名名 woodpecker-ci-extensions if (!verifySignature(req, await getWoodpeckerPublicKey())) { return 401; } // 2. 解析请求体按需使用 repo / pipeline / netrc 信息 const { repo, pipeline, netrc } req.body; // 3. 从 Vault / AWS Secrets Manager 等外部系统取密钥或按流水线动态生成 const secrets await fetchSecretsFor(repo, pipeline, netrc); // 4. 返回密钥数组不需要变更时返回 204 return { secrets }; }实现时请务必注意校验签名拒绝所有签名无效的请求可参考 server/services/utils/http.go 中 httpsign 的用法服务端反向使用公钥验签端点需公网可达默认情况下 Woodpecker 只允许访问 external 主机除非通过WOODPECKER_EXTENSIONS_ALLOWED_HOSTS显式放行处理 204不想返回任何密钥时直接返回204 No Content不要返回空的 2xx 之外的异常状态避免 4xx 之外的错误5xx 会被客户端自动重试最多 3 次4xx 则直接失败并回退到本地密钥。第三方扩展与风险提示:::danger 以下列出的第三方扩展既非 Woodpecker CI 开发也未经过其验证。使用前请确保你信任它们并仔细审查其源码与运维方。 :::由于扩展会收到令牌等私密信息、且其返回内容会被 Woodpecker 执行任何第三方扩展都应视为具有高权限的代码。建议优先选择开源、可自托管、由可信团队维护的扩展并将其部署在与生产网络隔离的环境中。如果你实现了自己的 Secret Extension欢迎在社区文档的 3rd Party Extensions 一节中补充你的扩展信息Add your extension here!。赞分享CI/CDDevOps【免费下载链接】woodpeckerWoodpecker is a simple, yet powerful CI/CD engine with great extensibility.项目地址https://gitcode.com/gh_mirrors/wo/woodpecker点击查看免费下载相关推荐External Secrets OperatorESO完全指南将外部密钥管理服务自动注入 Kubernetes SecretExternal Secrets OperatorESO完全指南将外部密钥管理服务自动注入 Kubernetes Secret External Secr云原生运维Woodpecker CI/CD 终极指南环境变量与服务配置完全解析Woodpecker CI/CD 终极指南环境变量与服务配置完全解析 Woodpecker 是一个简单而功能强大的 CI/CD 引擎其环境变量和服务配置功能CI/CDDevOpsAtom快捷键和效率工具终极指南10倍提升编码速度Atom快捷键和效率工具终极指南10倍提升编码速度 想要成为高效的开发者吗Atom编辑器配合正确的快捷键和效率工具可以让你在编码时如虎添翼 在这个完整上一篇Worktrunk wt step 命令深度解析merge 流水线的构建块与 worktree 实用工具集下一篇定制phpcs-security-audit规则从ParanoiaMode到CMS框架适配的高级技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →