Secret APIを試してみる

v0.11.0から導入されたSecret APIを試してみます。試したのは15/03/08時点のHEADです。

Secret APIは名前の通りSSHの秘密鍵やパスワードなどの秘密データを保存するためのAPIです。主な目的はPodが秘密データを安全に取得して利用できるようにするためのものです。Pod(Node)にデータを配布する方法は自由にできるようにプラグイン形式になっているようです。現在はetcdに保存して取得するものが実装されています。詳しいことは[ドキュメント](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/design/secrets.md)を読みましょう。導入の経緯はこのあたりです[PR4126](https://github.com/GoogleCloudPlatform/kubernetes/pull/4126), [PR4514](https://github.com/GoogleCloudPlatform/kubernetes/pull/4514)。

### 秘密データを保存する

Secret APIの使い方はまともなドキュメントがまだないですが、一番それらしいのはopenshiftの[example](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/examples/openshift-origin)の中にあります。

フォーマットとしては以下のようにkindに`Secret`を指定してdataに複数の秘密データを入れておきます。dataのvalueには**base64**で入れる必要があります。

```yaml
# secret.yml
apiVersion: v1beta1
kind: Secret
id: kubernetes-secret
data:
  foo: _secret-data-1_
  bar: _secret-data-2_
```

今回はfooのデータとして`foo-secret`、barのデータとして`bar-secret`を入れることにします。

```
$ echo -n foo-secret | base64 --wrap=0
Zm9vLXNlY3JldA==
$ echo -n bar-secret | base64 --wrap=0
YmFyLXNlY3JldA==

$ cat secret.yml
apiVersion: v1beta1
kind: Secret
id: kubernetes-secret
data:
  foo: Zm9vLXNlY3JldA==
  bar: YmFyLXNlY3JldA==
```

あとは`kubectl create`で作成するだけです。

```
$ kubectl create -f secret.yml
kubernetes-secret
```

データはetcdに入っています。もちろん**暗号化はされていません**。

```
 $ etcdctl --no-sync ls --recursive /registry/secrets/
/registry/secrets/default
/registry/secrets/default/kubernetes-secret

$ etcdctl --no-sync get /registry/secrets/default/kubernetes-secret | jq .
{
  "type": "Opaque",
  "data": {
    "foo": "Zm9vLXNlY3JldA==",
    "bar": "YmFyLXNlY3JldA=="
  },
  "namespace": "default",
  "apiVersion": "v1beta1",
  "creationTimestamp": "2015-03-08T08:26:04Z",
  "uid": "c2d4db23-c56c-11e4-8d70-08002763b728",
  "id": "kubernetes-secret",
  "kind": "Secret"
}
```

あとヘルプには出てこないですが実はkubectlからも参照できます。削除も`kubectl delete secrets`で可能です。

```
$ kubectl get secrets
NAME                DATA
kubernetes-secret   2

$ kubectl get secrets kubernetes-secret -o json
{
    "kind": "Secret",
    "id": "kubernetes-secret",
    "uid": "c2d4db23-c56c-11e4-8d70-08002763b728",
    "creationTimestamp": "2015-03-08T08:26:04Z",
    "selfLink": "/api/v1beta1/secrets/kubernetes-secret?namespace=default",
    "resourceVersion": 7621,
    "apiVersion": "v1beta1",
    "namespace": "default",
    "data": {
        "bar": "YmFyLXNlY3JldA==",
        "foo": "Zm9vLXNlY3JldA=="
    },
    "type": "Opaque"
}
```

### Podから参照する

_ちなみに以下の方法では動きませんでした。_

PodからSecretを参照する方法もいくつか用意(プラグイン)するようですが、今あるのはボリュームとしてマウントする方法のみです。

`examples/guestbook/redis-master-controller.json`を少し修正してSecretを使うように書き換えます。ポイントはcontainerからは単にボリュームをマウントするようにするのと、volumesのソースに`secret`を指定することです。

```yaml
# redis.yml
apiVersion: v1beta1
kind: ReplicationController
id: redis-master-controller
desiredState:
  replicas: 1
  replicaSelector:
    name: redis-master
  podTemplate:
    desiredState:
      manifest:
        version: v1beta1
        id: redis-master
        containers:
          - name: redis-master
            image: dockerfile/redis
            ports:
              - containerPort: 6379
            volumeMounts:
              - mountPath: /etc/secret-volume
                name: secret-volume
                readOnly: true
        volumes:
          - name: secret-volume
            source:
              secret:
                target:
                  kind: Secret
                  name: kubernetes-secret
                  namespace: default
    labels:
      name: redis-master
      app: redis
labels:
  name: redis-master
```

```
$ kubectl create -f sample/redis.yml
redis-master-controller

$ kubectl get po
POD                             IP                  CONTAINER(S)        IMAGE(S)            HOST                        LABELS                        STATUS              CREATED
redis-master-controller-i7hvs   10.244.87.6         redis-master        dockerfile/redis    172.17.8.103/172.17.8.103   app=redis,name=redis-master   Running             6 seconds
```

`172.17.8.103`は`node-02`なのでdocker containerに直接アクセスしてマウントされているか確認します。

```
$ ssh node-02 'docker ps'
CONTAINER ID        IMAGE                     COMMAND                CREATED             STATUS              PORTS                              NAMES
b7f255ec5f83        dockerfile/redis:latest   "redis-server /etc/r   48 seconds ago      Up 47 seconds                                          k8s_redis-master.810715e9_redis-master-controller-i7hvs.default.api_6abb1233-c56e-11e4-8d70-08002763b728_1cfff4fb   
3d00a7472b66        kubernetes/pause:go       "/pause"               48 seconds ago      Up 47 seconds                                          k8s_POD.5efe987_redis-master-controller-i7hvs.default.api_6abb1233-c56e-11e4-8d70-08002763b728_709dd17a             
1d0c5a165143        google/cadvisor:0.10.1    "/usr/bin/cadvisor -   2 hours ago         Up 2 hours          8080/tcp, 0.0.0.0:4194->4194/tcp   cadvisor                             

## inspectでマウントされているか確認する
$ ssh node-02 'docker inspect b7f255ec5f83' | jq '.[].Volumes'
{
  "/etc/secret-volume": "/var/lib/kubelet/pods/6abb1233-c56e-11e4-8d70-08002763b728/volumes/kubernetes.io~empty-dir/secret-volume",
  "/dev/termination-log": "/var/lib/kubelet/pods/6abb1233-c56e-11e4-8d70-08002763b728/containers/redis-master/b7f255ec5f83c777472a589b6ff899f91b2210f509bea1eca35cebb82e93ac92",
  "/data": "/var/lib/docker/vfs/dir/e1c55258f2e650ed631801a9ed1161f9065f12ebac726b4349e3894fd33d37bf"
}

## execでマウントの中身を見る
$ ssh node-02 'docker exec b7f255ec5f83 ls -al /etc/secret-volume'
total 8
drwxr-x--- 2 root root 4096 Mar  7 16:10 .
drwxr-xr-x 1 root root 4096 Mar  7 16:10 ..
```

というわけでマウントはできたけど、Secretはうまくとれなかったです。原因までは今回は調べていません。できていればファイルとしてSecretが保存されているので、アプリケーションからはそれを自分で読んで使うというスタイルになります。

自分で消化するのではなく環境変数としてexportする機能も追加される予定です([PR4710](https://github.com/GoogleCloudPlatform/kubernetes/issues/4710))。

**15/03/21追記**

再度最新版で確認したところ無事秘密データがマウントされていました。

```
$ ssh node-01 'docker exec 7d5aa958003f ls -al /etc/secret-volume' 
total 12
drwxrwxrwt 2 root root   80 Mar 21 10:33 .
drwxr-xr-x 1 root root 4096 Mar 21 10:33 ..
-rwxr-xr-x 1 root root   10 Mar 21 10:34 bar
-rwxr-xr-x 1 root root   10 Mar 21 10:34 foo

$ ssh node-01 'docker exec 7d5aa958003f cat /etc/secret-volume/bar'
bar-secret
$ ssh node-01 'docker exec 7d5aa958003f cat /etc/secret-volume/foo'
foo-secret
```