# Izlaganje usluga u Kubernetesu

{{#include ../../banners/hacktricks-training.md}}

Postoje **različiti načini za izlaganje usluga** u Kubernetesu tako da i **interni** i **eksterni** krajnji tačke mogu da im pristupe. Ova Kubernetes konfiguracija je prilično kritična jer administrator može dati pristup **napadačima uslugama kojima ne bi trebali imati pristup**.

### Automatska enumeracija

Pre nego što počnete da enumerišete načine na koje K8s nudi izlaganje usluga javnosti, znajte da ako možete da listate namespace-ove, usluge i ingrese, možete pronaći sve što je izloženo javnosti sa:
```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** servis je **podrazumevani** Kubernetes **servis**. Omogućava vam **servis unutar** vašeg klastera kojem mogu pristupiti druge aplikacije unutar vašeg klastera. **Nema spoljnog pristupa**.

Međutim, ovo se može pristupiti koristeći Kubernetes Proxy:
```bash
kubectl proxy --port=8080
```
Sada možete navigirati kroz Kubernetes API da biste pristupili uslugama koristeći ovu shemu:

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

Na primer, možete koristiti sledeći URL:

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

da biste pristupili ovoj usluzi:
```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
```
_Ova metoda zahteva da pokrenete `kubectl` kao **autentifikovani korisnik**._

Nabrojte sve ClusterIP-ove:
```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

Kada se koristi **NodePort**, određeni port je dostupan na svim čvorovima (koji predstavljaju virtuelne mašine). **Saobraćaj** usmeren na ovaj specifičan port se sistematski **usmerava ka servisu**. Obično, ova metoda se ne preporučuje zbog svojih nedostataka.

Lista svih NodePort-ova:
```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
```
Primer specifikacije 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
```
Ako **ne navedete** **nodePort** u yaml-u (to je port koji će biti otvoren), koristiće se port u **opsegu 30000–32767**.

### LoadBalancer <a href="#id-0d96" id="id-0d96"></a>

Izlaže Servis spolja **koristeći load balancer provajdera u oblaku**. Na GKE, ovo će pokrenuti [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) koji će vam dati jedinstvenu IP adresu koja će preusmeriti sav saobraćaj na vaš servis. U AWS-u će pokrenuti Load Balancer.

Morate plaćati za LoadBalancer po izloženom servisu, što može biti skupo.

Lista svih LoadBalancera:
```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
```
### Eksterne IP adrese <a href="#external-ips" id="external-ips"></a>

> [!TIP]
> Eksterne IP adrese su izložene od strane usluga tipa Load Balancers i obično se koriste kada se koristi eksterna Cloud Provider Load Balancer.
>
> Da biste ih pronašli, proverite load balancere sa vrednostima u polju `EXTERNAL-IP`.

Saobraćaj koji ulazi u klaster sa **eksternom IP adresom** (kao **odredišna IP adresa**), na portu usluge, biće **usmeren na jedan od krajnjih tačaka usluge**. `externalIPs` nisu upravljane od strane Kubernetesa i odgovornost su administratora klastera.

U specifikaciji usluge, `externalIPs` mogu biti navedene zajedno sa bilo kojim od `ServiceTypes`. U sledećem primeru, "`my-service`" može biti pristupljeno od strane klijenata na "`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

[**Iz dokumenata:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Servisi tipa ExternalName **mapiraju servis na DNS ime**, a ne na tipičan selektor kao što je `my-service` ili `cassandra`. Ove servise definišete pomoću parametra `spec.externalName`.

Ova definicija servisa, na primer, mapira `my-service` servis u `prod` imenskom prostoru na `my.database.example.com`:
```yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
```
Kada se traži host `my-service.prod.svc.cluster.local`, klasterska DNS usluga vraća `CNAME` zapis sa vrednošću `my.database.example.com`. Pristup `my-service` funkcioniše na isti način kao i druge usluge, ali sa ključnom razlikom da **preusmeravanje se dešava na DNS nivou** umesto putem proksiranja ili prosleđivanja.

Nabrojte sve ExternalNames:
```bash
kubectl get services --all-namespaces | grep ExternalName
```
### Ingress

Za razliku od svih gore navedenih primera, **Ingress NIJE tip usluge**. Umesto toga, on se nalazi **ispred više usluga i deluje kao “pametan ruter”** ili ulazna tačka u vaš klaster.

Možete raditi mnogo različitih stvari sa Ingress-om, i postoje **različite vrste Ingress kontrolera koji imaju različite mogućnosti**.

Podrazumevani GKE ingress kontroler će pokrenuti [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) za vas. Ovo će vam omogućiti da radite i rutiranje zasnovano na putanji i rutiranje zasnovano na poddomenama ka pozadinskim uslugama. Na primer, možete poslati sve na foo.yourdomain.com ka foo usluzi, i sve ispod putanje yourdomain.com/bar/ ka bar usluzi.

YAML za Ingress objekat na GKE sa [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) može izgledati ovako:
```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
```
Nabrojite sve ulaze:
```bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
```
Iako je u ovom slučaju bolje dobiti informacije o svakom pojedinačno kako bi se lakše pročitali:
```bash
kubectl get ingresses --all-namespaces -o=yaml
```
### Reference

- [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
- [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/)

{{#include ../../banners/hacktricks-training.md}}
