前面我们讲了ConfigMap的使用,我们说ConfigMap这个资源对象是Kubernetes当中非常重要的一个对象,一般情况下ConfigMap是用来存储一些非安全的配置信息,如果涉及到一些安全相关的数据的话用ConfigMap就非常不妥了,因为ConfigMap是明文存储的,我们说这个时候我们就需要用到另外一个资源对象了:Secret,Secret用来保存敏感信息,例如密码、OAuth 令牌和 ssh key等等,将这些信息放在Secret中比放在Pod的定义中或者docker镜像中来说更加安全和灵活。
Secret有四种TYPE(类型):
generic :base64编码格式的Secret,用来存储密码、密钥、信息、证书等,类型标识符为Opaque
;
docker-registry :用来存储私有docker registry的认证信息,类型标识为kubernetes.io/dockerconfigjson
。
tls:用于为SSL通信模式存储证书和私钥文件,命令式创建类型标识为kubernetes.io/tls
。
kubernetes.io/service-account-token:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/var/run/secrets/kubernetes.io/serviceaccount
目录中;
Opaque:
Opaque 类型的数据是一个 map 类型,要求value是base64编码格式,比如我们来创建一个用户名为 admin,密码为 admin321 的 Secret 对象,首先我们先把这用户名和密码做 base64 编码,
1 2 3 4 $ echo -n "admin" | base64 YWRtaW4=$ echo -n "admin321" | base64 YWRtaW4zMjE=
然后我们就可以利用上面编码过后的数据来编写一个YAML文件:(secret-demo.yaml)
1 2 3 4 5 6 7 8 apiVersion: v1kind: Secretmetadata: name: mysecrettype: Opaquedata: username: YWRtaW4= password: YWRtaW4zMjE=
然后同样的我们就可以使用kubectl命令来创建了:
1 2 $ kubectl create -f secret-demo .yaml secret "mysecret" created
利用get secret命令查看:
1 2 3 4 5 6 7 $ kubectl get secretNAME TYPE DATA AGEdefault -token-zmv4x kubernetes.io/service-account-token 3 40 h mysecret Opaque 2 45 m 其中default -token-zmv4x为创建集群时默认创建的secret,被serviceacount/default 引用。
使用describe命令,查看详情:
1 2 3 4 5 6 7 8 9 10 11 12 $ kubectl describe secret mysecret Name: mysecret Namespace: default Labels: <none> Annotations: <none> Type: OpaqueData ==== password: 8 bytes username: 5 bytes
我们可以看到利用describe命令查看到的Data没有直接显示出来,如果想看到Data里面的详细信息,同样我们可以输出成YAML文件进行查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ kubectl get secret mysecret -o yamlapiVersion: v1data: password: YWRtaW4zMjE= username: YWRtaW4=kind: Secretmetadata: creationTimestamp: 2018 -06 -19 T15:27 :06 Z name: mysecret namespace: default resourceVersion: "3694084" selfLink: /api/ v1/namespaces/ default/secrets/ mysecret uid: 39 c139f5-73 d5-11e8 -a101-525400 db4df7type: Opaque
Opaque类型也可以存放证书类型。
1 [root@k8s-m1 certs]# kubectl create secret generic kubernetes-dashboard-certs --from -file =./dashboard.crt --from -file =dashboard.key =./dashboard.key -n kube-system
1 2 3 [root@k8s-m1 certs]# kubectl get secrets kubernetes-dashboard-certs -n kube-system NAME TYPE DATA AGE kubernetes-dashboard-certs Opaque 2 7 m34s
1 2 3 4 5 6 7 8 9 10 11 [root@k8s-m1 certs ]Name: kubernetes-dashboard-certs Namespace: kube-system Labels: k8s-app=kubernetes-dashboard Annotations: Type: Opaque Data ==== dashboard.key: 1704 bytes dashboard.crt: 1005 bytes
kubernetes.io/dockerconfigjson 除了上面的Opaque这种类型外,我们还可以来创建用户docker registry认证的Secret,直接使用kubectl create命令创建即可,如下:
1 2 $ kubectl create secret docker-registry myregistry --docker-server =DOCKER_SERVER --docker-username =DOCKER_USER --docker-password =DOCKER_PASSWORD --docker-email =DOCKER_EMAILsecret "myregistry" created
然后查看Secret列表:
1 2 3 4 5 $ kubectl get secretNAME TYPE DATA AGEdefault -token-n9w2d kubernetes.io/service-account-token 3 33 d myregistry kubernetes.io/dockerconfigjson 1 15 s mysecret Opaque 2 34 m
注意看上面的TYPE类型,myregistry是不是对应的kubernetes.io/dockerconfigjson,同样的可以使用describe命令来查看详细信息:
1 2 3 4 5 6 7 8 9 10 11 $ kubectl describe secret myregistry Name: myregistry Namespace: default Labels: <none> Annotations: <none> Type: kubernetes.io/dockerconfigjsonData ==== .dockerconfigjson: 152 bytes
同样的可以看到Data区域没有直接展示出来,如果想查看的话可以使用-o yaml来输出展示出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 $ kubectl get secret myregistry -o yamlapiVersion: v1data: .dockerconfigjson: eyJhdXRocyI6eyJET0NLRVJfU0VSVkVSIjp7InVzZXJuYW1lIjoiRE9DS0VSX1VTRVIiLCJwYXNzd29yZCI6IkRPQ0tFUl9QQVNTV09SRCIsImVtYWlsIjoiRE9DS0VSX0VNQUlMIiwiYXV0aCI6IlJFOURTMFZTWDFWVFJWSTZSRTlEUzBWU1gxQkJVMU5YVDFKRSJ9fX0=kind: Secretmetadata: creationTimestamp: 2018 -06 -19 T16:01 :05 Z name: myregistry namespace: default resourceVersion: "3696966" selfLink: /api/ v1/namespaces/ default/secrets/ myregistry uid: f91db707-73 d9-11e8 -a101-525400 db4df7type: kubernetes.io/dockerconfigjson
可以把上面的data.dockerconfigjson下面的数据做一个base64解码,看看里面的数据是怎样的呢?
1 2 $ echo eyJhdXRocyI6 eyJET0 NLRVJfU0 VSVkVSIjp7 InVzZXJuYW1 lIjoiRE9 DS0 VSX1 VTRVIiLCJwYXNzd29 yZCI6 IkRPQ0 tFUl9 QQVNTV09 SRCIsImVtYWlsIjoiRE9 DS0 VSX0 VNQUlMIiwiYXV0 aCI6 IlJFOURTMFZTWDFWVFJWSTZSRTlEUzBWU1 gxQkJVMU5 YVDFKRSJ9 fX0 = | base64 -d {"auths" :{"DOCKER_SERVER" :{"username" :"DOCKER_USER" ,"password" :"DOCKER_PASSWORD" ,"email" :"DOCKER_EMAIL" ,"auth" :"RE9DS0VSX1VTRVI6RE9DS0VSX1BBU1NXT1JE" }}}
如果我们需要拉取私有仓库中的docker镜像的话就需要使用到上面的myregistry这个Secret:
1 2 3 4 5 6 7 8 9 10 apiVersion : v1 kind : Pod metadata : name : foo spec : containers : - name: foo image : 192.168.1.100:5000/test:v1 imagePullSecrets : - name: myregistry
我们需要拉取私有仓库镜像192.168.1.100:5000/test:v1,我们就需要针对该私有仓库来创建一个如上的Secret,然后在Pod的 YAML 文件中指定imagePullSecrets,我们会在后面的私有仓库搭建的课程中跟大家详细说明的。
kubernetes.io/tls kubernetes.io/tls
用于为SSL通信模式存储证书和私钥文件,一般用于构建TLS站点。
1 2 3 4 5 [root@k8s-m1 ye ]# openssl genrsa -out tls.key 2048 Generating RSA private key, 2048 bit long modulus .........................................................+++ .......................................+++ e is 65537 (0x10001 )
1 [root@k8s-m1 ye]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ ST=Beijing/L=Beijing/ O=DevOps/CN=demo.tomcat.com
1 2 [root@k8s-m1 ye]# kubectl create secret tls tomcat-secret --cert =tls.crt --key =tls.key secret/tomcat-secret created
1 2 3 4 [root@k8s-m1 ye]# kubectl get secretNAME TYPE DATA AGEdefault -token-pkx6j kubernetes.io/service-account-token 3 120 d tomcat-secret kubernetes.io/tls 2 34 s
kubernetes.io/service-account-token 有些情况下,我们希望在 pod 内部访问 apiserver,获取集群的信息,甚至对集群进行改动。针对这种情况,kubernetes 提供了一种特殊的认证方式:Service Account。 Service Account 是面向 namespace 的,每个 namespace 创建的时候,kubernetes 会自动在这个 namespace 下面创建一个默认的 Service Account;并且这个 Service Account 只能访问该 namespace 的资源。Service Account 和 pod、service、deployment 一样是kubernetes 集群中的一种资源,用户也可以创建自己的 serviceaccount。
ServiceAccount 主要包含了三个内容:namespace、Token 和 CA。namespace 指定了 pod 所在的 namespace,CA 用于验证 apiserver 的证书,token 用作身份验证。它们都通过mount 的方式挂载到 pod 中,其中 token 保存的路径是 /var/run/secrets/kubernetes.io/serviceaccount/token ,是 kube-controller-manager 通过–service-account-private-key-file私钥签发的token; CA 保存的路径是 /var/run/secrets/kubernetes.io/serviceaccount/ca.crt ,namespace 保存的路径是 /var/run/secrets/kubernetes.io/serviceaccount/namespace 。
如果 token 能够通过认证,那么请求的用户名将被设置为 system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT) ,而请求的组名有两个: system:serviceaccounts 和 system:serviceaccounts:(NAMESPACE)。
API Server的service account验证过程 以kube-system namespace下的“default” service account为例,Pod的usrname全称为:system:serviceaccount:kube-system:default。有了username,那么credentials呢?就是上面提到的service-account-token中的token。API Server的验证环节支持多种身份校验方式:CA 证书认证、Token 认证、Base 认证。一旦API Server发现client发起的request使用的是service account token的方式,API Server就会自动采用signed bearer token方式进行身份校验。而request就会使用携带的service account token参与验证。该token是API Server在创建service account时用API server启动参数:–service-account-key-file=/etc/kubernetes/pki/sa.pub的值签署(sign)生成的。如果–service-account-key-file=未传入任何值,那么将默认使用–tls-private-key-file的值,即API Server的私钥。
这里我们使用一个nginx镜像来验证一下,大家想一想为什么不是呀busybox镜像来验证?当然也是可以的,但是我们就不能在command里面来验证了,因为token是需要Pod运行起来过后才会被挂载上去的,直接在command命令中去查看肯定是还没有 token 文件的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ 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 ...$ kubectl exec secret-pod3-78c8c76db8-7zmqm ls /run/secrets/kubernetes.io/serviceaccount ca.crt namespace token$ kubectl exec secret-pod3-78c8c76db8-7zmqm cat /run/secrets/kubernetes.io/serviceaccount/token eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tbjl3MmQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjMzY2FkOWQxLTU5MmYtMTFlOC1hMTAxLTUyNTQwMGRiNGRmNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.0FpzPD8WO_fwnMjwpGIOphdVu4K9wUINwpXpBOJAQ-Tawd0RTbAUHcgYy3sEHSk9uvgnl1FJRQpbQN3yVR_DWSIlAtbmd4dIPxK4O7ZVdd4UnmC467cNXEBqL1sDWLfS5f03d7D1dw1ljFJ_pJw2P65Fjd13reKJvvTQnpu5U0SDcfxj675-Z3z-iOO3XSalZmkFIw2MfYMzf_WpxW0yMFCVkUZ8tBSTegA9-NJZededceA_VCOdKcUjDPrDo-CNti3wZqax5WPw95Ou8RJDMAIS5EcVym7M2_zjGiqHEL3VTvcwXbdFKxsNX-1VW6nr_KKuMGKOyx-5vgxebl71QQ
创建好Secret对象后,有两种方式来使用它:
环境变量 首先我们来测试下环境变量的方式,同样的,我们来使用一个简单的busybox镜像来测试下:(secret1-pod.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: v1kind: Podmetadata: name: secret1-podspec: 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:
1 2 $ kubectl create -f secret1-pod .yaml pod "secret1-pod" created
然后我们查看Pod的日志输出:
1 2 3 4 5 $ kubectl logs secret1-pod... USERNAME=admin PASSWORD=admin321...
可以看到有 USERNAME 和 PASSWORD 两个环境变量输出出来。
Volume 挂载 同样的我们用一个Pod来验证下Volume挂载,创建一个Pod文件:(secret2-pod.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: v1kind: Podmetadata: name: secret2-podspec: containers: - name: secret2 image: busybox command: ["/bin/sh" , "-c" , "ls /etc/secrets" ] volumeMounts: - name: secrets mountPath: /etc/ secrets volumes: - name: secrets secret: secretName: mysecret
创建Pod:
1 2 $ kubectl create -f secret-pod2 .yaml pod "secret2-pod" created
然后我们查看输出日志:
1 2 3 $ kubectl logs secret2-pod password username
可以看到secret把两个key挂载成了两个对应的文件。当然如果想要挂载到指定的文件上面,是不是也可以使用上一节课的方法:在secretName下面添加items指定 key 和 path,这个大家可以参考上节课ConfigMap中的方法去测试下。
Secret 与 ConfigMap 对比 最后我们来对比下Secret和ConfigMap这两种资源对象的异同点:
相同点:
key/value 的形式
属于某个特定的namespace
可以导出到环境变量
可以通过目录/文件形式挂载
通过volume挂载的配置信息均可热更新
不同点:
Secret 可以被ServerAccount关联
Secret 可以存储docker register的鉴权信息,用在ImagePullSecret 参数中,用于拉取私有仓库的镜像
Secret 支持Base64加密
Secret 分为 kubernetes.io/service-account-token、kubernetes.io/dockerconfigjson、Opaque 、kubernetes.io/tls 四种类型,而Configmap不区分类型