Kubernetes: RBACの設定におけるAPIリソース

Kubernetesの[RBAC(Role-based access control)](http://kubernetes.io/docs/admin/authorization/#rbac-mode)の設定用にAPIリソースについてまとめました。Kubernetes v1.4時点での情報になります。

# KubernetesのAPI

KubernetesのAPIは、**API Resource**と**Non-Resource URL**の2つに分けられます。

## API Resource

Kubernetes上で扱われる情報(Pod, Service等)は`apiserver`上では**API Resource**として定義されています。`kube-scheduler`や`kubelet`、`kubectl`などKubernetesのコンポーネントはこのAPIリソースをHTTPで操作することでPodの配置などの実際の操作を行います。(参考: [Kubernetes: コンテナが起動するまでの各コンポーネントの流れ
](http://qiita.com/tkusumi/items/346d41a6240590b899cd)

パスの形式例([requestinfo.goより](https://github.com/kubernetes/kubernetes/blob/c15758edf8329692291854c68242d15deae59acb/pkg/apiserver/request/requestinfo.go#L79-L96)): 

```
# Resource paths
/apis/{api-group}/{version}/namespaces
/api/{version}/namespaces
/api/{version}/namespaces/{namespace}
/api/{version}/namespaces/{namespace}/{resource}
/api/{version}/namespaces/{namespace}/{resource}/{resourceName}
/api/{version}/{resource}
/api/{version}/{resource}/{resourceName}

# Special verbs without subresources:
/api/{version}/proxy/{resource}/{resourceName}
/api/{version}/proxy/namespaces/{namespace}/{resource}/{resourceName}
/api/{version}/redirect/namespaces/{namespace}/{resource}/{resourceName}
/api/{version}/redirect/{resource}/{resourceName}

# Special verbs with subresources:
/api/{version}/watch/{resource}
/api/{version}/watch/namespaces/{namespace}/{resource}
```

### API Resourceの具体例

例えば`default`ネームスペースに配置された`nginx-526438288-n5fn9`という名前の`pods`リソースのパスは下記のようになります。 

```
/api/v1/namespaces/default/pods/nginx-526438288-n5fn9
```

### サブリソース

いくつかのリソースはサブリソースを持ちます。例えば`pods`リソースは`log`というサブリソースを持つため、上記例のPodのログは下記のようなパスになります。

```
/api/v1/namespaces/default/pods/nginx-526438288-n5fn9/log
```

RBACでは`{Resource}/{SubResource}`という形式でサブリソースを表記します。上記の例では`pods/log`という表記になります。

## Non-Resource URL

バージョン情報やヘルスチェックなどの一部のURLは**Non-Resource URL**として定義されており、リソースとは別に扱われています。

パスの形式例([requestinfo.goより](https://github.com/kubernetes/kubernetes/blob/c15758edf8329692291854c68242d15deae59acb/pkg/apiserver/request/requestinfo.go#L98-L105)):

```
# NonResource paths
/apis/{api-group}/{version}
/apis/{api-group}
/apis
/api/{version}
/api
/healthz
/
```

# RBACでの権限設定

RBACでは**ClusterRole / Role**で権限定義し、**ClusterRoleBinding / RoleBinding**でユーザとの紐付けを行います。なお**ClusterRole**と**Role**の違いはクラスタ全体に対してのロール(ClusterRole)か、ネームスペース内に対してのロール(Role)かの違いになります。

ClusterRoleでは下記のように権限の指定を行います。`rules`で複数のルールを指定し、APIリソースの場合、`verbs`、`apiGroups`, `resources`、Non-Resource URLの場合`verbs`(小文字のHTTPメソッド)、`nonResourceURLs`を指定します。どの項目も複数指定でき、`*`によってワイルドカードを表すことができます。多くの場合はワイルドカードの指定で充分だと思いますが、厳密に権限を管理したい場合にはリソース名を把握しておく必要があります。

```yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
  name: foo # ロールの名前
rules:
  - verbs: ["get", "list", "watch"] # 操作の定義
    apiGroups: [""]  # APIグループの指定(空はcore groupを表す
    resources: ["pods", "pods/exec"]  # リソースの指定
  - verbs: ["*"] # 全てのHTTPメソッドを許可する
    nonResourceURLs: ["/version", "/api", "/api/*", "/apis", "/apis/*"] # Non-Resource URL
  # ruleは複数指定できる
```

サブリソースについて少し注意が必要です。この例では"リソースに`pods`とサブリソースの`pods/exec`を指定しています。しかしログを見るための`pods/log`は指定していないのでPodのログを見る権限はありません。Kubernetes 1.4.4時点では`pods/*`のようにサブリソースにワイルドカードを指定することはできないようです。

ClusterRoleBinding / RoleBindingで下記のように権限をユーザに紐付けます。

```yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
  name: foo
subjects:
  # 複数のユーザを指定できる
  - kind: User  # Userの他にGroup、ServiceAccountが選択できる
    name: alice
  - kind: User
    name: bob
roleRef:
  kind: ClusterRole
  name: foo # 紐付ける対象のロールの名前
```

## 権限のブートストラップ

ClusterRole等RBACのリソース自体もRBACの管理するリソースになります。そのため、現時点ではAPIサーバーの`--authorization-rbac-super-user`オプションでRBACの制限を受けないスーパーユーザーを指定して、そのユーザの権限でRBACの初期設定を行う必要があります。

# 操作(verb)

Kubernetesのリソースへの操作は`verb`という形で表現されています。

## API Resourceへの操作

verb | HTTPメソッド | 備考
--- | --- | ---
`get` | `GET`, `HEAD` | リソースの取得
`list` | `GET` | リソースのリスト取得(`GET`かつリソース名が空のとき)
`create` | `POST` | リソースの作成
`update` | `PUT` | リソースの置き換え(`kubectl replace`等)
`patch` | `PATCH` | リソースの部分更新(`kubectl patch`等)
`delete` | `DELETE` | リソースの削除
`deletecollection` | `DELETE` | リソースの一括削除(`DELETE`かつリソース名が空のとき)
`watch` | | リソースの変更監視
`proxy` | | リソースへのproxy

この内`get`, `list`, `watch`がreadonlyの操作になります(参考: [policy.go](https://github.com/kubernetes/kubernetes/blob/c15758edf8329692291854c68242d15deae59acb/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go#L27))。

HTTPのリクエスト情報からverbへの変換は下記のコードで行われています。

- https://github.com/kubernetes/kubernetes/blob/master/pkg/apiserver/request/requestinfo.go

## Non-Resource URLへの操作

verbはHTTPメソッド(`get`, `post`等)をそのまま小文字にしたものになります。


# API Group

KubernetesのAPIはAPI Groupというグループに分かれて管理されています。また**ThirdPartyResource**という仕組みを使って独自にAPI Group及びリソースを作ることもできます。

グループ | 内容
--- | ---
 | **core group**や**Kubernetes API**と呼ばれる、Kubernetesの基本となるリソース(`Pod`, `Service`等)のグループ。RBACで指定する場合グループ名は空文字列(`""`)を指定する。
`extensions` | 拡張機能に関するグループ。`Deployment`, `Ingress`などが含まれている。
`apps` | ステートフルなアプリケーションを扱うためのグループ。現状は`PetSets`のみ(`StatefulSets`に改名予定)
`authentication.k8s.io` | 認証に関するグループ
`authorization.k8s.io` | 認可に関するグループ
`autoscaling` | オートスケールに関するグループ
`batch` | バッチ処理、ジョブに関するグループ
`certificates.k8s.io` | TLS証明書に関するグループ
`componentconfig` | Kubernetesコンポーネントの設定情報に関するグループ
`imagepolicy.k8s.io` | コンテナイメージのポリシー制御に関するグループ
`rbac.authorization.k8s.io` | RBACに関するグループ
`storage.k8s.io` | ストレージに関するグループ。現状は`StorageClass`のみ


core groupを除くAPI Groupは下記のように`/apis`で始まるリソースパスになります。

```
/apis/{api-group}/{version}/
```

例えば`extensions`グループに含まれる、`default`ネームスペースに配置された`nginx`という名前の`deployemnts`リソースのパスは下記のようになります。

```
/apis/extensions/v1beta1/namespaces/default/deployments/nginx
```


なお有効なAPI Groupの一覧はAPIサーバーから下記の様に取得できます。一覧を返す`/apis`はNon-Resource URLになります。

```
curl http://localhost:8080/apis | jq -r '.groups[].name'
```

## ThirdPartyResource

**ThirdPartyResource**というリソースを使うと独自にAPI Groupとリソースの定義を行うことができます。これによりKubernetesのリソースの仕組みをフレームワークのように扱うことができます。[CoreOSのOperators](https://coreos.com/blog/introducing-operators.html)などThirdPartyResourceの活用も進んできています。

設定例:

```yaml
kind: ThirdPartyResource
apiVersion: extensions/v1beta1 # ThirdPartyResource自体のAPIバージョン
metadata:
  name: awesome-resource.tpr.example.com
versions:
- name: v1
```

ThirdPatyResourceを上記のように定義した場合、metadata.nameの`awesome-resource.tpr.example.com`の内、`tpr.example.com`がAPI Groupになり、`awesome-resource`が`AwesomeResource`と変換されリソースのKindになります。(リソース名は`awesomeresources`)

定義したThirdPartyResourceはスキーマが無く自由にリソースの中身を定義できます。

```yaml
kind: AwesomeResource
apiVersion: tpr.example.com/v1
metadata:
  name: foo
# データは好きに定義できる
mydata:
  hello: world
```

このリソースを`default`ネームスペースに定義した場合、リソースのパスは以下のようになります。

```
/apis/tpr.example.com/v1/namespaces/default/awesomeresources/foo
```

ThirdPartyResourceも通常のAPIリソースと同様にRBACの権限の対象となり、下記のようにロールを設定することができます。ThirdPartyResource自体は`extensions`グループに属していますが、ここではThirdPartyResourceのmetadata.nameで定義した独自のAPIグループを使います。

```
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
  name: awesomerole
rules:
  - verbs: ["*"]
    apiGroups: ["tpr.example.com"] # 独自のAPIグループ
    resources: ["awesomeresources"]
```

ThirdPartyResourceについては下記のデザインドキュメントが参考になります。

- https://github.com/kubernetes/kubernetes/blob/master/docs/design/extending-api.md


# リソースの一覧

## Core Group

Kubernetesの基本的なリソースが含まれているグループです。Kubernetesのソースコード上の扱いもCore Groupのみが、[pkg/api](https://github.com/kubernetes/kubernetes/tree/master/pkg/api)以下で扱われており、それ以外は[pkg/apis](https://github.com/kubernetes/kubernetes/tree/master/pkg/apis)で扱われています。

core groupの場合は下記のように`/api`で始まるリソースパスになります。

```
/api/{version}
```

リソースの一覧

```
bindings
componentstatuses
configmaps
endpoints
events
limitranges
namespaces
namespaces/finalize
namespaces/status
nodes
nodes/proxy
nodes/status
persistentvolumeclaims
persistentvolumeclaims/status
persistentvolumes
persistentvolumes/status
pods
pods/attach
pods/binding
pods/eviction
pods/exec
pods/log
pods/portforward
pods/proxy
pods/status
podtemplates
replicationcontrollers
replicationcontrollers/scale
replicationcontrollers/status
resourcequotas
resourcequotas/status
secrets
serviceaccounts
services
services/proxy
services/status
```

なお、リソースの一覧はAPIサーバーから下記の様に取得できます。

```
kubectl get --raw /api/v1/ | jq -r .resources[].name
```

各リソースの詳細はマニュアルにまとまっています。

- [Kubernetes API Operations](http://kubernetes.io/docs/api-reference/v1/operations/)
- [Kubernetes API Definitions](http://kubernetes.io/docs/api-reference/v1/definitions/)

## extensions

```
daemonsets
daemonsets/status
deployments
deployments/rollback
deployments/scale
deployments/status
horizontalpodautoscalers
horizontalpodautoscalers/status
ingresses
ingresses/status
jobs
jobs/status
networkpolicies
replicasets
replicasets/scale
replicasets/status
replicationcontrollers
replicationcontrollers/scale
thirdpartyresources
```

各リソースの詳細はマニュアルにまとまっています。

- [Extensions API Operations](http://kubernetes.io/docs/api-reference/extensions/v1beta1/operations/)
- [Extensions API Definitions](http://kubernetes.io/docs/api-reference/extensions/v1beta1/definitions/)

## apps

```
petsets
petsets/status
```

## authentication.k8s.io

```
tokenreviews
```

## authorization.k8s.io

```
subjectaccessreviews
```

## autoscaling

```
horizontalpodautoscalers
horizontalpodautoscalers/status
```

各リソースの詳細はマニュアルにまとまっています。


- [Autoscaling API Operations](http://kubernetes.io/docs/api-reference/autoscaling/v1/operations/)
- [Autoscaling API Definitions](http://kubernetes.io/docs/api-reference/autoscaling/v1/definitions/)

## batch

```
jobs
jobs/status
scheduledjobs
scheduledjobs/status
```

各リソースの詳細はマニュアルにまとまっています。(v1のjobsのみ)

- [Batch API Operations](http://kubernetes.io/docs/api-reference/batch/v1/operations/)
- [Batch API Definitions](http://kubernetes.io/docs/api-reference/batch/v1/definitions/)

## certificates.k8s.io

```
certificatesigningrequests
certificatesigningrequests/approval
certificatesigningrequests/status
```

## rbac.authorization.k8s.io

```
clusterrolebindings
clusterroles
rolebindings
roles
```

## storage.k8s.io

```
storageclasses
```