转载

secrets in kubernetes

在kubernetes中,secret对象类型主要目的是 保存一些私密数据,比如密码,OAuth tokens,ssh keys等信息。将这些信息放在secret对象中 比 直接放在pod或docker image中更安全,也更方便使用。

secrets描述

创建secrets对象的方式有两种,一种是用户手动创建,另一种是集群自动创建。

一个已经创建好的secrets对象有两种方式被pod对象使用,其一,在container中的volume对象里以file的形式被使用,其二,在pull images时被kubelet使用。

为了使用secret对象,pod必须‘引用’这个secret,同样可以手动或者自动来执行‘引用’操作。

自动建立ServiceAccount && 使用secret API

kubernetes会自动创建包含证书信息的secret,并且使用它来访问api,kubernetes也将自动修改pod来使用这个secret。

自动创建的secret 以及 所使用的api证书 可以根据需要disable 或者 覆盖。如果仅仅需要 安全访问apiserver,那么上述的流程是推荐的方式。

手动创建secret

以下是一个简单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被创建,可以:

  • 通过ServiceAccount使用它自动创建pod;
  • 修改pod来使用secret;

手动为pod绑定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。

手动指定imagePullSecret

详细信息见: images documentation

Details

限制

在使用之前,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间接创建的。

Consuming Secret Values

在一个绑定了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中的程序可以读取其中的文件来获取其内容。

Secret 与 Pod Lifetime 关系

当通过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。

User Case

Use-Case: Pod with ssh keys

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连接。

Use-Case: Pods with prod / test credentials

下面的例子将会展示 一个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",     }   ] } 
正文到此结束
Loading...