由示例代码引出主题
当访问K8S API的代码运行在POD里的容器时,这就涉及到在集群内进行身份验证,在GitHub中的client-go库里有这么一段示例代码:
func main() {
// creates the in-cluster config
config, err := rest.InClusterConfig()
if err != nil {
panic(err.Error())
}
}
❝
因此,本篇要搞清楚的问题是:当访问K8S API的代码运行在POD里的容器时,在集群内部是怎么做到身份验证的?
❞
先看InClusterConfig函数
-
client-go库文档链接:https://pkg.go.dev/k8s.io/client-go/rest#InClusterConfig -
安装该库后的本地路径:./pkg/mod/k8s.io/client-go@v0.27.1/rest/config.go
源码:
func InClusterConfig() (*Config, error) {
const (
tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
if len(host) == 0 || len(port) == 0 {
return nil, ErrNotInCluster
}
token, err := os.ReadFile(tokenFile)
if err != nil {
return nil, err
}
tlsClientConfig := TLSClientConfig{}
if _, err := certutil.NewPool(rootCAFile); err != nil {
klog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)
} else {
tlsClientConfig.CAFile = rootCAFile
}
return &Config{
// TODO: switch to using cluster DNS.
Host: "https://" + net.JoinHostPort(host, port),
TLSClientConfig: tlsClientConfig,
BearerToken: string(token),
BearerTokenFile: tokenFile,
}, nil
}
这段代码是用于在 Golang 的 client-go 库中创建针对 Kubernetes 集群的配置(Config)的函数 InClusterConfig()。它通过读取容器内的特定路径和环境变量来确定集群的配置信息。
在这段代码中,首先定义了两个常量:
const (
tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)
tokenFile 是用于存放身份验证令牌的文件路径,rootCAFile 是用于存放根证书的文件路径。
接下来,代码从环境变量中读取 KUBERNETES_SERVICE_HOST 和 KUBERNETES_SERVICE_PORT 的值,如果这两个环境变量都为空,则表示代码未在 Kubernetes 集群中运行,将返回错误 ErrNotInCluster。
然后,代码读取 tokenFile 中的身份验证令牌,并将其作为字符串赋值给 token 变量。
接下来,创建了一个 TLSClientConfig 结构体,并尝试从 rootCAFile 加载根证书配置。如果成功加载根证书,则将其设置为 TLSClientConfig 的 CAFile 字段。
最后,返回一个 Config 结构体,其中包含以下信息:
-
Host 字段被设置为 https:// : ,其中 和 从环境变量中获取。 -
TLSClientConfig 字段被设置为之前创建的 TLSClientConfig 结构体。 -
BearerToken 字段被设置为 token 的值(身份验证令牌)。 -
BearerTokenFile 字段被设置为 tokenFile 的路径。
这样,InClusterConfig() 函数就返回了一个用于与 Kubernetes 集群进行通信的配置对象。
验证
❝
接下来,进入POD里的容器验证上面的常量和环境变量,看看到底有没有这玩意。
❞
1. 查看ca.crt和token文件
拉起一个nginx pod看看:
[root@k8s-b-master ~]# kubectl run nginx --image=nginx
[root@k8s-b-master ~]# kubectl exec -it nginx -- sh
# cd /var/run/secrets/kubernetes.io/serviceaccount/
# ls -l
total 0
lrwxrwxrwx 1 root root 13 May 19 01:44 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 May 19 01:44 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 May 19 01:44 token -> ..data/token
#
再进入从之前制作的goweb镜像拉起的pod看看:
[root@k8s-b-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
goweb-7db674b88c-d544x 1/1 Running 0 13m
goweb-7db674b88c-j5hd6 1/1 Running 0 13m
goweb-7db674b88c-v2z5r 1/1 Running 0 13m
nginx 1/1 Running 0 22m
[root@k8s-b-master ~]# kubectl exec -it goweb-7db674b88c-d544x -- sh
/app # cd /var/run/secrets/kubernetes.io/serviceaccount/
/run/secrets/kubernetes.io/serviceaccount # ls -l
total 0
lrwxrwxrwx 1 root root 13 May 19 01:53 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 May 19 01:53 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 May 19 01:53 token -> ..data/token
/run/secrets/kubernetes.io/serviceaccount #
ca.crt和token文件确实是存在的:
-
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt:这是一个用于验证与Kubernetes API服务器通信的CA(证书颁发机构)证书。容器可以使用该证书来建立安全连接并验证API服务器的身份。 -
/var/run/secrets/kubernetes.io/serviceaccount/namespace:该文件包含当前Pod所在的命名空间(Namespace)的名称。命名空间用于在Kubernetes集群中对资源进行逻辑隔离。 -
/var/run/secrets/kubernetes.io/serviceaccount/token:这是一个用于进行身份验证的令牌。容器可以使用该令牌与Kubernetes API服务器进行身份验证,并获得对API的访问权限。
❝
这些路径下的文件和目录是由Kubernetes自动创建和管理的,它们提供了容器与Kubernetes集群的连接和身份验证所需的关键信息。容器可以使用这些信息与Kubernetes API进行交互,例如获取其他资源的信息、创建或修改资源等操作。「这样设计的好处是,在不暴露敏感信息的情况下,容器可以方便地与Kubernetes集群进行安全通信和交互。」
❞
serviceaccount目录下的符号链接指向..data目录,进去看看:
/run/secrets/kubernetes.io/serviceaccount # cd ..data
/run/secrets/kubernetes.io/serviceaccount/..2023_05_19_01_53_58.3090367996 # ls -l
total 12
-rw-r--r-- 1 root root 1099 May 19 01:53 ca.crt
-rw-r--r-- 1 root root 7 May 19 01:53 namespace
-rw-r--r-- 1 root root 1014 May 19 01:53 token
可以看出/run/secrets/kubernetes.io/serviceaccount目录下的符号链接指向..data目录,而进入..data目录后,可以看到实际的文件ca.crt、namespace和token。这是因为Kubernetes将Secrets(密钥、证书等敏感信息)以数据卷的形式挂载到Pod中时,会将这些敏感数据放在..data目录下,并使用符号链接的方式提供给容器访问。
❝
符号链接是一种特殊的文件类型,它只是指向其他文件或目录的引用。在这种情况下,ca.crt、namespace和token这三个符号链接文件指向了..data目录下的对应文件。当容器访问这些符号链接文件时,实际上是在访问..data目录中的文件。
❞
2. 查看环境变量
# 先进入nginx pod查看:
[root@k8s-b-master ~]# kubectl exec -it nginx -- sh
# echo $KUBERNETES_SERVICE_HOST
10.96.0.1
# echo $KUBERNETES_SERVICE_PORT
443
# 在进入goweb pod查看:
[root@k8s-b-master ~]# kubectl exec -it goweb-7db674b88c-d544x -- sh
/app # echo $KUBERNETES_SERVICE_HOST
10.96.0.1
/app # echo $KUBERNETES_SERVICE_PORT
443
两个环境变量确实是存在的:
-
$KUBERNETES_SERVICE_HOST 的值为 10.96.0.1。这是Kubernetes API服务器的服务地址,容器可以使用该地址与API服务器进行通信。 -
$KUBERNETES_SERVICE_PORT 的值为 443。这是Kubernetes API服务器的服务端口,容器可以使用该端口与API服务器建立连接。
❝
说明在容器内部可以通过环境变量获取到 Kubernetes API 服务器的地址和端口,
❞
最后查看下svc:
[root@k8s-b-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
goweb NodePort 10.99.232.213 <none> 5678:30080/TCP 22m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d # 主要看这个
[root@k8s-b-master ~]#
kubectl get svc 命令列出了当前集群中的服务。kubernetes 是一个类型为 ClusterIP 的服务,其集群内部 IP 地址为 10.96.0.1,外部 IP 地址为空。该服务在端口 443 上监听,用于提供 Kubernetes API 服务。
原文始发于微信公众号(不背锅运维):通过源码分析告诉你:当访问K8S API的代码运行在POD里的容器时,在集群内是如何进行身份验证的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/149469.html