通过源码分析告诉你:当访问K8S API的代码运行在POD里的容器时,在集群内是如何进行身份验证的

由示例代码引出主题

当访问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文件确实是存在的:

  1. /var/run/secrets/kubernetes.io/serviceaccount/ca.crt:这是一个用于验证与Kubernetes API服务器通信的CA(证书颁发机构)证书。容器可以使用该证书来建立安全连接并验证API服务器的身份。
  2. /var/run/secrets/kubernetes.io/serviceaccount/namespace:该文件包含当前Pod所在的命名空间(Namespace)的名称。命名空间用于在Kubernetes集群中对资源进行逻辑隔离。
  3. /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

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!