K8S(Kubernetes)中的Secret是一种用于保存敏感信息的资源对象,如密码、OAuth令牌、SSH密钥等。这些信息通常不应该直接暴露在Pod的规范(Spec)或镜像中,因为这样做会增加数据泄露的风险。Secret提供了一种更安全的方式来管理这些敏感信息,并允许Pod以受控的方式访问它们。
Secret的主要用途
Kubernetes支持多种Secret类型,每种类型都有其特定的用途和限制。以下是一些常见的Secret类型:
- Opaque:这是默认的Secret类型,用于存储任意格式的敏感数据。数据以Base64编码的形式存储在Secret中。
- kubernetes.io/service-account-token:这种类型的Secret由Kubernetes自动创建,用于存储服务账号的令牌。Pod默认会使用这种类型的Secret与API服务器进行通信。
- kubernetes.io/dockerconfigjson:用于存储Docker仓库的认证信息,如用户名和密码。这种类型的Secret允许Pod从私有Docker仓库中拉取镜像。
- kubernetes.io/tls:用于存储TLS证书和私钥,以支持HTTPS等安全通信协议。
- kubernetes.io/basic-auth:用于存储基本身份认证所需的用户名和密码信息。
Secret的使用方式
Pod可以通过以下方式使用Secret:
- 作为卷挂载:Pod可以将Secret挂载为卷,并像访问普通文件一样访问其中的敏感数据。这种方式适用于需要读取Secret中数据的场景。
- 作为环境变量:Pod可以将Secret中的数据导出为环境变量,并在容器启动时注入到容器中。这种方式适用于需要将敏感数据作为环境变量传递给应用程序的场景。
- 由kubelet使用:在Pod拉取镜像时,kubelet可以使用存储在Secret中的认证信息来访问私有镜像仓库。
注意事项
- 安全性:虽然Secret提供了比硬编码敏感信息更安全的方式,但用户仍需注意保护Secret的安全。例如,应避免将Secret数据泄露到日志、监控系统等非安全位置。
- 权限管理:应确保只有授权的Pod和用户才能访问Secret。可以通过Kubernetes的RBAC(基于角色的访问控制)机制来实现权限管理。
- 更新和删除:当Secret中的数据发生变化时,应及时更新Secret对象。不再需要的Secret应及时删除,以避免潜在的安全风险。
为了安全地使用 Secret,请至少执行以下步骤:
- 为 Secret 启用静态加密。
- 以最小特权访问 Secret 并启用或配置 RBAC 规则。
- 限制 Secret 对特定容器的访问。
- 考虑使用外部 Secret 存储驱动。
试用场景
Secret 卷中带句点的文件
通过定义以句点(.)开头的主键,你可以“隐藏”你的数据。 这些主键代表的是以句点开头的文件或“隐藏”文件。 例如,当以下 Secret 被挂载到 secret-volume 卷上时,该卷中会包含一个名为 .secret-file 的文件,并且容器 dotfile-test-container 中此文件位于路径 /etc/secret-volume/.secret-file 处。
样例:
apiVersion: v1
kind: Secret
metadata:
name: dotfile-secret
data:
.secret-file: dmFsdWUtMg0KDQo=
---
apiVersion: v1
kind: Pod
metadata:
name: secret-dotfiles-pod
spec:
volumes:
- name: secret-volume
secret:
secretName: dotfile-secret
containers:
- name: dotfile-test-container
image: registry.k8s.io/busybox
command:
- ls
- "-l"
- "/etc/secret-volume"
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
对 Pod 中一个容器可见的 Secret
在Kubernetes(K8S)中,直接实现Secret仅对Pod中一个容器可见的功能并不是原生支持的,因为一旦Secret被挂载到Pod的某个卷上,Pod内的所有容器都可以访问这个卷。不过,我们可以通过一些设计模式和策略来模拟这种效果,尽管它们并不能完全阻止其他容器访问Secret数据(因为容器通常可以以root身份运行并访问Pod内的任何文件)。
样例:
- 创建Secret
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: YWRtaW4= # admin的base64编码
password: bXlzZWNyZXQwc3N3b3Jk= # mysecretpassword的base64编码
- 配置Pod
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: container-with-secret
image: myimage
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
- name: container-without-secret
image: anotherimage
# 这个容器没有配置环境变量来访问Secret
类型
Kubernetes 提供若干种内置的类型,用于一些常见的使用场景。 针对这些类型,Kubernetes 所执行的合法性检查操作以及对其所实施的限制各不相同。
内置类型 | 用法 |
---|---|
Opaque | 用户定义的任意数据 |
kubernetes.io/service-account-token | 服务账号令牌 |
kubernetes.io/dockercfg | ~/.dockercfg 文件的序列化形式 |
kubernetes.io/dockerconfigjson | ~/.docker/config.json 文件的序列化形式 |
kubernetes.io/basic-auth | 用于基本身份认证的凭据 |
kubernetes.io/ssh-auth | 用于 SSH 身份认证的凭据 |
kubernetes.io/tls | 用于 TLS 客户端或者服务器端的数据 |
bootstrap.kubernetes.io/token | 启动引导令牌数据 |
样例场景
1. 存储数据库密码并传递给Pod
场景描述:
在Kubernetes集群中部署的应用程序需要访问数据库,而数据库密码是敏感信息,不应明文存储在配置文件中。
应用步骤:
- 创建Secret:
使用kubectl命令行工具或YAML文件创建一个包含数据库密码的Secret。
kubectl create secret generic db-secret --from-literal=username=admin --from-literal=password=mysecretpassword
或者,使用YAML文件:
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: YWRtaW4= # admin的base64编码
password: bXlzZWNyZXQwc3N3b3Jk= # mysecretpassword的base64编码
- 配置Pod:
在Pod的配置文件中,通过环境变量或卷挂载的方式将Secret中的数据库密码传递给容器。
环境变量方式:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mycontainer
image: myimage
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
卷挂载方式(不推荐用于密码,但可用于证书等文件):
apiVersion: v1
kind: Pod
metadata:
name: mypod-volume
spec:
containers:
- name: mycontainer
image: myimage
volumeMounts:
- name: db-secret-volume
mountPath: "/etc/secrets"
readOnly: true
volumes:
- name: db-secret-volume
secret:
secretName: db-secret
2. 访问私有Docker Registry
场景描述:
需要从私有Docker Registry拉取镜像到Kubernetes集群中,而Registry需要认证信息。
应用步骤:
- 创建docker-registry类型的Secret:
使用kubectl命令行工具创建一个包含Registry认证信息的Secret。
kubectl create secret docker-registry my-registry \
--docker-server=https://index.docker.io/v1/ \
--docker-username=myusername \
--docker-password=mypassword \
--docker-email=myemail@example.com
- 在Pod的YAML文件中引用Secret:
在Pod的spec.imagePullSecrets字段中引用创建的Secret,以便Pod能够使用这些认证信息从私有Registry拉取镜像。
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mycontainer
image: myprivateimage
imagePullSecrets:
- name: my-registry
3. 存储TLS证书和私钥
场景描述:
Pod之间的通信需要加密,因此需要TLS证书和私钥。
应用步骤:
- 创建tls类型的Secret:
使用kubectl命令行工具或YAML文件创建一个包含TLS证书和私钥的Secret。
kubectl create secret tls my-tls-secret \
--cert=path/to/tls.crt \
--key=path/to/tls.key
或者,使用YAML文件:
apiVersion: v1
kind: Secret
metadata:
name: my-tls-secret
type: kubernetes.io/tls
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
- 在Ingress或Pod中引用Secret:
对于Ingress,可以在Ingress资源中通过tls字段引用Secret来实现HTTPS。对于Pod,可以通过卷挂载的方式将证书和私钥挂载到Pod