diff --git a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md index 5932428cd..6a8558ffe 100644 --- a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md +++ b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md @@ -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 à l’intérieur** de votre cluster auquel d’autres applications dans votre cluster peuvent accéder. Il n’y a **aucun accès externe**. +Un **ClusterIP** service est le **service** Kubernetes **par défaut**. Il vous fournit un **service à l’intérieur** de votre cluster auquel d’autres applications dans votre cluster peuvent accéder. Il n’y 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//services/:/` @@ -50,7 +50,7 @@ port: 80 targetPort: 80 protocol: TCP ``` -_Cette méthode nécessite d’exé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 n’est 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 n’est 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 (c’est le port qui sera ouvert), un port dans la **plage 30000–32767 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 30000–32767 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 l’adresse IP source originale du client pour le trafic NodePort/LoadBalancer et évite de transférer vers des endpoints sur d’autres 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 n’importe 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 s’agit de routage de proximité, pas d’une boundary d’autorisation. +- `sessionAffinity: ClientIP` peut faire en sorte que des tests répétés depuis un client touchent le même backend, masquant d’autres 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 d’un 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 d’un 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 lorsqu’un 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 l’un des endpoints du Service**. `externalIPs` ne sont pas gérés par Kubernetes et relèvent de la responsabilité de l’administrateur 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 c’est possible, les mécanismes d’exposition gérés par le controller, comme les intégrations LoadBalancer ou Gateway API, et restreignez/autorisez ce champ avec soin tant qu’il 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 n’importe lequel des `ServiceTypes`. Dans l’exemple 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 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 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 lorsqu’un Service n’a pas de selector, lorsque les labels n’expliquent 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 lorsqu’un Service n’a pas de selector, lorsque les labels n’expliquent 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 -l kubernetes.io/service-name= -o yaml kubectl get endpointslice -n -l kubernetes.io/service-name= \ -o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port' ``` -Lors de l’examen de l’exposition, 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 l’examen de l’exposition, comparez le selector du Service avec le `targetRef` de l’EndpointSlice, les adresses d’endpoint, 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 n’est PAS un type de service**. Il se place au contraire **devant plusieurs services et agit comme un “smart router”** ou point d’entrée vers votre cluster. +Contrairement à tous les exemples ci-dessus, **Ingress n’est PAS un type de service**. À la place, il se place **devant plusieurs services et agit comme un “smart router”** 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 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 d’un 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 d’obtenir les infos de chacun un par un pour mieux les lire : +Bien que, dans ce cas, il soit préférable d’obtenir 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 -o yaml kubectl get httproute -n -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 lorsqu’aucun objet legacy Ingress n’existe. ### 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/) diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-basics.md b/src/pentesting-cloud/kubernetes-security/kubernetes-basics.md index 1962a3a6d..21775365c 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-basics.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-basics.md @@ -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 d’exécuter un ou plusieurs container/s dans un container engine. +- Le schedule permet d’exé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 d’information. ### 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 doesn’t 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 d’un container ou de plusieurs containers avec. Un pod ne devrait contenir qu’une 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 d’exé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 l’un meurt, le **nouveau remplacement** (avec une IP interne différente) **sera accessible** exposé sur la **mê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.\ +Lorsqu’un **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 l’API server). Le kubelet ne gère pas les containers qui n’ont pas été créés par Kubernetes. +- **Kube-proxy**: est le service chargé des communications (services) entre l’apiserver et le node. La base est une IPtables pour les nodes. Les utilisateurs les plus expérimentés pourraient installer d’autres kube-proxies provenant d’autres vendors. +- **Sidecar container**: Les sidecar containers sont les containers qui doivent s’exé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. Aujourd’hui, nous savons que nous utilisons la technologie de container pour encapsuler toutes les dépendances afin que l’application puisse s’exécuter n’importe où. Un container ne fait qu’une 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 Kubernetes’s 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:** C’est 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 à s’assurer que les Pods sont associés aux Nodes afin que Kubelet puisse les exécuter. Il dispose de suffisamment d’intelligence 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 s’exécutant à l’inté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 d’exé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 l’API. +- **etcd**: Stockage de données, persistant, cohérent et distribué. C’est 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 d’exécution...) +- **Cloud controller manager**: C’est 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 d’ici pour savoir comment communiquer avec le reste des services (pods). Notez que ce n’est pas l’endroit recommandé pour stocker des credentials ! +- **Secret**: C’est l’endroit 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**: C’est 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 l’image à exécuter. +- **StatefulSet**: Ce component est destiné spécifiquement aux applications comme les **databases** qui doivent **accéder au même stockage**. +- **Ingress**: C’est la configuration utilisée pour **exposer l’application publiquement avec une URL**. Notez que cela peut aussi être fait avec des external services, mais c’est la bonne manière d’exposer l’application. +- Si vous implémentez un Ingress, vous devrez créer des **Ingress Controllers**. L’Ingress Controller est un **pod** qui sera l’endpoint recevant les requêtes, les examinant et les load balancer vers les services. l’ingress 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 d’utiliser un cloud load balancer ou un proxy server comme point d’entrée afin de n’avoir aucune partie du cluster Kubernetes exposée. +- Lorsqu’une requête qui ne correspond à aucune ingress rule est reçue, l’ingress controller la dirigera vers le "**Default backend**". Vous pouvez `describe` l’ingress controller pour obtenir l’adresse 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 qu’il 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 l’image à 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 l’exté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 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) : ```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 à l’inté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 d’utilisateurs, 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 l’application 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 d’un 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= ``` ### 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 ``` -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 d’un 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 qu’un 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 d’un 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` à l’inté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 +### Secrets in etcd **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 url’s 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 url’s qui se trouvent dans le FS. Une fois que vous les aurez obtenus, vous pourrez vous connecter à etcd. ```bash #ETCDCTL_API=3 etcdctl --cert --key --cacert endpoint=[] 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 --key --cacert endpoint=[] get @@ -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 qu’il pointe vers l’emplacement 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 qu’il pointe vers l’emplacement 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/ ``` -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é lorsqu’il 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 lorsqu’elles 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é lorsqu’il est récupéré via l’API : ``` @@ -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 d’autres 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}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md b/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md index 9d22c5721..0b663f4ba 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.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 d’un 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é d’un Pod, vous pouvez utiliser plusieurs attributs. D’un 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 l’accès au **groupe** de **privilège** via **runAsGroup** et **supplementaryGroups** | Parameter | Description | -|

fsGroup
integer

|

Un groupe supplémentaire spécial qui s’applique à **tous les containers d’un pod**. Certains types de volume permettent au Kubelet de **changer la propriété de ce volume** pour qu’elle appartienne au pod :
1. Le GID propriétaire sera le FSGroup
2. Le bit setgid est défini (les nouveaux fichiers créés dans le volume appartiendront au FSGroup)
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 d’aucun volume

| +|

fsGroup
integer

|

Un groupe supplémentaire spécial qui s’applique à **tous les containers d’un pod**. Certains types de volume permettent au Kubelet de modifier la propriété de ce volume pour qu’il appartienne au pod :
1. Le GID propriétaire sera le FSGroup
2. Le bit setgid est défini (les nouveaux fichiers créés dans le volume appartiendront au FSGroup)
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 d’aucun volume

| -|

fsGroupChangePolicy
string

| Ceci définit le comportement de **changement de propriété et de permissions du volume** avant son exposition à l’intérieur du Pod. | -|

runAsGroup
integer

| Le **GID utilisé pour exécuter le point d’entrée du processus du container**. Utilise la valeur par défaut du runtime si non défini. Peut aussi être défini dans SecurityContext. | -|

runAsNonRoot
boolean

| Indique que le container doit s’exécuter en tant qu’utilisateur non-root. Si vrai, le Kubelet vérifiera l’image au moment de l’exécution pour s’assurer qu’elle ne s’exécute pas avec UID 0 (root) et échouera à démarrer le container si c’est le cas. | -|

runAsUser
integer

| Le **UID utilisé pour exécuter le point d’entrée du processus du container**. Par défaut, l’utilisateur spécifié dans les métadonnées de l’image si non précisé. | -|

seLinuxOptions
SELinuxOptions
More info about seLinux

| Le **contexte SELinux à appliquer à tous les containers**. Si non spécifié, le runtime du container attribuera un contexte SELinux aléatoire à chaque container. | +|

fsGroupChangePolicy
string

| Cela définit le comportement de **changement de propriété et de permission du volume** avant son exposition à l’intérieur du Pod. | +|

runAsGroup
integer

| Le **GID utilisé pour exécuter l’entrypoint du processus du container**. Utilise la valeur par défaut du runtime si non défini. Peut aussi être défini dans SecurityContext. | +|

runAsNonRoot
boolean

| Indique que le container doit s’exécuter en tant qu’utilisateur non-root. Si true, le Kubelet validera l’image à l’exécution pour s’assurer qu’elle ne s’exécute pas avec UID 0 (root) et échouera au démarrage du container si c’est le cas. | +|

runAsUser
integer

| Le **UID utilisé pour exécuter l’entrypoint du processus du container**. Par défaut, l’utilisateur spécifié dans les métadonnées de l’image si non renseigné. | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| Le **contexte SELinux à appliquer à tous les containers**. Si non spécifié, le runtime du container allouera un contexte SELinux aléatoire pour chaque container. | |

seccompProfile
SeccompProfile
More info about Seccomp

| Les **options seccomp à utiliser par les containers** dans ce pod. | |

supplementalGroups
integer array

| Une liste de **groupes appliqués au premier processus exécuté dans chaque container**, en plus du GID principal du container. | -|

sysctls
Sysctl array
More info about sysctls

| 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. | -|

windowsOptions
WindowsSecurityContextOptions

| Les paramètres spécifiques à Windows appliqués à tous les containers. Si non spécifié, les options présentes dans le SecurityContext d’un container seront utilisées. | +|

sysctls
Sysctl array
More info about sysctls

| 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. | +|

windowsOptions
WindowsSecurityContextOptions

| Les paramètres spécifiques à Windows appliqués à tous les containers. Si non spécifié, les options du SecurityContext d’un 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 à l’intérieur des **définitions des containers**. D’un point de vue sécurité défensive, vous devriez considérer : - **allowPrivilegeEscalation** à **False** - Ne pas ajouter de **capabilities** sensibles (et retirer celles dont vous n’avez 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 l’accè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é**. -|

allowPrivilegeEscalation
boolean

| **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 possède **CAP_SYS_ADMIN** | +|

allowPrivilegeEscalation
boolean

| **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** | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -|

capabilities
Capabilities
More info about Capabilities

| Les **capabilities à ajouter/retirer lors de l’exécution des containers**. Valeur par défaut : l’ensemble par défaut des capabilities. | +|

capabilities
Capabilities
More info about Capabilities

| Les **capabilities à ajouter/supprimer lors de l’exécution des containers**. Par défaut, le jeu de capabilities par défaut. | |

privileged
boolean

| Exécuter le container en mode privilégié. Les processus dans des containers privilégiés sont essentiellement **équivalents à root sur l’hôte**. Valeur par défaut : false. | -|

procMount
string

| 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. | -|

readOnlyRootFilesystem
boolean

| Indique si ce **container a un système de fichiers racine en lecture seule**. La valeur par défaut est false. | -|

runAsGroup
integer

| Le **GID utilisé pour exécuter le point d’entrée** du processus du container. Utilise la valeur par défaut du runtime si non défini. | -|

runAsNonRoot
boolean

| Indique que le container doit **s’exécuter en tant qu’utilisateur non-root**. Si vrai, le Kubelet vérifiera l’image au moment de l’exécution pour s’assurer qu’elle ne s’exécute pas avec UID 0 (root) et échouera à démarrer le container si c’est le cas. | -|

runAsUser
integer

| Le **UID utilisé pour exécuter le point d’entrée** du processus du container. Par défaut, l’utilisateur spécifié dans les métadonnées de l’image si non précisé. | -|

seLinuxOptions
SELinuxOptions
More info about seLinux

| Le **contexte SELinux à appliquer au container**. Si non spécifié, le runtime du container attribuera un contexte SELinux aléatoire à chaque container. | +|

procMount
string

| 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. | +|

readOnlyRootFilesystem
boolean

| Indique si ce **container possède un système de fichiers racine en lecture seule**. Valeur par défaut : false. | +|

runAsGroup
integer

| Le **GID utilisé pour exécuter l’entrypoint** du processus du container. Utilise la valeur par défaut du runtime si non défini. | +|

runAsNonRoot
boolean

| Indique que le container doit **s’exécuter en tant qu’utilisateur non-root**. Si true, le Kubelet validera l’image à l’exécution pour s’assurer qu’elle ne s’exécute pas avec UID 0 (root) et échouera au démarrage du container si c’est le cas. | +|

runAsUser
integer

| Le **UID utilisé pour exécuter l’entrypoint** du processus du container. Par défaut, l’utilisateur spécifié dans les métadonnées de l’image si non renseigné. | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| Le **contexte SELinux à appliquer au container**. Si non spécifié, le runtime du container allouera un contexte SELinux aléatoire pour chaque container. | |

seccompProfile
SeccompProfile

| Les **options seccomp** à utiliser par ce container. | |

windowsOptions
WindowsSecurityContextOptions

| Les **paramètres spécifiques à Windows** appliqués à tous les containers. | ## Practical workload review checklist -Lors de la revue d’un Pod ou d’un 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 l’est. +Lors de la revue d’un Pod ou d’un 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 l’est. 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 d’exé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 l’absence 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. - L’absence de requests et limits CPU, mémoire ou ephemeral-storage dans des namespaces multi-tenant. +- L’absence 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 d’un Pod en cours d’exécution sans le recréer. -Pour la plupart des workloads applicatifs, une bonne base consiste à s’exé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 lorsqu’un container n’a 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 l’allocation d’exé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 c’est possible. Utilisez `restricted` pour les namespaces qui peuvent le supporter, au moins `baseline` pour les namespaces d’applications 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}}