🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] 我们知道,当客户端通过安全端口访问apiserver的API时,都需要携带一个身份凭证,能让apiserver认证为某个User、Group或者ServiceAccount。kubelet也要访问apiserver的API,所以它也需要携带一个身份凭证。 我们列举一些kubelet需要访问的API:第一次向apiserver注册(`POST /api/v1/nodes`)、定期向apiserver更新自身节点的状态(`PUT /api/v1/nodes/{nodeName}`)、获取pod列表以知道哪些pod是调度到自身节点上(`GET /api/v1/pods`)等等。我们发现,有一些API比如获取pod列表`GET /api/v1/pods`是每个kubelet都要能访问的,而有一些API比如更改节点状态`PUT /api/v1/nodes/{nodeName}`应该只能被该节点本身访问。 所以k8s做了这样的设计,每一个kubelet访问API时。其携带的身份凭证必须被apiserver识别成某个User`system:node:{nodeName}`以及Group`system:nodes`。授权服务器会给User`system:node:{nodeName}`授权使它有权限访问`PUT /api/v1/nodes/{nodeName}`,以及给Group`system:nodes`授权使其能够访问`GET /api/v1/pods`。 至于kubelet的身份凭证如何得到,以及如何被apiserver认证我们先不管,我们先来说一下授权。授权模式有很多种,常见的有ABAC以及RBAC。假设我们使用RBAC,那么我们给Group`system:nodes`授权时,必须创建一个类似于如下的ClusterRole以及一个ClusterRoleBinding使该Group能够访问`GET /api/v1/pods`: ``` apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: system:node rules: - apiGroups: [""] resources: ["pods"] verbs: ["get"] ``` ``` apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: system:node subjects: - kind: Group name: system:nodes apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: system:node apiGroup: rbac.authorization.k8s.io ``` 当每有一个Node注册成功后,我们必须在集群中为该Node创建一个ClusterRole和ClusterRoleBinding,以使该Node只能访问`PUT /api/v1/nodes/{nodeName}`。如果集群Node很多的时候,手动创建这么多的ClusterRole和ClusterRoleBinding是不是很麻烦?是的,非常麻烦。那么k8s可不可以自动地为Group`system:nodes`以及每个Node`system:node:{nodeName}`创建ClusterRole与ClusterRoleBinding呢?答案是:每个版本,k8s做了不同的事情。 在1.6版本中,如果使用RBAC授权模式,那么`system:node`这个ClusterRole会自动地绑定到Group`system:nodes`。但是每个Node所需要的ClusterRole与ClusterRoleBinding不会自动创建。 在1.7版本中,k8s想,既然我们要基于RBAC给每个Node创建ClusterRole与ClusterRoleBinding,那么我们就把这个功能抽出来,设计一个叫Node Authorizor的授权器,如果API请求携带的身份凭证被认证为User`system:node:<nodeName>`以及Group`system:nodes`,那么就由Node Authorizor对这次请求进行授权,而不再由RBAC Authorizor进行授权。Node Authorizor会自动地赋予Group`system:nodes`访问`GET /api/v1/pods`的权限,以及赋予User`system:node:<nodeName>`访问`PUT /api/v1/nodes/{nodeName}`的权限,不像RBAC那样还要创建一个ClusterRole与ClusterRoleBinding。 要开启Node Authorizor,需要配置apiserver的启动参数`--authoriztion-mode=Node,···`和`--enable-admission-plugins=···,NodeRestriction,···`。不过需要注意的是,由于Node Authorizor的权限规则是写死的,不像RBAC那样可以手动配置;所以不同的k8s版本,Node Authorzior对每个Node能访问的接口可能会有一样的规则。 OK,现在Node授权的问题解决了,那么接下来应该要讲讲认证的问题了。 我们在前面的文章中介绍了三种常见的认证方式:用户名密码认证、token认证、客户端证书认证。我们直接给出答案:k8s的Node使用的是客户端证书认证。 在客户端证书认证机制中,apiserver会用参数`--client-ca-file`指定的CA证书来验证API请求携带的签名证书,所以kubelet携带的签名证书应该是由CA证书对应的CA密钥签名的。k8s集群的管理员可以在添加一个新的节点的时候,手动为新节点生成一对密钥,然后再手动使用CA密钥进行签名,最后拿这个签名证书去启动kubelet。 有没有觉得这种人工去生成密钥对以及签名很麻烦?是的,非常麻烦。刚开始安装集群的时候,可以使用脚本批量处理。但是如果到了以后,集群需要添加新的节点时,这个时候管理员只能手动地去生成密钥、签名,然后配置好kubelet。那么有没有办法可以简化这些操作呢?答案是,有的。请看下一节《TLS bootstrapping》