【DevOps基础篇之k8s】Kubernetes API服务器认证/授权
@TOC
推荐超级课程:
Kubernetes API Server
Kubernetes控制平面的核心是API服务器。 API服务器暴露了一个HTTP API,使终端用户、集群的不同部分以及外部组件能够相互通信。 它允许您查询和操作Kubernetes中API对象的状态(例如:Pods、Namespaces、ConfigMaps和Events)。 API服务器是整个集群的主要管理点。简而言之,它处理REST操作,对其进行验证,并更新etcd中相应的对象。 API服务器提供Kubernetes API,并且旨在成为一个相对简单的服务器,大部分业务逻辑在单独的组件或插件中实现。
以下是API服务器中暴露的一些示例API。
# pods
api/v1/pods
# services
api/v1/services
# deployments
api/v1/deployments
当您使用kubectl命令行界面与您的Kubernetes集群进行交互时,实际上是在与主API服务器组件进行通信。kubectl命令转换为HTTP REST调用并在API服务器中调用。API服务器还负责认证和授权机制。所有API客户端都应进行身份验证以与API服务器交互。您可以使用这个API服务器编写Kubernetes客户端库/应用程序(例如您自己的kubectl、您自己的用于k8s的混沌工程系统)。
以下图显示了API服务器的架构和请求处理流程。
在本篇文章中,我将讨论如何使用curl命令行工具通过Kubernets API函数访问。
API服务器主机和端口
要调用任何API,您首先需要知道其服务器地址。 在Kubernetes的情况下,每个集群都有一个API服务器(我使用Minikube部署了K8s集群)。 因此,找到API主机和端口最简单的方法是查看kubectl cluster-info输出。 如下面的示例所示,API服务器运行在https://192.168.64.30:8443上。192.168.64.30是Minikube的IP,它在端口8443上公开HTTPS API。
# view cluster api server host and port
❯❯ kubectl cluster-info
Kubernetes control plane is running at https://192.168.64.30:8443
CoreDNS is running at https://192.168.64.30:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
API服务器认证/授权
默认情况下,Kubernetes通过HTTPS公开其API,特别是为了向客户端保证API服务器的强身份。 要调用此API,客户端请求需要实现正确的身份验证(认证和授权)。 我们可以使用两种主要的身份验证机制来处理API服务器的认证: 1)基于SSL证书的认证,2)基于令牌的认证。
基于SSL证书的认证
验证API请求的第一种方法是通过SSL证书。
正如我所提到的,我使用Minikube部署了Kubernetes集群。Minikube使用自签名证书引导本地集群。
因此,Kubernetes API服务器的TLS证书实际上是由Certificate Authority(CA)MinikubeCA签名的。
由MinikubeCA签名的证书是由Kubernetes API服务器信任的。
然而,curl并不知道这个MinikubeCA。默认情况下,curl信任与操作系统底层相同的一组CA。例如,在Ubuntu或Debian上,可在/etc/ssl/certs/ca-certificates.crt
找到信任的CA列表。Minikube没有将其证书添加到此文件中。
因此,我们首先需要将位于~/.minikube/ca.crt
中的MinikubeCA证书添加到curl命令中。
接下来,我们需要在curl请求中定义客户端证书信息。在引导集群时,Minikube还创建了一个用户。该用户获得了由相同MinikubeCA机构签名的证书。由于此CA被Kubernetes API服务器信任,因此在请求中呈现此证书将使其被验证为所述用户。
基本上,任何用户只要呈现由集群证书颁发机构签名的有效证书就被视为已认证。
客户端证书位于~/.minikube/profiles/minikube/client.crt
中。
客户端私钥位于~/.minikube/profiles/minikube/client.key
中。
我们需要在curl请求中设置客户端证书和客户端密钥以与API服务器进行身份验证。
# ca certificate location
❯❯ cat ~/.minikube/ca.crt | openssl x509 -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=minikubeCA
Validity
Not Before: Jun 16 07:13:11 2022 GMT
Not After : Jun 14 07:13:11 2032 GMT
Subject: CN=minikubeCA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
# cliet certificate location
❯❯ cat ~/.minikube/profiles/minikube/client.crt | openssl x509 -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=minikubeCA
Validity
Not Before: Jun 16 07:13:12 2022 GMT
Not After : Jun 16 07:13:12 2025 GMT
Subject: O=system:masters, CN=minikube-user
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
# client key location
❯❯ ls ~/.minikube/profiles/minikube/client.key
/Users/eranga/.minikube/profiles/minikube/client.key
---
# send request to api server with ca cert, client cert and client key
curl --cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/minikube/client.crt \
--key ~/.minikube/profiles/minikube/client.key \
https://192.168.64.30:8443/apis/apps/v1/deployments
# output
{
"kind": "DeploymentList",
"apiVersion": "apps/v1",
"metadata": {
"resourceVersion": "26715"
},
"items": [
--
--
]
}
基于令牌的认证
通过使用包含有效Service Account JWT令牌的bearer头部来验证API请求的另一种方法。 与用户类似,不同的Service Accounts将具有不同级别的访问权限。 我已经在之前的博客文章中详细讨论了有关服务帐户和访问级别(角色、集群角色等)的信息。在本篇文章中,我不会详细讨论Kubernetes服务帐户和权限处理的细节,因为我在之前的博客中已经详细讨论了相关信息。
服务帐户具有一个令牌。此令牌存储为一个Kubernetes Secret,并且可以读取为一个Secret。这个令牌是您将用于将第三方应用程序验证到Kubernetes API服务器的凭证。 在这种情况下,我创建了一个名为bassa-serviceaccount的Kubernetes服务帐户。然后,我使用ClusterRole定义了全局权限(例如获取、列出、监视Pods、服务、命名空间、部署、作业等)。 最后,通过ClusterRoleBinding将此ClusterRole分配给了服务帐户。 现在,服务账户内部的令牌可以用于验证/授权API服务器。我可以使用此令牌(带有bearer头部)调用Kubernetes API服务器API,并访问资源(例如Pods、服务、命名空间等)。
可以通过ClusterRoleBinding将此ClusterRole分配给服务帐户。这样,服务帐户就可以在集群中(所有命名空间)列出、获取、监视Pods。现在,我可以使用从前一步中提取的服务帐户令牌作为带有请求的Authorization头部的bearer令牌。
# bearer token assigned to BEARER_TOKEN env variable
export BEARER_TOKEN=xxxxxxxx
# set request to api server with Authorization header
# --cacert needs to be set since used minikube self signed certificates
❯❯ curl --cacert ~/.minikube/ca.crt \
--header "Authorization: Bearer $BEARER_TOKEN" \
https://192.168.64.30:8443/api/v1/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "28290"
},
"items": [
---
---
---
]
}