Exposing Services in Kubernetes

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Υπάρχουν διαφορετικοί τρόποι για να εκθέσετε υπηρεσίες στο Kubernetes ώστε τόσο οι εσωτερικοί όσο και οι εξωτερικοί τελικοί χρήστες να μπορούν να τις προσπελάσουν. Αυτή η ρύθμιση του Kubernetes είναι αρκετά κρίσιμη καθώς ο διαχειριστής θα μπορούσε να δώσει πρόσβαση σε επιτιθέμενους σε υπηρεσίες που δεν θα έπρεπε να έχουν πρόσβαση.

Automatic Enumeration

Πριν ξεκινήσετε να απαριθμείτε τους τρόπους που προσφέρει το K8s για να εκθέσετε υπηρεσίες στο κοινό, γνωρίστε ότι αν μπορείτε να καταγράψετε namespaces, υπηρεσίες και ingresses, μπορείτε να βρείτε τα πάντα εκτεθειμένα στο κοινό με:

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. Σας παρέχει μια υπηρεσία μέσα στο cluster σας που μπορούν να προσπελάσουν άλλες εφαρμογές μέσα στο cluster σας. Δεν υπάρχει εξωτερική πρόσβαση.

Ωστόσο, αυτό μπορεί να προσπελαστεί χρησιμοποιώντας τον 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

Αν δεν καθορίσετε το nodePort στο yaml (είναι η θύρα που θα ανοιχτεί) θα χρησιμοποιηθεί μια θύρα στην εμβέλεια 30000–32767.

LoadBalancer

Εκθέτει την Υπηρεσία εξωτερικά χρησιμοποιώντας τον φορτωτή ισχύος ενός παρόχου cloud. Στο GKE, αυτό θα εκκινήσει έναν Network Load Balancer που θα σας δώσει μια μοναδική διεύθυνση IP που θα προωθεί όλη την κίνηση στην υπηρεσία σας. Στο AWS θα εκκινήσει έναν Load Balancer.

Πρέπει να πληρώσετε για έναν LoadBalancer ανά εκτεθειμένη υπηρεσία, κάτι που μπορεί να είναι ακριβό.

Λίστα όλων των LoadBalancers:

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 και γενικά χρησιμοποιούνται όταν χρησιμοποιείται ένας εξωτερικός Load Balancer Cloud Provider.

Για να τις βρείτε, ελέγξτε για load balancers με τιμές στο πεδίο EXTERNAL-IP.

Η κίνηση που εισέρχεται στο cluster με την εξωτερική IP (ως destination IP), στην θύρα της Υπηρεσίας, θα δρομολογηθεί σε ένα από τα endpoints της Υπηρεσίας. Οι externalIPs δεν διαχειρίζονται από το Kubernetes και είναι ευθύνη του διαχειριστή του cluster.

Στην προδιαγραφή της Υπηρεσίας, οι 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 στο namespace 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 αντί μέσω proxy ή προώθησης.

Λίστα όλων των ExternalNames:

kubectl get services --all-namespaces | grep ExternalName

Ingress

Σε αντίθεση με όλα τα παραπάνω παραδείγματα, το Ingress ΔΕΝ είναι τύπος υπηρεσίας. Αντίθετα, βρίσκεται μπροστά από πολλές υπηρεσίες και λειτουργεί ως “έξυπνος δρομολογητής” ή σημείο εισόδου στο cluster σας.

Μπορείτε να κάνετε πολλά διαφορετικά πράγματα με ένα Ingress, και υπάρχουν πολλοί τύποι Ingress controllers που έχουν διαφορετικές δυνατότητες.

Ο προεπιλεγμένος GKE ingress controller θα δημιουργήσει έναν HTTP(S) Load Balancer για εσάς. Αυτό θα σας επιτρέψει να κάνετε δρομολόγηση τόσο με βάση τη διαδρομή όσο και με βάση το υποτομέα προς τις υπηρεσίες backend. Για παράδειγμα, μπορείτε να στείλετε τα πάντα στο foo.yourdomain.com στην υπηρεσία foo, και τα πάντα κάτω από τη διαδρομή yourdomain.com/bar/ στην υπηρεσία bar.

Το YAML για ένα αντικείμενο Ingress στο GKE με έναν L7 HTTP Load Balancer μπορεί να μοιάζει έτσι:

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

Αναφορές

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks