一、什么是 Secret?
在 Kubernetes 中,Secret 是一种用于存储敏感信息的对象,例如:
- 密码
- 令牌(Token)
- SSH 密钥
- TLS 证书
- Docker 镜像仓库认证信息
使用 Secret 可以避免将敏感数据直接写入 Pod 定义或容器镜像中,从而降低泄露风险。
二、为什么需要 Secret?
- 安全隔离:Secret 独立于 Pod 创建和管理,减少在 Pod 创建、查看、编辑过程中敏感数据暴露的可能性。
- 灵活分发:通过 Volume 或环境变量将敏感信息注入容器。
- 访问控制:可结合 RBAC 限制对 Secret 的访问权限。
注意:默认情况下,Secret 在 etcd 中是未加密存储的。任何有 API 访问权限或 etcd 访问权限的人都能读取或修改 Secret。因此,建议启用静态加密、配置最小权限 RBAC 规则,并考虑使用外部 Secret 存储方案。
三、Secret 的类型
Kubernetes 提供了多种内置 Secret 类型,用于常见场景:
| 类型 | 用途 |
|---|---|
Opaque |
用户自定义的任意数据(默认类型) |
kubernetes.io/service-account-token |
ServiceAccount 令牌(旧版机制) |
kubernetes.io/dockercfg |
旧版 Docker 配置文件(~/.dockercfg) |
kubernetes.io/dockerconfigjson |
新版 Docker 配置文件(~/.docker/config.json) |
kubernetes.io/basic-auth |
基本认证的用户名/密码 |
kubernetes.io/ssh-auth |
SSH 认证的私钥 |
kubernetes.io/tls |
TLS 证书和密钥 |
bootstrap.kubernetes.io/token |
节点引导令牌 |
你可以使用 kubectl create secret 命令或 YAML 文件创建这些类型的 Secret。
四、常用操作示例
1. 查看已有 Secret
bash
kubectl get secret
输出示例:
NAME TYPE DATA AGE
aliyun-kafka Opaque 2 2d
default-token-bzz7p kubernetes.io/service-account-token 3 8d
model-mongo Opaque 2 2d
2. 查看 Secret 详情(包含数据条目 Key)
bash
kubectl describe secret model-mongo
输出示例:
Name: model-mongo
Namespace: default
Type: Opaque
Data
====
password: 16 bytes
username: 10 bytes
这里可以看到 password 和 username 两个数据条目,但不显示具体值。
3. 查看 Secret 的完整 YAML(包含 Base64 编码的值)
bash
kubectl edit secret model-mongo
或者:
bash
kubectl get secret model-mongo -o yaml
输出片段:
yaml
apiVersion: v1
data:
password: MWYyZDFlMmU2N2Rm
username: MWYyZDFlMmU2N2Rm
kind: Secret
metadata:
name: model-mongo
type: Opaque
4. 解码 Secret 的值
Secret 中的 data 字段值是 Base64 编码 的。要查看原始值,可以解码:
bash
echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
输出就是原始的密码或用户名。
五、创建 Secret 的方法
方法一:使用 kubectl create secret generic(Opaque 类型)
bash
# 从字面值创建
kubectl create secret generic my-secret \
--from-literal=username=admin \
--from-literal=password=S3cRet!
# 从文件创建
kubectl create secret generic my-secret \
--from-file=./username.txt \
--from-file=./password.txt
方法二:使用 YAML 配置文件
yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
username: YWRtaW4= # echo -n 'admin' | base64
password: UzNjUmV0IQ== # echo -n 'S3cRet!' | base64
更方便的可读方式(未编码)使用 stringData:
yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
stringData:
username: admin
password: S3cRet!
stringData字段在写入 etcd 时会自动转为 Base64,且不能与data混用相同 key。
方法三:创建 Docker 仓库认证 Secret
bash
kubectl create secret docker-registry my-registry-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=myemail@example.com
方法四:创建 TLS Secret
bash
kubectl create secret tls my-tls-secret \
--cert=path/to/tls.crt \
--key=path/to/tls.key
六、在 Pod 中使用 Secret
1. 通过 Volume 挂载(文件形式)
yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mycontainer
image: nginx
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: my-secret
每个 key 会变成一个文件,文件内容为解码后的值。
2. 通过环境变量注入
yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mycontainer
image: nginx
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: my-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: password
3. 用于拉取私有镜像
在 Pod 中通过 imagePullSecrets 引用:
yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mycontainer
image: myprivaterepo/myimage:latest
imagePullSecrets:
- name: my-registry-secret
也可以通过 ServiceAccount 默认挂载 imagePullSecrets。
七、更新与不可变 Secret
- 当 Secret 数据更新时,已挂载到 Pod Volume 中的内容会最终一致 地更新(但以
subPath方式挂载的不会自动更新)。 - 环境变量方式注入的 Secret 不会自动更新,需要重启 Pod。
从 Kubernetes v1.21 开始,支持 不可变 Secret:
yaml
apiVersion: v1
kind: Secret
metadata:
name: immutable-secret
immutable: true
data:
key: dmFsdWU=
一旦标记为不可变,无法修改数据,也不能改回可变状态。这能提升大规模集群性能并防止意外修改。
八、最佳实践与安全建议
- 启用静态加密 :在 API Server 配置中开启
--encryption-provider-config。 - 最小权限 RBAC :只授予必要的
get、list权限,避免watch或delete范围过大。 - 避免将 Secret 放入环境变量(除非必要),环境变量可能被调试工具或日志泄漏。
- 使用 short-lived token :对于 ServiceAccount,优先使用
TokenRequestAPI 获取短期令牌,而不是长期 Secret 令牌。 - 限制 Secret 大小:每个 Secret 最大 1MiB,防止 API Server 内存过大。
- 审计与监控:定期检查谁访问了哪些 Secret。
九、参考链接
总结:Kubernetes Secret 是一种重要且灵活的资源对象,用于管理敏感信息。结合合理的安全策略和访问控制,可以安全地将凭证注入到 Pod 中,避免硬编码在镜像或配置中。