APIServer

  • 提供集群管理Restful接口,包括认证授权、数据校验及集群状态变更
  • 其它模块之间数据交互的枢纽,只有APIServer能连接Etcd

k8s API的每个请求都会经过多个阶段的访问控制后才会被接受:

  1. HTTP handler
  2. 认证、鉴权
  3. Mutating admission, webhook
  4. Object Schema Validation
  5. Validating admission, webhook
  6. Persisted to etcd

认证

K8s支持多种认证机制,只要有一个认证通过即可。认证成功继续鉴权验证,否则返回401。

认证插件

X509证书

使用X509客户端证书只需要APIServer启动时配置–client-ca-file=SOMEFILE。在证书认证时,客户端证书的其CN域用作用户名,而组织机构域则用作group名。

  • 修改 manifests/kube-apiserver.yaml

K8s相当于CA,可以颁发客户端证书,请求时携带客户端证书即可表明身份

  • CN 即用户名,kubenetes-admin
  • O 即group名,system:masters

~/.kube/config 中的x509认证信息,由kubectl读取使用

制作客户端证书

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 私钥和请求文件
openssl genrsa -out myuser.key 2048
openssl req -new -key myuser.key -out myuser.csr
# 编码请求文件
cat myuser.csr | base64 | tr -d "\n"

# 创建CSR对象
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: myuser
spec:
  request: ${csr_base64_encoded}
  signerName: kubernetes.io/kube-apiserver-client # using client ca
  expirationSeconds: 86400  # one day
  usages:
  - client auth
EOF

# approve csr
kubectl certificate approve myuser
# 查看 csr
kubectl get csr/myuser -o yaml

# 导出证书
kubectl get csr myuser -o jsonpath='{.status.certificate}'| base64 -d > myuser.crt

# 设置 credentials
kubectl config set-credentials myuser --client-key=myuser.key --client-certificate=myuser.crt --embed-certs=true

# 给用户授权
kubectl create role developer --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods
kubectl create rolebinding developer-binding-myuser --role=developer --user=myuser

# 使用新用户访问
kubectl get ns --user myuser

静态Token文件

API Server启动时配置–token-auth-file=SOMEFILE。该文件为csv格式,每行至少包括三列token,username,user id

1
cncamp-token,cncamp,1000,"group1,group2,group3"

另外,也可以直接将用户名和token配置到kube/config文件

ServiceAccount

机机帐号,创建namespace时,namespace控制器会自动生成名字叫default的serviceaccount,包含一个Secret对象,带着里面的token和APIServer通信,就能代表身份。

  • 这个token是apiserver颁发的jwttoken格式。base64解码后,就是由点号拼接的三段。代表身份标识:某个namespce下的serviceaccount。
  • k8s上的容器可以使用这个token访问APIServer
  • Pod访问k8s API的InClusterConfig方式
    • 在container spec中指定 serviceAccountName
    • 容器中会自动配置包含身份的config信息

Webhook认证

使用--authentication-token-webhook-XX相关配置,描述如何访问远程的webhook服务。

  • k8s与外部认证系统做集成
  • 这个webhook可以作为APIServer的sidecar部署,按照规范开发
  • 只有token方式
  • 请求: 包含客户端发来的token
  • 响应,包含认证服务返回的身份信息:用户名,id,group

OpenID

基于OAuth2.0的认证机制

授权

K8s支持多种授权机制,支持同时开启多个授权插件,一个插件验证通过即可。

  • 授权成功,用户请求会继续交给准入控制模块做进一步验证

支持的授权插件:

  • ABAC
  • RBAC
  • Webhook
  • Node

授权仅处理以下属性:

  • user,group
  • API(请求方法,请求路径),API Group
  • 请求资源和子资源
  • Namespace

授权不能针对某个Namespace的部分Pod。因此权限控制需要根据业务需要,规划好Namespace,通过Namespace做授权。

对接外部认证和授权的主要流程

  • 在外部认证平台如IAM/Keystone上创建用户和用户组
  • 用户从认证平台获取token,请求k8s
  • k8s的webhook去认证平台通过token获取用户及用户组信息,判断权限

RBAC在k8s中被映射为API资源和操作。

  • 角色
    • ClusterRole
      • APIGroup/Resources/SubResources
      • Verbs
      • 针对所有Namespace,使用ClusterRoleBindings进行绑定
    • Role
      • APIGroup/Resources/SubResources
      • Verbs
      • 针对某个Namespace,使用RoleBindings进行绑定
  • 主体
    • User,人机帐号
    • ServiceAccount,机机帐号,需要指定Namespace
1
2
3
4
5
6
7
8
9
kind: Role
apiVersion: rbac.authorizaiton.k8s.io/v1
metadata:
    namespace: default
    name: pod-reader
rules:
- apiGroups: [""] # indicates the core API group
  resourdes: ["pods"]
  verbs: ["get","watch","list"]
1
2
3
4
5
6
7
8
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
    name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get","watch","list"]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: default-admin
  namespace: default
subjects:
  - kind: User
    name: myuser
    apiGroup: rbac.authorization.k8s.io
#  - kind: ServiceAccount
#    name: default
#    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

user/group

RoleBinding将角色中定义的权限赋予一个用户user或一组用户group。

如果对接外部认证系统,user和group是在外部认证系统上创建,通过webhook根据token返回user所属的group列表

group的概念:

  • 对接外部系统时,UserInfo可以包含Group信息,授权就是针对这些Group
  • 对Serviceaccount授权时,Group代表某个Namespace下的所有Serviceaccount

针对群组授权

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: rbac.authorization.k8s.io/v1 
kind: ClusterRoleBinding 
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
# manager这个group下的所有user,都具有secret-reader角色的权限
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
subject:
- kind: Group
  name: system:serviceaccounts:qa
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io
# system:serviceaccounts:qa 这个Serviceaccount所属的namespace下的所有Serviceaccount,
# 都具有secret-reader角色的权限

自研案例

创建Namespace时,自动给创建者绑定相关角色

在cluster创建时,创建自定义的role,比如namespace-creator,定义用户可操作的对象和对应的读写操作。

  1. 创建自定义的namespace admission webhook
  • 当namespace创建请求被处理时,获取当前用户信息并annotate到namespace(通过mutating添加一个annotation createdBy: user)
  1. 创建RBAC controller
  • Watch namespace的创建事件
  • 获取当前namespace的创建者信息
  • 在当前namespace创建rolebinding对象,并将namespace-creator角色和用户绑定

准入

准入控制(Admission Control)在授权后对请求做进一步的验证或添加默认参数。不同于授权和认证只关心请求的用户和操作,准入控制还处理请求的内容, 并且仅对创建、更新、删除或连 接(如代理)等有效,而对读操作无效。

准入控制支持同时开启多个插件,它们依次调用,只有全部插件都通过的请求才可以放过进入系统。

k8s内置了很多准入控制插件。

1
ks exec -it kube-apiserver -- kube-apiserver --help

通过APIServer的help查看admission插件控制参数,–enable-admission-plugins和–disable-admission-plugins。

除默认的准入控制插件以外,Kubernetes预留了准入控制插件的扩展点,用户可自定义准入控制插件实现自定义准入功能

  • MutatingWebhook:变形插件,支持对准入对象的修改
  • ValidatingWebhook:校验插件,只能对准入对象合法性进行校验,不能修改

限流

常见限流算法:

  • 固定窗口
  • 滑动窗口
  • 漏桶
  • 令牌桶

APIServer中的限流配置

  • max-requests-inflight: 在给定时间内的最大 non-mutating 读请求数
  • max-mutating-requests-inflight: 在给定时间内的最大 mutating 写请求数,调整 apiserver 的 流控 qos

API Priority and Fairness 算法

  • APF 以更细粒度的方式对请求进行分类和隔离。
  • 引入了空间有限的排队机制,因此在非常短暂的突发情况下,API 服务器不会拒绝任何请 求。
  • 通过使用公平排队技术从队列中分发请求,这样, 一个行为不佳的控制器就不会饿死其他控制 器(即使优先级相同)。
  • 核心:多等级,多队列

APIServer高可用

apiserver是无状态的Rest Server,无状态所以方便Scale Up/down

负载均衡

  • 在多个apiserver实例之上,配置负载均衡
  • APIServer的证书可能需要加上Loadbalancer VIP重新生成

apimachinery

业务相关的一类对象放在一个Group,同一个group的ETCD请求默认复用同一个tcp链接。

  • 比如node和pod都是core group的
  • list pod请求过大会影响node类请求,可以通过调stream quota参数调整。

Kind用来表示资源类型。

Version分为

  • internel version,用于内部处理
  • external version,面向用户
  • 涉及版本转换,向前兼容3个版本。

可以在源码中定义新的Group/Kind,标记tag,然后使用code-generator生成新对象的clientset代码。