Exposing Services in Kubernetes

Unterstützen Sie HackTricks

Es gibt verschiedene Möglichkeiten, Services in Kubernetes freizugeben, damit sowohl interne Endpunkte als auch externe Endpunkte darauf zugreifen können. Diese Kubernetes-Konfiguration ist ziemlich kritisch, da der Administrator Angreifern Zugriff auf Services geben könnte, auf die sie keinen Zugriff haben sollten.

Automatische Enumeration

Bevor Sie damit beginnen, die Möglichkeiten zu enumerieren, die K8s bietet, um Services für die Öffentlichkeit freizugeben, wissen Sie, dass Sie, wenn Sie Namespaces, Services und Ingresses auflisten können, alles, was der Öffentlichkeit zugänglich ist, finden können mit:

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

Ein ClusterIP-Dienst ist der Standard-Kubernetes-Dienst. Es bietet Ihnen einen Dienst innerhalb Ihres Clusters, auf den andere Apps innerhalb Ihres Clusters zugreifen können. Es gibt keinen externen Zugriff.

Es kann jedoch über den Kubernetes-Proxy zugegriffen werden:

kubectl proxy --port=8080

Nun kannst du durch die Kubernetes API navigieren, um auf Services mit diesem Schema zuzugreifen:

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

Zum Beispiel könntest du die folgende URL verwenden:

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

um auf diesen Service zuzugreifen:

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

Dieser Methode erfordert, dass Sie kubectl als authentifizierter Benutzer ausführen.

Liste alle 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

Wenn NodePort verwendet wird, wird ein bestimmter Port auf allen Nodes (die virtuelle Maschinen repräsentieren) zur Verfügung gestellt. Der Datenverkehr, der an diesen spezifischen Port gerichtet ist, wird dann systematisch zum Dienst geroutet. In der Regel wird diese Methode aufgrund ihrer Nachteile nicht empfohlen.

Liste alle NodePorts auf:

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

Ein Beispiel für die NodePort-Spezifikation:

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

Wenn Sie nodePort nicht in der yaml angeben (es ist der Port, der geöffnet wird), wird ein Port im Bereich 30000–32767 verwendet.

LoadBalancer

Stellt den Service extern unter Verwendung eines Load Balancers des Cloud-Anbieters bereit. Auf GKE wird dies einen Network Load Balancer starten, der Ihnen eine einzelne IP-Adresse zur Verfügung stellt, die den gesamten Datenverkehr an Ihren Service weiterleitet. Bei AWS wird ein Load Balancer gestartet.

Sie müssen für jeden freigegebenen Service einen LoadBalancer bezahlen, was teuer sein kann.

Liste alle LoadBalancer auf:

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

Externe IPs

Externe IPs werden von Diensten des Typs Load Balancers freigelegt und werden in der Regel verwendet, wenn ein externer Cloud-Provider-Load-Balancer verwendet wird.

Um sie zu finden, überprüfen Sie Load Balancer mit Werten im Feld EXTERNAL-IP.

Der Datenverkehr, der in den Cluster mit der externen IP (als Ziel-IP) eintritt, wird auf den Serviceport geroutet und an einen der Service-Endpunkte weitergeleitet. externalIPs werden nicht von Kubernetes verwaltet und liegen in der Verantwortung des Cluster-Administrators.

In der Service-Spezifikation können externalIPs zusammen mit einem der ServiceTypes angegeben werden. Im folgenden Beispiel kann auf den Dienst "my-service" von Clients unter "80.11.12.10:80" (externalIP:port) zugegriffen werden.

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

Aus den Dokumenten: Services vom Typ ExternalName ordnen einen Service einem DNS-Namen zu, nicht einem typischen Selektor wie my-service oder cassandra. Diese Services werden mit dem Parameter spec.externalName spezifiziert.

Diese Service-Definition ordnet beispielsweise den Service my-service im Namespace prod zu my.database.example.com:

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

Wenn Sie den Host my-service.prod.svc.cluster.local nachschlagen, gibt der Cluster-DNS-Dienst einen CNAME-Datensatz mit dem Wert my.database.example.com zurück. Der Zugriff auf my-service funktioniert genauso wie bei anderen Diensten, jedoch mit dem entscheidenden Unterschied, dass die Umleitung auf DNS-Ebene statt über Proxying oder Weiterleitung erfolgt.

Liste alle ExternalNames auf:

kubectl get services --all-namespaces | grep ExternalName

Ingress

Im Gegensatz zu allen obigen Beispielen ist Ingress KEIN Typ von Service. Stattdessen sitzt es vor mehreren Services und fungiert als "intelligenter Router" oder Einstiegspunkt in Ihren Cluster.

Sie können viele verschiedene Dinge mit einem Ingress tun, und es gibt viele Arten von Ingress-Controllern, die unterschiedliche Fähigkeiten haben.

Der Standard GKE Ingress-Controller wird einen HTTP(S) Load Balancer für Sie starten. Dies ermöglicht Ihnen sowohl das Routing basierend auf Pfaden als auch das Routing basierend auf Subdomains zu Backend-Services. Zum Beispiel können Sie alles auf foo.yourdomain.com zum Foo-Service senden und alles unter dem Pfad yourdomain.com/bar/ zum Bar-Service.

Das YAML für ein Ingress-Objekt auf GKE mit einem L7 HTTP Load Balancer könnte so aussehen:

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

Liste alle Eingänge auf:

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

Obwohl es in diesem Fall besser ist, die Informationen einzeln abzurufen, um sie besser lesen zu können:

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

Referenzen

Unterstützen Sie HackTricks

Last updated