10.k8s-Service 资产发现

Pasted image 20250414094643

1. 模拟环境

kind创建集群,一个master节点即可

docker pull kindest/node:v1.27.1

kind create cluster --config - --image kindest/node:v1.27.1 <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: demo
nodes:
- role: control-plane
EOF
Warning

kindest/node:v1.27.1 版本需要cgroups v2
执行以下操作切换到 cgroups v2

# 编辑 GRUB 配置
sudo vi /etc/default/grub
#删除以下参数(如果存在)
systemd.unified_cgroup_hierarchy=0
#在 GRUB_CMDLINE_LINUX 中添加以下参数 确保追加到现有参数后
GRUB_CMDLINE_LINUX="... systemd.unified_cgroup_hierarchy=1"  
#更新并重启
sudo update-grub && sudo reboot
#验证:
stat -fc %T /sys/fs/cgroup/  # 应输出 cgroup2fs  tmpfs则表示cgroups v1

在不同命名空间中创建多个Services

#service.yaml
apiVersion: v1
kind: Service
metadata:
  name: admin-service
  namespace: default
spec:
  selector:
    app: admin
  ports:
    - name: admin
      protocol: TCP
      port: 6003
      targetPort: 6003
---
apiVersion: v1
kind: Service
metadata:
  name: airtable-service
  namespace: kube-public
spec:
  selector:
    app: airtable
  ports:
    - name: airtable
      protocol: TCP
      port: 5006
      targetPort: 5006
---
apiVersion: v1
kind: Service
metadata:
  name: apple-service
  namespace: kube-system
spec:
  selector:
    app: apple
  ports:
    - name: apple
      protocol: TCP
      port: 7005
      targetPort: 7005
---
apiVersion: v1
kind: Service
metadata:
  name: aws-service
  namespace: default
spec:
  selector:
    app: aws
  ports:
    - name: aws
      protocol: TCP
      port: 5003
      targetPort: 5003
---
apiVersion: v1
kind: Service
metadata:
  name: class-service
  namespace: kube-public
spec:
  selector:
    app: class
  ports:
    - name: class
      protocol: TCP
      port: 6005
      targetPort: 6005
---
apiVersion: v1
kind: Service
metadata:
  name: clip-service
  namespace: kube-system
spec:
  selector:
    app: clip
  ports:
    - name: clip
      protocol: TCP
      port: 6004
      targetPort: 6004
---
apiVersion: v1
kind: Service
metadata:
  name: gateway-service
  namespace: default
spec:
  selector:
    app: gateway
  ports:
    - name: gateway
      protocol: TCP
      port: 5001
      targetPort: 5001
---
apiVersion: v1
kind: Service
metadata:
  name: manager-service
  namespace: kube-public
spec:
  selector:
    app: manager
  ports:
    - name: manager
      protocol: TCP
      port: 5004
      targetPort: 5004
---
apiVersion: v1
kind: Service
metadata:
  name: web3-service
  namespace: kube-system
spec:
  selector:
    app: web3
  ports:
    - name: web3
      protocol: TCP
      port: 6010
      targetPort: 6010
---
apiVersion: v1
kind: Service
metadata:
  name: webhooks-service
  namespace: default
spec:
  selector:
    app: webhooks
  ports:
    - name: webhooks
      protocol: TCP
      port: 5005
      targetPort: 5005
---
apiVersion: v1
kind: Service
metadata:
  name: http-https-service
  namespace: kube-public
spec:
  selector:
    app: http-https
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: http
    - name: https
      protocol: TCP
      port: 443
      targetPort: http

检查资源创建情况,kubectl get svc -A
Pasted image 20250413185014

默认情况下,Kubernetes Service 资源的 IP 范围为 10.96.0.0/12

创建一个 Pod,处于 default 命名空间,

docker pull alpine:latest
kind load docker-image --name demo alpine:latest

kubectl run test-pod --image=docker.io/library/alpine:latest --restart=Always --command -- /bin/sh -c "while true; do sleep 3600; done"

Pasted image 20250413185138

2. Service

Note

Service(服务)用于公开运行在一个或多个 Pod 上的应用程序。具体来说,Service 充当了 Pod 的负载均衡器,并为它们提供了统一的入口点,从而向外界公开应用程序

Service 被分配了一个集群内部可访问的 IP 地址,这个 IP 地址称为集群 IP(Cluster IP),用于在集群内部将流量路由到 Service 后端的 Pod,Service 通常将一个或多个端口暴露给外部流量,以便外部用户或应用程序可以访问 Pod 上的应用程序。与 Service 相关联的 DNS 记录允许通过 Service 名称来访问 Service,而不必直接使用 IP 地址,这些 DNS 记录由集群的 DNS 解析器管理,从而允许使用Service 名称来解析到对应的 IP 地址。

  默认情况下,Kubernetes Service 资源的 IP 范围为 10.96.0.0/12

当你创建一个 Service 对象时,Kubernetes 会自动在同一命名空间中的 Pod 中注入一些与这个 Service 相关的环境变量。这些环境变量包括了服务的地址和端口信息。跨命名空间的 Pod 不会自动获得其他命名空间中服务的地址和端口信息。 env | grep SERVICE_HOST
Pasted image 20250413185956
通过此方法我们就可以获取到部分service的网段

3. DNS

Kubernetes 中 DNS 解析器为集群中的 Service 自动创建的各种 DNS 记录,官网文档在DNS for Services and Pods | Kubernetes
DNS 记录包括:

  • Service 的 A 记录:将服务的 DNS 名称映射到服务的 Cluster IP 地址。
  • Service 的 PTR 记录:将服务的 Cluster IP 地址映射回服务的 DNS 名称,用于反向 DNS 查找。(给了我们枚举IP爆破的可能性)
  • Service 的 SRV 记录:对于每个服务,如果它有多个监听端口,Kubernetes 会为每个端口自动创建一个 SRV 记录,这些 SRV 记录提供了服务监听端口的详细信息。

 
服务的 DNS 名称为 <service-name>.<namespace>.svc.cluster.local. ,例如集群中默认存在的Service: kubernetes.default.svc.cluster.local. ,这个是 Kubernetes 集群内部用于访问Kubernetes API 服务器的默认域名,

分解来看:

  • kubernetes Kubernetes API 服务器的服务名称,默认情况下是 kubernetes 。
  • default Kubernetes API 服务器所在的命名空间,默认情况下是 default 。
  • svc.cluster.local. 默认情况下 Kubernetes 集群所有内部服务的 DNS 后缀都是这个。

SRV 记录提供服务监听端口的详细信息, _<port-name>._<port-protocol>.<service-name>.<namespace>.svc.cluster.local

分解来看:

  • <port-name> 端口的名称
  • <port-protocol> 端口的协议(例如 TCP 或 UDP)
  • <service-name> 服务的名称
  • <namespace> 服务所在的命名空间

这些 DNS 记录使得在 Kubernetes 集群中的应用程序可以通过服务名称和端口进行发现和访问,而无需直接使用 IP 地址。

4. PTR记录

Note

PTR记录是 DNS 中的一种反向解析记录,​可以通过 IP 地址查找对应的域名(service的DNS名字)

先给 alpine 容器安装 dig 工具,

sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
apk add bind-tools

我们可以对已知 IP 进行反向 DNS 查找,例如获取 Kubernetes API 服务器的 IP:

env | grep KUBERNETES_SERVICE_HOST

#再反查 DNS
dig +short -x 10.96.0.1 

Pasted image 20250413191232

5. SRV 记录

我们可以对已知 DNS 名称查找 SRV 记录:

Note

SRV 记录​(Service Record)是 DNS 系统中的一种特殊记录类型,用于指定某个服务对应的服务器地址和端口号
我们可以通过DNS获取到服务的端口

dig +short SRV kubernetes.default.svc.cluster.local.

Pasted image 20250413191258

输出结果解析
  • 0 这是 SRV 记录的优先级,指示客户端尝试连接的顺序。在这里优先级为 0,表示没有特定的优先级。
  • 100 这是 SRV 记录的权重,用于负载均衡。权重越高,被选中的概率越大。
  • 443 这是 SRV 记录指定的服务端口号。在这里是 Kubernetes API 服务器的服务端口。
  • kubernetes.default.svc.cluster.local. 该服务的 DNS 名称。

6. 自动化工具

如果我们正在一个 Pod 中,根据 PTR 记录和 SRV 记录的特点,可以得到一个对 Kubernetes Service 资产进行扫描的路径:对相关网段进行扫描,获取对应 IP 的 PTR 记录;对每一个 PTR 记录获取其 SRV 记录;也就是 service_ip --> service_dns_name --> service_port --> service_host ,最终获取 Service 资产 service_host

昨天某师傅开源的工具: https://github.com/Esonhugh/k8spider 本文章则是为这个工具做铺垫的。

该工具的视角是 Pod 中,
一般来说可以先确定一部分 Service 的网段 env | grep SERVICE_HOST
再对该网段进行扫描 ./k8spider-linux-amd64-upx all -c 10.96.0.1/16
成功获取集群中所有的Service 资产。当然前提是模拟环境中所有 Service 资产都在 10.96.0.1/16 网段中,在实际情况下,需要对这个网段附近其他网段进行探测以获取更完整的服务列表。

7. 解决

对于业务不需要 PTR 与 SRV 记录的集群,可以禁用 CoreDNS 的 PTR 与 SRV 记录。

#修改CoreDNS的配置文件
kubectl edit configmap/coredns -n kube-system

加入如下两句配置,wq 修改保存后等待十几秒,

template IN PTR .
template IN SRV .

经过该配置,CoreDNS 会拦截掉 PTR 与 SRV 记录。
Pasted image 20250413192214