From ea0fad2a2a3f3492e97580cda727570e73a24f14 Mon Sep 17 00:00:00 2001 From: Translator Date: Sat, 4 Jul 2026 11:48:56 +0000 Subject: [PATCH] Translated ['src/pentesting-cloud/kubernetes-security/kubernetes-basics. --- .../exposing-services-in-kubernetes.md | 70 ++++++++------ .../kubernetes-security/kubernetes-basics.md | 90 +++++++++-------- .../kubernetes-securitycontext-s.md | 96 ++++++++++--------- 3 files changed, 143 insertions(+), 113 deletions(-) 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 25fb471e1..ee6dfd570 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}} -У Kubernetes є **різні способи expose services**, щоб до них могли звертатися як **internal** endpoints, так і **external** endpoints. Ця Kubernetes configuration є дуже критичною, оскільки administrator може надати **attackers доступ до services, до яких вони не повинні мати доступ**. +Існують **різні способи expose services** у Kubernetes, щоб і **internal** endpoints, і **external** endpoints могли до них доступатися. Ця Kubernetes configuration є дуже критичною, оскільки administrator може надати **attackers доступ до services**, до яких вони не повинні мати доступ. ### Automatic Enumeration -Перед тим як починати enumerating способи, які K8s пропонує для exposing services to the public, знайте, що якщо ви можете list namespaces, services and ingresses, ви можете знайти все, що exposed to the public, за допомогою: +Перш ніж починати enumerating способи, які K8s пропонує для expose services у public, майте на увазі: якщо ви можете list namespaces, services and ingresses, ви можете знайти все, що exposed to the public, за допомогою: ```bash kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do echo "Namespace: $ns" @@ -20,17 +20,17 @@ done | grep -v "ClusterIP" ``` ### ClusterIP -**ClusterIP** service — це **типовий** Kubernetes **service**. Він надає вам **service всередині** вашого кластеру, до якого можуть отримати доступ інші apps всередині вашого кластеру. **Зовнішнього доступу** немає. +**ClusterIP** service — це **default** Kubernetes **service**. Він надає вам **service всередині** вашого cluster, до якого можуть звертатися інші apps всередині вашого cluster. **Зовнішнього доступу** немає. -Однак до нього можна отримати доступ через Kubernetes Proxy: +Однак до нього можна отримати доступ за допомогою Kubernetes Proxy: ```bash kubectl proxy --port=8080 ``` -Тепер ви можете переміщатися через Kubernetes API, щоб отримувати доступ до services, використовуючи таку схему: +Тепер ви можете переходити через Kubernetes API, щоб отримувати доступ до services, використовуючи цю схему: `http://localhost:8080/api/v1/proxy/namespaces//services/:/` -Наприклад, ви можете використати такий URL: +Наприклад, ви можете використати таку URL-адресу: `http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/` @@ -50,7 +50,7 @@ port: 80 targetPort: 80 protocol: TCP ``` -_Цей метод вимагає, щоб ви запускали `kubectl` як **автентифікований користувач**._ +_Цей метод вимагає, щоб ви запускали `kubectl` як **authenticated user**._ Перелічіть усі ClusterIPs: ```bash @@ -58,13 +58,13 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam ``` ### NodePort -Коли використовується **NodePort**, на всіх Nodes (що представляють Virtual Machines) відкривається призначений порт. **Traffic**, спрямований на цей конкретний порт, далі **route to the service**. Зазвичай цей метод не рекомендується через його недоліки. +Коли використовується **NodePort**, на всіх Nodes (що представляють Virtual Machines) відкривається призначений порт. **Traffic**, спрямований на цей конкретний порт, потім систематично **routes to the service**. Зазвичай цей метод не рекомендується через його недоліки. -Перелічити всі NodePorts: +List all 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 ``` -Приклад specification NodePort: +Приклад NodePort specification: ```yaml apiVersion: v1 kind: Service @@ -81,22 +81,33 @@ targetPort: 80 nodePort: 30036 protocol: TCP ``` -Якщо ви **не вказуєте** **nodePort** у yaml (це порт, який буде відкрито), буде використано порт у **діапазоні 30000–32767**. +Якщо ви **не вкажете** **nodePort** у yaml (це порт, який буде відкрито), буде використано порт у **діапазоні 30000–32767**. + +Під час аналізу NodePort або LoadBalancer Services також перевіряйте поля traffic-policy, оскільки вони змінюють, які nodes і backends є корисними з певного source: +```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` зберігає оригінальну IP-адресу client для трафіку NodePort/LoadBalancer і не пересилає його на endpoints на інших nodes. node без local ready endpoint може відкинути трафік, навіть якщо Service має endpoints десь ще. +- `externalTrafficPolicy: Cluster` є default і може пересилати через будь-який node, але backend logs можуть бачити node IPs замість реальної external client IP. +- `internalTrafficPolicy: Local` обмежує in-cluster Service traffic endpoints, локальними для source node. Це locality routing, а не authorization boundary. +- `sessionAffinity: ClientIP` може зробити так, що повторні тести з одного client потраплятимуть у той самий backend, приховуючи інші ready endpoints під час manual checks. +- `trafficDistribution` і EndpointSlice topology hints можуть надавати перевагу same-zone або same-node endpoints на новіших clusters; розглядайте їх як routing preferences, а не як жорстку security policy. ### LoadBalancer -Публікує Service назовні **з використанням load balancer хмарного провайдера**. У GKE це підніме [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/), який надасть вам одну IP-адресу та перенаправлятиме весь трафік до вашого service. В AWS це запустить Load Balancer. +Exposes the Service externally **using a cloud provider's load balancer**. On GKE, this will spin up a [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) that will give you a single IP address that will forward all traffic to your service. In AWS it will launch a Load Balancer. -За кожен exposed service з LoadBalancer потрібно платити, що може бути дорого. +You have to pay for a LoadBalancer per exposed service, which can be expensive. -Список усіх 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 ``` ### External IPs > [!TIP] -> External IPs exposed by services of type Load Balancers and they are generally used when an external Cloud Provider Load Balancer is being used. +> External IPs are exposed by services of type Load Balancers and they are generally used when an external Cloud Provider Load Balancer is being used. > > For finding them, check for load balancers with values in the `EXTERNAL-IP` field. @@ -123,9 +134,9 @@ externalIPs: ``` ### ExternalName -[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Сервіси типу ExternalName **map a Service to a DNS name**, а не до типового selector, такого як `my-service` або `cassandra`. Ви вказуєте ці Services за допомогою параметра `spec.externalName`. +[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Services of type ExternalName **map a Service to a DNS name**, not to a typical selector such as `my-service` or `cassandra`. You specify these Services with the `spec.externalName` parameter. -Ось, наприклад, це визначення Service maps `my-service` Service у namespace `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 ``` -Під час пошуку хоста `my-service.prod.svc.cluster.local`, cluster DNS Service повертає запис `CNAME` зі значенням `my.database.example.com`. Доступ до `my-service` працює так само, як і до інших Services, але з важливою відмінністю: **redirecting відбувається на рівні DNS**, а не через proxying або forwarding. +Під час пошуку хоста `my-service.prod.svc.cluster.local`, DNS Service кластера повертає запис `CNAME` зі значенням `my.database.example.com`. Доступ до `my-service` працює так само, як і до інших Services, але з ключовою відмінністю: **redirection відбувається на рівні DNS**, а не через proxying або forwarding. -List all ExternalNames: +Перелічіть усі ExternalNames: ```bash kubectl get services --all-namespaces | grep ExternalName ``` ### EndpointSlices -EndpointSlices показують конкретні backend-адреси та порти, на які Service наразі маршрутизує трафік. Вони особливо корисні, коли Service не має selector, коли labels не пояснюють шлях трафіку, або коли готові лише деякі backend-и. +EndpointSlices показують конкретні backend-адреси та порти, на які Service наразі маршрутизує трафік. Вони особливо корисні, коли Service не має selector, коли labels не пояснюють шлях traffic, або коли готові лише деякі backends. -Перелічіть EndpointSlices, пов’язані з Services: +Перелічити EndpointSlices, пов’язані з 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' ``` -Під час перевірки exposure порівнюйте Service selector з EndpointSlice `targetRef`, endpoint addresses, readiness conditions і ports. Service без selector може бути пов’язаний із вручну керованими EndpointSlices і спрямовувати traffic до не-Pod або неочікуваних destinations. +Під час перевірки exposure порівнюйте Service selector з EndpointSlice `targetRef`, адресами endpoints, умовами readiness і ports. Selectorless Service можна поєднати з вручну керованими EndpointSlices і спрямувати traffic на не-Pod або неочікувані destinations. ### Ingress На відміну від усіх наведених вище прикладів, **Ingress — це НЕ тип service**. Натомість він стоїть **перед кількома services і діє як “smart router”** або entrypoint у ваш cluster. -Ви можете робити з Ingress багато різних речей, і існує **багато типів Ingress controllers, які мають різні capabilities**. +З Ingress можна робити багато різних речей, і існує **багато типів Ingress controllers, які мають різні capabilities**. -Default GKE ingress controller запустить для вас [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Це дасть змогу робити routing на backend services як на основі path, так і на основі subdomain. Наприклад, ви можете спрямувати все на foo.yourdomain.com до foo service, а все під path yourdomain.com/bar/ — до bar service. +Default GKE ingress controller підніме для вас [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Це дозволить вам робити як routing на основі path, так і на основі subdomain до backend services. Наприклад, ви можете направити все на foo.yourdomain.com до service foo, а все під path yourdomain.com/bar/ — до service bar. YAML для об’єкта Ingress у GKE з [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) може виглядати так: ```yaml @@ -197,17 +208,17 @@ name: bar port: number: 8080 ``` -Перелічіть усі ingresses: +Перелічити всі ingress: ```bash kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status' ``` -Хоча в цьому випадку краще отримати інформацію про кожен по одному, щоб читати її легше: +Хоча в цьому випадку краще отримувати інформацію про кожен по одному, щоб читати її зручніше: ```bash kubectl get ingresses --all-namespaces -o=yaml ``` ### Gateway API -Gateway API — це новіший Kubernetes API для exposure Services. Він розділяє infrastructure-owned Gateway objects від application-owned Route objects, таких як HTTPRoute. Це корисно для delegation, але також означає, що exposure може бути розподілений між namespaces. +Gateway API — це новіший Kubernetes API для exposing Services. Він розділяє об’єкти Gateway, що належать infrastructure, від Route-об’єктів, що належать application, таких як HTTPRoute. Це корисно для delegation, але також означає, що exposure може бути розділене між namespaces. List Gateway API exposure objects: ```bash @@ -217,13 +228,16 @@ kubectl get httproutes --all-namespaces kubectl get gateway -n -o yaml kubectl get httproute -n -o yaml ``` -Перевірте Gateway listeners, дозволені namespaces маршрутів, `parentRefs` Route, hostnames, filters, backend references і status conditions, наприклад, чи route було accepted. Route, який accepted спільним Gateway, може expose backend навіть тоді, коли не існує legacy Ingress object. +Перевірте Gateway listeners, allowed route namespaces, Route `parentRefs`, hostnames, filters, backend references і status conditions, такі як те, чи була route accepted. Route, яка accepted спільним Gateway, може expose backend навіть тоді, коли не існує legacy Ingress object. ### 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 db8f19020..aa185dda4 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-basics.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-basics.md @@ -10,8 +10,8 @@ - Дозволяє запускати container/s у container engine. - Schedule дозволяє containers mission efficient. -- Підтримує containers активними. -- Дозволяє communications між containers. +- Підтримує containers живими. +- Дозволяє container communications. - Дозволяє deployment techniques. - Обробляє volumes of information. @@ -20,7 +20,7 @@ ![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 навколо container або 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. +- **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. @@ -39,6 +39,8 @@ 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! @@ -105,7 +107,7 @@ $ minikube delete ``` ### Kubectl Basics -**`Kubectl`** — це командний інструмент для kubernetes clusters. Він взаємодіє з Api server процесу master, щоб виконувати дії в kubernetes або запитувати дані. +**`Kubectl`** — це інструмент командного рядка для кластерів kubernetes. Він взаємодіє з Api server master process, щоб виконувати дії в kubernetes або запитувати дані. ```bash kubectl version #Get client and server version kubectl get pod @@ -136,9 +138,9 @@ kubectl delete deployment mongo-depl #Deploy from config file kubectl apply -f deployment.yml ``` -### Панель Minikube +### Minikube Dashboard -Панель дозволяє легше побачити, що запускає minikube, ви можете знайти URL для доступу до неї в: +Dashboard дозволяє легше побачити, що запущено в minikube, URL для доступу до нього можна знайти в: ``` minikube dashboard --url @@ -154,7 +156,7 @@ http://127.0.0.1:50034/api/v1/namespaces/kubernetes-dashboard/services/http:kube ### YAML configuration files examples Кожен configuration file має 3 частини: **metadata**, **specification** (що потрібно запустити), **status** (бажаний стан).\ -Всередині specification deployment configuration file можна знайти template, визначений новою configuration structure, яка задає image для запуску: +Усередині specification deployment configuration file ви можете знайти template, визначений із новою configuration structure, що задає image для запуску: **Example of Deployment + Service declared in the same configuration file (from** [**here**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**)** @@ -205,7 +207,7 @@ ports: port: 27017 targetPort: 27017 ``` -**Приклад конфігурації external service** +**Приклад конфігурації зовнішнього service** Цей service буде доступний зовні (перевірте атрибути `nodePort` і `type: LoadBlancer`): ```yaml @@ -225,7 +227,7 @@ targetPort: 8081 nodePort: 30000 ``` > [!NOTE] -> Це корисно для тестування, але для production у вас мають бути лише internal services та Ingress, щоб expose application. +> Це корисно для тестування, але для production у вас мають бути лише internal services і Ingress, щоб expose application. **Example of Ingress config file** @@ -245,9 +247,9 @@ paths: serviceName: kubernetes-dashboard servicePort: 80 ``` -**Приклад файлу конфігурації secrets** +**Приклад конфігураційного файлу secrets** -Зверніть увагу, що паролі закодовані в B64 (що не є безпечно!) +Зверніть увагу, як паролі закодовані в B64 (що не є безпечно!) ```yaml apiVersion: v1 kind: Secret @@ -260,7 +262,7 @@ mongo-root-password: cGFzc3dvcmQ= ``` **Приклад ConfigMap** -**ConfigMap** — це конфігурація, яка надається pod'ам, щоб вони знали, як знаходити та отримувати доступ до інших services. У цьому випадку кожен pod знатиме, що ім'я `mongodb-service` є адресою pod'а, з яким він може взаємодіяти (цей pod буде запускати mongodb): +**ConfigMap** — це конфігурація, яка передається pods, щоб вони знали, як знаходити та отримувати доступ до інших services. У цьому випадку кожен pod знатиме, що ім’я `mongodb-service` — це адреса pod, з яким вони можуть взаємодіяти (цей pod виконуватиме mongodb): ```yaml apiVersion: v1 kind: ConfigMap @@ -269,7 +271,7 @@ name: mongodb-configmap data: database_url: mongodb-service ``` -Тоді, всередині **deployment config** цю адресу можна вказати таким чином, щоб вона завантажувалася всередині env pod: +Потім, всередині **deployment config** цю адресу можна вказати таким чином, щоб вона завантажувалася в env pod: ```yaml [...] spec: @@ -292,16 +294,16 @@ key: database_url ``` **Example of 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** +Ви можете знайти різні приклади YAML-файлів конфігурації storage у [https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes](https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes).\ +**Зверніть увагу, що volumes не знаходяться всередині 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 підтримує **multiple virtual clusters**, які працюють поверх того самого фізичного cluster. Ці virtual clusters називаються **namespaces**. Вони призначені для використання в середовищах із багатьма користувачами, розподіленими між кількома teams або projects. Для clusters із кількома або десятком користувачів вам зазвичай не потрібно створювати namespaces або взагалі про них думати. Використовувати namespaces варто починати, щоб мати кращий контроль і організацію кожної частини application, розгорнутої в 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**. +Namespaces надають scope для names. Names ресурсів мають бути унікальними в межах namespace, але не між namespaces. Namespaces не можуть вкладатися одна в одну, і **кожен** Kubernetes **resource** може бути лише **в** **одному** **namespace**. -There are 4 namespaces by default if you are using minikube: +Існує 4 namespaces за замовчуванням, якщо ви використовуєте minikube: ``` kubectl get namespace NAME STATUS AGE @@ -310,23 +312,23 @@ kube-node-lease Active 1d kube-public Active 1d kube-system Active 1d ``` -- **kube-system**: Це не призначено для використання користувачами, і вам не слід це чіпати. Це для master і kubectl процесів. -- **kube-public**: Публічно доступні дані. Містить configmap, який містить інформацію про cluster +- **kube-system**: Він не призначений для використання користувачами, і вам не слід його чіпати. Це для master і kubectl процесів. +- **kube-public**: Загальнодоступні дані. Містить configmap, який містить інформацію про кластер - **kube-node-lease**: Визначає доступність node -- **default**: namespace, який користувач використовуватиме для створення resources +- **default**: Namespace, який користувач використовуватиме для створення ресурсів ```bash #Create namespace kubectl create namespace my-namespace ``` > [!NOTE] -> Зверніть увагу, що більшість Kubernetes resources (наприклад, pods, services, replication controllers та інші) знаходяться в деяких namespaces. Однак інші resources, як-от namespace resources і low-level resources, такі як nodes та persistenVolumes, не знаходяться в namespace. Щоб побачити, які Kubernetes resources є в namespace, а які — ні: +> Зауважте, що більшість ресурсів Kubernetes (наприклад, pods, services, replication controllers та інші) знаходяться в деяких namespaces. Однак інші ресурси, як-от namespace resources і low-level resources, такі як nodes та persistenVolumes, не знаходяться в namespace. Щоб побачити, які ресурси Kubernetes знаходяться і не знаходяться в namespace: > > ```bash > kubectl api-resources --namespaced=true #In a namespace > kubectl api-resources --namespaced=false #Not in a namespace > ``` -Ви можете зберегти namespace для всіх наступних kubectl commands у цьому context. +You can save the namespace for all subsequent kubectl commands in that context. ```bash kubectl config set-context --current --namespace= ``` @@ -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 in etcd +### Секрети в etcd -**etcd** — це узгоджене та високодоступне **key-value store**, яке використовується як backing store Kubernetes для всіх даних кластера. Давайте отримаємо доступ до secrets, що зберігаються в etcd: +**etcd** — це узгоджене та високодоступне **key-value store**, яке використовується як backing store Kubernetes для всіх даних кластера. Давайте отримаємо доступ до secret'ів, збережених в etcd: ```bash cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd ``` -Ви побачите certs, keys та url’s, які знаходяться у FS. Щойно ви отримаєте їх, ви зможете підключитися до etcd. +Ви побачите certs, keys і url’s, які розташовані в FS. Після того, як ви їх отримаєте, ви зможете підключитися до 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 ``` -Після того, як вам вдасться встановити зв’язок, ви зможете отримати secrets: +Після того, як ви встановите communication, ви зможете отримати secrets: ```bash #ETCDCTL_API=3 etcdctl --cert --key --cacert endpoint=[] get @@ -440,7 +442,7 @@ ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key ``` **Додавання encryption до ETCD** -За замовчуванням усі secrets **stored in plain** text всередині etcd, якщо не застосувати encryption layer. Наступний приклад базується на [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) +За замовчуванням усі secrets **зберігаються у plain** text всередині etcd, якщо не застосувати encryption layer. Наведений нижче приклад заснований на [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) ```yaml:encryption.yaml apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration @@ -454,14 +456,14 @@ keys: secret: cjjPMcWpTPKhAdieVtd+KhG4NN+N6e3NmBPMXJvbfrY= #Any random key - identity: {} ``` -Після цього вам потрібно встановити прапорець `--encryption-provider-config` для `kube-apiserver`, щоб він вказував на розташування створеного файлу конфігурації. Ви можете змінити `/etc/kubernetes/manifest/kube-apiserver.yaml` і додати такі рядки: +Після цього потрібно встановити прапорець `--encryption-provider-config` для `kube-apiserver`, щоб він вказував на розташування створеного config file. Ви можете змінити `/etc/kubernetes/manifest/kube-apiserver.yaml` і додати такі рядки: ```yaml containers: - command: - kube-apiserver - --encriyption-provider-config=/etc/kubernetes/etcd/ ``` -Прокрутіть вниз у volumeMounts: +Прокрутіть униз у volumeMounts: ```yaml - mountPath: /etc/kubernetes/etcd name: etcd @@ -474,39 +476,39 @@ path: /etc/kubernetes/etcd type: DirectoryOrCreate name: etcd ``` -**Перевірка, що дані зашифровані** +**Перевірка, що data зашифровано** -Дані шифруються під час запису в etcd. Після перезапуску `kube-apiserver` будь-який новостворений або оновлений secret має зберігатися зашифрованим. Щоб перевірити це, можна використати командний рядок `etcdctl` для отримання вмісту вашого secret. +Data шифрується під час запису в etcd. Після перезапуску вашого `kube-apiserver` будь-який newly created або updated secret має бути зашифрований під час зберігання. Щоб перевірити це, ви можете використати команду `etcdctl` для отримання вмісту вашого secret. -1. Створіть новий secret з назвою `secret1` у namespace `default`: +1. Створіть новий secret під назвою `secret1` у namespace `default`: ``` kubectl create secret generic secret1 -n default --from-literal=mykey=mydata ``` -2. За допомогою командного рядка etcdctl прочитайте цей secret з etcd: +2. За допомогою команди etcdctl зчитайте цей secret з etcd: `ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C` -де `[...]` мають бути додаткові аргументи для підключення до сервера etcd. +де `[...]` має бути додатковими аргументами для підключення до etcd server. -3. Переконайтеся, що збережений secret має префікс `k8s:enc:aescbc:v1:`, який вказує, що provider `aescbc` зашифрував отримані дані. -4. Переконайтеся, що secret правильно розшифровується під час отримання через API: +3. Переконайтеся, що збережений secret має префікс `k8s:enc:aescbc:v1:`, який вказує, що provider `aescbc` зашифрував отримані data. +4. Переконайтеся, що secret правильно decrypted під час отримання через API: ``` kubectl describe secret secret1 -n default ``` -має відповідати `mykey: bXlkYXRh`, mydata encoded, перевірте [decoding a secret](https://kubernetes.io/docs/concepts/configuration/secret#decoding-a-secret), щоб повністю декодувати secret. +має відповідати `mykey: bXlkYXRh`, mydata is encoded, перевірте [decoding a secret](https://kubernetes.io/docs/concepts/configuration/secret#decoding-a-secret), щоб повністю decode secret. -**Оскільки secrets шифруються під час запису, виконання оновлення secret зашифрує цей вміст:** +**Оскільки secrets шифруються під час запису, виконання update для secret зашифрує цей content:** ``` kubectl get secrets --all-namespaces -o json | kubectl replace -f - ``` **Final tips:** - Намагайтеся не зберігати secrets у FS, отримуйте їх з інших місць. -- Перевірте [https://www.vaultproject.io/](https://www.vaultproject.io) для додаткового захисту ваших secrets. +- Перевірте [https://www.vaultproject.io/](https://www.vaultproject.io) щоб додати більше захисту до ваших 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 39cde80eb..46ddf359b 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 @@ -4,81 +4,87 @@ ## PodSecurityContext -[**From the docs:**](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) -Під час вказування security context Pod ви можете використовувати кілька атрибутів. З точки зору defensive security слід врахувати: +Під час вказання security context для Pod можна використовувати кілька атрибутів. З точки зору defensive security слід врахувати: -- Щоб **runASNonRoot** був **True** +- Мати **runASNonRoot** як **True** - Налаштувати **runAsUser** -- Якщо можливо, розгляньте **обмеження** **permissions**, вказавши **seLinuxOptions** і **seccompProfile** -- **НЕ** надавайте доступ до **privilege** **group** через **runAsGroup** і **supplementaryGroups** +- Якщо можливо, розгляньте **обмеження** **permissions**, вказуючи **seLinuxOptions** та **seccompProfile** +- **НЕ** надавати доступ до **privilege** **group** через **runAsGroup** і **supplementaryGroups** -| Parameter | Description | -|

fsGroup
integer

|

Спеціальна supplemental group, яка застосовується до all containers in a pod. Деякі типи volume дозволяють Kubelet змінювати ownership цього volume, щоб він належав pod:
1. Власницький GID буде FSGroup
2. Встановлюється setgid bit (нові файли, створені у volume, належатимуть FSGroup)
3. Біт permissions буде OR'd з rw-rw---- Якщо не задано, Kubelet не змінюватиме ownership і permissions жодного volume

| +| Параметр | Опис | +|

fsGroup
integer

|

Спеціальна додаткова група, яка застосовується до all containers in a pod. Деякі типи volume дозволяють Kubelet змінювати власника цього volume, щоб ним володів pod:
1. GID власника буде FSGroup
2. Встановлюється біт setgid (нові файли, створені у volume, належатимуть FSGroup)
3. Біти permissions будуть OR'd з rw-rw---- Якщо не задано, Kubelet не змінюватиме ownership і permissions жодного volume

| -|

fsGroupChangePolicy
string

| Це визначає поведінку **зміни ownership і permission volume** перед тим, як він стане доступним всередині Pod. | -|

runAsGroup
integer

| **GID для запуску entrypoint процесу container**. Використовує runtime default, якщо не задано. Також може бути задано в SecurityContext. | -|

runAsNonRoot
boolean

| Вказує, що container має запускатися як non-root user. Якщо true, Kubelet під час виконання перевірить image, щоб переконатися, що вона не запускається як UID 0 (root), і не дасть запустити container, якщо це не так. | -|

runAsUser
integer

| **UID для запуску entrypoint процесу container**. Якщо не вказано, за замовчуванням використовується user, заданий у metadata image. | -|

seLinuxOptions
SELinuxOptions
More info about seLinux

| **SELinux context, який буде застосовано до всіх containers**. Якщо не вказано, container runtime призначить випадковий SELinux context для кожного container. | -|

seccompProfile
SeccompProfile
More info about Seccomp

| **seccomp options, які використовуються container** у цьому pod. | -|

supplementalGroups
integer array

| Список **groups, які застосовуються до першого process, запущеного в кожному container**, додатково до primary GID container. | -|

sysctls
Sysctl array
More info about sysctls

| Sysctls містять список **namespaced sysctls, що використовуються для pod**. Pod із unsupported sysctls (за версією container runtime) можуть не запуститися. | -|

windowsOptions
WindowsSecurityContextOptions

| Windows-specific налаштування, застосовані до всіх containers. Якщо не вказано, будуть використані options всередині SecurityContext container. | +|

fsGroupChangePolicy
string

| Це визначає поведінку **зміни ownership і permission volume** перед тим, як його буде відкрито всередині Pod. | +|

runAsGroup
integer

| **GID для запуску entrypoint процесу контейнера**. Використовує runtime default, якщо не задано. Також може бути встановлено в SecurityContext. | +|

runAsNonRoot
boolean

| Вказує, що контейнер має запускатися не як root-користувач. Якщо true, Kubelet перевірить image під час виконання, щоб переконатися, що він не запускається як UID 0 (root), і не запустить контейнер, якщо це так. | +|

runAsUser
integer

| **UID для запуску entrypoint процесу контейнера**. За замовчуванням використовується користувач, вказаний у metadata image, якщо не задано інше. | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| **SELinux context, який буде застосовано до всіх контейнерів**. Якщо не вказано, container runtime призначить випадковий SELinux context для кожного контейнера. | +|

seccompProfile
SeccompProfile
More info about Seccomp

| **seccomp options, які використовуватимуться контейнерами** у цьому pod. | +|

supplementalGroups
integer array

| Список **groups, що застосовуються до першого процесу, запущеного в кожному контейнері**, на додаток до primary GID контейнера. | +|

sysctls
Sysctl array
More info about sysctls

| Sysctls містять список **namespaced sysctls, що використовуються для pod**. Pod із непідтримуваними sysctls (з боку container runtime) може не запуститися. | +|

windowsOptions
WindowsSecurityContextOptions

| Специфічні для Windows налаштування, що застосовуються до всіх контейнерів. Якщо не вказано, буде використано options із SecurityContext контейнера. | ## SecurityContext -[**From the docs:**](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) Цей context задається всередині **container definitions**. З точки зору defensive security слід врахувати: -- **allowPrivilegeEscalation** до **False** -- Не додавайте чутливі **capabilities** (і видаляйте ті, які вам не потрібні) -- **privileged** до **False** -- Якщо можливо, встановіть **readOnlyFilesystem** як **True** -- Встановіть **runAsNonRoot** як **True** і задайте **runAsUser** -- Якщо можливо, розгляньте **обмеження** **permissions**, вказавши **seLinuxOptions** і **seccompProfile** -- **НЕ** надавайте доступ до **privilege** **group** через **runAsGroup.** +- **allowPrivilegeEscalation** — **False** +- Не додавати чутливі **capabilities** (і видалити ті, які не потрібні) +- **privileged** — **False** +- Якщо можливо, встановити **readOnlyFilesystem** як **True** +- Встановити **runAsNonRoot** як **True** і задати **runAsUser** +- Якщо можливо, розгляньте **обмеження** **permissions**, вказуючи **seLinuxOptions** та **seccompProfile** +- **НЕ** надавати доступ до **privilege** **group** через **runAsGroup.** -Зверніть увагу, що для атрибутів, заданих і в **SecurityContext**, і в **PodSecurityContext**, перевагу має значення, вказане в **SecurityContext**. +Зверніть увагу, що для атрибутів, встановлених і в **SecurityContext, і в PodSecurityContext**, пріоритет має значення, вказане в **SecurityContext**. -|

allowPrivilegeEscalation
boolean

| **AllowPrivilegeEscalation** керує тим, чи може process **отримати більше privileges**, ніж його parent process. Цей bool безпосередньо керує тим, чи буде для container process встановлено прапорець no_new_privs. AllowPrivilegeEscalation завжди true, коли container запущено як **Privileged** або він має **CAP_SYS_ADMIN** | +|

allowPrivilegeEscalation
boolean

| **AllowPrivilegeEscalation** керує тим, чи може процес **отримати більше привілеїв**, ніж його батьківський процес. Цей bool безпосередньо керує тим, чи буде для процесу контейнера встановлено прапорець no_new_privs. AllowPrivilegeEscalation завжди true, коли контейнер запущено як **Privileged** або він має **CAP_SYS_ADMIN** | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -|

capabilities
Capabilities
More info about Capabilities

| **capabilities, які потрібно додати/видалити під час запуску containers**. За замовчуванням використовується стандартний набір capabilities. | -|

privileged
boolean

| Запускати container у privileged mode. Processes у privileged containers по суті **еквівалентні root на host**. За замовчуванням false. | -|

procMount
string

| procMount означає **тип proc mount, який слід використовувати для containers**. За замовчуванням це DefaultProcMount, який використовує defaults container runtime для readonly paths і masked paths. | -|

readOnlyRootFilesystem
boolean

| Чи має цей **container файлову систему root лише для читання**. За замовчуванням false. | -|

runAsGroup
integer

| **GID для запуску entrypoint** process container. Використовує runtime default, якщо не задано. | -|

runAsNonRoot
boolean

| Вказує, що container має **запускатися як non-root user**. Якщо true, Kubelet під час виконання перевірить image, щоб переконатися, що вона не запускається як UID 0 (root), і не дасть запустити container, якщо це не так. | -|

runAsUser
integer

| **UID для запуску entrypoint** process container. Якщо не вказано, за замовчуванням використовується user, заданий у metadata image. | -|

seLinuxOptions
SELinuxOptions
More info about seLinux

| **SELinux context, який буде застосовано до container**. Якщо не вказано, container runtime призначить випадковий SELinux context для кожного container. | -|

seccompProfile
SeccompProfile

| **seccomp options**, які використовуються цим container. | -|

windowsOptions
WindowsSecurityContextOptions

| **Windows-specific налаштування**, застосовані до всіх containers. | +|

capabilities
Capabilities
More info about Capabilities

| **capabilities, які потрібно додати/видалити під час запуску контейнерів**. За замовчуванням використовується default set of capabilities. | +|

privileged
boolean

| Запускати контейнер у privileged mode. Процеси в privileged containers по суті **еквівалентні root на host**. За замовчуванням false. | +|

procMount
string

| procMount означає **тип proc mount, який слід використовувати для контейнерів**. Значення за замовчуванням — DefaultProcMount, який використовує defaults container runtime для readonly paths і masked paths. | +|

readOnlyRootFilesystem
boolean

| Чи має цей **container файлову систему root лише для читання**. Значення за замовчуванням false. | +|

runAsGroup
integer

| **GID для запуску entrypoint** процесу контейнера. Використовує runtime default, якщо не задано. | +|

runAsNonRoot
boolean

| Вказує, що контейнер має **запускатися не як root-користувач**. Якщо true, Kubelet перевірить image під час виконання, щоб переконатися, що він не запускається як UID 0 (root), і не запустить контейнер, якщо це так. | +|

runAsUser
integer

| **UID для запуску entrypoint** процесу контейнера. За замовчуванням використовується користувач, вказаний у metadata image, якщо не задано інше. | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| **SELinux context, який буде застосовано до контейнера**. Якщо не вказано, container runtime призначить випадковий SELinux context для кожного контейнера. | +|

seccompProfile
SeccompProfile

| **seccomp options**, які використовуватиме цей контейнер. | +|

windowsOptions
WindowsSecurityContextOptions

| **Специфічні для Windows налаштування**, що застосовуються до всіх контейнерів. | -## Practical workload review checklist +## Практичний checklist перегляду workload -Під час перевірки Pod або workload template перевіряйте і `spec.securityContext`, і кожен `securityContext` на рівні container у `containers`, `initContainers` та `ephemeralContainers`. Поля на рівні container можуть перевизначати defaults на рівні pod, тому безпечний на вигляд pod default не гарантує, що кожен container є безпечним. +Під час перевірки Pod або шаблону workload переглядайте і `spec.securityContext`, і кожен container-level `securityContext` у `containers`, `initContainers` та `ephemeralContainers`. Поля на рівні контейнера можуть перевизначати default-и pod-рівня, тож безпечний на вигляд pod default не гарантує, що кожен контейнер є безпечним. -Комбінації підвищеного ризику, на які слід звернути першочергову увагу: +Комбінації підвищеного ризику, на які слід звернути увагу в першу чергу: - `privileged: true`, особливо разом із `hostPID`, `hostIPC`, `hostNetwork`, `hostPath`, host ports або runtime socket mounts. - Додані capabilities, такі як `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `SYS_MODULE`, `DAC_READ_SEARCH` або `DAC_OVERRIDE`. -- `allowPrivilegeEscalation: true` або не задано в containers, які можуть виконувати attacker-controlled code. -- `seccompProfile: Unconfined`, `procMount: Unmasked` або відсутні runtime profiles для sensitive workloads. -- Writable root filesystems або широкі writable volume mounts у workloads, що обробляють untrusted input. -- Відсутні CPU, memory або ephemeral-storage requests і limits у multi-tenant namespaces. +- `allowPrivilegeEscalation: true` або не задано в контейнерах, які можуть виконувати attacker-controlled code. +- `seccompProfile: Unconfined`, `procMount: Unmasked` або відсутність runtime profiles для чутливих workload. +- Записувані root filesystems або широкі writable volume mounts у workload, що обробляють untrusted input. +- Відсутні requests і limits для CPU, memory або ephemeral-storage у multi-tenant namespaces. +- Відсутні або нереалістичні pod-рівневі `spec.resources` budgets, а також principals із `patch` або `update` на підресурс Pod `resize`, оскільки підтримувані кластери можуть змінювати бажаний стан CPU і memory під час роботи без пересоздання Pod. -Для більшості application workloads хорошою базою є запуск як non-root UID, встановлення `runAsNonRoot: true`, `allowPrivilegeEscalation: false`, скидання всіх capabilities і додавання назад лише мінімально необхідних, використання `seccompProfile: RuntimeDefault`, надання переваги read-only root filesystem та уникнення host namespaces, hostPath mounts і privileged mode. +Resource controls не є частиною `securityContext`, але перевіряйте їх у тому ж проході по workload, бо вони визначають межу availability. Сучасний Kubernetes може задавати budgets для CPU, memory і hugepages на рівні Pod у `spec.resources` на додаток до container-level `resources`. Pod із sidecars може бути обмежений сукупним Pod envelope навіть тоді, коли один контейнер не має індивідуальних limits, тоді як локальне ephemeral storage все ще потребує окремих `ephemeral-storage` limits, `emptyDir.sizeLimit`, LimitRanges і ResourceQuotas. Також порівнюйте бажані ресурси в Pod spec зі `status.containerStatuses[].resources` після in-place resize request; невдалий або pending resize може залишити запитане значення в `spec`, тоді як kubelet зберігає попереднє runtime allocation і повідомляє умову `PodResizePending`. -На рівні cluster використовуйте мітки namespace для [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/), щоб де можливо примусово застосовувати Kubernetes [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/). Використовуйте `restricted` для namespaces, які це підтримують, принаймні `baseline` для звичайних application namespaces, а privileged винятки робіть вузькими, задокументованими та ізольованими до trusted platform namespaces або node pools. +Для більшості application workload хорошою базою є запуск під non-root UID, встановлення `runAsNonRoot: true`, `allowPrivilegeEscalation: false`, скидання всіх capabilities і додавання назад лише мінімально необхідних, використання `seccompProfile: RuntimeDefault`, перевага read-only root filesystem та уникання host namespaces, hostPath mounts і privileged mode. + +На рівні cluster використовуйте namespace labels [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) для enforcement Kubernetes [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) там, де це можливо. Використовуйте `restricted` для namespace, які це підтримують, щонайменше `baseline` для звичайних application namespaces, а privileged exceptions тримайте вузькими, задокументованими та ізольованими до trusted platform namespaces або node pools. ## 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}}