kubernetes Master节点组件(二)- APIServer

API Server 作为kubernetes中唯一一个直接和etcd打交道的组件,它自然需要对外提供增删查改etcd中资源配置数据的能力。
由于只有master节点才会有etcd和API Server, 所以worker节点kubelet只能同master节点的API Server进行交互。
同时Master节点的scheduler和controller manager组件也需要同API Server进行交互以获取和修改对应资源的状态。
而我们使用的外部kubectl客户端也是直接和API server进行交互来对操作具体资源的状态。
kubernetes Master节点组件(二)- APIServer_第1张图片

List & Watch

上一篇讲etcd的时候我们讲到etcd的watch机制。那么api server是通过什么方式将watch机制对外暴露的呢?
API server实际是根据list and watch机制来完成的。
kubernetes Master节点组件(二)- APIServer_第2张图片
从上图可以看到,比如当kubectl通过api server添加了一个replicaset之后,由于controller manager注册了自己的list&watch事件,所以api server就会将这个新的replicaset事件通知给controller manager,controller manager会根据信息请求api server创建相关的pod。而这个事件又会被scheduler watch到,这个时候scheduler就会根据自己的调度算法更新pod的node相关信息。这个更改又会被该node上面的kubelet watch到,这个时候kubelet就会根据pod的具体信息创建pod。
对于普通的list请求,api server 会返回所有的当前信息,没有什么特别的。
而在api server内部是怎么完成watch操作的呢?
kubernetes Master节点组件(二)- APIServer_第3张图片
从上图可以看到当client发起的请求里面带有watch=yes的时候,api server会为这个http请求创建一个专门的watcher,每当有新的事件发生时,watcher都会将该事件写到http 的response里面。直到http连接断开。

那么api server是直接根据watcher去etcd里面取数据么?不是的,在api server里面有一个专门的cache来缓存所有对象的当前状态以及事件。
kubernetes Master节点组件(二)- APIServer_第4张图片
当etcd内部对象发生改变时,会根据api server注册的watch接口通知到api server。api server会将事件缓存到cache里面的event缓存,同时更新store里面对象的当前状态。所以event缓存里面包含对象当前以及之前的状态,而store里面只会存对象的当前状态。
这个时候如果只是list获取对象信息的话,对象的当前状态就会转化为add事件传给list&watcher接口。

kubernetes Master节点组件(二)- APIServer_第5张图片
而这个时候如果有watcher关注这个对象的话,则会将该事件通知到watcher。

详细过程可以参考 https://www.kubernetes.org.cn/174.html

访问控制

kubernetes Master节点组件(二)- APIServer_第6张图片
如上图所示,不管是外部的用户(如用kubectl和k8s进行交互)还是内部的service account访问api server都需要闯过三关才能真正到达api server的业务逻辑:

Authentication

接入认证,这一步会对请求的接入信息进行认证,比如用户名,密码,各种token或者证书等。
对于内部service account,k8s会为其创建专门的secrets来存储相关的证书,然后对于绑定了service account的pod,会把相应的secret挂载到pod的相应目录下以方便pod调用api server的时候使用。
而对于外部用户,则需要配置api server添加相应的认证方式, 比如Static Token File,OpenID Connect Tokens等。

Authorization

授权,这一步api server会判断该请求的用户是否有对应操作的权限。
目前共有三种授权配置方式:
Node授权,这种授权方式只针对于node上面的kubelet。它可以配置kubelet对于该node上面的各种资源的操作权限。比如对该node在etcd里面的状态信息的管理,以及对该node上调度的resource的状态管理等。

ABAC授权,这种授权方式是基于用户的授权配置。它需要配置一个如下的json文件,然后在api server启动时指定该文件为ABAC的授权配置文件,这样就能够为用户或者用户组配置相关权限。

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group":"system:authenticated",  "nonResourcePath": "*", "readonly": true}}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group":"system:unauthenticated", "nonResourcePath": "*", "readonly": true}}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"admin",     "namespace": "*",              "resource": "*",         "apiGroup": "*"                   }}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"scheduler", "namespace": "*",              "resource": "pods",                       "readonly": true }}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"scheduler", "namespace": "*",              "resource": "bindings"                                     }}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"kubelet",   "namespace": "*",              "resource": "pods",                       "readonly": true }}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"kubelet",   "namespace": "*",              "resource": "services",                   "readonly": true }}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"kubelet",   "namespace": "*",              "resource": "endpoints",                  "readonly": true }}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"kubelet",   "namespace": "*",              "resource": "events"                                       }}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"alice",     "namespace": "projectCaribou", "resource": "*",         "apiGroup": "*"                   }}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"bob",       "namespace": "projectCaribou", "resource": "*",         "apiGroup": "*", "readonly": true }}

从上面我们可以看到ABAC可以针对每一个用户或者组配置一个policy,在这个policy里面指定该用户对于特定namspace下的特定资源的访问方式。

RBAC授权,这种基于role的授权方式相比于ABAC来说具有更细粒度的权限控制。
在k8s里面一个role的定义表示了对指定namespace下不同资源的访问方式。

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

如果我们需要指定对整个cluster中不同资源的访问方式则需要用到clusterRole。

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  # "namespace" omitted since ClusterRoles are not namespaced
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

但是我们定义了role规则之后由谁来使用它呢?
所以我们还需要定义role和用户,组或者service account等的绑定关系,将role的规则绑定到具体的使用者身上

# This role binding allows "dave" to read secrets in the "development" namespace.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-secrets
  namespace: development # This only grants permissions within the "development" namespace.
subjects:
- kind: User
  name: dave # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io
# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

这里的subjects可以用很多种,除了上面的user和group之外还可以有service account等

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

Admission

经过了上面两层认证和授权之后,按理说整个访问控制的环节应该差不多了。
但是对于不同的场景,我们仍然需要一些定制化的控制需求。
第一种是限制需求,比如对于资源的配额限制(比如可添加的pod的个数),对于资源的调度限制(污点判断),对于系统资源的申请大小的限制(比如对磁盘,内存,cpu的申请大小)。
第二种是修改配置需求,比如强制让用户在添加pod的时候总是从仓库拉取最新的image,为某些pod配置指定的持久化存储插件等。
而这些都可以通过添加特定的admission插件来完成控制,具体可以参考https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/。

你可能感兴趣的:(kubernetes)