本页介绍如何将密码和加密密钥等敏感数据安全地注入到 Pod 中。
你需要有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具以与你的集群通信。建议在至少有两个节点的集群上运行本教程,且这些节点不能作为控制平面主机。如果你还没有集群,可以通过 minikube 创建一个,或者使用以下 Kubernetes 演练场之一。
假设您有两条密钥数据:用户名 my-app 和密码 39528$vdg7Jb。首先,使用 base64 编码工具将您的用户名和密码转换为 base64 表示。以下是使用常见 base64 程序的示例:
echo -n 'my-app' | base64
echo -n '39528$vdg7Jb' | base64
输出显示您的用户名的 base-64 表示为 bXktYXBw,密码的 base-64 表示为 Mzk1MjgkdmRnN0pi。
这是可用于创建存储用户名和密码的 Secret 的配置文件:
apiVersion: v1
kind: Secret
metadata:
name: test-secret
data:
username: bXktYXBw
password: Mzk1MjgkdmRnN0pi
创建 Secret
kubectl apply -f https://k8s.io/examples/pods/inject/secret.yaml
查看有关 Secret 的信息
kubectl get secret test-secret
输出
NAME TYPE DATA AGE
test-secret Opaque 2 1m
查看有关 Secret 的更多详细信息
kubectl describe secret test-secret
输出
Name: test-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 13 bytes
username: 7 bytes
如果您想跳过 Base64 编码步骤,可以使用 kubectl create secret 命令创建相同的 Secret。例如:
kubectl create secret generic test-secret --from-literal='username=my-app' --from-literal='password=39528$vdg7Jb'
这样更方便。前面展示的详细方法是显式运行每个步骤,以演示其背后的原理。
这是可用于创建 Pod 的配置文件:
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
spec:
containers:
- name: test-container
image: nginx
volumeMounts:
# name must match the volume name below
- name: secret-volume
mountPath: /etc/secret-volume
readOnly: true
# The secret data is exposed to Containers in the Pod through a Volume.
volumes:
- name: secret-volume
secret:
secretName: test-secret
创建 Pod
kubectl apply -f https://k8s.io/examples/pods/inject/secret-pod.yaml
验证您的 Pod 是否正在运行
kubectl get pod secret-test-pod
输出
NAME READY STATUS RESTARTS AGE
secret-test-pod 1/1 Running 0 42m
进入在您的 Pod 中运行的容器的 Shell
kubectl exec -i -t secret-test-pod -- /bin/bash
Secret 数据通过挂载在 /etc/secret-volume 下的卷公开给容器。
在您的 Shell 中,列出 /etc/secret-volume 目录中的文件
# Run this in the shell inside the container
ls /etc/secret-volume
输出显示了两个文件,每条密钥数据对应一个文件
password username
在您的 Shell 中,显示 username 和 password 文件的内容
# Run this in the shell inside the container
echo "$( cat /etc/secret-volume/username )"
echo "$( cat /etc/secret-volume/password )"
输出即为您的用户名和密码
my-app
39528$vdg7Jb
修改您的镜像或命令行,使程序在 mountPath 目录中查找文件。Secret data 映射中的每个键都会成为该目录中的一个文件名。
您还可以控制卷内 Secret 键的投射路径。使用 .spec.volumes[].secret.items 字段来更改每个键的目标路径:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
当您部署此 Pod 时,会发生以下情况:
mysecret 中的 username 键现在可供容器在 /etc/foo/my-group/my-username 路径下访问,而不是在 /etc/foo/username 下。password 键不会被投射。如果您使用 .spec.volumes[].secret.items 显式列出键,请考虑以下事项:
items 中指定的键才会被投射。items 字段中列出所有键。您可以为单个 Secret 键设置 POSIX 文件访问权限位。如果您未指定任何权限,则默认使用 0644。您还可以为整个 Secret 卷设置默认的 POSIX 文件模式,并根据需要为每个键覆盖该模式。
例如,您可以像这样指定默认模式:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
volumes:
- name: foo
secret:
secretName: mysecret
defaultMode: 0400
Secret 被挂载在 /etc/foo 上;所有由 Secret 卷挂载创建的文件都具有 0400 权限。
0400 视为十进制值 400。在 JSON 中,请改用十进制值作为 defaultMode。如果您编写的是 YAML,则可以使用八进制格式书写 defaultMode。您可以将 Secret 中的数据作为环境变量在容器中使用。
如果容器已经在环境变量中使用了 Secret,则除非重启容器,否则容器将无法看到 Secret 的更新。目前有一些第三方解决方案可在 Secret 更改时触发重启。
将环境变量定义为 Secret 中的键值对
kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
将 Secret 中定义的 backend-username 值分配给 Pod 规范中的 SECRET_USERNAME 环境变量。
apiVersion: v1
kind: Pod
metadata:
name: env-single-secret
spec:
containers:
- name: envars-test-container
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: backend-user
key: backend-username
创建 Pod
kubectl create -f https://k8s.io/examples/pods/inject/pod-single-secret-env-variable.yaml
在您的 Shell 中,显示 SECRET_USERNAME 容器环境变量的内容。
kubectl exec -i -t env-single-secret -- /bin/sh -c 'echo $SECRET_USERNAME'
输出类似于
backend-admin
与前面的示例一样,首先创建 Secret。
kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
kubectl create secret generic db-user --from-literal=db-username='db-admin'
在 Pod 规范中定义环境变量。
apiVersion: v1
kind: Pod
metadata:
name: envvars-multiple-secrets
spec:
containers:
- name: envars-test-container
image: nginx
env:
- name: BACKEND_USERNAME
valueFrom:
secretKeyRef:
name: backend-user
key: backend-username
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-user
key: db-username
创建 Pod
kubectl create -f https://k8s.io/examples/pods/inject/pod-multiple-secret-env-variable.yaml
在您的 Shell 中,显示容器环境变量。
kubectl exec -i -t envvars-multiple-secrets -- /bin/sh -c 'env | grep _USERNAME'
输出类似于
DB_USERNAME=db-admin
BACKEND_USERNAME=backend-admin
创建一个包含多个键值对的 Secret
kubectl create secret generic test-secret --from-literal=username='my-app' --from-literal=password='39528$vdg7Jb'
使用 envFrom 将所有 Secret 数据定义为容器环境变量。Secret 中的键将成为 Pod 中的环境变量名称。
apiVersion: v1
kind: Pod
metadata:
name: envfrom-secret
spec:
containers:
- name: envars-test-container
image: nginx
envFrom:
- secretRef:
name: test-secret
创建 Pod
kubectl create -f https://k8s.io/examples/pods/inject/pod-secret-envFrom.yaml
在您的 Shell 中,显示 username 和 password 容器环境变量。
kubectl exec -i -t envfrom-secret -- /bin/sh -c 'echo "username: $username\npassword: $password\n"'
输出类似于
username: my-app
password: 39528$vdg7Jb
此示例说明了一个使用包含生产凭据的 Secret 的 Pod,以及另一个使用包含测试环境凭据的 Secret 的 Pod。
为生产环境凭据创建一个 Secret
kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
输出类似于
secret "prod-db-secret" created
为测试环境凭据创建一个 Secret。
kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
输出类似于
secret "test-db-secret" created
$、\、*、= 和 ! 等特殊字符会被您的 Shell 解析,因此需要转义。
在大多数 Shell 中,转义密码的最简单方法是用单引号 (') 将其括起来。例如,如果您的实际密码是 S!B\*d$zDsb=,您应该按如下方式执行命令:
kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb='
您无需转义来自文件 (--from-file) 的密码中的特殊字符。
创建 Pod 清单
cat <<EOF > pod.yaml
apiVersion: v1
kind: List
items:
- kind: Pod
apiVersion: v1
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: prod-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
- kind: Pod
apiVersion: v1
metadata:
name: test-db-client-pod
labels:
name: test-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: test-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
EOF
通过运行以下命令将所有这些对象应用于 API 服务器:
kubectl create -f pod.yaml
两个容器的文件系统中都会存在以下文件,且每个容器的环境变量值各不相同:
/etc/secret-volume/username
/etc/secret-volume/password
您可以通过使用两个服务账户进一步简化基础 Pod 规范:
prod-user 使用 prod-db-secrettest-user 使用 test-db-secretPod 规范可简化为:
apiVersion: v1
kind: Pod
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
serviceAccount: prod-db-client
containers:
- name: db-client-container
image: myClientImage