Kubernetes中提供了良好的多租户认证管理机制,如RBAC、ServiceAccount还有各种Policy等。

3.8.1 ServiceAccount

ServiceAccount为Pod中的进程提供身份信息。

使用默认的Service Account访问API Server
当创建Pod时,如果没有指定一个service account,系统会自动在与该Pod相同的namespace下为其指派一个default service account。

Service Account是否能够取得访问API的许可取决于您使用的授权插件和策略。

可以选择取消为Service Account自动挂载API凭证,只需在service account中设置automountServiceAccountToken: false。

  1. apiVersion: apps/v1
  2. kind: ServiceAccount
  3. metadata:
  4. name: build-robot
  5. automountServiceAccountToken: false

也可以取消单个Pod的API凭证自动挂载:

apiVersion: apps/v1
kind: Pod
metadata:
  name: my-pod
spec:
  serviceAccountName: build-robot
  automountServiceAccountToken: false

如果在 pod 和 service account 中同时设置了 automountServiceAccountToken , pod 设置中的优先级更高。

使用多个Service Account
每个namespace中都一个默认的叫做default的service account资源。
列出namespace下所有的ServiceAccount资源:

kubectl get serviceaccount

设置非默认的Service Account,只需要在pod的spec.serviceAccountName 字段中将name设置为您想要用的servie account名字即可。

在Pod创建之初service account就必须已经存在,否则创建将被拒绝。

您不能更新已创建的Pod的Service Account。但可以删除它。

kubectl delete serviceaccount/build-robot

为service account添加ImagePullSecret

先创建一个ImagePullSecret:

kubectl get secrets myregistrykey

修改namespace中的默认service account使用该secret作为imagepullsecret:

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'

3.8.2 RBAC-基于角色的访问控制

基于角色的访问控制使用“rbac.authorization.k8s.io” API Group实现授权决策。

Role与ClusterRole
在RBAC API中,一个角色包含了一套表示一组权限的规则。
权限以纯粹的累加方式进行累积。
角色可以由命名空间内的Role对象定义,整个Kubernetes集群范围内有效的角色则通过ClusterRole对象实现。

一个Role对象只能用于授予对某一单一命名空间中资源的访问权限。
如下示例描述了“default”命名空间中的一个Role对象的定义,用于授予对Pod的读访问权限:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]  #空字符串,表明使用core API group
  resources: ["pods"]
  verbs: ["get","watch","list"]

ClusteRole 对象可以授予与Role对象相同的权限,但由于它们属于集群范围对象,也可以使用它们授予对以下几种资源的访问权限:

  • 集群范围资源(例如:节点,即node)
  • 非资源类型endpoint(例如:“/healthz”)
  • 跨所有命名空间的命名空间范围资源(例如Pod,运行命令kubectl get pods —all-namespaces来查询集群中所有的Pod)

如下示例中的ClusterRole定义用于授予用户对某一特定命名空间,或者所有命名空间中的secret的读访问权限:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  #鉴于ClusterRole是集群范围对象,所以这里不需要定义namespace字段
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get","watch","list"]

RoleBinding与ClusterRoleBinding
角色绑定将一个角色中定义的权限授予一个或一组用户。
角色绑定包含了一组相关主体(即subject,包括用户—User、用户组—Group、或者服务账户—Service Account)以及被授予角色的引用。

在命名空间中可以通过RoleBinding对象授予权限,而集群范围内的权限通过ClusterRoleBinding对象来完成。

RoleBinding可以引用在同一命名空间内定义的Role对象。

如下示例中定义的RoleBinding对象在default命名空间中将“pod-reader”角色授予用户“jane”。这一授权允许用户“jane”从default命名空间中读取Pod。

以下角色绑定定义将允许用户“jane”从default命名空间中读取Pod。

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

RoleBinding对象也可以引用一个ClusterRole对象用于在RoleBinding所在的命名空间内授予用户对所引用的ClusterRole中定义的命名空间资源的访问权限。
这一点允许管理员在整个集群范围内首先定义一组通用的角色,然后再在不同的命名空间中复用这些角色。

例如:尽管示例中的RoleBinding引用的是一个ClusterRole对象,但用户Dave(即角色绑定主体)还是只能读取“development”命名空间中的secret(即RoleBinding所在的命名空间)。

#以下角色绑定允许用户“Dave”读取“development”命名空间中的secret
kind: RoleBinding
apiVerion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-secrets
  namespace: development #这里表明仅授权读取“development”命名空间中的资源
subjects:
- kind: User
  name: Dave
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

可以使用ClusterRoleBinding在集群级别和所有的命名空间中授予权限。

如下示例所定义的ClusterRoleBinding允许在用户组“manager”中的任何用户都可以读取集群中任何命名空间中的secret。

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
   name: read-secrets-global
subjects:
- kind: Group
  name: manager
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

对资源的引用

在Kubernetes中,pod logs endpoint的URL格式为:

GET /api/v1/namespaces/{namespace}/pods/{name}/log

这种情况下,“pods”是命名空间资源,“log”是pods的子资源。
为了在RBAC角色中表示出这一点,我们需要使用斜线来划分资源与子资源。
如果需要角色绑定主体读取pods以及pods log,需要定义如下角色:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
  resources: ["pods","pods/log"]
  verbs: ["get","list"]

通过resourceNames列表,角色可以针对不同种类的请求根据资源名引用资源实例。
当指定了resourceNames列表时,不同动作种类的请求的权限,如使用“get”、“delete”、“update”以及“patch”等动词的请求,将被限定到资源列表中所包含的资源实例上。

例如:如果需要限定一个角色绑定主体只能“get”或者“update”一个configmap时,您可以定义如下角色:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: configmap-updater
rules:
- apiGroups: [""]
  resources: ["configmap"]
  resourceNames: ["my-configmap"]
  verbs: ["update","get"]

如果设置了resourceNames,则请求所使用的动词不能是list、watch、create或者deletecollection。
由于资源名不会出现在create、list、watch和deletecollection等API请求的URL中,所以这些请求动词不会被设置了resourceNames的规则所允许,因为规则中的resourceNames部分不会匹配这些请求。

一些角色定义的例子
如下仅截取rules部分的定义:
允许读取core API Group中定义的资源“pods”:

rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["list","get","watch"]

允许读写在“extensions”和“apps” API Group中定义的资源“deployments”:

rules:
- apiGroup: ["extensions","apps"]
  resources: ["deployments"]
  verbs: ["get","list","watch","create","update","patch","delete"]

允许读取“pods”以及读写“jobs”:

rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","list","watch"]
- apiGroups: ["batch","extensions"]
  resources: ["jobs"]
  verbs: ["get","list","watch","create","update","patch","delete"]

允许读取一个名为“my-config”的ConfigMap实例(需要将其通过RoleBinding绑定从而限制针对某一个命名空间中定义的一个ConfigMap实例的访问):

rules:
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["my-config"]
  verbs: ["get"]

允许读取core API Group中的“nodes”资源(由于node是集群级别资源,所以此ClusterRole定义需要与一个ClusterRoleBinding绑定才有效):

rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get","list","watch"]

允许对非资源endpoint “/healthz”及其所有子路径的“GET”和“POST”请求(此ClusterRole定义需要与一个ClusterRoleBinding绑定才有效):

rules:
- nonResourceURLs: ["/healthz","/healthz/*"]  #在非资源URL中,“*”代表后缀通配符
  verbs: ["get","post"]

对角色绑定主体(Subject)的引用RoleBinding或者ClusterRoleBinding将角色绑定到角色绑定主体(Subject)。
角色绑定主体可以是用户组(Group)、用户(User)或者服务账户(Service Accounts)。

用户由字符串表示。
Kubernetes中的用户组信息由授权模块提供。用户组和用户一样都由字符串表示。
Kubernetes对用户组字符串没有格式要求。

服务账户拥有包含system:serviceaccount:前缀的用户名,并属于拥有system:servieaccounts:前缀的用户组。

角色绑定的一些例子
以下示例,仅截取展示了RoleBinding的Subjects字段。
一个名为“alice@example.com”的用户:

subjects:
- kind: User
  name: "alice@example.com"
  apiGroup: rbac.authorization.k8s.io

一个名为“frontend-admins”的用户组:

subjects:
- kind: Group
  name: "frontend-admins"
  apiGroup: rbac.authorization.k8s.io

kube-system命名空间中的默认服务账户:

subjects:
- kind: ServiceAccount
  name: default
  namespace: kube-system

名为“qa”命名空间中的所有服务账户:

subjects:
- kind: Group
  name: system:serviceaccounts:qa
  apiGroup: rbac.authorization.k8s.io
```在集群中的所有服务账户:
```yaml
subjects:
- kind: Group
  name: system:serviceaccounts
  apiGroup: rbac.authorization.k8s.io

所有认证过的用户:

subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.autorization.k8s.io
```所有未认证的用户
```yaml
subjects:
- kind: Group
  name: system:unauthenticated
  apiGroup: rbac.authorization.k8s.io

默认角色与默认角色绑定

API Server会创建一组默认的ClusterRole和ClusterRoleBinding对象。
默认对象中有需要包含system:前缀,表明这些资源由Kubernetes基础组件拥有。对这些资源的修改可能导致非功能性集群。

所有默认的ClusterRole和ClusterRoleBinding对象都会被标记为kubernetes.io/bootstrapping=rbac-defaults。

自动更新
每次启动时,API Server都会更新默认ClusterRole所缺乏的各种权限,并更新默认ClusterRoleBinding所缺乏的各个角色绑定主体。

要禁用自动更新,请将默认ClusterRole以及ClusterRoleBinding的rbac.authorization.kubernetes.io/autoupdate设置成为False。
注意:缺乏默认权限和角色绑定主体可能会导致非功能性集群问题。

面向用户的角色
一些默认角色并不包含system:前缀,它们是面向用户的角色。这些角色包含超级用户角色,即旨在利用ClusterRoleBinding在集群范围内授权的角色,以及那些使用RoleBinding在特定命名空间中授权的角色。

控制器角色
当使用—user-service-account-credentials选项运行controller manager时,每个控制循环都将使用单独的服务账户启动。而每个控制循环都存在对应的角色,前缀名为system:controller:。

初始化与预防权限升级
RBAC API 会阻止用户通过编辑角色或者角色绑定来升级权限。
用户只有在拥有了角色所包含的所有权限的条件下才能创建、更新一个角色,这些操作必须在角色所处的相同范围内进行。

例如:如果用户user-1没有权限读取集群范围内的secret列表,那么他也不能创建包含这种权限的ClusterRole。
为了能够创建、更新角色,需要:

  1. 授予用户一个角色以允许他们根据需要创建、更新Role或者ClusterRole对象;
  2. 授予用户一个角色包含他们在Role或者ClusterRole中所能够设置的所有权限。

用户只有在拥有所引用的角色中包含的所有权限时才可以创建、更新角色绑定或者用户被明确授权可以在所引用的角色上执行绑定操作。

例如:如果用户user-1没有权限读取集群范围内的Secret列表,那么他将不能创建ClusterRole来引用那些授予了此项权限的角色。
为了能够让用户创建、更新角色绑定,需要:

  1. 授予用户一个角色以允许他们根据需要创建、更新RoleBinding或者ClusterRoleBinding对象。
  2. 授予用户绑定某一特定角色所需要的权限:

    •隐式的,通过授予用户所有所引用的角色中所包含的权限;
    •显式的,通过授予用户在特定Role(ClusterRole)对象上执行bind操作的权限

如下例子中的ClusterRole和RoleBinding将允许用户user-1授予其它用户user-1-namespace命名空间内的admin、edit和view等角色和角色绑定。

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: role-grantor
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["rolebinding"]
  verbs: ["create"]
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["clusteroles"]
  verbs: ["bind"]
  resourceNames: ["admin","edit","view"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: role-grantor-binding
  namespace: user-1-namespace
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: role-grantor
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: user-1

当初始化第一个角色和角色绑定时,初始用户需要能够授予它们尚未拥有的权限。
初始化初始角色和角色绑定时需要:

  • 使用包含system:masters用户组的凭证,该用户组通过默认绑定绑定到cluster-admin超级用户角色。
  • 如果您的API Server在运行时启用了非安全端口(—insecure-port),您可以通过这个没有施行认证或者授权的端口发送角色或者角色绑定请求。

一些命令行工具
有两个kubectl命令可以用于在命名空间内或者整个集群内授予角色。

kubectl create rolebinding
在某一特定命名空间内授予Role或者ClusterRole。示例如下:

  • 在名为“acme”的命名空间中将admin ClusterRole授予用户“bob”:

    kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme
    
  • 在名为“acme”的命名空间中将view ClusterRole授予服务账户“myapp”:

    kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp --namespace=acme
    

kubectl create clusterrolebinding
在整个集群中授予ClusterRole,包括所有命名空间。示例如下:

  • 在整个集群范围内将cluster-admin ClusterRole授予用户“root”:

    kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root
    
  • 在整个集群范围内将system:node ClusterRole授予用户“kubelet”:

    kubectl create clusterrolebinding kubelet-node-binding --clusterrole=system:node --user=kubelet
    
  • 在整个集群范围内将view ClusterRole授予命名空间“acme”内的服务账户“myapp”:

    kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=myapp
    

服务账户(Service Account)权限
默认的RBAC策略将授予控制平面组件(control-pane component)、节点(node)和控制器(Controller)一组范围受限的权限。
但对于“kube-system”命名空间以外的服务账户,则不授予任何权限。

从最安全到最不安全可以排序以下方法:

  1. 对某一特定应用程序的服务账户授予角色(最佳实践)

要求应用程序在其Pod规范(pod spec)中指定serviceAccountName字段,并且要创建相应服务账户(例如通过API、应用程序清单或者命令kubectl create serviceaccount等)。
例如:在“my-namespace”命名空间中授予服务账户“my-sa”只读权限:

kubectl create rolebinding my-sa-view --clusterrole=view --serviceaccount=my-namespace:my-sa --namespace=my-namespace
  1. 在某一命名空间中授予“default”服务账户一个角色

如果一个应用程序没有在其pod规范中指定serviceAccountName,它将默认使用“default”服务账户。
注意:授予“default”服务账户的权限将可用于命名空间内任何没有指定serviceAccountName的pod。

将在“my-namespace”命名空间内授予“default”服务账号只读权限:

kubectl create rolebinding default-view --clusterrole=view --serviceaccount=my-namespace:default --namespace=my-namespace

目前,许多加载项作为“kube-system”命名空间中的“default”服务账户运行。
要允许这些加载项使用超级用户访问权限,请将cluster-admin权限授予“kube-system”命名空间中的“default”服务账户。
注意:启用上述操作意味着“kube-system”命名空间将包含允许超级用户访问API的密钥。

kubectl create clusterrolebinding add-on-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
  1. 为命名空间中所有的服务账户授予角色

如果希望命名空间内的所有应用程序都拥有一个角色,无论它们使用什么服务账户,可以为该命名空间的服务账户用户组授予角色。

将授予“my-namespace”命名空间中的所有服务账户只读权限:

kubectl create rolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts:my-namespace --namespace=my-namespace
  1. 对集群范围内的所有服务账户授予一个受限角色(不鼓励)

如果不想管理每个命名空间的权限,则可以将集群范围角色授予所有服务账户。

kubectl create clusterrolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts
  1. 授予超级用户访问权限给集群范围内的所有服务账户(超级不鼓励)

如果根本不关心权限分块,可以对所有服务账户授予超级用户访问权限。
警告:这种做法将允许任何具有读取权限的用户访问secret或者通过创建一个容器的方式来访问超级用户的凭据。

kubectl create clusterrolebinding serviceaccounts-cluster-admin --clusterrole=cluster-admin --group=system:serviceaccounts

3.8.3 Network Policy

网络策略说明一组Pod之间是如何被允许互相通信,以及如何与其它网络Endpoint进行通信。
Network Policy资源使用标签来选择Pod,并定义了一些规则,这些规则指明允许什么流量进入到选中的Pod上。

Network Policy的作用对象是Pod,也可以应用到Namespace和集群的Ingress、Egress流量。
Network Policy是作用在L3/4层的,即限制的是对IP地址和端口的访问,如果需要对应用层做访问限制需要使用如Istio这类Service Mesh。

前提条件
网络策略通过插件来实现,例如fannel、calico。