首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
External Secrets Operator 接入 BeyondTrust Workload Credentials:静态密钥同步与集群配置实战
📅 2026/9/17 3:31:05
✍️ 爱科研究院
👁 阅读 3,247
External Secrets Operator 接入 BeyondTrust Workload Credentials静态密钥同步与集群配置实战【免费下载链接】external-secretsExternal Secrets Operator reads information from a third-party service like AWS Secrets Manager and automatically injects the values as Kubernetes Secrets.项目地址: https://gitcode.com/GitHub_Trending/ex/external-secretsBeyondTrust Workload Credentials 是 BeyondTrust 提供的密钥管理 API支持以文件夹Folder形式组织静态键值密钥并具备动态凭据生成能力。External Secrets OperatorESO通过内置的beyondtrustworkloadcredentialsProvider 读取其中存储的静态密钥并将其自动同步为 Kubernetes Secret。本文基于 官方 Provider 文档结合仓库源码provider.go、client.go与 API 类型定义secretstore_beyondtrustworkloadcredentials_types.go完整讲解 SecretStore/ClusterSecretStore 配置、API Key 认证、证书信任、data/dataFrom三种取数方式、find批量拉取与过滤、删除策略等核心能力帮助你快速在集群中落地 BeyondTrust 密钥同步方案。前置说明本 Provider 的能力边界在动手配置之前先明确该 Provider 的定位这一结论同时来自 官方文档 与源码只读 Provider。Capabilities()返回esv1.SecretStoreReadOnly见 provider.go它通过data[].remoteRef、dataFromextract/find读取静态密钥不实现写操作。源码中PushSecret、DeleteSecret、SecretExists三个方法均直接返回not implemented错误见 client.go因此它无法在 BeyondTrust 侧创建、更新或删除任何密钥动态凭据走 Generator。若需要临时、短效的凭据例如临时 AWS 凭据应使用 BeyondTrust Workload Credentials Generator本文末尾会做衔接说明。快速开始第一个同步示例1. 创建 API Token 与 CA Bundle 密钥API Token 存放在 Kubernetes Secret 中由 SecretStore 引用kubectl create secret generic api-token \ --from-literaltokenYOUR_API_TOKEN \ -n external-secrets若你的 BeyondTrust 实例使用自签名证书还需要准备 CA Bundle 密钥kubectl create secret generic my-ca-bundle \ --from-fileca.crt/path/to/root.crt \ -n external-secrets2. 创建 SecretStore官方示例片段见 beyondtrustworkloadcredentials-secret-store.yamlapiVersion: external-secrets.io/v1 kind: SecretStore metadata: name: beyondtrustworkloadcredentials-ss namespace: external-secrets spec: provider: beyondtrustworkloadcredentials: auth: apikey: token: name: bts-api-token key: token server: apiUrl: https://api.beyondtrust.io/site siteId: SITE_ID folderPath: FOLDER_PATH3. 创建 ExternalSecretapiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: beyondtrustsecret namespace: external-secrets spec: refreshInterval: 1m refreshPolicy: Periodic secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: my-beyondtrust-secret dataFrom: - find: name: regexp: .*控制器会在每个refreshInterval周期从 BeyondTrust 拉取匹配的密钥自动生成/更新名为my-beyondtrust-secret的 Kubernetes Secret。认证API KeyBearer Token机制BeyondTrust Workload Credentials 使用 API Key 认证ESO 将其作为Authorization: Bearer token请求头发送给 API 服务端。从源码看认证的完整链路provider.go 中的loadAPIKeyFromSpec校验spec.Auth.APIKey.Token的name与key字段缺一不可然后通过resolvers.SecretKeyRef从 Kubernetes Secret 中解析出真实 Tokenhttpclient/client.go 中的setHeaders将 Token 拼入Authorization头同时携带bt-secrets-api-version版本头、Content-Type与AcceptValidateStore在 Admission 校验阶段就会检查Auth是否为空、Token 选择器是否合法provider.go对应错误码ErrNoAPIKey、ErrNoTokenName、ErrNoTokenKey。认证配置的标准写法auth: apikey: token: name: api-token # 存放 API Token 的 Kubernetes Secret 名称 key: token # Secret 中存放 Token 的键服务器配置apiUrl 与 siteIdserver块包含两个必填字段apiUrlBeyondTrust Workload Credentials API 的基础 URLsiteId你的 BeyondTrust 站点标识UUID 格式。Provider 会自动拼接完整 API 端点{apiUrl}/{siteId}/secrets对应源码 provider.go 中的fetchServerValuesFromSpec先通过strings.TrimRight(baseURL, /)去掉末尾斜杠防止出现双斜杠再fmt.Sprintf(%s/%s/secrets, baseURL, siteID)组装最终地址。此外ValidateStore与loadURLFromSpec还会执行严格校验validateAPIURL必须包含httpsscheme 与主机名非 https 会被拒绝provider.govalidateSiteID必须匹配 UUID v4 格式正则^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$provider.go。对应 API 类型定义见 secretstore_beyondtrustworkloadcredentials_types.goAPIURL、SiteID均标注required。证书信任caProvider 与 caBundleBeyondTrust Workload Credentials 通常使用公共 CA 签发的证书无需额外配置若使用自签名证书ESO 提供两种信任方式对应 API 字段见 secretstore_beyondtrustworkloadcredentials_types.go。caProvider推荐通过引用已有的 Kubernetes Secret 提供 PEM 编码的 CA 证书spec: provider: beyondtrustworkloadcredentials: # ... 其他配置 ... caProvider: type: Secret name: my-ca-bundle key: ca.crt namespace: external-secrets # 使用 ClusterSecretStore 时必填创建 CA Bundle 密钥kubectl create secret generic my-ca-bundle \ --from-fileca.crt/path/to/ca.crt \ -n external-secretscaBundle直接把 base64 编码的 PEM 证书内嵌到 SecretStore 中spec: provider: beyondtrustworkloadcredentials: # ... 其他配置 ... server: apiUrl: https://api.beyondtrust.io/site siteId: a1b2c3d4-e5f6-7890-abcd-ef1234567890 caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0t... # base64 编码的 PEM生成 base64 字符串cat /path/to/ca.crt | base64 -w 0从源码实现看newClient会通过 ESO 公共工具esutils.FetchCACertFromSource统一解析CABundle或CAProviderprovider.go拿到 CA 后调用httpclient.NewBeyondtrustWorkloadCredentialsClientWithCustomCA在 httpclient/client.go 中把证书装入x509.NewCertPool()并克隆默认 Transport 配置RootCAs与MinVersion: tls.VersionTLS12。两处都未配置时使用系统信任根。文件夹路径 folderPathfolderPath指定默认存放密钥的文件夹不是某个具体密钥的完整路径。例如密钥存储在eso/static/secret1eso/static/secret2eso/static/secret3则在 SecretStore 中设置folderPath: eso/static。语义区分如下与官方文档一致使用data或dataFrom.extract时密钥名相对于该文件夹解析使用dataFrom.find时默认在该文件夹中搜索除非用path字段覆盖。拉取密钥属性三种取值方式方式一按属性取单个键data property指定property字段只取密钥对象中的某个属性apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: postgres-credentials namespace: external-secrets spec: refreshInterval: 1m secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: postgres-creds data: - secretKey: username remoteRef: key: postgresCreds property: username - secretKey: password remoteRef: key: postgresCreds property: password执行后生成包含username、password两个独立键的 Kubernetes Secret。源码侧GetSecret在ref.Property ! 时从密钥 map 中取值并做了类型处理——string直接返回字节[]byte原样返回其余类型数字、对象等通过json.Marshal保留结构见 client.go属性不存在时返回property ... not found in secret错误。方式二省略 property整包 JSONdata不写property字段时返回整个密钥对象的 JSON 字符串apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: postgres-credentials-json namespace: external-secrets spec: refreshInterval: 1m secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: postgres-creds-json data: - secretKey: credentials remoteRef: key: postgresCreds结果为{username:user,password:pass}作为credentials键的值。源码侧无property时走 client.go 的json.Marshal(secret.Secret)分支一次性序列化整个密钥对象。方式三拆分为独立键dataFrom extract使用dataFrom.extract把密钥对象的每个属性展开为目标 Secret 的独立键apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: postgres-credentials-extracted namespace: external-secrets spec: refreshInterval: 1m secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: postgres-creds-extracted dataFrom: - extract: key: postgresCreds生成结果data: username: dXNlcg # base64(user) password: cGFzcw # base64(pass)源码侧由GetSecretMap实现client.go把密钥 map 中每个键值对逐一转换为[]byte同样对非字符串类型做 JSON 序列化保护。批量拉取dataFrom.finddataFrom.find支持从文件夹中一次拉取多个密钥并合并进一个目标 Secret。以文件夹eso/static中三个密钥为例anotherSecret:{someKey: value1}mySecret:{myKey: value2, someKey: value3}postgresCreds:{username: user, password: pass}拉取文件夹内全部密钥apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: all-secrets namespace: external-secrets spec: refreshInterval: 1m secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: all-folder-secrets dataFrom: - find: name: regexp: .*合并后的每个目标键由「密钥完整路径 属性名」组成例如eso/static/postgresCreds/username。由于/不是合法的 Kubernetes Secret 键字符ESO 会通过 ExternalSecret 的find.conversionStrategy重写默认将非法字符替换为_于是上述键变为eso_static_postgresCreds_username。源码实现位于GetAllSecretsclient.go先递归列出文件夹下所有密钥GetSecrets(..., recursivetrue)对每个条目按名称正则过滤后拉取完整密钥再以item.Path / k作为结果键放入 map。正则过滤只同步名称匹配特定模式的密钥apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: filtered-secrets namespace: external-secrets spec: refreshInterval: 1m secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: filtered-folder-secrets dataFrom: - find: name: regexp: Secret$以上只会同步名称以Secret结尾的密钥如anotherSecret、mySecret。正则由regexp.Compile编译非法正则会在同步时报错。按标签过滤BeyondTrust Workload Credentials 的每个密钥可以挂载元数据标签find.tags按标签键值对过滤密钥的元数据必须包含列出的每一对键值才会被同步apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: tagged-secrets namespace: external-secrets spec: refreshInterval: 1m secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: tagged-folder-secrets dataFrom: - find: tags: env: production team: platform当name.regexp与tags同时设置时密钥必须同时满足两者才会被同步。源码中的matchTagsclient.go实现「全部匹配」语义任一过滤标签缺失或值不同即排除对应的标签结构SecretMetadata.Tags map[string]string定义在 util/beyondtrustworkloadcredentials.go。指定其他文件夹find默认使用 SecretStore 中的folderPath用path字段可搜索其他文件夹apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: subfolder-secrets namespace: external-secrets spec: refreshInterval: 1m secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: subfolder-data dataFrom: - find: path: eso/production # 覆盖文件夹路径 name: regexp: .* # 拉取该文件夹全部密钥该示例会列出eso/production文件夹下的全部密钥与 SecretStore 中的folderPath无关。源码中GetAllSecrets用ref.Path覆盖默认folderPathclient.go。注意path字段指定的是文件夹路径不是某个具体密钥的路径。要取单个密钥请用dataextract或独立的remoteRef条目。源密钥删除时的处理deletionPolicy默认情况下当 BeyondTrust 侧源密钥被删除时Kubernetes 中已被托管的 Secret 会保留。可通过target.deletionPolicy改变行为apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: secret-with-deletion namespace: external-secrets spec: refreshInterval: 1m secretStoreRef: name: beyondtrustworkloadcredentials-ss kind: SecretStore target: name: managed-secret deletionPolicy: Delete # 源密钥被删除时同时删除 Kubernetes Secret data: - secretKey: myKey remoteRef: key: mySecret合法取值Retain默认源密钥被删除后仍保留 Kubernetes SecretDelete源密钥被删除后移除对应的 Kubernetes Secret。注意Delete只作用于KubernetesSecret永远不会删除 BeyondTrust 侧的任何数据。该机制与源码中的 404 处理相配合GetSecret/GetAllSecrets遇到 HTTP 404 时会包装为esv1.NoSecretError{}client.go、client.goESO 据此按deletionPolicy决定 Kubernetes Secret 的去留。刷新间隔 refreshIntervalrefreshInterval控制 ExternalSecret 多久检查一次更新spec: refreshInterval: 5m # 每 5 分钟检查一次支持的时间单位s秒、m分钟、h小时。最佳实践在密钥时效性与 API 调用次数之间取平衡大多数场景1m15m比较合适。如果源侧密钥更新频率低、且希望减少 API 压力可适当调大若密钥变更敏感则缩短间隔。ClusterSecretStore跨命名空间共享需要集群级共享配置时使用 ClusterSecretStore对所有命名空间可见。与 SecretStore 的关键区别是必须在 Token 引用中显式指定namespace因为 ClusterSecretStore 自身不绑定命名空间apiVersion: external-secrets.io/v1 kind: ClusterSecretStore metadata: name: beyondtrustworkloadcredentials-css spec: provider: beyondtrustworkloadcredentials: auth: apikey: token: name: api-token key: token namespace: external-secrets # 必填指定 Token Secret 所在命名空间 server: apiUrl: https://api.beyondtrust.io/site siteId: a1b2c3d4-e5f6-7890-abcd-ef1234567890 folderPath: eso/static在 ExternalSecret 中引用apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: my-secret namespace: my-app spec: secretStoreRef: name: beyondtrustworkloadcredentials-css kind: ClusterSecretStore # 指定 ClusterSecretStore # ... 其余 spec同理caProvider在使用 ClusterSecretStore 时也需带namespace。与动态凭据Generator的衔接本 Provider 只负责静态密钥同步。如果你需要临时、短效的凭据例如临时 AWS 凭据请使用 BeyondTrust Workload Credentials Generator。二者的边界可以这样理解静态密钥存于文件夹中的键值对由本文所述的data/dataFrom同步动态密钥先在 BeyondTrust 中定义动态密钥模板Generator 每次被调用时调用生成端点产出全新凭据返回accessKeyId、secretAccessKey、leaseId、expiration以及可选的sessionToken字段见 util/beyondtrustworkloadcredentials.go注意 Generator 的凭据过期不会被 ESO 自动处理需将 ExternalSecret 的refreshInterval设置为凭据生命周期的 75%80% 左右例如 1 小时凭据配45m。限制与注意事项汇总只读不支持PushSecret、DeleteSecret、SecretExists无法在 BeyondTrust 侧增删改密钥删除语义deletionPolicy: Delete删除的是 Kubernetes Secret不影响 BeyondTrust 源数据校验严格apiUrl必须是 httpssiteId必须是合法 UUID v4否则 SecretStore 无法通过校验404 处理密钥或文件夹不存在时按NoSecretError处理配合deletionPolicy生效动态凭据需要临时凭据时改用 Generator并自行规划refreshInterval防止凭据过期。更深入的行为验证可以参考 provider_test.go 中的单元测试以及 httpclient/client.go 中关于请求头、超时默认 30s、响应体上限10 MiB等 HTTP 层细节。【免费下载链接】external-secretsExternal Secrets Operator reads information from a third-party service like AWS Secrets Manager and automatically injects the values as Kubernetes Secrets.项目地址: https://gitcode.com/GitHub_Trending/ex/external-secrets创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/9/17 3:31:04
Terraform AWS Provider:aws_appintegrations_event_integration 数据源详解——按名称读取 AppIntegrations 事件集成
2026/9/17 3:26:04
Windows应用程序0xc000007b错误全面排查与修复指南
2026/9/17 3:26:04
civitai 仓库 ClickUp 自动化技能实战:CLI 任务管理、批量建任务与事件监控参考手册
2026/9/17 6:46:15
Linux安装xrdp实现远程桌面登录:从安装到加固的完整指南
2026/9/17 6:46:15
MOSFET驱动电路布线抗干扰设计:回路面积、栅极电阻与层叠策略全解析
2026/9/17 6:46:15
医疗陪护系统开发:SpringBoot+Vue3微服务架构实践
2026/9/17 6:46:15
CAN总线热失控检测模块设计与J1939工程实践
2026/9/17 6:46:15
柔性制造数字化转型:先画系统边界,再选MES/APS/WMS
2026/9/17 6:41:15
ASP.NET MVC到.NET Core迁移实战指南
2026/9/17 0:00:44
开学论文写作指南:核心框架梳理与高效完成技巧分享
2026/9/17 0:00:44
OpenMAIC:轻量级多Agent教学框架实战指南
2026/9/17 0:00:44
AWS无服务器应用开发指南:从Lambda到SAM的架构与实践
2026/9/16 18:36:59
拯救者Y7000黑屏故障排查与维修实战指南
2026/9/16 7:38:03
AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
2026/9/17 4:19:54
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化