Translated ['src/pentesting-cloud/kubernetes-security/kubernetes-hardeni

This commit is contained in:
Translator
2026-07-04 11:48:05 +00:00
parent 959e3a4507
commit f0a9cea8b3
3 changed files with 149 additions and 119 deletions
@@ -2,11 +2,11 @@
{{#include ../../banners/hacktricks-training.md}}
Il existe **différentes façons d'exposer des services** dans Kubernetes afin que des endpoints **internes** et **externes** puissent y accéder. Cette configuration Kubernetes est assez critique, car l'administrateur pourrait donner aux **attackers l'accès à des services auxquels ils ne devraient pas pouvoir accéder**.
Il existe **différentes façons 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 **attackers à des services auxquels ils ne devraient pas pouvoir accéder**.
### Automatic Enumeration
Avant de commencer à énumérer les façons dont K8s permet d'exposer des services au public, sachez que si vous pouvez lister les namespaces, les services et les ingresses, vous pouvez trouver tout ce qui est exposé au public avec :
Avant de commencer à énumérer les façons dont K8s permet d'exposer des services au public, sachez que si vous pouvez lister les namespaces, services et 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"
@@ -20,13 +20,13 @@ done | grep -v "ClusterIP"
```
### ClusterIP
Un service **ClusterIP** est le **service** Kubernetes **par défaut**. Il fournit un **service à lintérieur** de votre cluster auquel dautres applications dans votre cluster peuvent accéder. Il ny a **aucun accès externe**.
Un **ClusterIP** service est le **service** Kubernetes **par défaut**. Il vous fournit un **service à lintérieur** de votre cluster auquel dautres applications dans votre cluster peuvent accéder. Il ny a **aucun accès externe**.
Cependant, cela peut être accessible en utilisant le Kubernetes Proxy :
```bash
kubectl proxy --port=8080
```
Maintenant, vous pouvez naviguer à travers l'API Kubernetes pour accéder aux services en utilisant ce schéma :
Maintenant, vous pouvez naviguer dans 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>/`
@@ -50,7 +50,7 @@ port: 80
targetPort: 80
protocol: TCP
```
_Cette méthode nécessite dexécuter `kubectl` en tant qu**utilisateur authentifié**._
_Cette méthode nécessite d'exécuter `kubectl` en tant qu'**utilisateur authentifié**._
Lister tous les ClusterIPs :
```bash
@@ -58,9 +58,9 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam
```
### NodePort
Quand **NodePort** est utilisé, un port désigné est rendu disponible sur tous les Nodes (représentant les Virtual Machines). Le **trafic** dirigé vers ce port spécifique est alors systématiquement **routé vers le service**. En général, cette méthode nest pas recommandée en raison de ses inconvénients.
Lorsque **NodePort** est utilisé, un port dédié est rendu disponible sur tous les Nodes (représentant les Virtual Machines). Le **traffic** dirigé vers ce port spécifique est alors systématiquement **routed to the service**. En général, cette méthode nest pas recommandée en raison de ses inconvénients.
Lister tous les NodePorts:
Lister 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
```
@@ -81,30 +81,41 @@ targetPort: 80
nodePort: 30036
protocol: TCP
```
Si vous **ne spécifiez pas** le **nodePort** dans le yaml (cest le port qui sera ouvert), un port dans la **plage 3000032767 sera utilisé**.
Si vous **ne spécifiez pas** le **nodePort** dans le yaml (c'est le port qui sera ouvert), un port dans la **plage 3000032767 sera utilisé**.
Lors de l'examen des Services NodePort ou LoadBalancer, inspectez aussi les champs traffic-policy, car ils modifient quels nodes et backends sont utiles depuis une source donnée:
```bash
kubectl get services --all-namespaces \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,ETP:.spec.externalTrafficPolicy,ITP:.spec.internalTrafficPolicy,AFFINITY:.spec.sessionAffinity,DIST:.spec.trafficDistribution,NODEPORTS:.spec.ports[*].nodePort'
```
- `externalTrafficPolicy: Local` préserve ladresse IP source originale du client pour le trafic NodePort/LoadBalancer et évite de transférer vers des endpoints sur dautres nœuds. Un nœud sans endpoint local prêt peut drop le trafic même si le Service a des endpoints ailleurs.
- `externalTrafficPolicy: Cluster` est la valeur par défaut et peut transférer via nimporte quel nœud, mais les logs backend peuvent voir les IP des nœuds au lieu de la vraie IP du client externe.
- `internalTrafficPolicy: Local` limite le trafic du Service dans le cluster aux endpoints locaux au nœud source. Il sagit de routage de proximité, pas dune boundary dautorisation.
- `sessionAffinity: ClientIP` peut faire en sorte que des tests répétés depuis un client touchent le même backend, masquant dautres endpoints prêts lors des vérifications manuelles.
- `trafficDistribution` et les EndpointSlice topology hints peuvent privilégier les endpoints du même zone ou du même nœud sur les clusters plus récents ; considérez-les comme des préférences de routage plutôt que comme une politique de sécurité stricte.
### LoadBalancer
Expose le Service en externe **en utilisant le load balancer dun cloud provider**. Sur GKE, cela va créer 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.
Expose le Service en externe **en utilisant le load balancer dun cloud provider**. Sur GKE, cela va lancer 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 un LoadBalancer par service exposé, ce qui peut être coûteux.
Lister tous les LoadBalancers:
List all 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
```
### IPs externes
### External IPs
> [!TIP]
> Les IPs externes sont exposées par des services de type Load Balancers et elles sont généralement utilisées lorsquun external Cloud Provider Load Balancer est utilisé.
> External IPs sont exposées par des services de type Load Balancers et elles sont généralement utilisées lorsqu'un external Cloud Provider Load Balancer 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**external IP** (comme **destination IP**), sur le port du Service, sera **acheminé vers lun des endpoints du Service**. `externalIPs` ne sont pas gérés par Kubernetes et relèvent de la responsabilité de ladministrateur du cluster.
Le trafic qui entre dans le cluster avec l'**external IP** (comme **destination IP**), sur le port du Service, sera **routé vers l'un des endpoints du Service**. Les `externalIPs` ne sont pas gérés par Kubernetes et relèvent de la responsabilité de l'administrateur du cluster.
`externalIPs` est un champ sensible de contrôle de routage, car un utilisateur qui peut le définir pourrait capter le trafic destiné à une adresse IP que le propriétaire du Service ne devrait pas contrôler si le réseau environnant achemine cette IP vers le cluster. Kubernetes a annoncé la dépréciation et la suppression prévue de `externalIPs` pour les Services dans v1.36, donc privilégiez, lorsque cest possible, les mécanismes dexposition gérés par le controller, comme les intégrations LoadBalancer ou Gateway API, et restreignez/autorisez ce champ avec soin tant quil existe encore.
`externalIPs` est un champ sensible de contrôle du routage, car un utilisateur qui peut le définir pourrait s'approprier le trafic destiné à une adresse IP que le propriétaire du Service ne devrait pas contrôler si le réseau environnant achemine cette IP vers le cluster. Kubernetes a annoncé la dépréciation et la suppression prévue de `externalIPs` pour les Service dans v1.36, donc privilégiez autant que possible les mécanismes d'exposition gérés par des controllers, tels que les intégrations LoadBalancer ou Gateway API, et restreignez/autorisez ce champ avec soin tant qu'il existe encore.
Dans la spec du Service, `externalIPs` peut être spécifié avec nimporte lequel des `ServiceTypes`. Dans lexemple ci-dessous, "`my-service`" peut être accédé par des clients sur "`80.11.12.10:80`" (`externalIP:port`)
Dans la spec du Service, `externalIPs` peut être spécifié avec n'importe lequel des `ServiceTypes`. Dans l'exemple ci-dessous, "`my-service`" peut être accessible par des clients sur "`80.11.12.10:80`" (`externalIP:port`)
```yaml
apiVersion: v1
kind: Service
@@ -123,9 +134,9 @@ externalIPs:
```
### ExternalName
[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Les Services de type ExternalName **associent un Service à un nom DNS**, et non à un sélecteur classique comme `my-service` ou `cassandra`. Vous définissez ces Services avec le paramètre `spec.externalName`.
[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Les Services de type ExternalName **associent un Service à un nom DNS**, et non à un sélecteur typique comme `my-service` ou `cassandra`. Vous spécifiez ces Services avec le paramètre `spec.externalName`.
Cette définition de Service, par exemple, associe le Service `my-service` dans l'espace de noms `prod` à `my.database.example.com` :
This Service definition, for example, maps the `my-service` Service in the `prod` namespace to `my.database.example.com`:
```yaml
apiVersion: v1
kind: Service
@@ -136,32 +147,32 @@ spec:
type: ExternalName
externalName: my.database.example.com
```
Lors de la recherche du host `my-service.prod.svc.cluster.local`, le cluster DNS Service renvoie un enregistrement `CNAME` avec la valeur `my.database.example.com`. Accéder à `my-service` fonctionne de la même manière que pour les autres Services, mais avec la différence cruciale que la **redirection se fait au niveau DNS** plutôt que via du proxying ou du forwarding.
Lors de la recherche de lhôte `my-service.prod.svc.cluster.local`, le Service DNS du cluster renvoie un enregistrement `CNAME` avec la valeur `my.database.example.com`. Laccès à `my-service` fonctionne de la même manière que pour les autres Services, mais avec une différence cruciale : **la redirection se fait au niveau DNS** plutôt que via du proxying ou du forwarding.
Listez tous les ExternalNames:
Listez tous les ExternalNames :
```bash
kubectl get services --all-namespaces | grep ExternalName
```
### EndpointSlices
Les EndpointSlices montrent les adresses backend et les ports concrets vers lesquels un Service route actuellement. Ils sont particulièrement utiles lorsquun Service na pas de selector, lorsque les labels nexpliquent pas le chemin du trafic, ou lorsque seulement certains backends sont prêts.
Les EndpointSlices montrent les adresses et ports backend concrets vers lesquels un Service route actuellement. Ils sont particulièrement utiles lorsquun Service na pas de selector, lorsque les labels nexpliquent pas le chemin du trafic, ou lorsque seuls certains backends sont prêts.
Lister les EndpointSlices associés aux Services :
Lister les EndpointSlices associés aux Services:
```bash
kubectl get endpointslices --all-namespaces
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> -o yaml
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
```
Lors de lexamen de lexposition, comparez le Service selector avec le EndpointSlice `targetRef`, les adresses des endpoints, les conditions de readiness, et les ports. Un Service sans selector peut être associé à des EndpointSlices gérés manuellement et router le trafic vers des destinations non-Pod ou inattendues.
Lors de lexamen de lexposition, comparez le selector du Service avec le `targetRef` de lEndpointSlice, les adresses dendpoint, les conditions de readiness et les ports. Un Service sans selector peut être associé à des EndpointSlices gérés manuellement et router le trafic vers des destinations non-Pod ou inattendues.
### Ingress
Contrairement à tous les exemples ci-dessus, **Ingress nest PAS un type de service**. Il se place au contraire **devant plusieurs services et agit comme un “smart router”** ou point dentrée vers votre cluster.
Contrairement à tous les exemples ci-dessus, **Ingress nest PAS un type de service**. À la place, il se place **devant plusieurs services et agit comme un “smart router”** ou point dentrée dans votre cluster.
Vous pouvez faire beaucoup de choses différentes avec un Ingress, et il existe **de nombreux types de Ingress controllers qui ont des capacités différentes**.
Le Ingress controller GKE par défaut va créer pour vous un [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Cela vous permettra de faire du routage basé sur le path et basé sur le sous-domaine vers les backend services. Par exemple, vous pouvez envoyer tout ce qui arrive sur foo.yourdomain.com vers le service foo, et tout ce qui se trouve sous le path yourdomain.com/bar/ vers le service bar.
Le controller GKE Ingress par défaut déploiera un [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) pour vous. Cela vous permettra de faire du routage basé sur le chemin et basé sur le sous-domaine vers des backend services. Par exemple, vous pouvez envoyer tout ce qui se trouve sur foo.yourdomain.com vers le service foo, et tout ce qui se trouve sous le chemin yourdomain.com/bar/ vers le service bar.
Le YAML dun objet Ingress sur GKE avec un [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) pourrait ressembler à ceci :
```yaml
@@ -197,17 +208,17 @@ name: bar
port:
number: 8080
```
Listez tous les ingresses:
Lister tous les ingresses :
```bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
```
Bien que dans ce cas il soit préférable dobtenir les infos de chacun un par un pour mieux les lire :
Bien que, dans ce cas, il soit préférable dobtenir les infos de chacun un par un pour mieux les lire :
```bash
kubectl get ingresses --all-namespaces -o=yaml
```
### Gateway API
Gateway API est la nouvelle API Kubernetes pour exposer des Services. Elle sépare les objets Gateway, détenus par l'infrastructure, des objets Route détenus par l'application, tels que HTTPRoute. C'est utile pour la délégation, mais cela signifie aussi que l'exposition peut être répartie entre plusieurs namespaces.
Gateway API est la nouvelle API Kubernetes pour exposer des Services. Elle sépare les objets Gateway appartenant à l'infrastructure des objets Route appartenant aux applications, tels que HTTPRoute. Cela est utile pour la délégation, mais cela signifie aussi que l'exposition peut être répartie entre plusieurs namespaces.
Lister les objets d'exposition Gateway API :
```bash
@@ -217,13 +228,16 @@ kubectl get httproutes --all-namespaces
kubectl get gateway -n <namespace> <gateway-name> -o yaml
kubectl get httproute -n <namespace> <route-name> -o yaml
```
Vérifiez les listeners du Gateway, les namespaces de route autorisés, les `parentRefs` de `Route`, les `hostnames`, les filters, les références de backend, et les status conditions telles que savoir si la route a été acceptée. Une `Route` acceptée par un Gateway partagé peut exposer un backend même lorsqu'aucun objet `Ingress` legacy n'existe.
Vérifiez les listeners du Gateway, les route namespaces autorisés, les `parentRefs` de `Route`, les hostnames, les filters, les backend references, et les status conditions, comme si la route a été accepted. Une Route accepted par un shared Gateway peut exposer un backend même lorsquaucun objet legacy Ingress nexiste.
### References
- [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/)
- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/)
- [https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/)
- [https://kubernetes.io/docs/tutorials/services/source-ip/](https://kubernetes.io/docs/tutorials/services/source-ip/)
- [https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)
- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/)
- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/)
@@ -8,30 +8,30 @@
### What does Kubernetes do?
- Allows running container/s in a container engine.
- Schedule allows containers mission efficient.
- Keep containers alive.
- Allows container communications.
- Allows deployment techniques.
- Handle volumes of information.
- Permet dexécuter un ou plusieurs container/s dans un container engine.
- Le schedule permet dexécuter les containers de manière efficace.
- Maintient les containers en vie.
- Permet les communications entre containers.
- Permet les techniques de deployment.
- Gère des volumes dinformation.
### Architecture
![Kubernetes architecture diagram showing control plane components, API server, kubelet, kube-proxy, pods, and worker nodes](https://sickrov.github.io/media/Screenshot-68.jpg)
- **Node**: operating system with pod or pods.
- **Pod**: Wrapper around a container or multiple containers with. A pod should only contain one application (so usually, a pod run just 1 container). The pod is the way kubernetes abstracts the container technology running.
- **Service**: Each pod has 1 internal **IP address** from the internal range of the node. However, it can be also exposed via a service. The **service has also an IP address** and its goal is to maintain the communication between pods so if one dies the **new replacement** (with a different internal IP) **will be accessible** exposed in the **same IP of the service**. It can be configured as internal or external. The service also actuates as a **load balancer when 2 pods are connected** to the same service.\
When a **service** is **created** you can find the endpoints of each service running `kubectl get endpoints`
- **Kubelet**: Primary node agent. The component that establishes communication between node and kubectl, and only can run pods (through API server). The kubelet doesnt manage containers that were not created by Kubernetes.
- **Kube-proxy**: is the service in charge of the communications (services) between the apiserver and the node. The base is an IPtables for nodes. Most experienced users could install other kube-proxies from other vendors.
- **Sidecar container**: Sidecar containers are the containers that should run along with the main container in the pod. This sidecar pattern extends and enhances the functionality of current containers without changing them. Nowadays, We know that we use container technology to wrap all the dependencies for the application to run anywhere. A container does only one thing and does that thing very well.
- **Pod**: Wrapper autour dun container ou de plusieurs containers avec. Un pod ne devrait contenir quune seule application (donc en général, un pod exécute seulement 1 container). Le pod est la manière dont kubernetes abstrait la technologie de container en cours dexécution.
- **Service**: Chaque pod a 1 **adresse IP** interne provenant de la plage interne du node. Cependant, il peut aussi être exposé via un service. Le **service a aussi une adresse IP** et son objectif est de maintenir la communication entre les pods, donc si lun meurt, le **nouveau remplacement** (avec une IP interne différente) **sera accessible** exposé sur la **me IP du service**. Il peut être configuré en interne ou en externe. Le service agit aussi comme un **load balancer lorsque 2 pods sont connectés** au même service.\
Lorsquun **service** est **créé**, vous pouvez trouver les endpoints de chaque service en exécutant `kubectl get endpoints`
- **Kubelet**: Agent principal du node. Le composant qui établit la communication entre le node et kubectl, et qui peut uniquement exécuter des pods (via lAPI server). Le kubelet ne gère pas les containers qui nont pas été créés par Kubernetes.
- **Kube-proxy**: est le service chargé des communications (services) entre lapiserver et le node. La base est une IPtables pour les nodes. Les utilisateurs les plus expérimentés pourraient installer dautres kube-proxies provenant dautres vendors.
- **Sidecar container**: Les sidecar containers sont les containers qui doivent sexécuter avec le container principal dans le pod. Ce modèle sidecar étend et améliore les fonctionnalités des containers actuels sans les modifier. Aujourdhui, nous savons que nous utilisons la technologie de container pour encapsuler toutes les dépendances afin que lapplication puisse sexécuter nimporte où. Un container ne fait quune seule chose et la fait très bien.
- **Master process:**
- **Api Server:** Is the way the users and the pods use to communicate with the master process. Only authenticated request should be allowed.
- **Scheduler**: Scheduling refers to making sure that Pods are matched to Nodes so that Kubelet can run them. It has enough intelligence to decide which node has more available resources the assign the new pod to it. Note that the scheduler doesn't start new pods, it just communicate with the Kubelet process running inside the node, which will launch the new pod.
- **Kube Controller manager**: It checks resources like replica sets or deployments to check if, for example, the correct number of pods or nodes are running. In case a pod is missing, it will communicate with the scheduler to start a new one. It controls replication, tokens, and account services to the API.
- **etcd**: Data storage, persistent, consistent, and distributed. Is Kubernetess database and the key-value storage where it keeps the complete state of the clusters (each change is logged here). Components like the Scheduler or the Controller manager depends on this date to know which changes have occurred (available resourced of the nodes, number of pods running...)
- **Cloud controller manager**: Is the specific controller for flow controls and applications, i.e: if you have clusters in AWS or OpenStack.
- **Api Server:** Cest le moyen utilisé par les users et les pods pour communiquer avec le master process. Seules les requêtes authentifiées devraient être autorisées.
- **Scheduler**: Le scheduling consiste à sassurer que les Pods sont associés aux Nodes afin que Kubelet puisse les exécuter. Il dispose de suffisamment dintelligence pour décider quel node possède le plus de ressources disponibles et lui assigner le nouveau pod. Notez que le scheduler ne démarre pas de nouveaux pods, il communique seulement avec le processus Kubelet sexécutant à lintérieur du node, qui lancera le nouveau pod.
- **Kube Controller manager**: Il vérifie les ressources comme les replica sets ou les deployments pour contrôler par exemple que le nombre correct de pods ou de nodes est en cours dexécution. Dans le cas où un pod est manquant, il communiquera avec le scheduler pour en démarrer un nouveau. Il contrôle la replication, les tokens, et les account services vers lAPI.
- **etcd**: Stockage de données, persistant, cohérent et distribué. Cest la base de données de Kubernetes et le stockage key-value où il conserve l’état complet des clusters (chaque changement y est journalisé). Des composants comme le Scheduler ou le Controller manager dépendent de ces données pour savoir quels changements se sont produits (available resourced des nodes, nombre de pods en cours dexécution...)
- **Cloud controller manager**: Cest le controller spécifique pour les flow controls et applications, c.-à-d. : si vous avez des clusters dans AWS ou OpenStack.
Note that as the might be several nodes (running several pods), there might also be several master processes which their access to the Api server load balanced and their etcd synchronized.
@@ -39,16 +39,18 @@ Note that as the might be several nodes (running several pods), there might also
When a pod creates data that shouldn't be lost when the pod disappear it should be stored in a physical volume. **Kubernetes allow to attach a volume to a pod to persist the data**. The volume can be in the local machine or in a **remote storage**. If you are running pods in different physical nodes you should use a remote storage so all the pods can access it.
Kubernetes also supports **image volumes** in recent versions. An `image` volume mounts an OCI image or artifact as a **read-only** filesystem source inside the Pod, using fields such as `volumes[].image.reference` and `volumes[].image.pullPolicy`. The kubelet pulls the artifact with the same credential sources used for container images, including node credentials, Pod `imagePullSecrets`, and ServiceAccount `imagePullSecrets`. During a security review, treat image volumes as runtime inputs and supply-chain dependencies: check whether the reference is pinned by digest, which registry credentials can fetch it, where it is mounted, and whether `subPath` limits the visible directory.
**Other configurations:**
- **ConfigMap**: You can configure **URLs** to access services. The pod will obtain data from here to know how to communicate with the rest of the services (pods). Note that this is not the recommended place to save credentials!
- **Secret**: This is the place to **store secret data** like passwords, API keys... encoded in B64. The pod will be able to access this data to use the required credentials.
- **Deployments**: This is where the components to be run by kubernetes are indicated. A user usually won't work directly with pods, pods are abstracted in **ReplicaSets** (number of same pods replicated), which are run via deployments. Note that deployments are for **stateless** applications. The minimum configuration for a deployment is the name and the image to run.
- **StatefulSet**: This component is meant specifically for applications like **databases** which needs to **access the same storage**.
- **Ingress**: This is the configuration that is use to **expose the application publicly with an URL**. Note that this can also be done using external services, but this is the correct way to expose the application.
- If you implement an Ingress you will need to create **Ingress Controllers**. The Ingress Controller is a **pod** that will be the endpoint that will receive the requests and check and will load balance them to the services. the ingress controller will **send the request based on the ingress rules configured**. Note that the ingress rules can point to different paths or even subdomains to different internal kubernetes services.
- A better security practice would be to use a cloud load balancer or a proxy server as entrypoint to don't have any part of the Kubernetes cluster exposed.
- When request that doesn't match any ingress rule is received, the ingress controller will direct it to the "**Default backend**". You can `describe` the ingress controller to get the address of this parameter.
- **ConfigMap**: Vous pouvez configurer des **URLs** pour accéder aux services. Le pod obtiendra les données dici pour savoir comment communiquer avec le reste des services (pods). Notez que ce nest pas lendroit recommandé pour stocker des credentials !
- **Secret**: Cest lendroit pour **stocker des données secrètes** comme des passwords, API keys... encodées en B64. Le pod pourra accéder à ces données pour utiliser les credentials requis.
- **Deployments**: Cest ici que sont indiqués les composants à exécuter par kubernetes. En général, un user ne travaillera pas directement avec les pods, les pods sont abstraits dans des **ReplicaSets** (nombre de mêmes pods répliqués), qui sont exécutés via des deployments. Notez que les deployments sont destinés aux applications **stateless**. La configuration minimale pour un deployment est le nom et limage à exécuter.
- **StatefulSet**: Ce component est destiné spécifiquement aux applications comme les **databases** qui doivent **accéder au même stockage**.
- **Ingress**: Cest la configuration utilisée pour **exposer lapplication publiquement avec une URL**. Notez que cela peut aussi être fait avec des external services, mais cest la bonne manière dexposer lapplication.
- Si vous implémentez un Ingress, vous devrez créer des **Ingress Controllers**. LIngress Controller est un **pod** qui sera lendpoint recevant les requêtes, les examinant et les load balancer vers les services. lingress controller **enverra la requête en fonction des ingress rules configurées**. Notez que les ingress rules peuvent pointer vers différents paths ou même des subdomains vers différents internal kubernetes services.
- Une meilleure pratique de security serait dutiliser un cloud load balancer ou un proxy server comme point dentrée afin de navoir aucune partie du cluster Kubernetes exposée.
- Lorsquune requête qui ne correspond à aucune ingress rule est reçue, lingress controller la dirigera vers le "**Default backend**". Vous pouvez `describe` lingress controller pour obtenir ladresse de ce paramètre.
- `minikube addons enable ingress`
### PKI infrastructure - Certificate Authority CA:
@@ -105,7 +107,7 @@ $ minikube delete
```
### Kubectl Basics
**`Kubectl`** est l'outil en ligne de commande pour les clusters kubernetes. Il communique avec le Api server du processus master pour effectuer des actions dans kubernetes ou pour demander des données.
**`Kubectl`** est l'outil en ligne de commande pour les clusters kubernetes. Il communique avec le serveur Api du processus master pour effectuer des actions dans kubernetes ou demander des données.
```bash
kubectl version #Get client and server version
kubectl get pod
@@ -138,7 +140,7 @@ kubectl apply -f deployment.yml
```
### Minikube Dashboard
Le dashboard permet de voir plus facilement ce que minikube exécute, vous pouvez trouver l'URL pour y accéder dans :
Le dashboard permet de voir plus facilement ce qui est en cours d'exécution dans minikube, vous pouvez trouver l'URL pour y accéder dans :
```
minikube dashboard --url
@@ -153,10 +155,10 @@ http://127.0.0.1:50034/api/v1/namespaces/kubernetes-dashboard/services/http:kube
```
### Exemples de fichiers de configuration YAML
Chaque fichier de configuration a 3 parties : **metadata**, **specification** (ce quil faut lancer), **status** (état désiré).\
Dans la specification du fichier de configuration du deployment, vous pouvez trouver le template défini avec une nouvelle structure de configuration définissant limage à exécuter :
Chaque fichier de configuration a 3 parties : **metadata**, **specification** (ce qui doit être lancé), **status** (état désiré).\
À l'intérieur de la specification du fichier de configuration de deployment, vous pouvez trouver le template défini avec une nouvelle structure de configuration définissant l'image à exécuter :
**Exemple de Deployment + Service déclarés dans le même fichier de configuration (depuis** [**ici**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**)**
**Exemple de Deployment + Service déclarés dans le même fichier de configuration (from** [**here**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**)**
Comme un service est généralement lié à un deployment, il est possible de déclarer les deux dans le même fichier de configuration (le service déclaré dans cette config est accessible uniquement en interne) :
```yaml
@@ -207,7 +209,7 @@ targetPort: 27017
```
**Exemple de configuration de service externe**
Ce service sera accessible de lextérieur (vérifiez les attributs `nodePort` et `type: LoadBlancer`):
Ce service sera accessible depuis l'extérieur (vérifiez les attributs `nodePort` et `type: LoadBlancer`):
```yaml
---
apiVersion: v1
@@ -225,9 +227,9 @@ targetPort: 8081
nodePort: 30000
```
> [!NOTE]
> Ceci est utile pour les tests, mais en production vous devriez avoir uniquement des services internes et un Ingress pour exposer l'application.
> C'est utile pour les tests, mais en production vous devriez n'avoir que des services internes et un Ingress pour exposer l'application.
**Exemple de fichier de configuration Ingress**
**Example of Ingress config file**
Cela exposera l'application sur `http://dashboard.com`.
```yaml
@@ -247,7 +249,7 @@ servicePort: 80
```
**Exemple de fichier de configuration de secrets**
Notez comment les mots de passe sont encodés en B64 (ce qui n'est pas sûr !)
Notez comment les mots de passe sont encodés en B64 (ce qui n'est pas sécurisé !)
```yaml
apiVersion: v1
kind: Secret
@@ -260,7 +262,7 @@ mongo-root-password: cGFzc3dvcmQ=
```
**Exemple de ConfigMap**
Une **ConfigMap** est la configuration donnée aux pods afin qu'ils sachent comment localiser et accéder à d'autres services. Dans ce cas, chaque pod saura que le nom `mongodb-service` est l'adresse d'un pod avec lequel il peut communiquer (ce pod exécutera un mongodb):
Un **ConfigMap** est la configuration donnée aux pods pour quils sachent comment localiser et accéder à dautres services. Dans ce cas, chaque pod saura que le nom `mongodb-service` est ladresse dun pod avec lequel il peut communiquer (ce pod exécutera un mongodb) :
```yaml
apiVersion: v1
kind: ConfigMap
@@ -292,16 +294,16 @@ key: database_url
```
**Exemple de volume config**
You can find different example of storage configuration yaml files in [https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes](https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes).\
**Note that volumes aren't inside namespaces**
Vous pouvez trouver différents exemples de fichiers yaml de configuration de storage dans [https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes](https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes).\
**Notez que les volumes ne se trouvent pas à lintérieur des namespaces**
### Namespaces
Kubernetes supports **multiple virtual clusters** backed by the same physical cluster. These virtual clusters are called **namespaces**. These are intended for use in environments with many users spread across multiple teams, or projects. For clusters with a few to tens of users, you should not need to create or think about namespaces at all. You only should start using namespaces to have a better control and organization of each part of the application deployed in kubernetes.
Kubernetes prend en charge **plusieurs clusters virtuels** reposant sur le même cluster physique. Ces clusters virtuels sont appelés **namespaces**. Ils sont destinés à être utilisés dans des environnements avec de nombreux utilisateurs répartis sur plusieurs équipes ou projets. Pour des clusters avec quelques utilisateurs à quelques dizaines dutilisateurs, vous ne devriez pas avoir besoin de créer ou même de penser aux namespaces du tout. Vous ne devriez commencer à utiliser les namespaces que pour avoir un meilleur contrôle et une meilleure organisation de chaque partie de lapplication déployée dans kubernetes.
Namespaces provide a scope for names. Names of resources need to be unique within a namespace, but not across namespaces. Namespaces cannot be nested inside one another and **each** Kubernetes **resource** can only be **in** **one** namespace.
Les namespaces fournissent un scope pour les noms. Les noms des ressources doivent être uniques au sein dun namespace, mais pas entre les namespaces. Les namespaces ne peuvent pas être imbriqués les uns dans les autres et **chaque** **resource** Kubernetes ne peut être que **dans** **un seul** **namespace**.
There are 4 namespaces by default if you are using minikube:
Il y a 4 namespaces par défaut si vous utilisez minikube :
```
kubectl get namespace
NAME STATUS AGE
@@ -319,36 +321,36 @@ kube-system Active 1d
kubectl create namespace my-namespace
```
> [!NOTE]
> Notez que la plupart des ressources Kubernetes (par ex. pods, services, replication controllers, et autres) se trouvent dans certains namespaces. Cependant, d'autres ressources comme les namespace resources et les ressources de bas niveau, telles que les nodes et les persistenVolumes, ne se trouvent pas dans un namespace. Pour voir quelles ressources Kubernetes sont et ne sont pas dans un namespace :
> Notez que la plupart des ressources Kubernetes (par ex. pods, services, replication controllers, et autres) se trouvent dans certains namespaces. Cependant, d'autres ressources comme les namespace resources et les ressources de bas niveau, telles que les nodes et les persistenVolumes, ne sont pas dans un namespace. Pour voir quelles ressources Kubernetes sont et ne sont pas dans un namespace :
>
> ```bash
> kubectl api-resources --namespaced=true #In a namespace
> kubectl api-resources --namespaced=false #Not in a namespace
> ```
Vous pouvez enregistrer le namespace pour toutes les commandes kubectl suivantes dans ce context.
Vous pouvez enregistrer le namespace pour toutes les commandes kubectl suivantes dans ce contexte.
```bash
kubectl config set-context --current --namespace=<insert-namespace-name-here>
```
### Helm
Helm est le **gestionnaire de paquets** pour Kubernetes. Il permet de packager des fichiers YAML et de les distribuer dans des dépôts publics et privés. Ces paquets sont appelés **Helm Charts**.
Helm est le **gestionnaire de paquets** pour Kubernetes. Il permet de regrouper des fichiers YAML et de les distribuer dans des dépôts publics et privés. Ces paquets sont appelés **Helm Charts**.
```
helm search <keyword>
```
Helm is also a template engine that allows to generate config files with variables:
Helm est aussi un moteur de template qui permet de générer des fichiers de config avec des variables :
## Kubernetes secrets
Un **Secret** est un objet qui **contient des données sensibles** comme un mot de passe, un token ou une key. Ces informations pourraient sinon être placées dans une spécification de Pod ou dans une image. Les users peuvent create des Secrets et le system en create aussi. Le nom dun objet Secret doit être un **DNS subdomain name** valide. Lisez ici [la documentation officielle](https://kubernetes.io/docs/concepts/configuration/secret/).
Un **Secret** est un objet qui **contient des données sensibles** telles quun password, un token ou une key. De telles informations pourraient sinon être placées dans une spécification de Pod ou dans une image. Les users peuvent créer des Secrets et le système en crée aussi. Le nom dun objet Secret doit être un **DNS subdomain name** valide. Lisez ici [la documentation officielle](https://kubernetes.io/docs/concepts/configuration/secret/).
Les Secrets peuvent être des choses comme :
Les Secrets peuvent être des éléments comme :
- API, SSH Keys.
- OAuth tokens.
- Credentials, Passwords (plain text or b64 + encryption).
- Information or comments.
- Database connection code, strings… .
- Credentials, Passwords (plain text ou b64 + encryption).
- Information ou comments.
- Code de connexion à la database, strings… .
Il existe différents types de secrets dans Kubernetes
@@ -364,13 +366,13 @@ Il existe différents types de secrets dans Kubernetes
| bootstrap.kubernetes.io/token | bootstrap token data |
> [!NOTE]
> **Le type Opaque est celui par défaut, le couple clé-valeur typique défini par les users.**
> **Le type Opaque est celui par défaut, le typique couple clé-valeur défini par les users.**
**How secrets works:**
**Comment les secrets fonctionnent :**
![Kubernetes secrets diagram showing secret data reaching the API server and being consumed by a pod](https://sickrov.github.io/media/Screenshot-164.jpg)
Le fichier de configuration suivant définit un **secret** appelé `mysecret` avec 2 paires clé-valeur `username: YWRtaW4=` et `password: MWYyZDFlMmU2N2Rm`. Il définit aussi un **pod** appelé `secretpod` qui aura le `username` et le `password` définis dans `mysecret` exposés dans les **environment variables** `SECRET_USERNAME` \_\_ et \_\_ `SECRET_PASSWOR`. Il **mount** aussi le secret `username` dans `mysecret` dans le chemin `/etc/foo/my-group/my-username` avec des permissions `0640`.
Le fichier de configuration suivant définit un **secret** appelé `mysecret` avec 2 couples clé-valeur `username: YWRtaW4=` et `password: MWYyZDFlMmU2N2Rm`. Il définit aussi un **pod** appelé `secretpod` qui aura les `username` et `password` définis dans `mysecret` exposés dans les **environment variables** `SECRET_USERNAME` \_\_ et \_\_ `SECRET_PASSWOR`. Il **mount** aussi le secret `username` à lintérieur de `mysecret` dans le path `/etc/foo/my-group/my-username` avec des permissions `0640`.
```yaml:secretpod.yaml
apiVersion: v1
kind: Secret
@@ -420,19 +422,19 @@ kubectl get pods #Wait until the pod secretpod is running
kubectl exec -it secretpod -- bash
env | grep SECRET && cat /etc/foo/my-group/my-username && echo
```
### Secrets dans etcd <a href="#discover-secrets-in-etcd" id="discover-secrets-in-etcd"></a>
### Secrets in etcd <a href="#discover-secrets-in-etcd" id="discover-secrets-in-etcd"></a>
**etcd** est un **key-value store** cohérent et hautement disponible utilisé comme backing store de Kubernetes pour toutes les données du cluster. Accédons aux secrets stockés dans etcd :
```bash
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd
```
Vous verrez que les certs, keys et urls sont situés dans le FS. Une fois que vous les aurez, vous pourrez vous connecter à etcd.
Vous verrez des certs, des keys et des urls qui se trouvent dans le FS. Une fois que vous les aurez obtenus, vous pourrez vous connecter à etcd.
```bash
#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] health
ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] health
```
Une fois que vous avez établi la communication, vous pourrez obtenir les secrets :
Une fois que vous aurez établi la communication, vous pourrez obtenir les secrets :
```bash
#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] get <path/to/secret>
@@ -454,29 +456,29 @@ keys:
secret: cjjPMcWpTPKhAdieVtd+KhG4NN+N6e3NmBPMXJvbfrY= #Any random key
- identity: {}
```
Après cela, vous devez définir le flag `--encryption-provider-config` sur le `kube-apiserver` pour quil pointe vers lemplacement du fichier de config créé. Vous pouvez modifier `/etc/kubernetes/manifest/kube-apiserver.yaml` et ajouter les lignes suivantes :
Après cela, vous devez définir le flag `--encryption-provider-config` sur le `kube-apiserver` pour quil pointe vers lemplacement du fichier de configuration créé. Vous pouvez modifier `/etc/kubernetes/manifest/kube-apiserver.yaml` et ajouter les lignes suivantes :
```yaml
containers:
- command:
- kube-apiserver
- --encriyption-provider-config=/etc/kubernetes/etcd/<configFile.yaml>
```
Faites défiler vers le bas dans les volumeMounts:
Faites défiler vers le bas dans les volumeMounts :
```yaml
- mountPath: /etc/kubernetes/etcd
name: etcd
readOnly: true
```
Faites défiler vers le bas dans les volumeMounts jusqu'à hostPath:
Faites défiler vers le bas dans les volumeMounts jusquà hostPath :
```yaml
- hostPath:
path: /etc/kubernetes/etcd
type: DirectoryOrCreate
name: etcd
```
**Vérifier que les données sont chiffrées**
**Vérification que les données sont chiffrées**
Les données sont chiffrées lors de lécriture dans etcd. Après avoir redémarré votre `kube-apiserver`, tout secret nouvellement créé ou mis à jour doit être chiffré lorsquil est stocké. Pour vérifier cela, vous pouvez utiliser le programme en ligne de commande `etcdctl` pour récupérer le contenu de votre secret.
Les données sont chiffrées lorsquelles sont écrites dans etcd. Après avoir redémarré votre `kube-apiserver`, tout secret nouvellement créé ou mis à jour devrait être chiffré lors du stockage. Pour vérifier cela, vous pouvez utiliser le programme en ligne de commande `etcdctl` pour récupérer le contenu de votre secret.
1. Créez un nouveau secret appelé `secret1` dans le namespace `default` :
@@ -488,9 +490,9 @@ kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
`ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C`
où `[...]` doit être les arguments supplémentaires pour se connecter au serveur etcd.
où `[...]` doit contenir les arguments supplémentaires pour se connecter au serveur etcd.
3. Vérifiez que le secret stocké est préfixé par `k8s:enc:aescbc:v1:` ce qui indique que le provider `aescbc` a chiffré les données résultantes.
3. Vérifiez que le secret stocké est préfixé par `k8s:enc:aescbc:v1:`, ce qui indique que le provider `aescbc` a chiffré les données résultantes.
4. Vérifiez que le secret est correctement déchiffré lorsquil est récupéré via lAPI :
```
@@ -499,13 +501,13 @@ kubectl describe secret secret1 -n default
doit correspondre à `mykey: bXlkYXRh`, mydata est encodé, consultez [decoding a secret](https://kubernetes.io/docs/concepts/configuration/secret#decoding-a-secret) pour décoder complètement le secret.
**Puisque les secrets sont chiffrés à l’écriture, effectuer une mise à jour sur un secret chiffrera ce contenu :**
**Puisque les secrets sont chiffrés à l’écriture, effectuer une mise à jour sur un secret chiffrera ce contenu :**
```
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
```
**Conseils finaux :**
- Essayez de ne pas garder de secrets dans le FS, récupérez-les depuis d'autres endroits.
- Essayez de ne pas conserver de secrets dans le FS, récupérez-les depuis dautres endroits.
- Consultez [https://www.vaultproject.io/](https://www.vaultproject.io) pour ajouter plus de protection à vos secrets.
- [https://kubernetes.io/docs/concepts/configuration/secret/#risks](https://kubernetes.io/docs/concepts/configuration/secret/#risks)
- [https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm](https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm)
@@ -520,4 +522,12 @@ https://sickrov.github.io/
https://www.youtube.com/watch?v=X48VuDVv0do
{{#endref}}
{{#ref}}
https://kubernetes.io/docs/concepts/storage/volumes/#image
{{#endref}}
{{#ref}}
https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/
{{#endref}}
{{#include ../../banners/hacktricks-training.md}}
@@ -6,31 +6,31 @@
[**From the docs:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
Lors de la spécification du security context dun Pod, vous pouvez utiliser plusieurs attributs. Du point de vue de la sécurité défensive, vous devriez considérer :
Lors de la spécification du contexte de sécurité dun Pod, vous pouvez utiliser plusieurs attributs. Dun point de vue sécurité défensive, vous devriez considérer :
- Avoir **runASNonRoot** à **True**
- Configurer **runAsUser**
- Si possible, envisager de **limiter** les **permissions** en indiquant **seLinuxOptions** et **seccompProfile**
- Ne **PAS** donner un accès de **groupe** à **privilège** via **runAsGroup** et **supplementaryGroups**
- Ne **PAS** donner laccès au **groupe** de **privilège** via **runAsGroup** et **supplementaryGroups**
| Parameter | Description |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroup</strong></a><br><em>integer</em></p> | <p>Un groupe supplémentaire spécial qui sapplique à **tous les containers dun pod**. Certains types de volume permettent au Kubelet de **changer la propriété de ce volume** pour quelle appartienne au pod :<br>1. Le GID propriétaire sera le FSGroup<br>2. Le bit setgid est défini (les nouveaux fichiers créés dans le volume appartiendront au FSGroup)<br>3. Les bits de permissions sont combinés avec rw-rw---- Si non défini, le Kubelet ne modifiera pas la propriété ni les permissions daucun volume</p> |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroup</strong></a><br><em>integer</em></p> | <p>Un groupe supplémentaire spécial qui sapplique à **tous les containers dun pod**. Certains types de volume permettent au Kubelet de <strong>modifier la propriété de ce volume</strong> pour quil appartienne au pod :<br>1. Le GID propriétaire sera le FSGroup<br>2. Le bit setgid est défini (les nouveaux fichiers créés dans le volume appartiendront au FSGroup)<br>3. Les bits de permission sont combinés avec rw-rw---- Si non défini, le Kubelet ne modifiera ni la propriété ni les permissions daucun volume</p> |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroupChangePolicy</strong></a><br><em>string</em></p> | Ceci définit le comportement de **changement de propriété et de permissions du volume** avant son exposition à lintérieur du Pod. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | Le **GID utilisé pour exécuter le point dentrée du processus du container**. Utilise la valeur par défaut du runtime si non défini. Peut aussi être défini dans SecurityContext. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | Indique que le container doit sexécuter en tant quutilisateur non-root. Si vrai, le Kubelet vérifiera limage au moment de lexécution pour sassurer quelle ne sexécute pas avec UID 0 (root) et échouera à démarrer le container si cest le cas. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | Le **UID utilisé pour exécuter le point dentrée du processus du container**. Par défaut, lutilisateur spécifié dans les métadonnées de limage si non précisé. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | Le **contexte SELinux à appliquer à tous les containers**. Si non spécifié, le runtime du container attribuera un contexte SELinux aléatoire à chaque container. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroupChangePolicy</strong></a><br><em>string</em></p> | Cela définit le comportement de **changement de propriété et de permission du volume** avant son exposition à lintérieur du Pod. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | Le **GID utilisé pour exécuter lentrypoint du processus du container**. Utilise la valeur par défaut du runtime si non défini. Peut aussi être défini dans SecurityContext. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | Indique que le container doit sexécuter en tant quutilisateur non-root. Si true, le Kubelet validera limage à lexécution pour sassurer quelle ne sexécute pas avec UID 0 (root) et échouera au démarrage du container si cest le cas. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | Le **UID utilisé pour exécuter lentrypoint du processus du container**. Par défaut, lutilisateur spécifié dans les métadonnées de limage si non renseigné. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | Le **contexte SELinux à appliquer à tous les containers**. Si non spécifié, le runtime du container allouera un contexte SELinux aléatoire pour chaque container. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a><br><em>More info about</em> <em><strong>Seccomp</strong></em></p> | Les **options seccomp à utiliser par les containers** dans ce pod. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>supplementalGroups</strong></a><br><em>integer array</em></p> | Une liste de **groupes appliqués au premier processus exécuté dans chaque container**, en plus du GID principal du container. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>sysctls</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#sysctl-v1-core"><em>Sysctl</em></a> <em>array</em><br><em>More info about</em> <a href="https://www.garron.me/en/go2linux/sysctl-linux.html"><em><strong>sysctls</strong></em></a></p> | Les Sysctls contiennent une liste de **sysctls namespaced utilisés pour le pod**. Les Pods avec des sysctls non pris en charge (par le runtime du container) peuvent échouer au lancement. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | Les paramètres spécifiques à Windows appliqués à tous les containers. Si non spécifié, les options présentes dans le SecurityContext dun container seront utilisées. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>sysctls</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#sysctl-v1-core"><em>Sysctl</em></a> <em>array</em><br><em>More info about</em> <a href="https://www.garron.me/en/go2linux/sysctl-linux.html"><em><strong>sysctls</strong></em></a></p> | Les Sysctls contiennent une liste de **sysctls namespacés utilisés pour le pod**. Les Pods avec des sysctls non pris en charge (par le runtime du container) peuvent échouer au démarrage. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | Les paramètres spécifiques à Windows appliqués à tous les containers. Si non spécifié, les options du SecurityContext dun container seront utilisées. |
## SecurityContext
[**From the docs:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
Ce contexte est défini dans les **définitions des containers**. Du point de vue de la sécurité défensive, vous devriez considérer :
Ce contexte est défini à lintérieur des **définitions des containers**. Dun point de vue sécurité défensive, vous devriez considérer :
- **allowPrivilegeEscalation** à **False**
- Ne pas ajouter de **capabilities** sensibles (et retirer celles dont vous navez pas besoin)
@@ -38,47 +38,53 @@ Ce contexte est défini dans les **définitions des containers**. Du point de vu
- Si possible, définir **readOnlyFilesystem** à **True**
- Définir **runAsNonRoot** à **True** et définir un **runAsUser**
- Si possible, envisager de **limiter** les **permissions** en indiquant **seLinuxOptions** et **seccompProfile**
- Ne **PAS** donner un accès de **groupe** à **privilège** via **runAsGroup.**
- Ne **PAS** donner laccès au **groupe** de **privilège** via **runAsGroup.**
Notez que pour les attributs définis à la fois dans **SecurityContext** et **PodSecurityContext**, la valeur spécifiée dans **SecurityContext** a **priorité**.
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>allowPrivilegeEscalation</strong></a><br><em>boolean</em></p> | **AllowPrivilegeEscalation** contrôle si un processus peut **obtenir plus de privilèges** que son processus parent. Ce booléen contrôle directement si le flag no_new_privs sera défini sur le processus du container. AllowPrivilegeEscalation est toujours true lorsque le container est exécuté en mode **Privileged** ou posde **CAP_SYS_ADMIN** |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>allowPrivilegeEscalation</strong></a><br><em>boolean</em></p> | **AllowPrivilegeEscalation** contrôle si un processus peut **obtenir plus de privilèges** que son processus parent. Ce bool contrôle directement si le flag no_new_privs sera défini sur le processus du container. AllowPrivilegeEscalation est toujours true lorsque le container est exécuté en mode **Privileged** ou dispose de **CAP_SYS_ADMIN** |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>capabilities</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#capabilities-v1-core"><em>Capabilities</em></a><br><em>More info about</em> <em><strong>Capabilities</strong></em></p> | Les **capabilities à ajouter/retirer lors de lexécution des containers**. Valeur par défaut : lensemble par défaut des capabilities. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>capabilities</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#capabilities-v1-core"><em>Capabilities</em></a><br><em>More info about</em> <em><strong>Capabilities</strong></em></p> | Les **capabilities à ajouter/supprimer lors de lexécution des containers**. Par défaut, le jeu de capabilities par défaut. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>privileged</strong></a><br><em>boolean</em></p> | Exécuter le container en mode privilégié. Les processus dans des containers privilégiés sont essentiellement **équivalents à root sur lhôte**. Valeur par défaut : false. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>procMount</strong></a><br><em>string</em></p> | procMount désigne le **type de proc mount à utiliser pour les containers**. La valeur par défaut est DefaultProcMount, qui utilise les valeurs par défaut du runtime du container pour les chemins en lecture seule et les chemins masqués. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>readOnlyRootFilesystem</strong></a><br><em>boolean</em></p> | Indique si ce **container a un système de fichiers racine en lecture seule**. La valeur par défaut est false. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | Le **GID utilisé pour exécuter le point dentrée** du processus du container. Utilise la valeur par défaut du runtime si non défini. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | Indique que le container doit **sexécuter en tant quutilisateur non-root**. Si vrai, le Kubelet vérifiera limage au moment de lexécution pour sassurer quelle ne sexécute pas avec UID 0 (root) et échouera à démarrer le container si cest le cas. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | Le **UID utilisé pour exécuter le point dentrée** du processus du container. Par défaut, lutilisateur spécifié dans les métadonnées de limage si non précisé. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | Le **contexte SELinux à appliquer au container**. Si non spécifié, le runtime du container attribuera un contexte SELinux aléatoire à chaque container. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>procMount</strong></a><br><em>string</em></p> | procMount indique le **type de montage proc à utiliser pour les containers**. La valeur par défaut est DefaultProcMount, qui utilise les valeurs par défaut du runtime du container pour les chemins en lecture seule et les chemins masqués. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>readOnlyRootFilesystem</strong></a><br><em>boolean</em></p> | Indique si ce **container possède un système de fichiers racine en lecture seule**. Valeur par défaut : false. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | Le **GID utilisé pour exécuter lentrypoint** du processus du container. Utilise la valeur par défaut du runtime si non défini. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | Indique que le container doit **sexécuter en tant quutilisateur non-root**. Si true, le Kubelet validera limage à lexécution pour sassurer quelle ne sexécute pas avec UID 0 (root) et échouera au démarrage du container si cest le cas. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | Le **UID utilisé pour exécuter lentrypoint** du processus du container. Par défaut, lutilisateur spécifié dans les métadonnées de limage si non renseigné. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | Le **contexte SELinux à appliquer au container**. Si non spécifié, le runtime du container allouera un contexte SELinux aléatoire pour chaque container. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a></p> | Les **options seccomp** à utiliser par ce container. |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | Les **paramètres spécifiques à Windows** appliqués à tous les containers. |
## Practical workload review checklist
Lors de la revue dun Pod ou dun modèle de workload, inspectez à la fois `spec.securityContext` et chaque `securityContext` au niveau du container sous `containers`, `initContainers` et `ephemeralContainers`. Les champs au niveau du container peuvent remplacer les valeurs par défaut du pod, donc un pod qui semble sûr par défaut ne garantit pas que chaque container lest.
Lors de la revue dun Pod ou dun modèle de workload, inspectez à la fois `spec.securityContext` et chaque `securityContext` au niveau container sous `containers`, `initContainers` et `ephemeralContainers`. Les champs au niveau container peuvent remplacer les valeurs par défaut au niveau pod, donc un Pod qui semble sûr par défaut ne garantit pas que chaque container lest.
Combinaisons à haut risque à prioriser :
- `privileged: true`, surtout avec `hostPID`, `hostIPC`, `hostNetwork`, `hostPath`, les ports hôte, ou des montages de socket runtime.
- `privileged: true`, en particulier avec `hostPID`, `hostIPC`, `hostNetwork`, `hostPath`, les ports hôte, ou des montages de socket runtime.
- Des capabilities ajoutées comme `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `SYS_MODULE`, `DAC_READ_SEARCH` ou `DAC_OVERRIDE`.
- `allowPrivilegeEscalation: true` ou non défini dans les containers capables dexécuter du code contrôlé par un attaquant.
- `seccompProfile: Unconfined`, `procMount: Unmasked`, ou des profils runtime absents sur des workloads sensibles.
- Des root filesystems inscriptibles ou des montages de volumes larges en écriture dans des workloads qui traitent des entrées non fiables.
- `allowPrivilegeEscalation: true` ou non défini dans des containers qui peuvent exécuter du code contrôlé par un attaquant.
- `seccompProfile: Unconfined`, `procMount: Unmasked`, ou labsence de profils runtime sur des workloads sensibles.
- Des root filesystems inscriptibles ou des montages de volumes largement inscriptibles dans des workloads qui traitent des entrées non fiables.
- Labsence de requests et limits CPU, mémoire ou ephemeral-storage dans des namespaces multi-tenant.
- Labsence de budgets `spec.resources` au niveau pod ou des valeurs irréalistes, ainsi que des principals ayant `patch` ou `update` sur le sous-ressource `resize` du Pod, car les clusters pris en charge peuvent modifier l’état désiré CPU et mémoire dun Pod en cours dexécution sans le recréer.
Pour la plupart des workloads applicatifs, une bonne base consiste à sexécuter avec un UID non-root, définir `runAsNonRoot: true`, définir `allowPrivilegeEscalation: false`, retirer toutes les capabilities puis ne rajouter que le minimum requis, utiliser `seccompProfile: RuntimeDefault`, préférer un root filesystem en lecture seule et éviter les host namespaces, les montages hostPath et le mode privilégié.
Les contrôles de ressources ne font pas partie de `securityContext`, mais il faut les revoir dans la même passe de revue du workload car ils définissent la frontière de disponibilité. Les versions modernes de Kubernetes peuvent définir des budgets CPU, mémoire et hugepage au niveau Pod dans `spec.resources`, en plus des `resources` au niveau container. Un Pod avec des sidecars peut être limité par une enveloppe Pod agrégée même lorsquun container na pas de limites individuelles, tandis que le stockage éphémère local nécessite toujours des limites séparées `ephemeral-storage`, `emptyDir.sizeLimit`, `LimitRanges` et `ResourceQuotas`. Comparez aussi les ressources désirées dans le Pod spec avec `status.containerStatuses[].resources` après une demande de resize à chaud ; un resize échoué ou en attente peut laisser la valeur demandée dans `spec` tandis que le kubelet conserve lallocation dexécution précédente et signale une condition `PodResizePending`.
Au niveau du cluster, utilisez les labels de namespace de [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) pour appliquer les [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) Kubernetes lorsque possible. Utilisez `restricted` pour les namespaces qui peuvent le supporter, au moins `baseline` pour les namespaces applicatifs ordinaires, et gardez les exceptions privilégiées étroites, documentées et isolées dans des namespaces de plateforme de confiance ou des node pools.
Pour la plupart des workloads applicatifs, une bonne base consiste à exécuter avec un UID non-root, définir `runAsNonRoot: true`, définir `allowPrivilegeEscalation: false`, supprimer toutes les capabilities et ne rajouter que le minimum requis, utiliser `seccompProfile: RuntimeDefault`, privilégier un root filesystem en lecture seule, et éviter les namespaces hôte, les montages `hostPath` et le mode privilégié.
Au niveau cluster, utilisez les labels de namespace [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) pour appliquer les [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) de Kubernetes lorsque cest possible. Utilisez `restricted` pour les namespaces qui peuvent le supporter, au moins `baseline` pour les namespaces dapplications ordinaires, et gardez les exceptions privilégiées étroites, documentées et isolées dans des namespaces de plateforme ou des pools de nœuds de confiance.
## References
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
- [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
- [https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)
- [https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/](https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/)
- [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
- [https://kubernetes.io/docs/concepts/security/pod-security-admission/](https://kubernetes.io/docs/concepts/security/pod-security-admission/)
- [https://kubernetes.io/docs/tasks/configure-pod-container/assign-pod-level-resources/](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pod-level-resources/)
- [https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/](https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/)
{{#include ../../../banners/hacktricks-training.md}}