K8S 之 Secret

摘要

Secret 介绍

  • Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。

  • 由于创建 Secret 可以独立于使用它们的 Pod, 因此在创建、查看和编辑 Pod 的工作流程中暴露 Secret(及其数据)的风险较小。 Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施, 例如避免将敏感数据写入非易失性存储。

  • Secret 类似于 ConfigMap 但专门用于保存机密数据。

  • 每个 Secret 的尺寸最多为 1MiB

  • 在 K8S 中,Secret 有多种类型:本文只讲解 Opaque 类型,其余类型参考[官网]((https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/)。

内置类型 用法描述
Opaque 用户自定义的任意数据(默认类型)
kubernetes.io/service-account-token 自动挂载的服务账号令牌,供 Pod 访问 API 使用
kubernetes.io/dockercfg 序列化的 ~/.dockercfg 文件,用于私有仓库认证(旧格式)
kubernetes.io/dockerconfigjson 序列化的 ~/.docker/config.json 文件(推荐)
kubernetes.io/basic-auth 存储用户名和密码,用于 HTTP 基本认证
kubernetes.io/ssh-auth 存储 SSH 私钥,用于 SSH 身份认证
kubernetes.io/tls 存储 TLS 密钥和证书,用于 HTTPS 或服务加密通信
bootstrap.kubernetes.io/token 用于 kubelet 加入集群的引导令牌

Secret 创建及使用

  • Secret 与 ConfigMap 创建及使用类似,都是存储键值对,但存储内容不同,Secret 存储的是 Base64 编码后的内容。

环境变量引用

  • yaml创建

1
2
3
4
5
6
7
8
9
10
# mysevret.yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque # 默认类型 ,可以省略
data:
username: YWRtaW4= # "admin" 的 base64 编码
password: MWYyZDFlMmU2N2Rm # "1f2d1e2e67df" 的 base64 编码

  • 命令行创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# key:value 方式创建,这里 value 值是 明文,k8s 会进行 base64 编码
kubectl create secret generic my-secret \
--from-literal=username=admin \
--from-literal=password=1f2d1e2e67df

# 文件方式创建
# --from-env-file=app.env 作用:将 app.env 中的每一行解析为 key=value,每一行变成 Secret 中的一个键值对。
kubectl create secret generic my-secret \
--from-env-file=username.env \
--from-env-file=password.env

# username.env 文件内容如下:
# username=admin

# password.env 文件内容如下:
# password=1f2d1e2e67df

# 创建完成后,查看 Secret 的内容
$ k get secrets my-secret -o yaml
apiVersion: v1
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: "2025-07-05T13:21:22Z"
name: my-secret
namespace: default
resourceVersion: "747355"
uid: 4f77269d-d4c3-4ae8-aafc-7cfa56b84a5d
type: Opaque
  • 将 Secret 中的全部数据作为环境变量使用

1
2
3
4
5
6
7
8
9
10
11
12
13
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: env-secret
spec:
containers:
- name: app
command: ["/bin/sh", "-c", "printenv"] # 打印环境变量
image: busybox:latest
envFrom: # 环境变量引用文件、 Secret ,等等
- secretRef: # 这里引用 Secret ,此处将 Secret 中的全部数据作为环境变量使用
name: my-secret # Secret 名称
  • 将 Secret 中的部分数据作为环境变量使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: env-secret2
spec:
containers:
- name: app
command: ["/bin/sh", "-c"]
args: # 容器启动命令
- |
echo "username: ${SECRET_USERNAME}"
echo "password: ${SECRET_PASSWORD}"
image: busybox:latest
env: # 环境变量配置,key: value 形式
- name: SECRET_USERNAME # 要在pod中配置的环境变量的 key
valueFrom: # value 来源
secretKeyRef: # 引用 Secret 中的 key
name: my-secret # Secret 名称
key: username # Secret 中 key 的名称
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: password
  • 查看pod日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ k logs pods/env-secret
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=env-secret
SHLVL=1
username=admin
HOME=/root
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
password=1f2d1e2e67df
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/


$ k logs pods/env-secret2
username: admin
password: 1f2d1e2e67df

存储卷引用

  • yaml创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# secret-configfile.yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
stringData: # 使用 stringData,K8s 会自动将其转换为 base64 编码
app.properties: | # 文件名
server.port=8080
log.level=INFO
db.properties: | # 文件名
db.host=localhost
db.port=5432

  • 命令行创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 注意这里是 --from-file,作为文件配置,而非环境变量
# 文件内容是明文,k8s 会自动将其转换为 base64 编码
kubectl create secret generic my-secret \
--from-file=app.properties \
--from-file=db.properties
# app.properties 文件内容如下:
# server.port=8080
# log.level=INFO

# db.properties 文件内容如下:
# db.host=localhost
# db.port=5432

$ k get secrets my-secret -oyaml
apiVersion: v1
data:
app.properties: c2VydmVyLnBvcnQ9ODA4MApsb2cubGV2ZWw9SU5GTwo=
db.properties: ZGIuaG9zdD1sb2NhbGhvc3QKZGIucG9ydD0xMjU0MzIK
kind: Secret
metadata:
creationTimestamp: "2025-07-05T13:45:14Z"
name: my-secret
namespace: default
resourceVersion: "750742"
uid: 35ffcdd6-d70a-4f3a-9246-5c56da630bc1
type: Opaque
  • Pod 挂载 Secret 为文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# secret-pod.yaml 文件内容如下:
apiVersion: v1
kind: Pod
metadata:
name: secret-demo
spec:
containers:
- name: myapp
image: busybox
command: ["sleep", "3600"]
volumeMounts:
- name: config-volume
mountPath: /etc/config # 挂载路径
readOnly: true
volumes:
- name: config-volume # 存储卷 名称
secret: # 存储卷类型为 Secret
secretName: my-secret # 挂载的 Secret 名称,本利中将 Secret 中的全部文件都挂载到pod目录下
  • 容器内的 /etc/config/ 目录下会有两个文件:

1
2
3
4
5
/etc/config/app.properties
/etc/config/db.properties

$ k exec -it secret-demo -- ls /etc/config/
app.properties db.properties
  • 如果只想挂载 Secret 中的某些文件,可以通过 items 字段指定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# secret-pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-demo2
spec:
containers:
- name: myapp
image: busybox
command: ["sleep", "3600"]
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
volumes:
- name: config-volume
secret:
secretName: my-secret
items: # 明确指定挂载的key
- key: app.properties # secret 中的key
path: app.properties # 映射到容器内的路径,最终挂载路径为 /etc/config/app.properties

后记

  • Secret 的特点与使用方法与 ConfigMap 非常类似。

  • 🔍 ConfigMap vs Secret 对比表:

特性 ConfigMap Secret
用途 存储非敏感配置信息(如环境变量、配置文件) 存储敏感信息(如密码、证书、token)
数据是否加密 否,明文存储(Base64 编码可读) 否(默认 Base64 编码),可配置加密存储(如使用 KMS)
字段名 data / binaryData data(需 base64) / stringData(明文)
可存储的最大大小 每个对象最多约 1MB 每个对象最多约 1MB
支持的挂载方式 - 环境变量
- 卷(文件)
- 环境变量
- 卷(文件)
默认类型(type) 无类型字段 默认为 Opaque
可定义为多个文件挂载
默认 RBAC 访问控制强度 弱(多数用户/Pod 可读取) 强(默认受限访问)
支持的内置类型 ✅ 如:kubernetes.io/tlskubernetes.io/basic-auth
是否适合存储密钥/密码 ❌ 不推荐 ✅ 推荐
可视化明文读取 ✅ 直接读取 ✅ 但 Base64 编码后需要解码
常见用途示例 App 配置、日志级别、连接参数等 数据库密码、TLS 证书、API Token 等