Secret详解
secret用来保存小片敏感数据的k8s资源,例如密码,token,或者秘钥。这类数据当然也可以存放在Pod或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,并减少暴露的风险。
用户可以创建自己的secret,系统也会有自己的secret。
Pod需要先引用才能使用某个secret
Pod有2种方式来使用secret:
1. 作为volume的一个域被一个或多个容器挂载
2. 在拉取镜像的时候被kubelet引用。
內建的Secrets:
由ServiceAccount创建的API证书附加的秘钥k8s自动生成的用来访问apiserver的Secret,所有Pod会默认使用这个Secret与apiserver通信
创建自己的Secret:
方式1:使用kubectl create secret命令
方式2:yaml文件创建Secret
命令方式创建secret:
假如某个Pod要访问数据库,需要用户名密码,分别存放在2个文件中:username.txt,password.txt
例子:
[root@kub-k8s-master ~]# echo -n 'admin' > ./username.txt
[root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' > ./password.txt
kubectl create secret指令将用户名密码写到secret中,并在apiserver创建Secret
[root@kub-k8s-master ~]# kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
secret/db-user-pass created
查看创建结果:
[root@kub-k8s-master ~]# kubectl get secrets
NAME TYPE DATA AGE
db-user-pass Opaque 2 54s
default-token-6svwp kubernetes.io/service-account-token 3 4d11h
注: opaque:英[əʊˈpeɪk] 美[oʊˈpeɪk] 模糊
查看详细信息:
[root@kub-k8s-master ~]# 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的实际内容,这是出于对数据的保护的考虑,如果想查看实际内容使用命令:
[root@kub-k8s-master ~]# kubectl get secret db-user-pass -o json
base64解码:
[root@kub-k8s-master ~]# echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
1f2d1e2e67df
yaml方式创建Secret:
创建一个secret.yaml文件,内容用base64编码:明文显示容易被别人发现,这里先转码。
[root@kub-k8s-master ~]# echo -n 'admin' | base64
YWRtaW4=
[root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
创建一个secret.yaml文件,内容用base64编码
[root@kub-k8s-master prome]# vim secret.yml
---
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque #模糊
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
创建:
[root@kub-k8s-master prome]# kubectl apply -f secret.yml
secret/mysecret created
解析Secret中内容,还是经过编码的---需要解码
[root@kub-k8s-master ~]# kubectl get secrets
NAME TYPE DATA AGE
default-token-7vc82 kubernetes.io/service-account-token 3 30h
mysecret Opaque 2 6s
[root@kub-k8s-master prome]# kubectl get secret mysecret -o yaml
apiVersion: v1
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: "2019-10-21T03:07:56Z"
name: mysecret
namespace: default
resourceVersion: "162855"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: 36bcd07d-92eb-4755-ac0a-a5843ed986dd
type: Opaque
使用Secret
一个Pod中引用Secret的列子:
[root@kub-k8s-master prome]# vim pod_use_secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: testredis
image: daocloud.io/library/redis
volumeMounts: #挂载一个卷
- name: foo #这个名字需要与定义的卷的名字一致
mountPath: "/etc/foo" #挂载到容器里哪个目录下,随便写
readOnly: true
volumes: #数据卷的定义
- name: foo #卷的名字这个名字自定义
secret: #卷是直接使用的secret。
secretName: mysecret #调用刚才定义的secret
创建:
[root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml
pod/mypod created
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# cd /etc/foo/
root@mypod:/etc/foo# ls
password username
root@mypod:/etc/foo# cat password
1f2d1e2e67df
每一个被引用的Secret都要在spec.volumes中定义
如果Pod中的多个容器都要引用这个Secret那么每一个容器定义中都要指定自己的volumeMounts,但是Pod定义中声明一次spec.volumes就好了。
映射secret key到指定的路径
[root@kub-k8s-master prome]# kubectl delete -f pod_use_secret.yaml
pod "mypod" deleted
[root@kub-k8s-master prome]# vim pod_use_secret.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: testredis
image: daocloud.io/library/redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items: #定义一个items
- key: username #将那个key重新定义到那个目录下
path: my-group/my-username #相对路径,相对于/etc/foo的路径
2.创建
[root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml
pod/mypod created
3.从volume中读取secret的值
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# cd /etc/foo/my-group
root@mypod:/etc/foo/my-group# ls
my-username
root@mypod:/etc/foo/my-group# cat my-username
admin
root@mypod:/etc/foo/my-group#
username被映射到了文件/etc/foo/my-group/my-username而不是/etc/foo/username
被挂载的secret内容自动更新
也就是如果修改一个Secret的内容,那么挂载了该Secret的容器中也将会取到更新后的值,但是这个时间间隔是由kubelet的同步时间决定的。
1.设置base64加密
[root@kub-k8s-master prome]# echo qianfeng | base64
cWlhbmZlbmcK
2.将admin替换成qianfeng
[root@kub-k8s-master prome]# vim secret.yml
---
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: cWlhbmZlbmcK #修改为qianfeng的base64加密后的
password: MWYyZDFlMmU2N2Rm
1.创建
[root@kub-k8s-master prome]# kubectl apply -f secret.yml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
secret/mysecret configured
2.连接pod容器
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# cd /etc/foo/my-group
root@mypod:/etc/foo/my-group# ls
my-username
root@mypod:/etc/foo/my-group# cat my-username
qianfeng
以环境变量的形式使用Secret
[root@kub-k8s-master prome]# kubectl delete -f pod_use_secret.yaml
pod "mypod" deleted
[root@kub-k8s-master prome]# vim pod_use_secret.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: testredis
image: daocloud.io/library/redis
env: #定义环境变量
- name: SECRET_USERNAME #创建新的环境变量名称
valueFrom:
secretKeyRef: #调用的key是什么
name: mysecret #变量的值来自于mysecret
key: username #username里面的值
2.创建使用secret的pod容器
[root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml
pod/mypod created
3.连接
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# echo $SECRET_USERNAME #打印一下定义的变量
qianfeng
实验
1. 通过编写 YAML 文件的方式来创建这个 Secret 对象
Secret 对象要求这些数据必须是经过 Base64 转码的,以免出现明文密码的安全隐患。
转码操作:
[root@kub-k8s-master ~]# echo -n 'admin' | base64
YWRtaW4=
[root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
注意:像这样创建的 Secret 对象,它里面的内容仅仅是经过了转码,并没有被加密。生产环境中,需要在 Kubernetes 中开启 Secret 的加密插件,增强数据的安全性。
[root@kub-k8s-master prome]# vim create_secret.yml
---
apiVersion: v1
kind: Secret
metadata:
name: mysecret-01
type: Opaque
data:
user: YWRtaW4=
pass: MWYyZDFlMmU2N2Rm
[root@kub-k8s-master prome]# kubectl apply -f create_secret.yml
secret/mysecret-01 created
[root@kub-k8s-master prome~]# kubectl get secret
用yaml方式创建的secret调用方法如下:
[root@kub-k8s-master prome]# vim test-projected-volume.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume
spec:
containers:
- name: test-secret-volume
image: daocloud.io/library/nginx
volumeMounts:
- name: mysql-cred
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: mysql-cred
secret:
secretName: mysecret-01
创建这个 Pod:
[root@kub-k8s-master prome]# kubectl apply -f test-projected-volume.yaml
pod/test-projected-volume1 created
验证这些 Secret 对象是不是已经在容器里了:
[root@kub-k8s-master prome]# kubectl exec -it test-projected-volume /bin/bash
root@test-projected-volume:/# ls
bin dev home lib64 mnt proc root sbin sys usr
boot etc lib media opt projected-volume run srv tmp var
root@test-projected-volume:/# ls projected-volume/
pass user
root@test-projected-volume:/# cat projected-volume/pass
1f2d1e2e67df
root@test-projected-volume:/# cat projected-volume/user
admin
root@test-projected-volume:/#
注意:
如果报错:上面这条命令会报错如下
# kubectl exec -it test-projected-volume /bin/sh
error: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)
解决:绑定一个cluster-admin的权限
# kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
clusterrolebinding.rbac.authorization.k8s.io/system:anonymous created
结果中看到,保存在 Etcd 里的用户名和密码信息,已经以文件的形式出现在了容器的 Volume 目录里。
而这个文件的名字,就是 kubectl create secret 指定的 Key,或者说是 Secret 对象的 data 字段指定的 Key。