在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",
    }
  ]
}

刘阳龙Herman
672 声望106 粉丝

Herman.Liu.1988.avi