深入理解Kube-APIServer¶
目录 - 认证 - 鉴权 - 准入 Mutating Validating Admission - 限流 - APIServer对象的实现
API Server¶
kube-apiserver是Kubernetes最重要的核心组件之一,主要提供以下的功能
- 提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更 等
- 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或 修改数据,只有API Server才直接操作etcd)
访问控制概览¶
Kubernetes API的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证、授权以及 准入控制(Admission Control)等。
访问控制细节¶
认证¶
开启TLS时,所有的请求都需要首先认证。Kubernetes支持多种认证机制,并支持同时
开启多个认证插件(只要有一个认证通过即可)。如果认证成功,则用户的username会
传入授权模块做进一步授权验证;而对于认证失败的请求则返回HTTP 401。
认证插件¶
- X509证书
- 使用X509客户端证书只需要API Server启动时配置--client-ca-file=SOMEFILE。在证书认证时,其CN域用作用户名,而组织 机构域则用作group名。
- 静态Token文件
- 使用静态Token文件认证只需要APIServer启动时配置--token-auth-file=SOMEFILE。
- 该文件为csv格式,每行至少包括三列token,username,userid, token,user,uid,"group1,group2,group3”
- 引导Token
- 为了支持平滑地启动引导新的集群,Kubernetes 包含了一种动态管理的持有者令牌类型,称作启动引导令牌(Bootstrap Token)。
- 这些令牌以Secret 的形式保存在kube-system名字空间中,可以被动态管理和创建。
- 控制器管理器包含的TokenCleaner控制器能够在启动引导令牌过期时将其删除。
- 在使用kubeadm部署Kubernetes时,可通过kubeadmtoken list命令查询。
- 静态密码文件
- 需要APIServer启动时配置--basic-auth-file=SOMEFILE,文件格式为csv,每行至少三列password, user, uid,后面是可选 的group名 password,user,uid,"group1,group2,group3”
- ServiceAccount
- ServiceAccount是Kubernetes自动生成的,并会自动挂载到容器的/run/secrets/kubernetes.io/serviceaccount目录中。
- OpenID
- OAuth 2.0的认证机制
- Webhook 令牌身份认证
- --authentication-token-webhook-config-file指向一个配置文件,其中描述如何访问远程的Webhook 服务。
- --authentication-token-webhook-cache-ttl用来设定身份认证决定的缓存时间。默认时长为 2 分钟。
- 匿名请求
- 如果使用AlwaysAllow以外的认证模式,则匿名请求默认开启,但可用--anonymous-auth=false禁止匿名请求。
基于webhook的认证服务集成¶
https://github.com/appscode/guard
构建符合Kubernetes规范的认证服务¶
需要依照Kubernetes规范,构建认证服务,用来认证tokenreviewrequest
构建认证服务
- 认证服务需要满足如下Kubernetes的规范 ➢ URL:https://authn.example.com/authenticate ➢ Method:POST ➢ Input: ➢ Output:
{
"apiVersion": "authentication.k8s.io/v1beta1", "kind": "TokenReview", "spec": {
"token": "(BEARERTOKEN)" } } { "apiVersion": "authentication.k8s.io/v1beta1", "kind": "TokenReview", "status": { "authenticated": true, "user": { "username": "janedoe@example.com", "uid": "42", "groups": [ "developers", "qa" ]}} }
开发认证服务¶
解码认证请求
decoder := json.NewDecoder(r.Body) var tr authentication.TokenReview err := decoder.Decode(&tr) if err != nil { log.Println("[Error]", err.Error()) w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]interface{}{ "apiVersion": "authentication.k8s.io/v1beta1", "kind": "TokenReview", "status": authentication.TokenReviewStatus{ Authenticated: false, }, }) return }
转发认证请求至认证服务器
//CheckUser
ts:=oauth2.StaticTokenSource( &oauth2.Token{
AccessToken:tr.Spec.Token}, ) tc:=oauth2.NewClient(oauth2.NoContext,ts) client:=github.NewClient(tc) user,_,err:=client.Users.Get(context.Background(),"") iferr!=nil{ log.Println("[Error]",err.Error()) w.WriteHeader(http.StatusUnauthorized) json.NewEncoder(w).Encode(map[string]interface{}{ "apiVersion":"authentication.k8s.io/v1beta1", "kind": "TokenReview", "status":authentication.TokenReviewStatus{ Authenticated:false, }, }) return }
认证结果返回给APIServer
w.WriteHeader(http.StatusOK) trs := authentication.TokenReviewStatus{ Authenticated: true, User: authentication.UserInfo{ Username: *user.Login, UID: *user.Login, }, } json.NewEncoder(w).Encode(map[string]interface{}{ "apiVersion": "authentication.k8s.io/v1beta1", "kind": "TokenReview", "status": trs, })
配置认证服务¶
{
"kind": "Config", "apiVersion": "v1", "preferences": {}, "clusters": [ { "name": "github-authn", "cluster": { "server": "http://localhost:3000/authenticate" } }], "users": [ { "name": "authn-apiserver", "user": { "token": "secret"