一般情况下ConfigMap是用来存储一些非安全的配置信息,如果涉及到一些安全相关的数据的话,用ConfigMap就不妥了,因为ConfigMap是明文存储的,这时候就需要另外一个资源对象,Secret—用来保存敏感信息,例如密码、OAuth令牌和ssh key等等,将这些信息放在Secret中比放在Pod的定义中或者Docker镜像中要更加安全和灵活。
Secret主要使用的有以下三种类型:
Opaque:base64编码格式的Secret,用来存储密码、密钥等;但数据也可以通过base64-decode解码得到原始数据,所以加密性很弱。kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。kubernetes.io/service-account-token:用于ServiceAccount,ServiceAccount创建时。k8s会默认创建一个对应的Secret对象,Pod如果使用了ServiceAccount,对应的Secret会自动挂载到Pod目录/run/secrets/kubernetes.io/serviceaccount中。bootstrap.kubernetes.io/token:用于节点接入集群的校验的Secret。
Opaque Secret
Opaque类型的数据是一个map类型,要求value必须是base64编码格式,比如创建一个用户名为admin,密码为admin321的Secret对象,首先需要先把用户名和密码做base64编码;
$ echo -n "admin" | base64YWRtaW4=$ echo -n "admin321" | base64YWRtaW4zMjE=
然后编写一个Yaml文件(secret-demo.yaml):
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: YWRtaW4zMjE=
使用kubectl来创建:
$ kubectl get secret
NAME TYPE DATA AGE
default-token-n9w2d kubernetes.io/service-account-token 3 33d
mysecret Opaque 2 40s
其中default-token-n9w2d为创建集群时默认创建的Secret,被serviceaccount/default引用。使用describe命令查看详情:
$ kubectl describe secret mysecret
Name: mysecret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 8 bytes
username: 5 bytes
利用 describe 命令查看到的 Data 没有直接显示出来,如果想看到 Data 里面的详细信息,可以输出成YAML 文件进行查看:
$ kubectl get secret mysecret -o yaml
apiVersion: v1
data:
password: YWRtaW4zMjE=
username: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: 2018-06-19T15:27:06Z
name: mysecret
namespace: default
resourceVersion: "3694084"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: 39c139f5-73d5-11e8-a101-525400db4df7
type: Opaque
创建好Secret对象后,有两种方式来使用:
- 以环境变量的形式
- 以Volume的形式挂载
环境变量
编写一个yaml文件(secret1-pod.yaml)
apiVersion: v1
kind: Pod
metadata:
name: secret1-pod
spec:
containers:
- name: secret1
image: busybox
command: ["/bin/sh", "-c", "env"]
env:
- name: USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
主要注意的是上面环境变量中定义的secretkeyRef字段,和前面configMapKeyRef类似,一个是从Secret对象中获取,一个是从ConfigMap对象中获取,创建上面的Pod:
$ kubectl create -f secret1-pod.yaml
pod "secret1-pod" created
查看日志输出:
$ kubectl logs secret1-pod
...
USERNAME=admin
PASSWORD=admin321
...
Volume挂载
验证下Volume挂载,创建一个Pod文件(secret2-pod.yaml):
apiVersion: v1
kind: Pod
metadata:
name: secret2-pod
spec:
volumes:
- name: secrets
secret:
secretName: mysecret
containers:
- name: secret2
image: busybox
command: ["/bin/sh", "-c", "ls /etc/secrets"]
volumeMounts:
- name: secrets
mountPath: /etc/secrets
创建Pod,然后查看输出日志:
$ kubectl create -f secret-pod2.yaml
pod "secret2-pod" created
$ kubectl logs secret2-pod
password
username
可看到Secret把两个Key挂载成两个对应的文件。当然如果想要挂载到指定的文件上面,???可以在secretName下面添加items指定key和path
kubernetes.io/dockerconfigjson
除了上面的Opaque类型外,还可以创建用户docker registry认证的Secret,直接用kubectl create命令创建,如下:
$ kubectl create secret docker-registry myregistry --docker-server=DOCKER_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
secret "myregistry" created
还可以通过指定文件的方式来创建镜像仓库认证信息,需要注意对应的KEY和TYPE:
$ kubectl create secret generic myregistry --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson
查看Secret列表:
$ kubectl get secret
NAME TYPE DATA AGE
default-token-n9w2d kubernetes.io/service-account-token 3 33d
myregistry kubernetes.io/dockerconfigjson 1 15s
mysecret Opaque 2 34m
注意上面的TYPE类型,myregistry对应的是kubernetes.io/dockerconfigjson,使用describe命令查看详细信息:
$ kubectl describe secret myregistry
Name: myregistry
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/dockerconfigjson
Data
====
.dockerconfigjson: 152 bytes
使用-o yaml来展示完整信息:
$ kubectl get secret myregistry -o yaml
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyJET0NLRVJfU0VSVkVSIjp7InVzZXJuYW1lIjoiRE9DS0VSX1VTRVIiLCJwYXNzd29yZCI6IkRPQ0tFUl9QQVNTV09SRCIsImVtYWlsIjoiRE9DS0VSX0VNQUlMIiwiYXV0aCI6IlJFOURTMFZTWDFWVFJWSTZSRTlEUzBWU1gxQkJVMU5YVDFKRSJ9fX0=
kind: Secret
metadata:
creationTimestamp: 2018-06-19T16:01:05Z
name: myregistry
namespace: default
resourceVersion: "3696966"
selfLink: /api/v1/namespaces/default/secrets/myregistry
uid: f91db707-73d9-11e8-a101-525400db4df7
type: kubernetes.io/dockerconfigjson
把上面的data.dockerconfigjson下的数据做base64解码,看下数据:
$ echo eyJhdXRocyI6eyJET0NLRVJfU0VSVkVSIjp7InVzZXJuYW1lIjoiRE9DS0VSX1VTRVIiLCJwYXNzd29yZCI6IkRPQ0tFUl9QQVNTV09SRCIsImVtYWlsIjoiRE9DS0VSX0VNQUlMIiwiYXV0aCI6IlJFOURTMFZTWDFWVFJWSTZSRTlEUzBWU1gxQkJVMU5YVDFKRSJ9fX0= | base64 -d
{"auths":{"DOCKER_SERVER":{"username":"DOCKER_USER","password":"DOCKER_PASSWORD","email":"DOCKER_EMAIL","auth":"RE9DS0VSX1VTRVI6RE9DS0VSX1BBU1NXT1JE"}}}
如果需要拉去私有仓库中的Docker镜像的话,需要使用上面的myregistry这个Secret:
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: 192.168.1.100:5000/test:v1
imagePullSecret:
- name: myregistry
imagePullSecret与secret不同,因为Secret可以挂载到Pod中,但是imagePullSecret只能有kubelet访问。
需要拉去私有仓库镜像192.168.1.100:5000/test:v1,就需要针对该私有仓库来创建一个如上的Secret,然后在Pod中指定imagePullSecrets。
除了设置Pod.spec.imagePullSecrets这种方式来获取私有镜像外,还可以通过在ServiceAccount中设置imagePullsecrets,然后就会自动为使用该SA的Pod注入imagePullsecrets信息:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2019-11-08T12:00:04Z"
name: default
namespace: default
resourceVersion: "322"
selfLink: /api/v1/namespaces/default/serviceaccount/default
uid: cc37a719-c4fe-4ebf-92da-e92c3e24d5d0
secrets:
- name: default-token-Stsh4
imagePullSecrets:
- name: myregistry
kubernetes.io/service-account-token
另外一种Secret类型就是kubernetes.io/service-account-token,用于被ServiceAccount引用。ServiceAccount创建时Kubernetes会默认创建对应的Secret、Pod如果使用了ServiceAccount,对应的Secret会自动挂载到Pod的/var/run/secrets/kubernetes.io/serviceaccount/目录中。如下所示随意创建一个 Pod:
$ kubectl run secret-pod3 --image nginx:1.7.9
deployment.apps "secret-pod3" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
secret-pod3-78c8c76db8-7zmqm 1/1 Running 0 13s
...
查看Pod的详细信息:
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-5tsh4
readOnly: true
......
serviceAccount: default
serviceAccountName: default
volumes:
- name: default-token-5tsh4
secret:
defaultMode: 420
secretName: default-token-5tsh4
可以看到默认把名为default(自动创建的)的ServiceAccount对应的Secret对象通过Volume挂载到了容器的/var/run/secrets/kubernetes.io/serviceaccount的目录中。
Secret vs ConfigMap
相同点
- key/value的形式
- 属于某个特定的命名空间
- 可以导出到环境变量
- 可以通过目录/文件形式挂载
- 通过Volume挂载的配置信息均可热更新
不同点
- Secret可以被ServiceAccount关联
- Secret可以寻出docker registry的鉴权信息,用在imagePullSecret参数中,用于拉取私有仓库的镜像
- Secret支持Base64加密
- Secret分为kubernetes.io/service-account-token、kubernetes.io/dockerconfigjson、Opaque三种类型,而ConfigMap不区分类型
同样 Secret 文件大小限制为 1MB(ETCD 的要求);Secret 虽然采用 Base64 编码,但是我们还是可以很方便解码获取到原始信息,所以对于非常重要的数据还是需要慎重考虑,可以考虑使用 Vault 来进行加密管理。
