1.1、概述
Aggregated(聚合的)API server
是为了将原来的 API server 这个巨石(monolithic)应用给拆分开,为了方便用户开发自己的 API server 集成进来,而不用直接修改 Kubernetes 官方仓库的代码,这样一来也能将 API server 解耦,方便用户使用实验特性。这些 API server 可以跟 core API server
无缝衔接,使用 kubectl 也可以管理它们。
在 1.7+
版本中,聚合层和 kube-apiserver 一起运行。在扩展资源被注册前,聚合层不执行任何操,要注册其 API,用户必需添加一个 APIService
对象,该对象需在 Kubernetes API 中声明 URL 路径,聚合层将发送到该 API 路径(e.g. /apis/myextension.mycompany.io/v1/…)的所有对象代理到注册的 APIService。
通常,通过在集群中的一个 Pod 中运行一个 extension-apiserver
来实现 APIService。如果已添加的资源需要主动管理,这个 extension-apiserver 通常需要和一个或多个控制器配对。
1.2、设计理念
- api的扩展性:这样k8s的开发人员就可以编写自己的API服务器来公开他们想要的API。集群管理员应该能够使用这些服务,而不需要对核心库存储库进行任何更改。
- 丰富了APIs:核心kubernetes团队阻止了很多新的API提案。通过允许开发人员将他们的API作为单独的服务器公开,并使集群管理员能够在不对核心库存储库进行任何更改的情况下使用它们,这样就无须社区繁杂的审查了
- 开发分阶段实验性API的地方:新的API可以在单独的聚集服务器中开发,当它稳定之后,那么把它们封装起来安装到其他集群就很容易了。
- 确保新API遵循kubernetes约定:如果没有这里提出的机制,社区成员可能会*推出自己的东西,这可能会或可能不遵循kubernetes约定。
Aggregator for Kubernetes-style API servers: dynamic registration, discovery summarization, secure proxy
二、认证流程
2.1、工作方式
与自定义资源定义(CRD)不同,除标准的 Kubernetes apiserver 外,Aggregation API 还涉及另一个服务器:Extension apiserver
。Kubernetes apiserver 将需要与您的 Extension apiserver 通信,并且您的 Extension apiserver 也需要与 Kubernetes apiserver 通信。为了确保此通信的安全,Kubernetes apiserver 使用 x509 证书向 Extension apiserver 认证。
- Kubernetes apiserver:对发出请求的用户身份认证,并对请求的 API 路径执行鉴权
- Kubernetes apiserver (aggregator):将请求转发到 Extension apiserver (aggregated apiserver)
- Extension apiserver:认证来自 Kubernetes apiserver 的请求
- Extension apiserver:对来自原始用户的请求鉴权
- Extension apiserver:执行
2.2、Kubernetes Apiserver 认证和授权
假设我们已经在 Kubernetes apiserver 注册了 Extension apiserver。
当用户请求访问 path ,Kubernetes apiserver 使用它的标准认证和授权配置来对用户认证,以及对特定 path 的鉴权,到目前为止,所有内容都是标准的 Kubernetes API 请求,认证与鉴权,接下来 Kubernetes apiserver 现在准备将请求发送到 Extension apiserver。
2.3、Kubernetes Apiserver 代理请求
Kubernetes apiserver 现在将请求发送或代理到注册以处理该请求的 Extension apiserver。为此,它需要了解几件事:
- Kubernetes apiserver 应该如何向 Extension apiserver 认证,以通知 Extension apiserver 通过网络发出的请求来自有效的 Kubernetes apiserver?
- Kubernetes apiserver 应该如何通知 Extension apiserver 原始请求已通过认证的用户名和组?
简而言之,就是 Kubernetes apiserver 已经认证和鉴权用户的请求,怎么这这些信息传递给 Extension apiserver,为提供这两条信息,我们必须使用若干标志来配置 Kubernetes apiserver。
2.3.1、Kubernetes Apiserver 客户端认证
Kubernetes apiserver 通过 TLS 连接到 Extension apiserver,并使用客户端证书认证,这里 Kubernetes apiserver (aggregator or proxy) 是 Extension apiserver 的客户端。必须在启动时使用提供的标志向 Kubernetes apiserver 提供以下内容:
- 通过
--proxy-client-key-file
指定私钥文件 - 通过
--proxy-client-cert-file
签名的客户端证书文件 - 通过
--requestheader-client-ca-file
签署客户端证书文件的 CA 证书 - 通过
--requestheader-allowed-names
在签署的客户证书中有效的公用名(CN)
Kubernetes apiserver 将使用由 –proxy-client-*-file
指示的文件来通过 Extension apiserver 验证。为了使合规的 Extension apiserver 能够将该请求视为有效,必须满足以下条件:
- 连接必须使用由 CA 签署的客户端证书,该证书的证书位于
--requestheader-client-ca-file
中。 - 连接必须使用客户端证书,该客户端证书的 CN 是
--requestheader-allowed-names
中列出的证书之一。 注意:您可以将此选项设置为空白,即为--requestheader-allowed-names=""
。这将向扩展 apiserver 指示任何 CN 是可接受的。
使用这些选项启动时,Kubernetes apiserver 将:
- 使用它们来通过 Extension apiserver 的认证。
- 在名为
kube-system
命名空间中创建一个 configmapextension-apiserver-authentication
,它将在其中放置 CA 证书和允许的 CN。反过来,Extension apiserver 可以检索这些内容以验证请求。
2.3.2、原始请求用户名和组
当 Kubernetes apiserver 将请求代理到 Extension apiserver 时,它将向 Extension apiserver 通知原始请求已成功通过其验证的用户名和组。它在其代理请求的 http 标头中提供这些。您必须将要使用的标头名称告知 Kubernetes apiserver。
- 通过
--requestheader-username-headers
标明用来保存用户名的头部 - 通过
--requestheader-group-headers
标明用来保存 group 的头部 - 通过
--requestheader-extra-headers-prefix
标明用来保存拓展信息前缀的头部
这些标头名称也放置在extension-apiserver-authentication
的 configmap 中,因此 Extension apiserver 可以检索和使用它们。
2.4、Extension apiserver 认证
Extension apiserver 在收到来自 Kubernetes apiserver 的代理请求后,必须验证该请求确实确实来自有效的身份验证代理,该认证代理由 Kubernetes apiserver 履行。Extension apiserver 通过以下方式对其认证:
- 如上所述,从
kube-system
中的 configmap 中检索以下内容:
- 客户端 CA 证书
--requestheader-client-ca-file
。 - 允许名称(CN)列表
--requestheader-allowed-names
。 - 用户名,组和其他信息的头部。
- 使用以下证书检查 TLS 连接是否已通过认证:
- 由其证书与检索到的 CA 证书匹配的 CA 签名。
- 在允许的 CN 列表中有一个 CN,除非列表为空,在这种情况下允许所有 CN。
- 从适当的头部中提取用户名和组。
如果以上均通过,则该请求是来自合法认证代理(在本例中为 Kubernetes apiserver)的有效代理请求。
为了具有检索 configmap 的权限,Extension apiserver 需要适当的角色。在 kube-system
名字空间中有一个默认角色extension-apiserver-authentication-reader
可用于设置。
2.5、Extension apiserver 对请求鉴权
Extension apiserver 现在可以验证从标头检索的user/group
是否有权执行给定请求。通过向 Kubernetes apiserver 发送标准 SubjectAcce***eview 请求来实现。
SubjectAcce***eview
是 authorization.k8s.io
API 组的一部分资源,它将 API 服务器授权公开给外部服务。该 API 组中的其他资源可以通过如下命令查看:
kubectl get --raw /apis/authorization.k8s.io/v1/
为了使 Extension apiserver 本身被鉴权可以向 Kubernetes apiserver 提交 SubjectAcce***eview 请求,它需要正确的权限。Kubernetes 包含一个具有相应权限的名为system:auth-delegator
的默认 ClusterRole
,可以将其授予 Extension apiserver 的服务帐户。
2.6、Extension apiserver 执行
如果SubjectAcce***eview
通过,则扩展 apiserver 执行请求。
三、部署过程
3.1、安装 cfssl
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /usr/local/bin/cfssl
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /usr/local/bin/cfssljson
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -O /usr/local/bin/cfssl-certinfo
cd /usr/local/bin/
chmod +x cfssl cfssljson cfssl-certinfo
3.2、创建 CA
3.2.3、CA 配置文件
$ cat > aggregator-ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"aggregator": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
}
EOF
-
profiles
: 可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile。 -
signing
:表示该证书可用于签名其它证书;生成的 aggregator-ca.pem 证书中CA=TRUE
。 -
server auth
:表示 Client 可以用该 CA 对 Server 提供的证书进行验证。 -
client auth
:表示 Server 可以用该 CA 对 Client 提供的证书进行验证。
3.2.3、创建 CA 证书签名请求
$ cat > aggregator-ca-csr.json <<EOF
{
"CN": "aggregator",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "wzlinux"
}
],
"ca": {
"expiry": "87600h"
}
}
-
“CN” :
Common Name
,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name);浏览器使用该字段验证网站是否合法。 -
“O” :
Organization
,kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group);
3.2.4、生成 CA 证书和私钥
cfssl gencert -initca aggregator-ca-csr.json | cfssljson -bare aggregator-ca
3.3、创建 kubernetes 证书
3.3.1、创建 aggregator 证书签名请求
$ cat > aggregator-csr.json <<EOF
{
"CN": "aggregator",
"hosts": [
"127.0.0.1",
"172.18.0.101",
"172.18.0.102",
"172.18.0.103",
"10.96.0.1",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "wzlinux"
}
]
}
如果 hosts 字段不为空则需要指定授权使用该证书的 IP 或域名列表,由于该证书后续kubernetes master 集群使用,所以上面指定kubernetes master
集群的主机 IP 和 kubernetes 服务的服务 IP(一般是 kube-apiserver 指定的 service-cluster-ip-range
网段的第一个 IP,如 10.96.0.1)。
3.3.2、生成 aggreagtor 证书和私钥
cfssl gencert -ca=aggregator-ca.pem -ca-key=aggregator-ca-key.pem -config=aggregator-ca-config.json -profile=aggregator aggregator-csr.json | cfssljson -bare aggregator
3.3.3、分发证书
将生成的证书和秘钥文件(后缀名为.pem)拷贝到 Master 节点的 /etc/kubernetes/pki
目录下备用。
3.4、开启聚合层 API
kube-apiserver
增加以下配置:
--requestheader-client-ca-file=/etc/kubernetes/pki/aggregator-ca.pem
--requestheader-allowed-names=aggregator
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--proxy-client-cert-file=/etc/kubernetes/pki/aggregator.pem
--proxy-client-key-file=/etc/kubernetes/pki/aggregator-key.pem
前面创建的证书的
CN
字段的值必须和参数–requestheader-allowed-names
指定的值aggregator
相同。
重启 kube-apiserver:
$ systemctl daemon-reload
$ systemctl restart kube-apiserver
如果 kube-proxy
没有在 Master 上面运行,kube-proxy
还需要添加配置:
--enable-aggregator-routing=true