Exposing Services in Kubernetes

Підтримайте HackTricks

Існують різні способи викриття сервісів в 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:

kubectl proxy --port=8080

Зараз ви можете перейти до API Kubernetes, щоб отримати доступ до сервісів за допомогою цієї схеми:

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

Якщо ви не вказуєте nodePort в yaml (це порт, який буде відкрито), буде використано порт у діапазоні від 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

Зовнішні IP-адреси

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

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

Трафік, який входить у кластер з зовнішнім 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.

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

Перелік усіх ExternalNames:

kubectl get services --all-namespaces | grep ExternalName

Ingress

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

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

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

YAML для об'єкта Ingress на GKE з L7 HTTP балансувальником навантаження може виглядати наступним чином:

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

Перелік усіх входів:

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

Посилання

Підтримайте HackTricks

Last updated