# Role 和 RoleBinding

`Role` 和 `RoleBinding` 资源都是命名空间中的资源。前者决定可以针对哪些 URL 路径执行哪些操作；后者将前者与用户主体绑定（当然后者也可以与 `ClusterRole` 进行绑定，虽然这样还是只能操作 `RoleBinding` 所在命名空间的 URL 路径）。

## 创建 Role

`Role` 是 Kubernetes 中的一种资源，因此可以通过 YAML 定义来生成。如下，在 `foo` 命名空间中创建一个名为 `service-reader` 的 Role 对象，该角色规定能够对 `services/test-service` 资源对象执行 `get` 和 `list` 操作：

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role    # 类型为 Role
metadata:
  namespace: foo    # 所在命名空间名
  name: service-reader
rules:    # 重点！定义了能够对哪些 URL 路径执行哪些操作
- apiGroups: [""]    # 由于 services.apiGroup=v1，即没有 "/"，"/" 前面是资源所属的组，所以 services 不属于任何组，所以这里为空
  verbs: ["get", "list"]    # 能够执行 get 和 list 操作
  resources: ["services"]    # 针对 Service 资源
  resourceNames: ["test-service"] # 针对 Service 资源中的名为 test-service 的对象；若这里省略，则表示针对所有 Service 资源
```

当然也可以使用 `kubectl create role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run] [options]` 命令来创建该资源：

```bash
kubectl create role service-reader --verb=get,list --resource=services --resource-name=test-service -n foo
```

## 创建 RoleBinding

在创建完 `Role` 之后，需要创建 `RoleBinding` 来将 **用户主体** 与 `Role` 绑定，从而限制用户主体可以对哪些 URL 路径执行哪些操作。

创建 `RoleBinding` 同样可以使用 YAML 定义来生成。如下，在 `foo` 命名空间中创建一个名为 `test` 的 RoleBinding 对象，其与名为 `service-reader` 的 Role 对象绑定，并与 `foo` 命名空间中名为 `default` 的 ServiceAccount 以及 `bar` 命名空间中名为 `default` 的 ServiceAccount 绑定：

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding    # 类型为 RoleBinding
metadata:
  name: test
  namespace: foo    # 所在命名空间名
roleRef:    # 绑定的 Role（也支持绑定 ClusterRole 资源）
  apiGroup: rbac.authorization.k8s.io    # Role 资源所属的 API 组
  kind: Role    # 类型为 Role
  name: service-reader    # Role 的名字
subjects:    # 绑定的用户主体（可以是 用户名、ServiceAccount、组）
- kind: ServiceAccount    # 绑定的用户主体类型为 ServiceAccount
  name: default    # ServiceAccount 名
  namespace: foo    # 用户主体所属的 命名空间
- kind: ServiceAccount
  name: default
  namespace: bar
```

当然也可以使用 `kubectl create rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run] [options]` 命令来创建该资源：

```bash
kubectl create rolebinding test --role=service-reader --serviceaccount=foo:default --serviceaccount=bar:default -n foo
```

## 测试

根据上述的创建命令创建完后，会得到下面的关系图，由于 ServiceAccount 均为各自命名空间中的默认 ServiceAccount，因此若 Pod 的 `pod.spec.serviceAccountName` 没有指定的话，则默认使用其所在命名空间的 `default` ServiceAccount。

![部署结果关系图](https://2906552408-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6Ub8CloS5kJszh6xSR%2Fsync%2F19ef454e7e8aa558226d7b83722a37183f778fc3.png?generation=1588594619986864\&alt=media)

在命名空间 `foo` 和 `bar` 中分别生成一个 Pod，均使用各自命名空间中的默认 ServiceAccount，那么正常情况下，这两个 Pod 将均能通过 API 服务器获得命名空间 `foo` 中的名为 `test-service` 的 Service 对象信息。在 Pod 中的测试命令如下（Pod 使用的是 luksa/kubectl-proxy 镜像，内部安装了 kubectl 组件）：

```bash
curl localhost:8001/api/v1/namespaces/foo/services/test-service
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "services \"test-service\" not found",
  "reason": "NotFound",
  "details": {
    "name": "test-service",
    "kind": "services"
  },
  "code": 404
}
```

> 从输出结果可以看出，提示的不是没有权限，而是 404 资源不存在，这是因为集群中并没有 `test-service` 这个资源对象，所以授权是成功的
