一、启动应用安全信息的保护
1、Secret介绍
应用启动过程中可能需要一些敏感信息,比如访问数据库的用户名密码或者秘钥。将这些信息直接保存在容器镜像中显然不妥,Kubernetes 提供的解决方案是 Secret。
Secret 会以密文的方式存储数据,避免了直接在配置文件中保存敏感信息。Secret 会以 Volume 的形式被 mount 到 Pod,容器可通过文件的方式使用 Secret 中的敏感数据;此外,容器也可以环境变量的方式使用这些数据。
Secret 可通过命令行或 YAML 创建。比如希望 Secret 中包含如下信息:
1)用户名 admin
2)密码 123456
2、创建 Secret
有四种方法创建 Secret:
(1)通过 --from-literal:
[root@ren7 ~]# kubectl create secret generic mysecret --from-literal=username=admin --from-literal=password=123
secret/mysecret created
[root@ren7 ~]# kubectl get secret
NAME TYPE DATA AGE
default-token-qvqql kubernetes.io/service-account-token 3 4d23h
mysecret Opaque 2 9s
[root@ren7 ~]# kubectl get secret mysecret
NAME TYPE DATA AGE
mysecret Opaque 2 25s
每个 --from-literal 对应一个信息条目。
(2)通过 --from-file:
echo -n admin > ./username
echo -n 123456 > ./password
kubectl create secret generic mysecret --from-file=./username --from-file=./password
每个文件内容对应一个信息条目。
(3)通过 --from-env-file:
cat << EOF > env.txt
username=admin
password=123456
EOF
kubectl create secret generic mysecret --from-env-file=env.txt
文件 env.txt 中每行 Key=Value 对应一个信息条目。
(4)通过 YAML 配置文件:
apiVersion: v1 kind: Secret metadata: name: mysecret data: username: YWRtaW4= password: MTIzNDU2
文件中的敏感数据必须是通过 base64 编码后的结果。(-n 不换行)
[root@ren7 ~]# echo -n admin | base64 YWRtaW4= [root@ren7 ~]# echo -n 123456 | base64 MTIzNDU2
执行 kubectl apply 创建 Secret:
[root@ren7 yaml]# kubectl apply -f secret.yml secret/mysecret created [root@ren7 yaml]# kubectl get secret mysecret NAME TYPE DATA AGE mysecret Opaque 2 17s
显示有两个数据条目,kubectl describe secret 查看条目的 Key:
[root@ren7 yaml]# kubectl describe secret mysecret Name: mysecret Namespace: default Labels: <none> Annotations: Type: Opaque Data ==== password: 6 bytes username: 5 bytes
如果还想查看 Value,可以用 kubectl edit secret mysecret
[root@ren7 yaml]# kubectl describe secret mysecret Name: mysecret Namespace: default Labels: <none> Annotations: Type: Opaque Data ==== password: 6 bytes username: 5 bytes [root@ren7 yaml]# kubectl edit secret mysecret # Please edit the object below. Lines beginning with a '#' will be ignored, # and an empty file will abort the edit. If an error occurs while saving this file will be # reopened with the relevant failures. # apiVersion: v1 data: password: MTIzNDU2 username: YWRtaW4= kind: Secret metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","data":{"password":"MTIzNDU2","username":"YWRtaW4="},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"}} creationTimestamp: "2019-10-28T11:06:44Z" name: mysecret namespace: default resourceVersion: "206718" selfLink: /api/v1/namespaces/default/secrets/mysecret uid: 070c7284-f973-11e9-8d3b-000c297d011c type: Opaque
然后通过 base64 将 Value 反编码:
[root@ren7 ~]# echo -n YWRtaW4= | base64 --decode admin[root@ren7 ~]# [root@ren7 ~]# echo -n MTIzNDU2 | base64 --decode 123456[root@ren7 ~]#
二、secret在pod中的应用
1、volume 方式使用 Secret
Pod 可以通过 Volume 或者环境变量的方式使用 Secret,先学习 Volume 方式。
(1)Pod 的配置文件如下所示:
[root@ren7 yaml]# cat pod2.yaml apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: reg.yunwei.com/learn/busybox:latest args: - /bin/sh - -c - sleep 10; touch /tmp/healthy; sleep 30000 volumeMounts: - mountPath: "/etc/foo" name: foo readOnly: true volumes: - name: foo secret: secretName: mysecret
① 定义 volume foo,来源为 secret mysecret
② 将 foo mount 到容器路径 /etc/foo,可指定读写权限为 readOnly
创建 Pod 并在容器中读取 Secret:
[root@ren7 yaml]# kubectl get secret NAME TYPE DATA AGE default-token-qvqql kubernetes.io/service-account-token 3 4d23h [root@ren7 yaml]# kubectl create secret generic mysecret --from-literal=username=admin --from-literal=password=123 secret/mysecret created [root@ren7 yaml]# kubectl get secret NAME TYPE DATA AGE default-token-qvqql kubernetes.io/service-account-token 3 4d23h mysecret Opaque 2 2s [root@ren7 yaml]# kubectl apply -f pod2.yaml pod/mypod created [root@ren7 yaml]# [root@ren7 yaml]# kubectl exec -it mypod sh / # / # ls /etc/foo password username / # cat /etc/foo/password 123/ # / # cat /etc/foo/username admin/ # / # exit
可以看到,Kubernetes 会在指定的路径 /etc/foo 下为每条敏感数据创建一个文件,文件名就是数据条目的 Key,这里是 /etc/foo/username 和 /etc/foo/password,Value 则以明文存放在文件中。
(2)我们也可以自定义存放数据的文件名,比如将配置文件改为:
[root@ren7 yaml]# cat pod4.yaml apiVersion: v1 kind: Pod metadata: name: mypod2 spec: containers: - name: mypod2 image: reg.yunwei.com/learn/busybox:latest args: - /bin/sh - -c - sleep 10; touch /tmp/healthy; sleep 30000 volumeMounts: - mountPath: "/etc/foo" name: foo readOnly: true volumes: - name: foo secret: secretName: mysecret items: - key: username path: my-group/my-username - key: password path: my-group/my-password
这时数据将分别存放在 /etc/foo/my-group/my-username 和 /etc/foo/my-group/my-password 中。
以 Volume 方式使用的 Secret 支持动态更新:Secret 更新后,容器中的数据也会更新。
将 password 更新为 abcdef,base64 编码为 YWJjZGVm
[root@ren7 ~]# echo -n abcdef |base64 YWJjZGVm
更新 Secret。
[root@ren7 yaml]# cat secret.yml apiVersion: v1 kind: Secret metadata: name: mysecret data: username: YWRtaW4= password: YWJjZGVm
[root@ren7 yaml]# kubectl apply -f secret.yml
secret/mysecret configured
几秒钟或,新的 password 会同步到容器。
[root@ren7 yaml]# kubectl exec -it mypod sh / # cat /etc/foo/password abcdef/ # / # cat /etc/foo/username admin/ # / # exit [root@ren7 yaml]# kubectl exec -it mypod2 /bin/sh / # / # cd /etc/foo/ /etc/foo # ls my-group /etc/foo # cat my-group/my-username admin/etc/foo # /etc/foo # cat my-group/my-password abcdef/etc/foo # /etc/foo # exit
2、环境变量方式使用 Secret
通过 Volume 使用 Secret,容器必须从文件读取数据,会稍显麻烦,Kubernetes 还支持通过环境变量使用 Secret。
Pod 配置文件示例如下:
[root@ren7 yaml]# cat pod3.yml apiVersion: v1 kind: Pod metadata: name: mypod3 spec: containers: - name: mypod3 image: reg.yunwei.com/learn/busybox:latest args: - /bin/sh - -c - sleep 10; touch /tmp/healthy; sleep 30000 env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: mysecret key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password
创建 Pod 并读取 Secret。
[root@ren7 yaml]# kubectl apply -f pod3.yml pod/mypod3 created [root@ren7 yaml]# kubectl exec -it mypod3 /bin/sh / # / # ls /etc/foo ls: /etc/foo: No such file or directory / # echo $SECRET_USERNAME admin / # echo $SECRET_PASSWORD abcdef / # exit
通过环境变量 SECRET_USERNAME 和 SECRET_PASSWORD 成功读取到 Secret 的数据。
需要注意的是,环境变量读取 Secret 很方便,但无法支撑 Secret 动态更新。
Secret 可以为 Pod 提供密码、Token、私钥等敏感数据。