写点什么

如何通过抓包来查看 Kubernetes API 流量

作者:Robert Lu
  • 2021 年 11 月 21 日
  • 本文字数:1870 字

    阅读完需:约 6 分钟

当我们通过 kubectl 来查看、修改 Kubernetes 资源时,有没有想过后面的接口到底是怎样的?有没有办法探查这些交互数据呢?


Kuberenetes 客户端和服务端交互的接口,是基于 http 协议的。所以只需要能够捕捉并解析 https 流量,我们就能看到 kubernetes 的 API 流量。


但是由于 kubenetes 使用了客户端私钥来实现对客户端的认证,所以抓包配置要复杂一点。具体是如下的结构:



如果想了解更多 Kubernetes 证书的知识,可以看下这篇Kubernetes证书解析的文章

从 kubeconfig 中提取出客户端证书和私钥

kubeconfig 中包含了客户端的证书和私钥,我们首先要把它们提取出来:


# 提取出客户端证书grep client-certificate-data ~/.kube/config | \  awk '{ print $2 }' | \  base64 --decode > client-cert.pem# 提取出客户端私钥grep client-key-data ~/.kube/config | \  awk '{ print $2 }' | \  base64 --decode > client-key.pem# 提取出服务端CA证书grep certificate-authority-data ~/.kube/config | \  awk '{ print $2 }' | \  base64 --decode > cluster-ca-cert.pem
复制代码


参考自Reddit

配置 Charles 代理软件

从第一张图可以看出,代理软件的作用有两个:一是接收 https 流量并转发,二是转发到 kubernetes apiserver 的时候,使用指定的客户端私钥。


首先配置 Charles,让他拦截所有的 https 流量:



然后配置客户端私钥,即对于发送到 apiserver 的请求,统一使用指定的客户端私钥进行认证:



配置 kubectl

需要抓包 kubectl 的流量,需要两个条件:1. kubectl 使用 Charles 作为代理,2. kubectl 需要信任 Charles 的证书。


# Charles的代理端口是8888,设置https_proxy环境变量,让kubectl使用Charles代理$ export https_proxy=http://127.0.0.1:8888/# insecure-skip-tls-verify表示不校验服务端证书$ kubectl --insecure-skip-tls-verify get podNAME                    READY   STATUS    RESTARTS   AGEsc-b-7f5dfb694b-xtfrz   2/2     Running   0          2d20h
复制代码


我们就可以看到get pod的网络请求了:



可以看到,get pod 的 endpoint 是GET /api/v1/namespaces/<namespace>/pods


让我们再尝试下创建 pod 的请求:


$ cat <<EOF >pod.yamlapiVersion: v1kind: Podmetadata:  name: nginx-robberphexspec:  containers:  - name: nginx    image: nginx:1.14.2EOF$ kubectl --insecure-skip-tls-verify apply -f pod.yamlpod/nginx-robberphex created
复制代码


也同样可以抓到包:



创建 pod 的 endpoint 是POST /api/v1/namespaces/<namespace>/pods

配置 kubenetes client

我们先从写一个用 kubernetes go client 来获取 pod 的例子(注意,代码中已经信任所有的证书,所以可以抓到包):


package main
/*require ( k8s.io/api v0.18.19 k8s.io/apimachinery v0.18.19 k8s.io/client-go v0.18.19)*/import ( "context" "flag" "fmt" "path/filepath"
apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir")
func main() { ctx := context.Background() var kubeconfig *string if home := homedir.HomeDir(); home != "" { kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file") } else { kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file") } flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) if err != nil { panic(err) } // 让clientset信任所有证书 config.TLSClientConfig.CAData = nil config.TLSClientConfig.Insecure = true clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err) } podClient := clientset.CoreV1().Pods(apiv1.NamespaceDefault) podList, err := podClient.List(ctx, metav1.ListOptions{}) if err != nil { panic(err) }
for _, pod := range podList.Items { fmt.Printf("podName: %s\n", pod.Name) }
fmt.Println("done!")}
复制代码


然后编译执行:


$ go build -o kube-client$ export https_proxy=http://127.0.0.1:8888/$ ./kube-clientpodName: nginx-robberphexpodName: sc-b-7f5dfb694b-xtfrzdone!
复制代码


这时也可以抓到同样的结果:



基于此,我们就可以分析一个 Kubernetes 到底干了什么,也是我们分析 Kubernetes​实现的入口。


发布于: 4 小时前阅读数: 4
用户头像

Robert Lu

关注

还未添加个人签名 2015.04.06 加入

阿里云高级开发工程师

评论

发布
暂无评论
如何通过抓包来查看Kubernetes API流量