Exposing Services in Kubernetes

Wesprzyj HackTricks

Istnieje różne sposoby ujawniania usług w Kubernetes, dzięki czemu zarówno wewnętrzne punkty końcowe, jak i zewnętrzne punkty końcowe mogą uzyskać do nich dostęp. Konfiguracja Kubernetes jest dość krytyczna, ponieważ administrator może udzielić dostępu atakującym do usług, do których nie powinni mieć dostępu.

Automatyczne Wyliczanie

Zanim zaczniesz wyliczać sposoby, jakie oferuje K8s do ujawniania usług publicznie, wiedz, że jeśli możesz wymienić przestrzenie nazw, usługi i wpisy, możesz znaleźć wszystko ujawnione publicznie za pomocą:

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

Usługa ClusterIP to domyślna usługa Kubernetes. Zapewnia ona usługę wewnątrz klastra, do której inne aplikacje wewnątrz klastra mogą uzyskać dostęp. Nie ma dostępu zewnętrznego.

Jednak można uzyskać do niej dostęp za pomocą Kubernetesa Proxy:

kubectl proxy --port=8080

Teraz możesz nawigować przez interfejs API Kubernetes, aby uzyskać dostęp do usług za pomocą tego schematu:

http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/

Na przykład, możesz użyć następującego adresu URL:

http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/

aby uzyskać dostęp do tej usługi:

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

Ta metoda wymaga uruchomienia kubectl jako uwierzytelniony użytkownik.

Lista wszystkich ClusterIPów:

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

Kiedy jest wykorzystywany NodePort, określony port jest udostępniany na wszystkich węzłach (reprezentujących maszyny wirtualne). Ruch skierowany do tego konkretnego portu jest następnie systematycznie kierowany do usługi. Zazwyczaj ta metoda nie jest zalecana ze względu na jej wady.

Lista wszystkich NodePortów:

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

Przykład specyfikacji 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

Jeśli nie określisz pola nodePort w pliku yaml (jest to port, który zostanie otwarty), zostanie użyty port z zakresu 30000–32767.

LoadBalancer

Wystawia usługę na zewnątrz za pomocą load balancera dostawcy chmury. Na GKE spowoduje to uruchomienie Network Load Balancer, który udostępni pojedynczy adres IP przekierowujący cały ruch do Twojej usługi. W AWS spowoduje to uruchomienie Load Balancera.

Trzeba płacić za każdy LoadBalancer na wystawioną usługę, co może być kosztowne.

Wyświetl wszystkie LoadBalancery:

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

Zewnętrzne adresy IP

Zewnętrzne adresy IP są udostępniane przez usługi typu Load Balancers i zazwyczaj są używane, gdy używany jest zewnętrzny Load Balancer dostawcy chmury.

Aby je znaleźć, sprawdź balansery obciążenia z wartościami w polu EXTERNAL-IP.

Ruch, który wchodzi do klastra z zewnętrznym adresem IP (jako adres docelowy IP), na porcie usługi, będzie kierowany do jednego z punktów końcowych usługi. externalIPs nie są zarządzane przez Kubernetes i są odpowiedzialnością administratora klastra.

W specyfikacji usługi, externalIPs mogą być określone wraz z dowolnymi ServiceTypes. W poniższym przykładzie "moja-usługa" może być dostępna dla klientów pod adresem "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

Z dokumentacji: Usługi typu ExternalName mapują usługę na nazwę DNS, a nie na typowy selektor, taki jak my-service lub cassandra. Określasz te Usługi za pomocą parametru spec.externalName.

Poniższa definicja Usługi mapuje Usługę my-service w przestrzeni nazw prod na my.database.example.com:

apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com

Gdy wyszukujemy hosta my-service.prod.svc.cluster.local, usługa DNS klastra zwraca rekord CNAME o wartości my.database.example.com. Dostęp do my-service działa tak samo jak w przypadku innych Usług, ale z istotną różnicą, że przekierowanie następuje na poziomie DNS, a nie poprzez proxy lub przekazywanie.

Lista wszystkich ExternalNames:

kubectl get services --all-namespaces | grep ExternalName

Ingress

W przeciwieństwie do wszystkich powyższych przykładów, Ingress NIE jest rodzajem usługi. Zamiast tego znajduje się przed wieloma usługami i działa jak "inteligentny router" lub punkt wejścia do klastra.

Możesz wykonać wiele różnych czynności za pomocą Ingress, a istnieje wiele rodzajów kontrolerów Ingress o różnych możliwościach.

Domyślny kontroler Ingress w GKE uruchomi Balancer obciążenia HTTP(S) dla Ciebie. Pozwoli to na zarządzanie ruchem zarówno na podstawie ścieżki, jak i subdomeny do usług backendowych. Na przykład możesz przekierować wszystko na foo.twojadomena.com do usługi foo, a wszystko pod ścieżką twojadomena.com/bar/ do usługi bar.

YAML dla obiektu Ingress w GKE z Balancerem obciążenia HTTP L7 może wyglądać tak:

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

Wypisz wszystkie wejścia:

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

Chociaż w tym przypadku lepiej jest uzyskać informacje o każdym z osobna, aby lepiej je przeczytać:

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

Odnośniki

Wesprzyj HackTricks

Last updated