# Exposing Services in Kubernetes

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

Il existe **différentes manières d'exposer des services** dans Kubernetes afin que les points de terminaison **internes** et **externes** puissent y accéder. Cette configuration Kubernetes est assez critique car l'administrateur pourrait donner accès à **des attaquants à des services auxquels ils ne devraient pas avoir accès**.

### Automatic Enumeration

Avant de commencer à énumérer les manières dont K8s offre d'exposer des services au public, sachez que si vous pouvez lister les espaces de noms, les services et les ingresses, vous pouvez trouver tout ce qui est exposé au public avec :
```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

Un service **ClusterIP** est le service **par défaut** de Kubernetes. Il vous fournit un **service à l'intérieur** de votre cluster auquel d'autres applications à l'intérieur de votre cluster peuvent accéder. Il n'y a **pas d'accès externe**.

Cependant, cela peut être accessible en utilisant le Proxy Kubernetes :
```bash
kubectl proxy --port=8080
```
Maintenant, vous pouvez naviguer à travers l'API Kubernetes pour accéder aux services en utilisant ce schéma :

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

Par exemple, vous pourriez utiliser l'URL suivante :

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

pour accéder à ce service :
```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
```
_Cette méthode nécessite que vous exécutiez `kubectl` en tant qu'**utilisateur authentifié**._

Listez tous les ClusterIPs :
```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

Lorsque **NodePort** est utilisé, un port désigné est rendu disponible sur tous les nœuds (représentant les machines virtuelles). **Le trafic** dirigé vers ce port spécifique est ensuite systématiquement **acheminé vers le service**. En général, cette méthode n'est pas recommandée en raison de ses inconvénients.

Liste de tous les NodePorts :
```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
```
Un exemple de spécification 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
```
Si vous **ne spécifiez pas** le **nodePort** dans le yaml (c'est le port qui sera ouvert), un port dans la **plage 30000–32767 sera utilisé**.

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

Expose le Service à l'extérieur **en utilisant le load balancer d'un fournisseur de cloud**. Sur GKE, cela lancera un [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) qui vous donnera une seule adresse IP qui redirigera tout le trafic vers votre service. Sur AWS, cela lancera un Load Balancer.

Vous devez payer pour un LoadBalancer par service exposé, ce qui peut être coûteux.

Listez tous les LoadBalancers :
```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
```
### External IPs <a href="#external-ips" id="external-ips"></a>

> [!TIP]
> Les IP externes sont exposées par des services de type Load Balancers et elles sont généralement utilisées lorsqu'un Load Balancer de fournisseur de Cloud externe est utilisé.
>
> Pour les trouver, vérifiez les load balancers avec des valeurs dans le champ `EXTERNAL-IP`.

Le trafic qui entre dans le cluster avec l'**IP externe** (comme **IP de destination**), sur le port du Service, sera **acheminé vers l'un des points de terminaison du Service**. `externalIPs` ne sont pas gérés par Kubernetes et relèvent de la responsabilité de l'administrateur du cluster.

Dans la spécification du Service, `externalIPs` peuvent être spécifiés avec n'importe lequel des `ServiceTypes`. Dans l'exemple ci-dessous, "`my-service`" peut être accessible par les clients sur "`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

[**D'après la documentation :**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Les Services de type ExternalName **mappent un Service à un nom DNS**, et non à un sélecteur typique tel que `my-service` ou `cassandra`. Vous spécifiez ces Services avec le paramètre `spec.externalName`.

Cette définition de Service, par exemple, mappe le Service `my-service` dans l'espace de noms `prod` à `my.database.example.com` :
```yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
```
Lors de la recherche de l'hôte `my-service.prod.svc.cluster.local`, le Service DNS du cluster renvoie un enregistrement `CNAME` avec la valeur `my.database.example.com`. L'accès à `my-service` fonctionne de la même manière que d'autres Services, mais avec la différence cruciale que **la redirection se produit au niveau DNS** plutôt que par le biais de proxy ou de transfert.

Listez tous les ExternalNames :
```bash
kubectl get services --all-namespaces | grep ExternalName
```
### Ingress

Contrairement à tous les exemples ci-dessus, **Ingress n'est PAS un type de service**. Au lieu de cela, il se trouve **devant plusieurs services et agit comme un "routeur intelligent"** ou point d'entrée dans votre cluster.

Vous pouvez faire beaucoup de choses différentes avec un Ingress, et il existe **de nombreux types de contrôleurs Ingress qui ont des capacités différentes**.

Le contrôleur d'ingress GKE par défaut va créer un [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) pour vous. Cela vous permettra de faire à la fois un routage basé sur le chemin et un routage basé sur le sous-domaine vers des services backend. Par exemple, vous pouvez envoyer tout sur foo.yourdomain.com au service foo, et tout sous le chemin yourdomain.com/bar/ au service bar.

Le YAML pour un objet Ingress sur GKE avec un [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) pourrait ressembler à ceci :
```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
```
Listez tous les ingresses :
```bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
```
Bien qu'il soit préférable dans ce cas d'obtenir les informations de chacun un par un pour mieux les lire :
```bash
kubectl get ingresses --all-namespaces -o=yaml
```
### Références

- [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}}
