Всем привет, меня зовут Сергей Прощаев, и в этой статье я расскажу про базовые принципы безопасности в Kubernetes, которые уберегут вас от кошмаров вроде взлома кластера для майнинга криптовалюты.
Если вы только начинаете работать с k8s, то ваша главная задача — не просто задеплоить приложение, а сделать это так, чтобы завтра не проснуться героем техновостей. Помните инцидент с Tesla в 2018 году? Тогда хакеры нашли незащищенный Kubernetes Dashboard, выставленный в интернет без пароля. Через него они получили доступ к AWS-ключам и другим секретам, а потом тихо использовали вычислительные мощности облака Tesla для майнинга Monero. Компания не только понесла прямые финансовые потери, но и оказалась в крайне неприятной ситуации с точки зрения доверия клиентов и регуляторов.
Это не какая-то сложная атака нулевого дня. Это цепочка элементарных упущений: незакрытый доступ, избыточные права сервисного аккаунта, секреты в открытом доступе. И именно такие ошибки — daily bread для начинающих инженеров, которые торопятся «завести» кластер и забывают про security by design.
Я руковожу направлением Java-разработки в FinTech, и вместе с командой мы активно изучаем и внедряем лучшие практики деплоя бэкенд-приложений. Поэтому сегодня я разберу три кита безопасности Kubernetes: аутентификацию и доступ, управление секретами и изоляцию workload'ов. Мы посмотрим, где чаще всего ошибаются, и как эти ошибки исправить простыми, но эффективными практиками. А в конце расскажу, где можно системно прокачать эти навыки, чтобы не учиться на своих дорогих ошибках.
Кто в доме хозяин? Минимизация доступа (Principle of Least Privilege)
Самая частая и опасная ошибка — раздача прав «на всё». По умолчанию сервисный аккаунт pod'а в namespace default имеет совсем не нулевые права в этом же неймспейсе. А если ему дали cluster-admin для «удобства деплоя», то один скомпрометированный под становится королём всего кластера.
Что чаще всего идёт не так?
Сервисные аккаунты с правами
cluster-adminилиedit. «Ну чтобы всё работало». С одной стороны понятно, что хочется чтобы все быстрее взлетело, но с другой стороны это может стать результатом эскалация привилегий при любой уязвимости в приложении.Использование
defaultсервисного аккаунта. У него часто есть права на чтение секретов в своём неймспейсе. И это обязательно я рекомендовал бы проверить!Широкие роли (Role/ClusterRole) с правилами на ресурсы . «Так проще потом не искать, почему нет доступа». Да, но тут опасность как раз кроется в том, что доступ будет у того, у кого его быть не должно.
Как делать правильно?
Во-первых, всегда создавайте отдельный сервисный аккаунт для каждого приложения или компонента. Это базис для изоляции!
Во-вторых — назначайте права по принципу минимальной необходимости. Используйте встроенные роли (
view,edit) только как отправную точку, а лучше создавайте кастомные.И в третьих, регулярно аудитируйте права. Лучше аудита может быть только два аудита! Инструменты вроде
kubectl-who-canилиrbac-lookupпокажут, у кого какие есть права.
Практический пример: роли вместо всевластия
Чтобы не быть голословным — давайте на практическом примере создадим безопасную роль для приложения, которому нужно только читать конфигурационные мапы и логировать события в своём неймспейсе.
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: myapp-production name: myapp-reader-logger rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create"] --- apiVersion: v1 kind: ServiceAccount metadata: namespace: myapp-production name: myapp-backend-sa --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: namespace: myapp-production name: bind-myapp-sa-to-role roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: myapp-reader-logger subjects: - kind: ServiceAccount name: myapp-backend-sa namespace: myapp-production
Этот код — антипод подходу «дадим edit и забудем». Мы явно прописали, что можно делать, и ничего лишнего.
При проведении аудита одного из проектов я обнаружил, что более 80% сервисных аккаунтов имели права на чтение секретов во всём кластере. Угроза была не в злом умысле, а в случайной утечке логов или ошибке в библиотеке, которая могла прочитать все секреты и отправить «куда не надо». Устраняли это два месяца, компонент за компонентом.
Секреты — не для всех глаз. Управление чувствительными данными
Вторая по популярности ошибка — отношение к секретам Kubernetes (объектам Secret) как к безопасному хранилищу. Они не шифруются на диске etcd по умолчанию (только base64). Если злоумышленник получит доступ к API или бэкапу etcd, все пароли, токены и ключи — его.
Что чаще всего идёт не так?
Хранение секретов в виде plain-text или base64 в git-репозиториях. Вспомните кейс 2023 года от Aqua Security, когда утечки из публичных репозиториев затронули гигантов вроде SAP.
Монтирование всего объекта
Secretв под, когда нужно только одно конкретное значение.Отсутствие ротации секретов. Ключи живут годами.
Как делать правильно?
Никогда не коммитьте секреты в git. Даже в приватный репозиторий. Используйте инструменты типа HashiCorp Vault или облачные менеджеры секретов (AWS Secrets Manager, Azure Key Vault). Для GitOps-подхода отлично подходит External Secrets Operator (ESO), который автоматически подтягивает секреты из внешних систем в кластер.
Включайте шифрование данных на rest (at-rest encryption) для etcd. Это must-have для любого продакшн-кластера. Настраивается через
EncryptionConfiguration.Монтируйте секреты как отдельные файлы или переменные окружения с минимальными правами. И используйте
securityContext.readOnlyRootFilesystem: trueтам, где возможно.
Пример безопасного использования секрета через переменную окружения:
apiVersion: apps/v1 kind: Deployment metadata: name: myapp-backend spec: template: spec: serviceAccountName: myapp-backend-sa # Используем созданный ранее SA containers: - name: app image: myapp:latest env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: postgres-credentials key: password securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false
Оптимальный способ дополнительной защиты — это настройка в CI/CD-пайплайне статического анализа манифестов с помощью Checkov или kubeaudit. Эти инструменты подсветят потенциальные проблемы: от незашифрованных секретов до подов, запущенных от root.
Крепость для каждого подка: изоляция workload'ов с помощью Security Context и Policies
Запуск контейнера с правами root (USER 0 в Dockerfile) внутри пода — это как оставить ключи от квартиры под ковриком. Если злоумышленник скомпрометирует такое приложение, он получит root-права внутри ноды. В истории с Tesla это был один из ключевых факторов эскалации.
Что чаще всего идёт не так?
Запуск контейнеров от
root(или без явногоsecurityContext).Использование
privileged: trueдля решения проблем с доступом к устройству или сети.Это почти всегда можно решить безопаснее.Монтирование чувствительных путей ноды (
/,/etc,/var/run/docker.sock) в поды.
Как делать правильно?
Всегда задавайте
securityContextдля пода и контейнера. Указывайте не привилегированного пользователя (UID/GID), запрещайте эскалацию привилегий.Внедряйте стандарты безопасности подов. Начните с Pod Security Standards (PSS). Примените хотя бы уровень
baselineкак advisory, а потом как enforcement. Для более гибкого и мощного контроля используйте Kyverno или OPA Gatekeeper. Kyverno, на мой взгляд, идеален для начинающих: политики пишутся на YAML, и есть богатая библиотека готовых правил.Запрещайте
privileged. ИспользуйтеSecurityContextDenyадмиссион-контроллер или политики в Kyverno.
Пример безопасного securityContext для пода:
apiVersion: apps/v1 kind: Deployment metadata: name: security-demo-app spec: template: spec: securityContext: # Контекст на уровне пода runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 2000 containers: - name: app image: nginx:alpine securityContext: # Контекст на уровне контейнера allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: true
Эта конфигурация делает под максимально замкнутым: не-root пользователь, сброшены все Linux capabilities, корневая ФС только для чтения.
Моя ошибка, ставшая правилом: Раньше я думал, что runAsNonRoot: true — это излишняя строгость. Пока в одном тестовом окружении приложение с уязвимостью в библиотеке не начало пытаться писать в /etc/passwd. Блокировка на уровне securityContext остановило эту попытку моментально. С тех пор это обязательный атрибут в наших шаблонах.
Чекап-лист для начинающего: с чего начать завтра
Чтобы всё это не казалось горой несделанного, вот план действий на первые недели внедрения:
Неделя 1: Аудит.
Запустите
kubectl get serviceaccounts --all-namespacesи проверьте, кто и где используетdefault.С помощью
kubectl-who-canилиrbac-lookupпроверьте, у кого есть праваcluster-adminили наsecrets.Просканируйте манифесты в git с помощью
checkovилиkubeaudit.Неделя 2: Базовые защиты.
Для нового неймспейса включите Pod Security Admission (PSA) на уровне
baseline: warn. Посмотрите, какие поды не проходят.Начните создавать отдельные ServiceAccount для новых приложений с кастомными Role/RoleBinding.
Включите (или запланируйте включение) шифрование rest для etcd.
Неделя 3: Инструментарий и культура.
Установите Kyverno и внедрите 2-3 ключевые политики (например, запрет
privilegedи требованиеrunAsNonRoot).Интегрируйте проверку манифестов в CI/CD-пайплайн.
Проведите ликбез для команды: покажите на примере Tesla, к чему ведут пробелы в безопасности.
Заключение: Безопасность — это не фича, а процесс
Как вы видите, основы безопасности в Kubernetes — это не про сложные инструменты и сертификаты. Это про дисциплину, внимание к деталям и отказ от шаблона «работает — и ладно».
Тот самый инцидент с Tesla начался не с хакерской атаки нулевого дня, а с банально открытого дашборда. Цепочка из небольших упущений привела к крупному скандалу. Ваша цель — разорвать эту цепь в самом начале.

Если вам хочется не просто прочитать статью, а разобрать эти практики на реальных задачах, посмотреть на полные конфигурации и пообщаться с практиками, приглашаю вас на бесплатный урок «Основы безопасности Kubernetes» 17 февраля в 20:00.
Занятие пройдёт в рамках курса «Инфраструктурная платформа на основе Kubernetes» в OTUS. Мы разберём не только теоретические основы, но и конкретные инструменты, рассмотрим архитектурные паттерны и типичные ошибки, которые не описаны в официальной документации. А чтобы узнать, подойдет ли вам программа курса, пройдите вступительный тест.
Полный список бесплатных уроков от преподавателей курсов можно посмотреть в календаре мероприятий.
