使用aggregation API扩展你的kubernetes API
Overview
What is Kubernetes aggregation
Kubernetes apiserver aggregation AA 是Kubernetes提供的一种扩展API的方法,目前并没有GA
Difference between CRD and AA
众所周知,kubernetes扩展API的方法大概为三种:CRD、AA、手动扩展源码。根据CNCF分享中Min Kim说的AA更关注于实践,而用户无需了解底层的原理,这里使用过 kubebuilder, code-generator 的用户是很能体会到这点。官方也给出了CRD与AA的区别
API Access Control
Authentication
- CR: All strategies supported. Configured by root apiserver.
- AA: Supporting all root apiserver's authenticating strategies but it has to be done via authentication token review api except for authentication proxy which will cause an extra cost of network RTT.
Authorization
- CR: All strategies supported. Configured by root apiserver.
- AA: Delegating authorization requests to root apiserver via SubjectAccessReview api. Note that this approach will also cost a network RTT.
Admission Control
- CR: You could extend via dynamic admission control webhook (which is costing network RTT).
- AA: While You can develop and customize your own admission controller which is dedicated to your AA. While You can't reuse root-apiserver's built-in admission controllers nomore.
API Schema
Note: CR's integration with OpenAPI schema is being enhanced in the future releases and it will have a stronger integration with OpenAPI mechanism.
Validating
- CR: (landed in 1.12) Defined via OpenAPIv3 Schema grammar. more
- AA: You can customize any validating flow you want.
Conversion
- CR: (landed in 1.13) The CR conversioning (basically from storage version to requested version) could be done via conversioning webhook.
- AA: Develop any conversion you want.
SubResource
- CR: Currently only status and scale sub-resource supported.
- AA: You can customize any sub-resouce you want.
OpenAPI Schema
- CR: (landed in 1.13) The corresponding CRD's OpenAPI schema will be automatically synced to root-apiserver's openapi doc api.
- AA: OpenAPI doc has to be manually generated by code-generating tools.
Authentication
要想很好的使用AA,就需要对kubernetes与 AA 之间认证机制进行有一定的了解,这里涉及到一些概念
- 客户端证书认证
- token认证
- 请求头认证
在下面的说明中,所有出现的APIServer都是指Kubernetes集群组件APIServer也可以为 root APIServer;所有的AA都是指 extension apiserver,就是自行开发的 AA。
客户端证书
客户端证书就是CA签名的证书,由客户端指定CA证书,在客户端连接时进行身份验证,在Kubernetes APIserver也使用了相同的机制。
默认情况下,APIServer在启动时指定参数 --client-ca-file ,这时APIServer会创建一个名为 extension-apiserver-authentication ,命名空间为 kube-system 下的 configMap。
$ kubectl get cm -A
NAMESPACE NAME DATA AGE
kube-system extension-apiserver-authentication 6 21h
kubectl get cm extension-apiserver-authentication -n kube-system -o yaml
由上面的命令可以看出这个configMap将被填充到客户端(AA Pod实例)中,使用此CA证书作为用于验证客户端身份的CA。这样客户端会读取这个configMap,与APIServer进行身份认证。
I0622 14:24:00.509486 1 secure_serving.go:178] Serving securely on [::]:443
I0622 14:24:00.509556 1 configmap_cafile_content.go:202] Starting client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file
token认证
Token认证是指通过HTTP Header传入 Authorization: Bearer $TOKEN 的方式进行客户端认证,这也是Kubernetes集群内认证常用的方法。
在这种情况下,允许对APIServer进行认证也同样可以对AA进行认证。如果不想 AA 对同一集群进行身份验证,或AA在集群外部运行,可以将参数 --authentication-kubeconfig 以指定要使用的不同 Kubeconfig 认证。
下面实例是AA的启动参数
./bin/apiserver -h|grep authentication-kubeconfig
--authentication-kubeconfig string kubeconfig file pointing at the 'core' kubernetes server with enough righ
ts to create tokenreviews.authentication.k8s.io. This is optional. If empty, all token requests are considered to be anonymous and no cli
ent CA is looked up in the cluster.
请求头认证
RequestHeader 认证是指,APIServer对来自AA代理连接进行的身份认证。
默认情况下,AA 从 extension-apiserver-authentication 中提到的 ConfigMap 中 提取 requestheader 客户端 CA 证书与 CN。如果主 Kubernetes APIServer 配置了选项 --requestheader-client-ca-file ,则它会填充此内容。
跳过客户端认证 --authentication-skip-lookup
授权
默认情况下,AA 服务器会通过自动注入到 Kubernetes 集群上运行的 pod 的连接信息和凭据,来连接到主 Kubernetes API 服务器。
E0622 11:20:12.375512 1 errors.go:77] Post "https://192.168.0.1:443/apis/authorization.k8s.io/v1/subjectaccessreviews": write tcp 192.168.0.36:39324->192.168.0.1:443: write: connection reset by peer
如果AA在集群外部部署,可以指定--authorization-kubeconfig 通过kubeconfig进行认证,这就类似于二进制部署中的信息。
默认情况下,Kubernetes 集群会启用RBAC,这就意味着AA 创建多个clusterrolebinding。
下面日志是 AA 对于集群中资源访问无权限的情况
E0622 09:01:26.750320 1 reflector.go:178] pkg/mod/k8s.io/client-go@v0.18.10/tools/cache/reflector.go:125: Failed to list *v1.MutatingWebhookConfiguration: mutatingwebhookconfigurations.admissionregistration.k8s.io is forbidden: User "system:serviceaccount:default:default" cannot list resource "mutatingwebhookconfigurations" in API group "admissionregistration.k8s.io" at the cluster scope
E0622 09:01:29.357897 1 reflector.go:178] pkg/mod/k8s.io/client-go@v0.18.10/tools/cache/reflector.go:125: Failed to list *v1.Namespace: namespaces is forbidden: User "system:serviceaccount:default:default" cannot list resource "namespaces" in API group "" at the cluster scope
E0622 09:01:39.998496 1 reflector.go:178] pkg/mod/k8s.io/client-go@v0.18.10/tools/cache/reflector.go:125: Failed to list *v1.ValidatingWebhookConfiguration: validatingwebhookconfigurations.admissionregistration.k8s.io is forbidden: User "system:serviceaccount:default:default" cannot list resource "validatingwebhookconfigurations" in API group "admissionregistration.k8s.io" at the cluster scope
需要手动在namespace kube-system 中创建rolebindding到 role extension-apiserver-authentication-reader 。这样就可以访问到configMap了。
apiserver-builder
apiserver-builder 项目就是创建AA的工具,可以参考 installing.md 来安装
初始化项目
初始化命令
<your-domain>这个是你的API资源的组,参考k8s.io/api- 如果组的名称是域名就设置为主域名,例如内置组
/apis/authentication.k8s.io/apis/batch
- 如果组的名称是域名就设置为主域名,例如内置组
- 生成的go mod 包名为你所在的目录的名称
- 例如,在firewalld目录下,go.mod 的名称为 firewalld
apiserver-boot init repo --domain <your-domain>
例如
apiserver-boot init repo --domain fedoraproject.org
注:这里--domain设置为主域名就可以了,后面生成的group会按照格式 +
apiserver-boot must be run from the directory containing the go package to bootstrap. This must
be under $GOPATH/src/<package>.
必须在 $GOPATH/src 下创建你的项目,我这里的为 GOPATH=go/src ,这时创建项目必须在目录 go/src/src/{project} 下创建
创建一个GVK
apiserver-boot create group version resource \
--group firewalld \
--version v1 \
--kind PortRule
在创建完成之后会生成 api-like的类型,我们只需要填充自己需要的就可以了
type PortRule struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec PortRuleSpec `json:"spec,omitempty"`
Status PortRuleStatus `json:"status,omitempty"`
}
// PortRuleSpec defines the desired state of PortRule
type PortRuleSpec struct { // 这里内容都为空的,自己添加即可
Name string `json:"name"`
Host string `json:"host"`
Port int `json:"port"`
IsPremanent bool `json:"isPremanent,omitempty"`
}
// PortRuleStatus defines the observed state of PortRule
type PortRuleStatus struct {
}
生成代码
apiserver-boot 没有专门用来生成代码的命令,可以执行任意生成命令即可,这里使用生成二进制执行文件命令,这个过程相当长。
apiserver-boot build executables
如果编译错误可以使用 --generate=false 跳过生成,这样就可以节省大量时间。
运行方式
运行方式无非三种,本地运行,集群内运行,集群外运行
running_locally
本地运行需要有一个etcd服务,不用配置ca证书,这里使用docker运行
docker run -d --name Etcd-server \
--publish 2379:2379 \
--publish 2380:2380 \
--env ALLOW_NONE_AUTHENTICATION=yes \
--env ETCD_ADVERTISE_CLIENT_URLS=http://etcd-server:2379 \
bitnami/etcd:latest
然后执行命令,执行成功后会弹出对应的访问地址
apiserver-boot build executables
apiserver-boot run local
running_in_cluster
构建镜像
需要先构建容器镜像,apiserver-boot build container --image <image> 这将生成代码,构建 apiserver 和controller二进制文件,然后构建容器映像。构建完成后还需要将对应的镜像push到仓库(可选)
apiserver-boot build config \
--name <servicename> \
--namespace <namespace to run in> \
--image <image to run>
注,这个操作需要在支持Linux内核的环境下构建,wsl不具备内核功能故会报错,需要替换为wsl2,而工具是下载的,如果需要wsl1+Docker Desktop构建,需要自己修改
构建配置
apiserver-boot build config \
--name <servicename> \
--namespace <namespace to run in> \
--image <image to run>
构建配置的操作会执行以下几个步骤:
- 在
<project/config/certificates目录下创建一个 CA证书 - 在目录
<project/config/*.yaml下生成kubernetes所需的资源清单。
注:
实际上这个清单并不能完美适配任何环境,需要手动修改一下配置
运行的Pod中包含apiserver与controller,如果使用kubebuilder创建的controller可以自行修改资源清单
修改apiserver的配置
下面参数是有关于 AA 认证的参数
--proxy-client-cert-file=/etc/kubernetes/pki/firewalld.crt \
--proxy-client-key-file=/etc/kubernetes/pki/firewalld.key \
--requestheader-allowed-names=kube-apiserver-kubelet-client,firewalld.default.svc,firewalld-certificate-authority \
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-username-headers:用于存储用户名的标头--requestheader-group-headers:用于存储组的标题--requestheader-extra-headers-prefix:附加到所有额外标头的前缀--proxy-client-key-file:私钥文件--proxy-client-cert-file:客户端证书文件--requestheader-client-ca-file:签署客户端证书文件的 CA 的证书--requestheader-allowed-names:签名客户端证书中的CN)
由以上信息得知,实际上 apiserver-boot 所生成的ca用不上,需要kubernetes自己的ca进行签署,这里简单提供两个命令,使用kubernetes集群证书进行颁发证书。这里kubernetes集群证书使用kubernetes-generator 生产的。这里根据这个ca再次生成用于 AA 认证的证书。
openssl req -new \
-key firewalld.key \
-subj "/CN=firewalld.default.svc" \
-config <(cat /etc/pki/tls/openssl.cnf <(printf "[aa]\nsubjectAltName=DNS:firewalld, DNS:firewalld.default.svc, DNS:firewalld-certificate-authority, DNS:kubernetes.default.svc")) \
-out firewalld.csr
openssl ca \
-in firewalld.csr \
-cert front-proxy-ca.crt \
-keyfile front-proxy-ca.key \
-out firewalld.crt \
-days 3650 \
-extensions aa \
-extfile <(cat /etc/pki/tls/openssl.cnf <(printf "[aa]\nsubjectAltName=DNS:firewalld, DNS:firewalld.default.svc, DNS:firewalld-certificate-authority, DNS:kubernetes.default.svc"))
完成后重新生成所需的yaml资源清单即可,通过资源清单来测试下扩展的API
apiVersion: firewalld.fedoraproject.org/v1
kind: PortRule
metadata:
name: portrule-example
spec:
name: "nginx"
host: "10.0.0.3"
port: 80
$ kubectl apply -f http.yaml
portrule.firewalld.fedoraproject.org/portrule-example created
$ kubectl get portrule
NAME CREATED AT
portrule-example 2022-06-22T15:12:59Z
更详细的说明建议阅读下Reference,都是官方提供的详细说明文档
Reference
使用aggregation API扩展你的kubernetes API的更多相关文章
- 资深专家深度剖析Kubernetes API Server第3章(共3章)
在本系列的前两部分中我们介绍了API Server的总体流程,以及API对象如何存储到etcd中.在本文中我们将探讨如何扩展API资源. 在一开始的时候,扩展API资源的唯一方法是扩展相关API源代码 ...
- 资深专家深度剖析Kubernetes API Server第2章(共3章)
欢迎来到深入学习Kubernetes API Server的系列文章的第二部分.在上一部分中我们对APIserver总体,相关术语及request请求流进行探讨说明.在本部分文章中,我们主要聚焦于探究 ...
- 资深专家深度剖析Kubernetes API Server第1章(共3章)
欢迎来到深入学习Kubernetes API Server的系列文章,在本系列文章中我们将深入的探究Kubernetes API Server的相关实现.如果你对Kubernetes的内部实现机制比较 ...
- 深度剖析Kubernetes API Server三部曲 - part 3
在本系列的前两部分中我们介绍了API Server的总体流程,以及API对象如何存储到etcd中.在本文中我们将探讨如何扩展API资源. 在一开始的时候,扩展API资源的唯一方法是扩展相关API源代码 ...
- 深度剖析Kubernetes API Server三部曲 - part 2
欢迎来到深入学习Kubernetes API Server的系列文章的第二部分.在上一部分中我们对APIserver总体,相关术语及request请求流进行探讨说明.在本部分文章中,我们主要聚焦于探究 ...
- 深度剖析Kubernetes API Server三部曲 - part 1
欢迎来到深入学习Kubernetes API Server的系列文章,在本系列文章中我们将深入的探究Kubernetes API Server的相关实现.如果你对Kubernetes 的内部实现机制比 ...
- 亲历者说:Kubernetes API 与 Operator,不为人知的开发者战争
如果我问你,如何把一个 etcd 集群部署在 Google Cloud 或者阿里云上,你一定会不假思索的给出答案:当然是用 etcd Operator! 实际上,几乎在一夜之间,Kubernetes ...
- 第24 章 : Kubernetes API 编程利器:Operator 和 Operator Framework
Kubernetes API 编程利器:Operator 和 Operator Framework 本节课程主要分享以下三方面的内容: operator 概述 operator framework 实 ...
- 第23 章 : Kubernetes API 编程范式
Kubernetes API 编程范式 需求来源 首先我们先来看一下 API 编程范式的需求来源. 在 Kubernetes 里面, API 编程范式也就是 Custom Resources Defi ...
随机推荐
- keytools命令生成证书
平时开发中可以使用keytools命令生成证书,一般常用格式为: keytool -genkey -alias tzzxxt -keyalg RSA -keypass 123456 -validity ...
- 帝国cms插件 一键替换数据表中已发表文章的内容关键字
你是不是也在优化网站,是不是网站发展了一段时间之后才来做优化的,这样当然就会导致已经发表文章里的内容关键字,不能得到替换了! 小编根据后台替换内容关键字的程序,重写了一段 通过运行单个页面就能直接替换 ...
- vue--vuex 状态管理模式
前言 vuex作为vue的核心插件,同时在开发中也是必不可少的基础模块,本文来总结一下相关知识点. 正文 1.基于单向数据流问题而产生了Vuex 单向数据流是vue 中父子组件的核心概念,props ...
- Conda安装及第一个py程序
Conda安装及第一个py程序 安装Conda 下载安装 在Anaconda官网下载Anaconda 打开Conda安装程序 设置好安装目录(这个一定要记好,后边要用),比如我的目录就是 D:\Pro ...
- 【课程汇总】OpenHarmony全场景Demo数字管家系列课(附链接)
小孩放学了,做作业的时间到,窗帘.护眼灯自动打开,关掉电视和扫地机,给小孩一个安静舒适的学习环境:碰到学习难题,可以随时请求你的远程指导:晚上回家休息了,选择舒适的氛围灯,伴随着睡眠音乐进入梦乡:出门 ...
- Web安全中的常见Session攻击(预测+劫持+固定)
攻击者至少可以通过以下三种方式来获取一个有效的session标识符: 1.预测 2.捕获(劫持) 3.固定 一.会话预测 预测这种方式,也就是攻击者需要猜测出系统中使用的有效的session标识符(P ...
- 踹掉后端,前端导出Excel!
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一个下载链接,但有时候我们只想导出前端页面上已经有了的数据,不想再调后端导出接口浪费服务器资源,学习本文demo例子,我们踹掉后端,直接在前 ...
- input 标签的 pattern 属性
定义和用法 pattern 属性规定用于验证输入字段的模式. 模式指的是正则表达式. 注释:pattern 属性适用于以下 <input>类型:text, search, url, tel ...
- python学习-Day19
目录 今日内容详细 正则表达式 开端 概念及相关符号 正则表达式之字符组 正则表达式之特殊符号 正则表达式之量词 小试牛刀 实现手机号码校验功能 复杂正则的编写 校验用户身份证号码 校验邮箱.快递单号 ...
- 记一次调试YOLOv5+DeepSort车辆跟踪项目的经过
摘要:学习别人的开源项目是日常的一项必备技能,本文通过一个车辆跟踪(YOLOv5+DeepSort)的例子介绍如何配置和调试GitHub上的开源代码.以第一人称的视角给出本人调试代码的过程,包括项目r ...