在kubernetes中,secret对象类型主要目的是 保存一些私密数据,比如密码,OAuth tokens,ssh keys等信息。将这些信息放在secret对象中 比 直接放在pod或docker image中更安全,也更方便使用。
创建secrets对象的方式有两种,一种是用户手动创建,另一种是集群自动创建。
一个已经创建好的secrets对象有两种方式被pod对象使用,其一,在container中的volume对象里以file的形式被使用,其二,在pull images时被kubelet使用。
为了使用secret对象,pod必须‘引用’这个secret,同样可以手动或者自动来执行‘引用’操作。
kubernetes会自动创建包含证书信息的secret,并且使用它来访问api,kubernetes也将自动修改pod来使用这个secret。
自动创建的secret 以及 所使用的api证书 可以根据需要disable 或者 覆盖。如果仅仅需要 安全访问apiserver,那么上述的流程是推荐的方式。
以下是一个简单secret对象的例子:
apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: password: dmFsdWUtMg0K username: dmFsdWUtMQ0K
数据中的字段为map类型。其中keys必须符合dns_subdomain规则,values可以为任意类型,使用base64编码。上述例子中,username和password的数据值在base64编码前的值为value-1 和 value-2。
一旦secret被创建,可以:
以下是一个例子,绑定secret到一个pod的volume:
{ "apiVersion": "v1", "kind": "Pod", "metadata": { "name": "mypod", "namespace": "myns" }, "spec": { "containers": [{ "name": "mypod", "image": "redis", "volumeMounts": [{ "name": "foo", "mountPath": "/etc/foo", "readOnly": true }] }], "volumes": [{ "name": "foo", "secret": { "secretName": "mysecret" } }] } }
注意,必须有spec.volumes才能使用secret。如果一个pod中有多个container,每个container需要他们单独对应的volumeMounts ,但是一个secret只能对应一个spec.volumes。
只要需要,可以将许多文件打包进一个secret,或者使用多个secret。
详细信息见: images documentation
在使用之前,secret volume 资源被验证,以确保指定的对象引用真是指向一个secret对象。因此,在pod使用它之前必须保证需要的secret被成功创建。
secret api对象从属于namespace,一个secret对象只能被同namespace的pod所使用。
单个secret限制在1Mb之内,防止过大的secret耗尽apiserver & kubelet的内存。然而,创建许多类似的secret同样也会无用的消耗掉apiserver&kubelet的内存。
kubelet目前只支持pod使用来自于apiserver的secret。pods包括了被 kubectl创建的pod 或者 被replication controller间接创建的。
在一个绑定了secret的container中,会以secret keys为名的文件,其内容为secret value的base64 decode后的内容。下面是上述例子的输出:
$ ls /etc/foo/ username password $ cat /etc/foo/username value-1 $ cat /etc/foo/password value-2
container中的程序可以读取其中的文件来获取其内容。
当通过api创建一个pod后,不会去检查所引用的secret是否存在。一旦这个pod被使用,kubelet将会尝试去获取引用的secret的值。如果这个secret不存在,或者kubelet暂时链接不上apiserver,kubelet将会定期重试,并发送一个event来解释pod没有启动的原因。如果获取到了对应的secret,kubelet将会创建对应的volume并绑定到container。
一旦kubelet创建了一个pod,则container使用的相关secret volume不会在改变,即使对应的secret对象被修改。如果为了改变使用的secret,则必须删除旧的pod,并重新创建一个新的pod。
pod通过secret来使用ssh-key,首先得先创建对应的secret:
{ "kind": "Secret", "apiVersion": "v1", "metadata": { "name": "ssh-key-secret" }, "data": { "id-rsa": "dmFsdWUtMg0KDQo=", "id-rsa.pub": "dmFsdWUtMQ0K" } }
Note:其中secret的data数据经过base64编码,不包含换行符。
现在我们能创建使用这个secret的pod:
{ "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" } ] } ] } }
当这个pod中的container运行后,将会有如下两个文件及对应的内容:
/etc/secret-volume/id-rsa.pub /etc/secret-volume/id-rsa
现在container可以用这个secret数据来建立ssh连接。
下面的例子将会展示 一个pod使用包含prod环境证书的secret对象,另一个pod使用包含test环境证书的secret对象:
secret对象:
{ "apiVersion": "v1", "kind": "List", "items": [{ "kind": "Secret", "apiVersion": "v1", "metadata": { "name": "prod-db-secret" }, "data": { "password": "dmFsdWUtMg0KDQo=", "username": "dmFsdWUtMQ0K" } }, { "kind": "Secret", "apiVersion": "v1", "metadata": { "name": "test-db-secret" }, "data": { "password": "dmFsdWUtMg0KDQo=", "username": "dmFsdWUtMQ0K" } }] }
建立pods:
{ "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" } ] } ] } }] }
建立的两个pod都拥有两个文件:
/etc/secret-volume/username /etc/secret-volume/password
可以使用service accounts来简化上述的流程,一个是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", } ] }