586просмотров
29 августа 2025 г.
story📷 ФотоScore: 645
Я не root, и ты не root: защита от себя в kubernetes 1. Запуск контейнеров от имени непривилегированного пользователя Проблема: Запуск от UID 0 дает злоумышленнику, скомпрометировавшему контейнер, права суперпользователя, что упрощает атаку на хост.
Решение: Использовать securityContext для запуска от обычного пользователя и ограничения прав. securityContext: runAsUser: 1000 runAsGroup: 3000 runAsNonRoot: true readOnlyRootFilesystem: true runAsNonRoot: true - запрещает запуск, если образ пытается запуститься как root.
runAsUser - указывает UID пользователя внутри контейнера.
runAsGroup — задаёт основную группу.
readOnlyRootFilesystem: true — делает корневую ФС только для чтения. 2. Отказ от привилегированных контейнеров и точечная выдача Capabilities Проблема: privileged: true дает контейнеру все возможные Linux Capabilities и отключает большинство механизмов изоляции. Это эквивалентно запуску процесса на хосте.
Решение: Всегда устанавливать privileged: false.
Использовать механизм Capabilities для точечной выдачи только необходимых привилегий. Опасные Capabilities, которые следует избегать: CAP_SYS_ADMIN - Включает множество административных операций (монтирование, debug процессов и т.д.).
CAP_NET_RAW - Позволяет создавать raw сокеты (нужен для ping, но может использоваться в spoofing-атаках).
CAP_DAC_OVERRIDE - Игнорирует проверки прав доступа к файлам.
CAP_SYS_MODULE - Позволяет загружать kernel-модули. 3. Безопасная работа с томами, без hostPath Проблема: hostPath монтирует файлы и директории с узла напрямую в под, что может привести к утечке чувствительных данных или компрометации узла.
Решение: Использовать абстракции Kubernetes. emptyDir: Для обмена данными между контейнерами в рамках одного пода.
configMap/secret: Для монтирования конфигурации и секретов.
PVC: Для хранения данных. 4. Корректное предоставление доступа к сервисам: вместо hostPort Проблема: hostPort привязывает порт контейнера к порту на конкретном узле, создавая проблемы с планированием (конфликт портов) и нарушая принципы балансировки нагрузки.
Решение: Использовать сервисы Kubernetes: • ClusterIP: Сервис по умолчанию. Доступен только внутри кластера. • NodePort: Открывает статический порт на КАЖДОМ узле кластера. Упрощает доступ извне, но не является идеальным для продакшена. • LoadBalancer: Интегрируется с облачным провайдером для создания внешнего балансировщика нагрузки. Идеальный выбор для доступа извне. • Ingress: Управляет HTTP/HTTPS-трафиком. Предоставляет функциональность L7. Для работы требует Ingress-контроллер (nginx, traefik). 5. Использовать Pod Security Admission Pod Security Policies устарели. Необходимо использовать встроенный Pod Security Admission. Он определяет три уровня: privileged: Неограниченная политика.
baseline: Минимальные ограничения, предотвращающие известные эскалации привилегий.
restricted: Жесткая политика, соответствующая современным лучшим практикам. apiVersion: v1
kind: Namespace
metadata: name: my-restricted-namespace labels: # Блокирует создание несоответствующих Pod'ов pod-security.kubernetes.io/enforce: restricted # Предупреждает в аудит-логах при создании несоответствующих Pod'ов pod-security.kubernetes.io/audit: restricted # Выводит предупреждение пользователю при создании Pod'а pod-security.kubernetes.io/warn: restricted 6. Принцип наименьших привилегий с помощью Network Policies Проблема: Namespaces сами по себе - создают логические разделы, но не обеспечивают изоляцию по умолчанию.
Решение: Для настройки изоляции использовать сетевые политики, которые контролируют трафик между подами и извне. apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: name: allow-app-to-db
spec: podSelector: matchLabels: app: postgres-db policyTypes: - Ingress ingress: - from: - podSelector: # Разрешаем трафик только от подов с меткой app=api-server matchLabels: app: api-server