在Kubernetes中暴露服务
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
在Kubernetes中有不同的方式来暴露服务,以便内部和外部端点都可以访问它们。这个Kubernetes配置非常关键,因为管理员可能会给攻击者访问他们不应该能够访问的服务的权限。
自动枚举
在开始枚举K8s提供的暴露服务的方式之前,请知道如果您可以列出命名空间、服务和入口,则可以找到所有暴露给公众的内容:
kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
echo "Namespace: $ns"
kubectl get service -n "$ns"
kubectl get ingress -n "$ns"
echo "=============================================="
echo ""
echo ""
done | grep -v "ClusterIP"
# Remove the last '| grep -v "ClusterIP"' to see also type ClusterIP
ClusterIP
一个 ClusterIP 服务是 默认 的 Kubernetes 服务。它为您提供一个 集群内部 的服务,集群内的其他应用可以访问。没有 外部访问。
然而,这可以通过 Kubernetes Proxy 访问:
kubectl proxy --port=8080
现在,您可以通过以下方案导航 Kubernetes API 以访问服务:
http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/
例如,您可以使用以下 URL:
http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/
来访问此服务:
apiVersion: v1
kind: Service
metadata:
name: my-internal-service
spec:
selector:
app: my-app
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
此方法要求您以 经过身份验证的用户 身份运行 kubectl。
列出所有 ClusterIPs:
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep ClusterIP
NodePort
当 NodePort 被使用时,所有节点(代表虚拟机)上会开放一个指定的端口。流量 定向到这个特定端口后,会系统地 路由到服务。通常,由于其缺点,这种方法不推荐使用。
列出所有 NodePorts:
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep NodePort
NodePort规格的示例:
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
selector:
app: my-app
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30036
protocol: TCP
如果您不指定yaml中的nodePort(这是将要打开的端口),将使用30000–32767范围内的端口。
LoadBalancer
通过使用云提供商的负载均衡器将服务公开到外部。在GKE上,这将启动一个网络负载均衡器,它将为您提供一个单一的IP地址,该地址将所有流量转发到您的服务。在AWS上,它将启动一个负载均衡器。
您必须为每个公开的服务支付负载均衡器的费用,这可能会很昂贵。
列出所有负载均衡器:
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer
外部 IPs
Tip
外部 IPs 是由类型为 Load Balancers 的服务暴露的,通常在使用外部 Cloud Provider Load Balancer 时使用。
要查找它们,请检查
EXTERNAL-IP字段中有值的负载均衡器。
流量以 external IP(作为 目标 IP)进入集群时,将在服务端口上被 路由到其中一个服务端点。externalIPs 不是由 Kubernetes 管理的,而是集群管理员的责任。
在服务规格中,externalIPs 可以与任何 ServiceTypes 一起指定。在下面的示例中,“my-service” 可以通过 “80.11.12.10:80”(externalIP:port)被客户端访问。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
ExternalName
来自文档: ExternalName 类型的服务 将服务映射到 DNS 名称,而不是典型的选择器,如 my-service 或 cassandra。您可以使用 spec.externalName 参数指定这些服务。
例如,此服务定义将 prod 命名空间中的 my-service 服务映射到 my.database.example.com:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
当查找主机 my-service.prod.svc.cluster.local 时,集群 DNS 服务返回一个值为 my.database.example.com 的 CNAME 记录。访问 my-service 的方式与其他服务相同,但有一个关键的区别,即 重定向发生在 DNS 层面 而不是通过代理或转发。
列出所有 ExternalNames:
kubectl get services --all-namespaces | grep ExternalName
Ingress
与上述所有示例不同,Ingress 不是一种服务。相反,它位于**多个服务前面,充当“智能路由器”**或进入集群的入口点。
您可以使用 Ingress 做很多不同的事情,并且有许多类型的 Ingress 控制器具有不同的功能。
默认的 GKE ingress 控制器将为您启动一个 HTTP(S) Load Balancer。这将允许您对后端服务进行基于路径和子域的路由。例如,您可以将 foo.yourdomain.com 上的所有请求发送到 foo 服务,将 yourdomain.com/bar/ 路径下的所有请求发送到 bar 服务。
在 GKE 上使用 L7 HTTP Load Balancer 的 Ingress 对象的 YAML 可能如下所示:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
backend:
serviceName: other
servicePort: 8080
rules:
- host: foo.mydomain.com
http:
paths:
- backend:
serviceName: foo
servicePort: 8080
- host: mydomain.com
http:
paths:
- path: /bar/*
backend:
serviceName: bar
servicePort: 8080
列出所有的 ingresses:
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
虽然在这种情况下,逐个获取每个信息以便更好地阅读是更好的选择:
kubectl get ingresses --all-namespaces -o=yaml
参考
- https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0
- https://kubernetes.io/docs/concepts/services-networking/service/
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks Cloud

