Sealed Secrets 文档全景指南:安装部署、加密实战与密码学原理
Sealed Secrets 是一个面向 Kubernetes 的"单向加密 Secret"方案:你可以在本地使用客户端工具 kubeseal 把明文 Secret 加密为 SealedSecret,加密后的内容可以安全地提交到代码仓库,再由集群内的控制器解密并重建真正的 Kubernetes Secret。本文以官方文档索引(site/content/docs/latest/README.md)为骨架,完整串联教程、操作指南、背景知识与参考 FAQ 四大板块,并结合仓库源码深入讲解其运行原理,帮助你一次性掌握从部署、加密到密码学实现的完整链路。
文档体系总览:一份文档,四个入口
官方文档的顶层索引将全部内容按读者需求划分为四个板块,其定位清晰、层层递进:
| 板块 | 定位 | 适用场景 |
|---|---|---|
| 教程(Tutorials) | 面向新手的动手式入门,手把手带你跑通全流程 | 第一次接触 Sealed Secrets |
| 操作指南(How-to guides) | 针对具体问题给出可复用的解决步骤 | 已有一定基础,想解决特定问题 |
| 背景(Background) | 解释整体架构与实现细节,重在"建立理解" | 想深入原理、评估安全性 |
| 参考(Reference) | 技术参考与开发者指南(FAQ 等) | 查阅设计决策与常见问题 |
阅读顺序建议:新手从教程的 Getting Started 起步,熟悉基本操作后按需查阅操作指南;若关心加密是否足够安全、密钥如何管理,则进入 密码学细节;遇到具体疑问时检索 FAQ。
教程:从零开始使用 Sealed Secrets
前置条件
官方文档声明,使用 Sealed Secrets 需要:
- 一个可用的 Kubernetes 集群(v1.16+),以及已安装并配置好的
kubectlCLI; - 若采用 Helm 方式安装控制器,需要
helmv3.1.0+; - 若采用 Carvel 方式安装,需要
kappCLI。
官方文档还声明 Sealed Secrets 已在 Amazon EKS、Azure AKS、Google GKE、minikube 以及 OpenShift 等平台上完成测试。需要特别说明的是,这里要求的是"可用的集群"——因为 Sealed Secrets 的完整工作流(加密 → 提交仓库 → 控制器解密)高度依赖集群侧控制器,你至少需要一次部署控制器的机会。
两大核心组件
Sealed Secrets 由两部分组成,理解二者的分工是掌握整个项目的第一步:
- 集群侧控制器(sealed-secrets-controller):运行在 Kubernetes 集群中,负责持有私钥、生成证书、监听
SealedSecret资源并解密为普通Secret; - 客户端工具(kubeseal):运行在你的本机或 CI 环境中,从控制器拉取公钥证书,将明文 Secret 加密为
SealedSecret。
从源码目录也能清晰看到这一分工:控制器代码位于 pkg/controller 与 cmd/controller,而客户端逻辑位于 pkg/kubeseal 与 cmd/kubeseal。
部署控制器:三种官方支持的方式
官方文档提供了三种部署控制器的途径:直接应用 YAML 清单、Helm Chart、Carvel 包。
方式一:直接应用 YAML 清单
控制器清单从项目 Releases 页面获取,分为两个版本:
controller.yaml:完整清单,包含控制器运行所需的全部组件,包括 ClusterRole 权限和 CRD 定义;controller-norbac.yaml:受限版本,不包含 CRD 与 ClusterRole,适合在 RBAC 受限环境中按需裁剪后使用。
安装命令如下({{VERSION}} 替换为具体版本号,例如 v0.22.0):
$ kubectl apply -f https://github.com/bitnami/sealed-secrets/releases/download/{{VERSION}}/controller.yaml
role.rbac.authorization.k8s.io/sealed-secrets-service-proxier created
rolebinding.rbac.authorization.k8s.io/sealed-secrets-controller created
clusterrolebinding.rbac.authorization.k8s.io/sealed-secrets-controller created
serviceaccount/sealed-secrets-controller created
deployment.apps/sealed-secrets-controller created
customresourcedefinition.apiextensions.k8s.io/sealedsecrets.bitnami.com configured
rolebinding.rbac.authorization.k8s.io/sealed-secrets-service-proxier created
service/sealed-secrets-controller created
role.rbac.authorization.k8s.io/sealed-secrets-key-admin created
clusterrole.rbac.authorization.k8s.io/secrets-unsealer configured
从输出可见,该清单一次性地创建了 ServiceAccount、Deployment、Service、CRD sealedsecrets.bitnami.com 以及多组 RBAC 角色,控制器默认安装到 kube-system 命名空间。部署完成后,控制器会在启动后生成密钥对并进入就绪状态;若未就绪,请查看控制器日志。
GKE 集群的补充说明:在没有管理员权限的 GKE 集群上安装控制器可能受限,此时需要先为你的账号授予 cluster-admin 权限:
USER_EMAIL={{your-email}}
kubectl create clusterrolebinding $USER-cluster-admin-binding --clusterrole=cluster-admin --user=$USER_EMAIL
GKE 平台的更多细节可参考仓库中的 docs/GKE.md。
方式二:Helm Chart
官方 Helm Chart 托管在本仓库的 helm/sealed-secrets 目录下,安装命令为:
helm repo add sealed-secrets https://bitnami.github.io/sealed-secrets
helm install sealed-secrets-controller sealed-secrets/sealed-secrets \
--set namespace=kube-system \
重要提示:
kubesealCLI 默认假设控制器安装在kube-system命名空间,且 Deployment 名为sealed-secrets-controller。上面的安装命令显式指定了相同配置,以避免使用 kubeseal 时产生不必要的摩擦。
OpenShift 集群的补充说明:OpenShift 对容器的 Security Context 有标准限制,需要做如下调整(在 Helm values 中配置):
containerSecurityContext:
enabled: true
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: null
podSecurityContext:
方式三:Carvel 包
Sealed Secrets 也支持以 Carvel 包 的形式安装。首先需要在目标集群部署 kapp-controller,然后应用 Package 清单:
$ kapp deploy -a kc -f https://github.com/vmware-tanzu/carvel-kapp-controller/releases/latest/download/release.yml
$ kapp deploy -a sealed-secrets-carvel -f https://raw.githubusercontent.com/bitnami/sealed-secrets/main/carvel/package.yaml
Changes
Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri
default sealedsecrets.bitnami.com.2.10.0 Package - - create - reconcile - -
...
Succeeded
$ kubectl get Package
NAME PACKAGEMETADATA NAME VERSION AGE
sealedsecrets.bitnami.com.2.10.0 sealedsecrets.bitnami.com 2.10.0 18s
Package 就绪后,还需按照 Carvel 官方文档执行 PackageInstall 操作才能真正安装控制器。仓库中对应的包定义位于 carvel/package.yaml。
安装 kubeseal CLI:五种途径
kubeseal 是加密侧的核心工具,官方文档给出了五种安装方式:
Homebrew(macOS/Linux):
brew install kubeseal
MacPorts(macOS):
port install kubeseal
Nixpkgs(Nix 系系统)(注意:该包不由 Sealed Secrets 项目维护):
nix-env -iA nixpkgs.kubeseal
Linux(手动下载二进制):
wget https://github.com/bitnami/sealed-secrets/releases/download/<release-tag>/kubeseal-<version>-linux-amd64.tar.gz
tar -xvzf kubeseal-<version>-linux-amd64.tar.gz kubeseal
sudo install -m 755 kubeseal /usr/local/bin/kubeseal
其中 release-tag 为 kubeseal 的版本标签,例如 v0.21.0。
从源码安装(Go 环境):
go install github.com/bitnami/sealed-secrets/cmd/kubeseal@main
@main 可替换为具体的 release tag 或 commit SHA。安装完成后,二进制位于 $(go env GOPATH)/bin/kubeseal。
用 kubeseal 加密本地 Secret:完整工作流
这是整个项目最核心的用法。它的价值在于:加密动作完全发生在本地,明文 Secret 从不离开你的机器。官方文档给出了完整可复现的流程:
# 1. 在本地生成一个 json/yaml 格式的 Secret
# (注意使用 --dry-run,这只是生成一个本地文件!)
echo -n bar | kubectl create secret generic mysecret --dry-run=client --from-file=foo=/dev/stdin -o json >mysecret.json
# 2. 关键步骤:用 kubeseal 将明文 Secret 加密为 SealedSecret
kubeseal -f mysecret.json -w mysealedsecret.json
# 3. 此时 mysealedsecret.json 已经可以安全地提交到代码仓库
# 4. 部署到集群(控制器会解密并重建 Secret)
kubectl create -f mysealedsecret.json
# 5. 验证结果
kubectl get secret mysecret
约束:
SealedSecret与最终生成的Secret必须同名同命名空间。这是一个刻意设计的安全特性,防止同一集群上的其他用户复用你提交的 Sealed Secret。
从源码看,上述第 2 步对应 pkg/kubeseal/kubeseal.go 中的 Seal 函数:它读取输入的 Secret,按 scope 计算加密标签(label),然后用控制器的公钥完成混合加密并输出 SealedSecret 资源。整个加密的具体算法细节,将在下文"背景知识"部分深入展开。
操作指南:校验已有 Sealed Secret
当 SealedSecret 需要跨环境共享、或需要确认某个已存在的 SealedSecret 是否仍能被当前控制器正确解密时,官方推荐使用 kubeseal --validate 进行校验——它能验证加密/解密链路是否按预期工作。
假设有一个名为 sealed-secrets.yaml 的文件,内容如下:
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysecret
namespace: mynamespace
spec:
encryptedData:
foo: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq.....
校验命令极其简单:
$ cat sealed-secrets.yaml | kubeseal --validate
若 SealedSecret 无效(例如公钥不匹配、label 不符或数据被篡改),则会得到如下报错:
$ cat sealed-secrets.yaml | kubeseal --validate
error: unable to decrypt sealed secret
这个错误信息与源码中的实现一一对应:在 pkg/kubeseal/kubeseal.go 中,校验过程会尝试用控制器私钥解密该 SealedSecret,失败时返回 cannot validate sealed secret 类错误。由此可知,--validate 的本质不是"语法检查",而是一次真实的试解密——只有能成功解密的 SealedSecret 才是真正可用的。
背景知识:Sealed Secrets 的密码学原理
加密功能的正确性直接决定 Secrets 的安全性,因此官方专门用一篇文档讲透密码学实现,仓库源码 pkg/crypto/crypto.go 与之完全对应。
使用的协议与工具
Sealed Secrets 使用了如下密码学协议组合:
- AES-256-GCM:使用随机生成的、一次性的 32 字节会话密钥加密 Secret 本体,保证机密性与完整性。由于会话密钥只用一次,因此不使用 nonce;
- RSA-OAEP(搭配 SHA-256):用于封装(encapsulate)AES-256-GCM 的会话密钥,即密钥封装机制(Key Encapsulation Mechanism, KEM)——用控制器的 RSA 公钥加密这个短小的会话密钥;
- X509 证书:用于承载和管理 RSA 公钥,供 kubeseal 拉取使用。
控制器生成的证书每 30 天轮换一次,证书有效期为 10 年。
这一协议组合在源码 pkg/crypto/crypto.go 的 HybridEncrypt 中有直接体现:先生成随机会话密钥并用 AES-GCM 加密明文,再用 RSA-OAEP(SHA-256)加密会话密钥,最终输出 RSA 密文长度 || RSA 密文 || AES 密文 的混合密文结构。
熵的来源
随机数的质量是密码学安全的基石。项目使用 Go 标准库 crypto/rand 作为熵源,其底层行为如下:
// On Linux, FreeBSD, Dragonfly and Solaris, Reader uses getrandom(2) if
// available, /dev/urandom otherwise.
// On OpenBSD and macOS, Reader uses getentropy(2).
// On other Unix-like systems, Reader reads from /dev/urandom.
// On Windows systems, Reader uses the RtlGenRandom API.
// On Wasm, Reader uses the Web Crypto API.
这些操作系统级密码学 API 都能提供良好的密码学熵,在种子未知的前提下不易受密码学攻击。
密封(Sealing)流程拆解
公私钥对管理
控制器在启动时会查找集群级公私钥对:如果找不到且未手动提供,控制器会生成一对 4096 位(默认)RSA 密钥对,并持久化到与控制器同命名空间的普通 Secret 中。
公钥(若由控制器生成,则是自签名证书形式)应公开发布给所有想使用该集群 Sealed Secrets 的用户。获取公钥有两个途径:
- 控制器启动日志会打印证书;
- 对控制器的
/v1/cert.pem端点发起 HTTP GET 请求即可获取。
如果希望使用自己的 X509 证书,可以用 kubeseal 指定:
kubeseal --cert [https:/]/path/to/your-cert.pem
自带证书的完整操作流程见 docs/bring-your-own-certificates.md。
Secret 加密(步骤 1)
Secret 本体使用 AES-256-GCM 加密,密钥为随机生成的单次使用 32 字节会话密钥,输出记为 AES encrypted data。
会话密钥加密(步骤 2)
AES 会话密钥使用控制器的 RSA 公钥,通过 RSA-OAEP + SHA-256 封装。RSA-OAEP 的输入中有一个名为 label 的附加参数,其内容取决于控制器的 scope(作用域)配置:
- 默认(strict)scope:
label= Secret 的namespace + name(源码实现为namespace/name拼接); - namespace-wide scope:
label= Secret 的namespace; - cluster-wide scope:
label为空。
这一设计在源码 pkg/apis/sealedsecrets/v1alpha1/sealedsecret_expansion.go(scope 枚举定义)与 同文件 L90-L104 的 EncryptionLabel 函数 中均有实现:StrictScope(默认)把 SealedSecret 钉死在特定命名空间 + 特定名称;NamespaceWideScope 只钉死在特定命名空间;ClusterWideScope 允许在任何命名空间解封。这正是"同名同命名空间才能解密"这一约束的密码学根源——label 不一致,RSA-OAEP 解密就会失败。
RSA-OAEP 加密的输出记为 RSA encrypted data。
Sealed Secret 存储格式
最终 Sealed Secret 的数据格式为(|| 表示拼接):
Sealed Secret data = size of AES encrypted key (2 bytes) || RSA encrypted data || AES encrypted data
即:2 字节的 AES 加密密钥长度 + RSA 密文 + AES 密文。示意图如下:
Secret
|
│
K_s────────────►│
│ │
K_pub───────►│ │
│ │ 1.
label───────►│ 2. │
│ │
┌──────────────────────┬───────▼───────┬──────▼───────┐
Sealed Secret data = │size of AES encrypted │ RSA encrypted │ AES encrypted│
│key (2 bytes) │ data │ data │
└──────────────────────┴───────────────┴──────────────┘
K_s = 256 bits single-use session key, used by AES-GCM
K_pub = Public key from the self-signed certificate, used by RSA-OAEP
label = Additional input for RSA-OAEP encryption.
Content differs depending on the scope configuration:
* Default config : label = Secret's namespace || Secret's name
* Namespace-wide : label = Secret's namespace
* Cluster-wide : label is empty
解密流程
解密就是加密的逆过程,对应源码 pkg/crypto/crypto.go 中的 HybridDecrypt:
- 读取前 2 字节,得到 AES 加密密钥的长度,据此把
RSA encrypted data和AES encrypted data正确分离; - 用与公钥配对的私钥,配合相同的
label对RSA encrypted data做 RSA-OAEP 解密,恢复出 AES 会话密钥; - 用该会话密钥解密
AES encrypted data,还原出原始 Secret。
后量子密码学(Post-quantum)考量
官方文档还对三个密码学组件做了后量子安全分析:
熵来源:量子随机数生成器(QRNG)虽有理论优势,但依赖物理设备,超出 Sealed Secrets 的范围,项目继续使用 crypto/rand。
AES-256-GCM:分析认为 AES-256-GCM 具备量子抗性——Grover 算法可将密钥暴力破解复杂度从 2²⁵⁶ 降至 2¹²⁸,仍非常安全。但由于 AES 使用不可变的 128 位块,某些情况下复杂度可能降至 2⁶⁴;不过结合本项目 AES 的实际使用方式,2⁶⁴ 场景不太可能发生,且即便发生,当下仍可视为安全(长期则不然)。官方给出的低优先级建议是:关注能提供 128 位后量子安全强度的 AES 替代方案(如 ChaCha20-Poly1305)。
SHA-256:具备量子抗性,Grover 算法只能将暴力破解从 2²⁵⁶ 降到 2¹²⁸,且用非量子算法生成碰撞在计算上更便宜。官方结论:无需调整。
RSA-OAEP:与所有 RSA 算法一样,不具备量子抗性。Shor 算法能在合理时间内解决 RSA 所依赖的整数分解、离散对数等数学难题,因此具备量子能力的攻击者可轻松破解 RSA-OAEP。官方将其列为最高优先级的替换对象,候选方案包括 LMS、XMSS(基于格)与 McEliece(基于编码);同时强调替换需满足两个前提:业界出现明确的标准替代算法、且有兼容开源许可证的可靠 Go 实现。
参考:FAQ 中的实战要点
密钥备份与灾难恢复
解密私钥只存在于控制器管理的 Secret 中,没有后门。若丢失私钥且集群内的明文 Secret 也不可访问,则只能重新生成密码并重新密封。因此官方强烈建议备份私钥:
kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml >main.key
echo "---" >> main.key
kubectl get secret -n kube-system sealed-secrets-key -o yaml >>main.key
第二条命令仅在集群上安装过 0.9.x 之前的老版本时才需要。 该文件包含控制器的公钥与私钥,必须妥善保管。
灾难恢复时,在控制器启动前将这些 Secret 放回集群即可;若控制器已启动,则替换新生成的 Secret 后重启控制器:
kubectl apply -f main.key
kubectl delete pod -n kube-system -l name=sealed-secrets-controller
离线解密
虽然官方不推荐把 Sealed Secrets 当作长期存储系统,但确有合法场景需要在集群不可用时恢复 Secret。若已备份私钥,可使用:
kubeseal --recovery-unseal --recovery-private-key file1.key,file2.key,...
多个私钥文件用逗号分隔,适合密钥轮换后仍有旧 SealedSecret 的情况。
控制器不在 kube-system 命名空间时
若控制器安装在其它命名空间,需要告知 kubeseal。两种方式任选其一:
# 方式一:命令行参数
kubeseal --controller-namespace sealed-secrets <mysecret.json >mysealedsecret.json
# 方式二:环境变量
export SEALED_SECRETS_CONTROLLER_NAMESPACE=sealed-secrets
kubeseal <mysecret.json >mysealedsecret.json
一个控制器管理部分命名空间
若希望一个控制器服务多个(但不是全部)命名空间,可使用 --additional-namespaces 参数:
--additional-namespaces=<namespace1>,<namespace2>,<...>
同时需在目标命名空间中配置合适的 Role 与 RoleBinding,让控制器能够管理其中的 Secret。
镜像签名校验
项目的容器镜像使用 cosign 签名(v0.20.2 及更早使用 Cosign v1,更新镜像使用 Cosign v2),签名保存在 GitHub Container Registry 的 signs 路径。校验方式:
$ export COSIGN_REPOSITORY=ghcr.io/bitnami/sealed-secrets-controller/signs
$ cosign verify --key .github/workflows/cosign.pub ghcr.io/bitnami/sealed-secrets-controller:latest
Verification for ghcr.io/bitnami/sealed-secrets-controller:latest --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The signatures were verified against the specified public key
...
如何更新配置文件类 Secret 的局部字段
Kubernetes Secret 本质是扁平化的键值对映射,Sealed Secrets 只在这一层工作,无法理解值内部的结构化配置文件(JSON/YAML/TOML 等),因此不能帮你更新其中的单个字段。针对这一常见痛点,官方在 docs/examples/config-template 提供了一套可行的变通方案,其中包含 deployment.yaml 与 sealedsecret.yaml 示例。
总结:从文档到源码的完整知识闭环
Sealed Secrets 的价值在于把"加密"与"解密"两侧彻底分离:kubeseal 在本地用控制器的公钥完成 AES-256-GCM + RSA-OAEP 混合加密,加密产物可安全入库;控制器在集群内持有私钥,按 scope 计算出的 label 严格约束解密范围,保证同名同命名空间才能解封。理解这一点,也就理解了为什么备份私钥、正确设置 controller namespace 与 scope 配置,是生产环境使用 Sealed Secrets 的三个关键操作。若想继续深入,可以直接阅读仓库中的源码:加密实现、scope 与 label 逻辑、kubeseal 密封流程 以及控制器入口 pkg/controller/main.go。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.25 K640- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python860
SlideSCIPPT插件,支持素材库、AI助手、一键添加图片标题,复制粘贴位置、一键图片对齐、一键插入Markdown(加粗、超链接等行内样式、代码块、LaTeX等块级样式)、便捷导出图片!C#601
Agent-Reach给你的 AI Agent 一键装上互联网能力。13 个平台(网页/GitHub/YouTube/小红书/B站/Twitter/Reddit 等)多后端路由,当下最稳的接入方式替你选好、装好、体检好。GitHub 主仓库同步镜像。Python1284
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go23245
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java37451