SPIREのk8s pluginについて


昨日はSPIFFEとその参照実装であるSPIREについてのエントリを書きましたが、本日はSPIREのワークロードとしてKubernetesのPodを対象とする場合に利用するKubernetesのworkload attestor pluginの動きを説明します。

### Kubernetes workload attestor plugin とは

SPIRE-Agentのworkload attestorのプラグインとして動作します。
Worload AttestorとはWorkload APIの呼び出し元の情報からSelector情報を生成するコンポーネントでした。

Kubernetes pluginの場合には呼び出し元Workloadのpidからそのpidで動作するPodのNamespaceとServiceAccountの情報を収集します。つまり、呼び出し元のワークロードが動作するPodに紐づくNamespaceとServiceAccount情報を収集します。

### How to work this plugin?

```
/proc/${PID}/cgroup
```

KubernetesのPodを動しているpidの場合、上記ファイルを開くとこのような情報が確認できます。このプラグインはkubepodsのエントリのContainerID(一番後ろの要素)を抜き出します。(ContainerIDは全部同じ)

```
11:memory:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
10:freezer:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
9:perf_event:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
8:devices:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
7:pids:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
6:cpu,cpuacct:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
5:net_cls,net_prio:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
4:hugetlb:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
3:blkio:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
2:cpuset:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
1:name=systemd:/kubepods/besteffort/pod2ece296c-c5ec-11e7-858e-fa163e451acc/bc1eb339399eae78dd1115c765fda84b71ac6a954291b223820cfe775d8af778
```

また、kubeletのReadOnlyポートにアクセスし、自身の上で動作するPod情報の一覧をPod情報を取得します。

```
http://localhost:${KUBELET_READONLY_PORT}/pods
```

<https://kubernetes.io/docs/api-reference/v1.8/#podlist-v1-core>

アクセスすると上記URLにて定義されている情報が返ってきます。

Kuberentes Pluginにおいて必要な情報は各レコードの３つの情報です。

-   `.metadata.namespace`
-   `.spec.serviceaccount`
-   `.status.containerStatuses[*].containerID` (e.g., docker://<ID>')

プラグインはcgroupの情報から取得したContainerIDと上記Kubeletから取得したContainer情報が一致するPod情報を探します。ちなみに、Podの情報に含まれるContainerIDは `docker://...` のような文字列になっているのでURL構造と見立てた場合のホスト部とcgroupのContainerIDを比較します。

そうして、一致したPod情報に含まれるServiceAccountとNamespaceの情報をSelectorとして返却するわけです。

```go
[]*Selector{
  &Selector{
    Type:  "k8s",
    Value: "k8s:ns:${Namespace}"
  },
  &Selector{
    Type:  "k8s",
    Value: "k8s:sa:${ServiceAccount}"
  },
  ...
}
```

最後にこれを受け取ったWorkload AttestorはSPIRE-Server側にこのワークロードが対象として登録済みかどうかを確かめるために、Serverから取得した自身の上で動作可能なSelector情報と、Workload Atterstorによって生成されたSelector情報を比較します。

一致するものがあれば許可されたWorkloadであると判断しSVIDを渡します。


### おわりに

このようにKubernetesのPodもSPIREのワークロードとして動作させることが可能であり、PodとKubernetesクラスタ外のアプリケーションを相互認証させることができます。

自分は今後も継続してSPIFFE/SPIREの動向をウォッチしていこうと思っています。また何かあれば何らかの形でフィードバックしたいと思います。