Exposing Services in Kubernetes

Reading time: 7 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримка HackTricks

Існує різні способи експонування сервісів у Kubernetes, щоб як внутрішні, так і зовнішні кінцеві точки могли до них отримати доступ. Ця конфігурація Kubernetes є досить критичною, оскільки адміністратор може надати доступ зловмисникам до сервісів, до яких вони не повинні мати доступ.

Automatic Enumeration

Перед тим, як почати перераховувати способи, які K8s пропонує для експонування сервісів публічно, знайте, що якщо ви можете перерахувати простори імен, сервіси та інгреси, ви можете знайти все, що експоновано публічно за допомогою:

bash
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:

bash
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/

щоб отримати доступ до цього сервісу:

yaml
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:

bash
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, призначений порт стає доступним на всіх вузлах (які представляють віртуальні машини). Трафік, спрямований на цей конкретний порт, систематично перенаправляється на сервіс. Зазвичай цей метод не рекомендується через його недоліки.

Список усіх NodePort:

bash
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:

yaml
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

Якщо ви не вкажете nodePort у yaml (це порт, який буде відкритий), буде використано порт у діапазоні 30000–32767.

LoadBalancer

Відкриває Сервіс зовні за допомогою балансувальника навантаження постачальника хмари. У GKE це запустить Network Load Balancer, який надасть вам одну IP-адресу, що буде пересилати весь трафік до вашого сервісу. У AWS це запустить Load Balancer.

Вам потрібно платити за LoadBalancer за кожен відкритий сервіс, що може бути дорого.

Список усіх LoadBalancers:

bash
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

External IPs

tip

Зовнішні IP-адреси відкриті службами типу Load Balancers і зазвичай використовуються, коли використовується зовнішній Cloud Provider Load Balancer.

Щоб їх знайти, перевірте навантажувачі з значеннями в полі EXTERNAL-IP.

Трафік, який входить у кластер з зовнішнім IP (як цільовий IP), на порту служби, буде направлений на одну з кінцевих точок служби. externalIPs не керуються Kubernetes і є відповідальністю адміністратора кластера.

У специфікації служби externalIPs можуть бути вказані разом з будь-яким з ServiceTypes. У наведеному нижче прикладі, "my-service" може бути доступний клієнтами на "80.11.12.10:80" (externalIP:port)

yaml
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.

Це визначення Сервісу, наприклад, відображає Сервіс my-service в просторі імен prod на my.database.example.com:

yaml
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 кластера повертає запис CNAME зі значенням my.database.example.com. Доступ до my-service працює так само, як і з іншими службами, але з важливою різницею, що перенаправлення відбувається на рівні DNS, а не через проксування або пересилання.

Перерахуйте всі ExternalNames:

bash
kubectl get services --all-namespaces | grep ExternalName

Ingress

На відміну від усіх наведених вище прикладів, Ingress НЕ є типом служби. Натомість, він знаходиться попереду кількох служб і діє як “розумний маршрутизатор” або точка входу у ваш кластер.

Ви можете робити багато різних речей з Ingress, і існує багато типів контролерів Ingress, які мають різні можливості.

Контролер Ingress за замовчуванням GKE створить для вас HTTP(S) Load Balancer. Це дозволить вам здійснювати маршрутизацію як на основі шляху, так і на основі піддомену до бекенд-служб. Наприклад, ви можете надіслати все на foo.yourdomain.com до служби foo, а все під шляхом yourdomain.com/bar/ до служби bar.

YAML для об'єкта Ingress на GKE з L7 HTTP Load Balancer може виглядати так:

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

Список всіх вхідних точок:

bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'

Хоча в цьому випадку краще отримувати інформацію про кожен окремо, щоб легше її читати:

bash
kubectl get ingresses --all-namespaces -o=yaml

Посилання

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримка HackTricks