secret
weight: 76
title: Secret 配置
date: “2022-05-21T00:00:00+08:00”
type: book
Secret
对象类型用来保存敏感信息,例如密码、secret
中比放在 pod
的定义中或者
Secret 概览
用户可以创建
要使用
内置secret
Service Account 使用API 凭证自动创建和附加secret
如果需要,可以禁用或覆盖自动创建和使用
参阅 Service Account 文档获取关于
创建您自己的Secret
使用kubectl 创建Secret
假设有些./username.txt
和 ./password.txt
文件里。
# Create files needed for rest of example.
$ echo -n "admin" > ./username.txt
$ echo -n "1f2d1e2e67df" > ./password.txt
kubectl create secret
命令将这些文件打包到一个
$ kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
secret "db-user-pass" created
您可以这样检查刚创建的
$ kubectl get secrets
NAME TYPE DATA AGE
db-user-pass Opaque 2 51s
$ kubectl describe secrets/db-user-pass
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password.txt: 12 bytes
username.txt: 5 bytes
请注意,默认情况下,get
和 describe
命令都不会显示文件的内容。这是为了防止将
请参阅 解码
手动创建Secret
您也可以先以
每一项必须是
$ echo -n "admin" | base64
YWRtaW4=
$ echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm
现在可以像这样写一个
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
数据字段是一个映射。它的键必须匹配
使用 kubectl create
创建
$ kubectl create -f ./secret.yaml
secret "mysecret" created
编码注意: base64
实用程序时,用户应避免使用 -b
选项来拆分长行。另外,对于-w
选项不可用的话,应该添加选项 -w 0
到 base64
命令或管道 base64 | tr -d '\n'
。
解码Secret
可以使用 kubectl get secret
命令获取
$ kubectl get secret mysecret -o yaml
apiVersion: v1
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
kind: Secret
metadata:
creationTimestamp: 2016-01-22T18:41:56Z
name: mysecret
namespace: default
resourceVersion: "164619"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: cfee02d6-c137-11e5-8d73-42010af00002
type: Opaque
解码密码字段:
$ echo "MWYyZDFlMmU2N2Rm" | base64 --decode
1f2d1e2e67df
使用Secret
在Pod 中使用Secret 文件
在
- 创建一个
secret 或者使用已有的secret 。多个pod 可以引用同一个secret 。 - 修改您的
pod 的定义在spec.volumes[]
下增加一个volume 。可以给这个volume 随意命名,它的spec.volumes[].secret.secretName
必须等于secret 对象的名字。 - 将
spec.containers[].volumeMounts[]
加到需要用到该secret 的容器中。指定spec.containers[].volumeMounts[].readOnly = true
和spec.containers[].volumeMounts[].mountPath
为您想要该secret 出现的尚未使用的目录。 - 修改您的镜像并且/或者命令行让程序从该目录下寻找文件。
Secret 的data
映射中的每一个键都成为了mountPath
下的一个文件名。
这是一个在
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
您想要用的每个spec.volumes
中指明。
如果volumeMounts
配置块,但是每个spec.volumes
。
您可以打包多个文件到一个
向特性路径映射
我们还可以控制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
将会发生什么呢:
username
secret 存储在/etc/foo/my-group/my-username
文件中而不是/etc/foo/username
中。password
secret 没有被影射
如果使用了 spec.volumes[].secret.items
,只有在 items
中指定的items
字段中。所有列出的密钥必须存在于相应的
您还可以指定0644
。您可以为整个保密卷指定默认模式,如果需要,可以覆盖每个密钥。
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: 256
然后,/etc/foo
目录,所有通过该0400
。
请注意,
您还可以是用映射,如上一个示例,并为不同的文件指定不同的权限,如下所示:
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
items:
- key: username
path: my-group/my-username
mode: 511
在这种情况下,导致 /etc/foo/my-group/my-username
的文件的权限值为 0777
。由于
请注意,如果稍后阅读此权限值可能会以十进制格式显示。
从
在挂载的
$ ls /etc/foo/
username
password
$ cat /etc/foo/username
admin
$ cat /etc/foo/password
1f2d1e2e67df
容器中的程序负责从文件中读取
挂载的
当已经在
Secret 作为环境变量
将
- 创建一个
secret 或者使用一个已存在的secret 。多个pod 可以引用同一个secret 。 - 在每个容器中修改您想要使用
secret key 的Pod 定义,为要使用的每个secret key 添加一个环境变量。消费secret key 的环境变量应填充secret 的名称,并键入env[x].valueFrom.secretKeyRef
。 - 修改镜像并/或者命令行,以便程序在指定的环境变量中查找值。
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: mycontainer
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
restartPolicy: Never
消费环境变量里的
在一个消耗环境变量
$ echo $SECRET_USERNAME
admin
$ echo $SECRET_PASSWORD
1f2d1e2e67df
使用imagePullSecret
手动指定
安排imagePullSecrets 自动附加
您可以手动创建
自动挂载手动创建的Secret
手动创建的
详细
限制
验证
每个
--manifest-url
--config
标志或其
必须先创建
通过 secretKeyRef
对不存在于命名的
用于通过 envFrom
填充环境变量的InvalidVariableNames
,该消息将包含被跳过的无效键的列表。该示例显示一个
$ kubectl get events
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON
0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names.
Secret 与Pod 生命周期的联系
通过
使用案例
使用案例:包含ssh 密钥的pod
创建一个包含
$ kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
安全性注意事项:发送自己的
现在我们可以创建一个使用
kind: Pod
apiVersion: v1
metadata:
name: secret-test-pod
labels:
name: secret-test
spec:
volumes:
- name: secret-volume
secret:
secretName: ssh-key-secret
containers:
- name: ssh-test-container
image: mySshImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
当容器中的命令运行时,密钥的片段将可在以下目录:
/etc/secret-volume/ssh-publickey
/etc/secret-volume/ssh-privatekey
然后容器可以自由使用密钥数据建立一个
使用案例:包含prod/test 凭据的pod
下面的例子说明一个
创建
$ kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
secret "prod-db-secret" created
$ kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
secret "test-db-secret" created
创建
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"
这两个容器将在其文件系统上显示以下文件,其中包含每个容器环境的值:
/etc/secret-volume/username
/etc/secret-volume/password
请注意,两个prod-user
拥有 prod-db-secret
,另一个称为 test-user
拥有 test-db-secret
。然后,
kind: Pod
apiVersion: v1
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
serviceAccount: prod-db-client
containers:
- name: db-client-container
image: myClientImage
使用案例:secret 卷中以点号开头的文件
为了将数据“隐藏”起来(即文件名以点号开头的文件
kind: Secret
apiVersion: v1
metadata:
name: dotfile-secret
data:
.secret-file: dmFsdWUtMg0KDQo=
---
kind: Pod
apiVersion: v1
metadata:
name: secret-dotfiles-pod
spec:
volumes:
- name: secret-volume
secret:
secretName: dotfile-secret
containers:
- name: dotfile-test-container
image: gcr.io/google_containers/busybox
command:
- ls
- "-l"
- "/etc/secret-volume"
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
Secret-volume
将包含一个单独的文件,叫做 .secret-file
,dotfile-test-container
的 /etc/secret-volume/.secret-file
路径下将有该文件。
注意
以点号开头的文件在 ls -l
的输出中被隐藏起来了;列出目录内容时,必须使用 ls -la
才能查看它们。
使用案例:Secret 仅对pod 中的一个容器可见
考虑以下一个需要处理
这可以在两个容器中分为两个进程:前端容器,用于处理用户交互和业务逻辑,但无法看到私钥;以及可以看到私钥的签名者容器,并且响应来自前端的简单签名请求(例如通过本地主机网络
使用这种分割方法,攻击者现在必须欺骗应用程序服务器才能进行任意的操作,这可能比使其读取文件更难。
最佳实践
客户端使用secret API
当部署与
由于这些原因,在命名空间中 watch
和list
watch
和 list
所有
需要访问get
请求。这允许管理员限制对所有
为了提高循环获取的性能,客户端可以设计引用watch
资源,在引用更改时重新请求
安全属性
保护
因为 secret
对象可以独立于使用它们的 pod
而创建,所以在创建、查看和编辑secret
对象采取额外的预防措施,例如避免将其写入到磁盘中可能的位置。
只有当节点上的
在大多数
节点上的
同一节点上的很多个
风险
API server 的secret 数据以纯文本的方式存储在etcd 中;因此:- 管理员应该限制
admin 用户访问etcd ; API server 中的secret 数据位于etcd 使用的磁盘上;管理员可能希望在不再使用时擦除/ 粉碎etcd 使用的磁盘
- 管理员应该限制
- 如果您将
secret 数据编码为base64 的清单(JSON 或YAML )文件,共享该文件或将其检入代码库,这样的话该密码将会被泄露。Base64 编码不是一种加密方式,一样也是纯文本。 - 应用程序在从卷中读取
secret 后仍然需要保护secret 的值,例如不会意外记录或发送给不信任方。 - 可以创建和使用
secret 的pod 的用户也可以看到该secret 的值。即使API server 策略不允许用户读取secret 对象,用户也可以运行暴露secret 的pod 。 - 如果运行了多个副本,那么这些
secret 将在它们之间共享。默认情况下,etcd 不能保证与SSL/TLS 的对等通信,尽管可以进行配置。 - 目前,任何节点的
root 用户都可以通过模拟kubelet 来读取API server 中的任何secret 。只有向实际需要它们的节点发送secret 才能限制单个节点的根漏洞的影响,该功能还在计划中。