«У нас тридцать два кластера». Руководитель команды platform engineering произнес это как на исповеди. Тридцать два. В компании с девятью продуктовыми командами. По шесть окружений на каждую. Никто не планировал такого — оно просто росло по одному кластеру за раз, каждый раз, когда команде требовалось что-то чуть иное, а самым простым ответом было «подними новый».

Я слышала ту или иную версию этой фразы почти в каждой компании, достигшей определенного размера. Цифра меняется — иногда двенадцать, иногда шестьдесят, — но динамика всегда одна. Kubernetes легко позволяет создавать кластеры, никто намеренно не решал, когда их использовать совместно, а когда нет, и в какой-то момент кто-то смотрит на счет за облако и ротацию дежурств — и понимает, что управление десятками кластеров медленно пожирает платформенную команду заживо.

Multitenancy — ответ на эту проблему. Kubernetes не был спроектирован для multitenancy из коробки, и, чтобы построить его правильно, требуются реальные инженерные инвестиции, но именно так зрелые команды platform engineering решают эту задачу в 2026 году — со все более удобным инструментарием и все лучше понятыми паттернами.

Команда VK Cloud перевела статью, охватывающую все, что автор узнал о Kubernetes multitenancy в нескольких продакшен-окружениях: какие модели существуют, где каждая из них дает сбой, как выстроить слои изоляции, которые действительно защищают тенантов друг от друга, какие инструменты стоят вашего времени и как выглядит хорошо управляемый общий кластер на практике.

Если ваша команда управляет слишком большим количеством кластеров или строит платформу для безопасного обслуживания нескольких команд — это руководство, которого мне так не хватало в начале пути.

Почему Multitenancy стал неизбежным

Ежегодное исследование CNCF 2025 года показало: 82% пользователей контейнеров запускают Kubernetes в продакшене, а 78% организаций ожидают роста числа команд, развертывающих приложения в кластере. Больше команд — больше окружений, и без осознанной стратегии совместного использования это неизбежно превращается в больше кластеров.

Экономика cluster sprawl жестока. Каждый кластер требует control plane — на EKS это 73$ в месяц до того, как запущена хоть одна рабочая нагрузка, и тридцать два кластера превращаются в 2336$ ежемесячно только на control plane. Прибавьте node pool'ы, накладные расходы на мониторинг каждого кластера отдельно, трудоемкость применения патчей безопасности и обновлений в тридцати двух отдельных окружениях — и операционная нагрузка нарастает быстро.

Разговор о FinOps, который ведется в вашей инженерной организации прямо сейчас — или вот-вот начнется, почти наверняка включает консолидацию кластеров. Multitenancy — инженерная работа, которая делает эту консолидацию безопасной, а не безрассудной.

Есть и compliance-фактор, приобретающий все большее значение в 2026 году. Регулируемые среды — финансовые сервисы, здравоохранение, государственный сектор — все чаще требуют, чтобы общая инфраструктура демонстрировала изоляцию на каждом уровне, и multitenancy с документированными средствами контроля на уровне namespace, RBAC, сетевого взаимодействия и рабочей нагрузки удовлетворяет этому требованию так, как «у каждой команды свой кластер» зачастую не может: индивидуальные кластеры команд нередко имеют несогласованную конфигурацию безопасности.

Вопрос не в том, делиться ли кластерами. Нужно понять, как сделать это, не создав катастрофы в области безопасности или операционной деятельности.

Три модели tenancy и уместность каждой из них

Multitenancy — не одно явление. Существуют три различные модели, каждая из которых представляет разный компромисс между силой изоляции и операционными накладными расходами, и выбор между ними — самое важное решение, которое нужно принять до начала разработки.

Модель 1: программная (soft) tenancy на основе namespace

Простейшая модель: каждый тенант получает один или несколько namespace на общем кластере с общим control plane и общими узлами. Изоляция обеспечивается через Kubernetes RBAC (что тенант может делать), NetworkPolicies (с кем тенант может взаимодействовать) и ResourceQuotas (сколько вычислительных ресурсов тенант может потреблять).

Это правильная модель для внутренних команд с определенным уровнем взаимного доверия — окружений, где неверная конфигурация является честной ошибкой, а не преднамеренной атакой и где главная цель в том, чтобы предотвратить случайные взаимные помехи, а не чтобы защититься от злонамеренных действий. Большинство enterprise-установок platform engineering попадают именно в эту категорию.

Программная tenancy быстро настраивается и операционно нетребовательна, но изоляция реальна не идеальна: побеги из контейнеров, эксплойты ядра и некоторые пути эскалации привилегий теоретически могут нарушить изоляцию namespace. Для внутренних команд в невраждебной среде этот теоретический риск приемлем, а вот для ситуаций, когда тенанты — внешние клиенты с реальным враждебным потенциалом, нет.

Модель 2: tenancy на виртуальных кластерах (vCluster)

Промежуточный путь. Каждый тенант получает виртуальный Kubernetes-кластер — полноценный control plane (API server, controller manager, etcd), работающий как рабочие нагрузки внутри namespace на реальном кластере. С точки зрения тенанта у него есть собственный кластер. С точки зрения хост-кластера все окружение тенанта — это рабочие нагрузки в namespace.

vCluster — доминирующая реализация этой модели в 2026 году, и изоляция здесь значительно сильнее, чем при tenancy на основе namespace: тенанты взаимодействуют с собственным API server, а не с API server хост-кластера, что устраняет целый класс атак на эскалацию привилегий. При этом модель значительно дешевле выделенных кластеров, поскольку control plane работает на общих узлах, а не на выделенной инфраструктуре.

Модель уместна, когда тенантам нужен доступ на уровне кластера — возможность устанавливать CRD, управлять ресурсами уровня кластера или использовать инструменты, предполагающие наличие прав администратора полноценного кластера. Она также подходит для SaaS-продуктов, где каждое клиентское окружение должно быть по-настоящему изолированным, но выделенные кластеры на каждого клиента экономически нецелесообразны.

Модель 3: tenancy на выделенных кластерах

Каждый тенант получает собственный кластер — максимальная изоляция и максимальная стоимость. Это правильный ответ, когда модель угроз предполагает враждебных тенантов, когда требования compliance предписывают разделение на уровне оборудования или когда операционные накладные расходы на управление общим кластером превышают накладные расходы на управление отдельными.

Это также правильный ответ для продакшен-окружений в зрелых организациях, способных позволить себе операционные инвестиции: многие компании используют общие кластеры для разработки и стейджинга ради экономии затрат, тогда как продакшен держат на выделенных ради изоляции.

Понимание того, какую модель вы строите, определяет, какие инструменты вы используете, каковы реальные гарантии безопасности и что вы можете честно сообщить команде по compliance.

Четыре слоя изоляции, которые нельзя пропустить

Независимо от выбранной модели, надлежащий multitenancy требует изоляции на четырех различных уровнях. Большинство команд правильно реализуют первые два и оставляют остальные незавершенными, хотя пропущенный уровень — не незначительный пробел, а готовый путь, по которому один тенант может воздействовать на другой, случайно или намеренно.

Уровень 1: идентификация и доступ (RBAC). Кто что может делать и в каких namespace. Здесь начинает большинство команд, и начинать здесь правильно, но одного RBAC недостаточно — он контролирует доступ к API, но не сетевой трафик и не потребление ресурсов.

Уровень 2: сетевая изоляция. Без NetworkPolicies каждый pod в кластере может взаимодействовать с любым другим подом вне зависимости от namespace — поведение Kubernetes по умолчанию, которое в общей среде активно опасно. Сетевая изоляция — тот уровень, который большинство команд недооценивают.

Уровень 3: управление ресурсами. ResourceQuotas и LimitRanges не дают одному тенанту потреблять столько CPU, памяти или хранилища, что другие тенанты деградируют. Без этого уровня неверно настроенный batch-джоб или утечка памяти в приложении одного тенанта может дестабилизировать весь кластер.

Уровень 4: безопасность рабочей нагрузки. Pod Security Standards (современная замена PodSecurityPolicy, удаленного в Kubernetes 1.25) контролируют, что контейнерам разрешено делать: могут ли они работать от root, могут ли использовать привилегированный режим, могут ли монтировать файловую систему хоста. Этот уровень предотвращает сценарии побегов из контейнеров, которые RBAC и NetworkPolicies не могут устранить.

Все четыре уровня обязательны. Команды, реализующие RBAC и игнорирующие NetworkPolicies, имеют открытую внутреннюю сеть; команды, реализующие сетевую изоляцию и игнорирующие Pod Security Standards, имеют контейнеры, способные потенциально эскалировать доступ до хоста. Безопасность общего кластера определяется прочностью самого слабого уровня.

Проектирование namespace: фундамент, на котором строится все остальное

Решения по проектированию namespace очень значимы. Допустите ошибки — и RBAC станет неуправляемым, атрибуция затрат невозможной, а команды выработают обходные пути, которые подорвут все выстроенные средства контроля.

Подход, который я использую и постоянно рекомендую: один namespace на команду на окружение с единым соглашением об именовании по всему парку кластеров.

text

# Паттерн именования: <команда>-<окружение>
kubectl create namespace payments-production
kubectl create namespace payments-staging
kubectl create namespace payments-development
kubectl create namespace identity-production
kubectl create namespace identity-staging
kubectl create namespace identity-development

Суффикс окружения важен. Команды, использующие единый namespace для всех окружений, склонны накапливать сложность конфигурации, которая в конечном счете ломает что-то в продакшене. А вот отдельные namespace позволяют применять разные квоты ресурсов (продакшен-окружения, как правило, получают больший запас), разные политики безопасности (продакшен должен быть строже разработки) и разные средства контроля доступа (к разработке могут иметь доступ больше инженеров, чем к продакшену).

Уникальность имен namespace по всему парку — практическое решение, направленное в будущее: если когда-нибудь потребуется консолидировать кластеры или внедрить multicluster-инструментарий, уникальные имена значительно упростят этот процесс.

Метки namespace обязательны. Каждый namespace должен содержать метки, идентифицирующие команду-владельца, окружение и cost centre, — без них атрибуция затрат разваливается, а policy-engine'ы не могут различать namespace.

text

apiVersion: v1
kind: Namespace
metadata:
  name: payments-production
  labels:
    team: payments
    environment: production
    cost-centre: "eng-platform-001"
    contact: "payments-team@company.com"
    tier: critical

Эти метки — фундамент для каждого последующего инструмента: Kubecost для атрибуции затрат, Kyverno для применения политик, Grafana для фильтрации дашбордов. Задайте их правильно с самого начала, потому что ретроспективное проставление меток на пятидесяти namespace — болезненное занятие на полдня, которое вам не нужно.

RBAC: кто к чему может прикасаться

Kubernetes RBAC мощен, и при небрежном проектировании становится источником дыр в безопасности, невидимых до тех пор, пока их не начнут эксплуатировать. Главное правило для мультитенантных окружений: ни один тенант не должен иметь разрешений на уровне кластера, если только архитектура этого явно не требует.

Хорошо спроектированная мультитенантная модель RBAC имеет три уровня.

Уровень 1 — платформенная команда (эквивалент cluster-admin): управляет инфраструктурой кластера, развертывает и обновляет общие сервисы, имеет доступ уровня кластера. Это небольшая группа — в большинстве организаций от двух до пяти человек.

Уровень 2 — тимлиды (администратор namespace): могут управлять всеми ресурсами в namespace своей команды, но не могут взаимодействовать с namespace других команд, создавать новые namespace или получать доступ к ресурсам уровня кластера.

Уровень 3 — разработчики (developer в namespace): могут развертывать рабочие нагрузки, просматривать логи, выполнять exec в поды для отладки, управлять ConfigMap и Secret в своем namespace, но не могут изменять RBAC, создавать PersistentVolume или просматривать ресурсы в других namespace.

text

# Role для разработчиков namespace — ограничена одним namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: namespace-developer
  namespace: payments-production
rules:
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets", "statefulsets"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec", "services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]  # Только чтение — без create/update/delete

---
# Привязать роль к команде
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: payments-developers
  namespace: payments-production
subjects:
- kind: Group
  name: payments-team  # Берется из вашего identity provider (Okta, Azure AD и др.)
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: namespace-developer
  apiGroup: rbac.authorization.k8s.io

Две конкретные ошибки, которые я вижу постоянно и которые приводят к реальным инцидентам безопасности:

Привязки с wildcard-глаголами. Выдача verbs: ["*"] кажется удобной при настройке и становится проблемой, когда разработчик может удалить продакшен-PersistentVolume или изменить RBAC-привязки. Определяйте конкретные глаголы для каждого ресурса.

Случайно выданные привязки уровня кластера. ClusterRoleBinding применяются ко всему кластеру независимо от namespace, и ClusterRoleBinding для разработчиков команды означает, что эти разработчики могут видеть каждый namespace и каждый ресурс. Проверяйте существующие ClusterRoleBinding командой kubectl get clusterrolebindings -o wide и тщательно изучайте список subjects.

NetworkPolicies: потому что Kubernetes открыт по умолчанию

Это тот уровень изоляции, который большинство команд реализуют неправильно — не потому, что он сложен, а потому, что поведение Kubernetes по умолчанию — «разрешить всё» и проблема остается невидимой до тех пор, пока это не перестает быть так.

По умолчанию pod в namespace payments-production может делать HTTP-запросы к поду в namespace identity-production, infra-production и любом другом namespace в кластере. Между namespace нет сетевой стены, если только явно не построить ее с помощью NetworkPolicies, поэтому правильная отправная точка для каждого нового namespace в мультитенантном кластере — политика default-deny, блокирующая весь входящий и исходящий трафик, с последующими явными правилами разрешения для трафика, который действительно необходим.

text

# Шаг 1: запретить весь трафик в namespace по умолчанию
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: payments-production
spec:
  podSelector: {}  # Применяется ко всем подам в namespace
  policyTypes:
  - Ingress
  - Egress

---
# Шаг 2: разрешить DNS-разрешение (требуется для всех рабочих нагрузок)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: payments-production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP

---
# Шаг 3: разрешить конкретное межнеймспейсное взаимодействие
# Только namespace API-шлюза может обращаться к payments
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-api-gateway
  namespace: payments-production
spec:
  podSelector:
    matchLabels:
      app: payments-api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          team: api-gateway
      podSelector:
        matchLabels:
          app: gateway
    ports:
    - protocol: TCP
      port: 8080

Паттерн «default-deny плюс явное разрешение» означает, что новые сервисы стартуют без сетевого доступа и вы добавляете ровно то, что им нужно. Альтернатива — «default-allow плюс избирательный запрет» — означает, что новые сервисы стартуют с доступом ко всему и вы рассчитываете, что разработчики не забудут его ограничить. В общем кластере с несколькими командами такой расчет не работает как модель безопасности.

Если кластер использует Cilium в качестве CNI-плагина, вы получаете значительно более богатые примитивы сетевых политик: политики с поддержкой L7, фильтрацию исходящего трафика на основе DNS и наблюдаемость политик через Hubble, что делает отладку сетевой связности намного быстрее. Одни только преимущества наблюдаемости делают Cilium достойным рассмотрения при построении мультитенантной платформы.

ResourceQuotas и LimitRanges: проблема «шумного соседа»

Проблему «шумного соседа» просто описать, но удивительно сложно предотвратить без правильных средств контроля. Batch-джоб одной команды потребляет всю доступную память на узле, поды других команд не могут быть запланированы, продакшен-нагрузки деградируют — никто этого не планировал, просто неограниченный джоб с утечкой памяти.

ResourceQuotas устанавливают лимиты на суммарное потребление ресурсов на уровне namespace, а LimitRanges задают дефолтные запросы и лимиты для отдельных контейнеров. Оба инструмента необходимы для хорошо управляемого общего кластера.

text

# ResourceQuota для продакшн-namespace
apiVersion: v1
kind: ResourceQuota
metadata:
  name: payments-production-quota
  namespace: payments-production
spec:
  hard:
    requests.cpu: "20"
    requests.memory: "40Gi"
    limits.cpu: "40"
    limits.memory: "80Gi"
    pods: "100"
    services: "20"
    persistentvolumeclaims: "15"
    services.loadbalancers: "3"

---
# LimitRange — гарантирует, что у каждого контейнера заданы запросы ресурсов
# Не позволяет неограниченным контейнерам работать без декларированных потребностей
apiVersion: v1
kind: LimitRange
metadata:
  name: payments-container-limits
  namespace: payments-production
spec:
  limits:
  - type: Container
    default:          # Применяется, если лимиты не указаны
      cpu: "500m"
      memory: "256Mi"
    defaultRequest:   # Применяется, если запросы не указаны
      cpu: "100m"
      memory: "128Mi"
    max:              # Жесткий потолок на контейнер
      cpu: "4"
      memory: "8Gi"
    min:              # Минимум для предотвращения истощения ресурсов
      cpu: "50m"
      memory: "64Mi"

Поля default и defaultRequest в LimitRange особенно важны. Без них разработчики, забывшие указать запросы ресурсов, создают неограниченные контейнеры — поды, способные потреблять неограниченное количество CPU и памяти до тех пор, пока не вытеснят другие рабочие нагрузки. LimitRange делает безопасным отсутствие спецификации ресурсов, задавая разумные значения по умолчанию и защищая кластер от неограниченного потребления.

Устанавливайте квоты на основе реалистичных оценок пикового потребления, а не минимального использования. Команда, чья рабочая нагрузка потребляет 4 Гб памяти в нормальном режиме, может законно вырастать до 12 Гб в ходе rollout развертывания, и слишком жесткая квота вызывает сбои планирования именно в неподходящие моменты. Закладывайте запас в 2–3 раза сверх измерений потребления на уровне P95.

vCluster и Capsule: когда namespace недостаточно

В сообществе платформенных инженеров выделились два инструмента как предпочтительные решения для сценариев, где изоляции на основе namespace недостаточно.

vCluster создает виртуальный Kubernetes-кластер внутри реального namespace. Тенант получает полноценный Kubernetes API server, которым может администрировать как настоящим кластером: устанавливать CRD, управлять ресурсами уровня кластера и использовать любой инструмент, предполагающий наличие прав cluster-admin, — не затрагивая при этом control plane хост-кластера.

bash

# Установить vCluster CLI
curl -L -o vcluster \

  https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64
chmod +x vcluster && sudo mv vcluster /usr/local/bin

# Создать виртуальный кластер для тенанта
vcluster create payments-team \
  --namespace vcluster-payments \
  --values tenant-values.yaml

# Подключиться к виртуальному кластеру
vcluster connect payments-team --namespace vcluster-payments

Операционные накладные расходы vCluster невелики по сравнению с выделенными кластерами: каждый виртуальный кластер — это несколько подов в namespace, а не полноценный cloud-managed control plane. Для платформенных команд, строящих Internal Developer Platform, vCluster дает developer experience «у каждой команды свой кластер» за долю стоимости.

Capsule использует другой подход: расширяет Kubernetes с помощью Tenant CRD, создающего конструкцию мультинеймспейсного тенанта с общими политиками. Вместо управления пятьюдесятью отдельными конфигурациями namespace вы определяете ресурс Tenant, и Capsule применяет согласованные RBAC, NetworkPolicies и квоты ко всем namespace, принадлежащим этому тенанту.

text

# Определение Capsule Tenant
apiVersion: capsule.clastix.io/v1beta2
kind: Tenant
metadata:
  name: payments-team
spec:
  owners:
  - name: alice@company.com
    kind: User
  - name: payments-leads
    kind: Group
  namespaceOptions:
    quota: 5             # Максимальное число namespace, которое тенант может создать
    additionalMetadata:
      labels:
        team: payments
        cost-centre: "eng-001"
  resourceQuotas:
    scope: Tenant        # Квота применяется ко всем namespace тенанта суммарно
    items:
    - hard:
        requests.cpu: "20"
        requests.memory: "40Gi"
  networkPolicies:
    items:
    - spec:
        podSelector: {}
        policyTypes: [Ingress, Egress]
        # default deny применяется к каждому namespace автоматически

Подход Capsule масштабируется значительно лучше, чем ручное управление конфигурациями на уровне namespace по мере роста числа команд. Новые команды получают правильную изоляцию с первого дня, поскольку Tenant CRD шаблонизирует все, а дополнительные namespace они могут создавать самостоятельно в рамках своей квоты — без привлечения платформенной команды.

Атрибуция затрат: ответ на вопрос «сколько нам стоит команда X?»

Это вопрос, на котором всегда сходятся FinOps-разговоры и на который мультитенантные кластеры удивительно трудно отвечают без намеренно выбранного инструментария.

Kubernetes-кластеры генерируют единый счет от облачного провайдера, и без атрибуции на уровне namespace этот счет — черный ящик: вы знаете суммарные расходы, но не можете сказать инженерному руководству, сколько стоит инфраструктура команды payments, почему namespace data engineering утроил расходы в прошлом месяце или какие команды являются главными кандидатами на оптимизацию затрат.

Kubecost — инструмент, который я рекомендую большинству команд. Он работает внутри кластера, запрашивает API метрик Kubernetes для получения данных о потреблении ресурсов, подтягивает цены облачного провайдера и формирует детализацию затрат по namespace и меткам. Open-source-версия бесплатна и покрывает основные сценарии для большинства инженерных организаций.

bash

# Установить Kubecost через Helm
helm repo add cost-analyzer https://kubecost.github.io/cost-analyzer/
helm install kubecost cost-analyzer/cost-analyzer \
  --namespace kubecost \
  --create-namespace \
  --set kubecostToken="your-token"

Критическое предусловие — согласованная маркировка, именно поэтому метки namespace так важны. Kubecost строит атрибуцию затрат на основе ваших меток: namespace без метки team нельзя отнести ни к какой команде, а namespace без метки cost-centre нельзя выставить на chargeback. Расставьте метки правильно до развертывания инструментария для учета затрат — иначе придется провести послеобеденное время за ретроспективной маркировкой namespace.

Для команд, которым нужно полностью открытое решение, OpenCost — альтернатива Kubecost из песочницы CNCF. Покрывает основы атрибуции затрат без премиальных функций, но и то и другое несравнимо лучше, чем полное отсутствие атрибуции.

Ошибки безопасности, которые команды совершают в продакшне

Консультируя по мультитенантным окружениям Kubernetes в разных организациях, я снова и снова вижу одни и те же ошибки — не гипотетические риски, а паттерны, которые привели к реальным инцидентам.

Забытая плоская сеть. Команды выстраивают тщательный RBAC и детальные квоты ресурсов, а затем оставляют сеть полностью открытой, потому что никто не подумал развернуть default-deny NetworkPolicies. Выполните прямо сейчас kubectl get networkpolicies --all-namespaces. Если список короткий или пустой — тенанты вашего кластера могут свободно взаимодействовать друг с другом.

ClusterRoleBinding, выданные целым командам. Удобство выдачи команде доступа с ClusterRole «просто для отладки» имеет тенденцию становиться постоянным. Проверяйте ClusterRoleBinding раз в квартал: разработчик с доступом на чтение уровня кластера может перечислить каждый Secret в каждом namespace, что в мультитенантном окружении означает доступ к учетным данным других команд.

Привилегированные контейнеры, нарушающие изоляцию для всех. Контейнер с securityContext.privileged: true имеет почти root-доступ к ядру хоста, а контейнер, способный монтировать произвольные пути хоста, может читать файлы других контейнеров на том же узле. Pod Security Standards с профилем restricted предотвращают это — но только при принудительном применении, а не просто в режиме аудита.

text

# Принудительное применение restricted Pod Security Standards на уровне namespace
apiVersion: v1
kind: Namespace
metadata:
  name: payments-production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted

Отсутствие policy engine. RBAC предотвращает прямое злоупотребление API, NetworkPolicies предотвращают атаки на сетевом уровне, но ни то ни другое не помешает разработчику развернуть контейнер, работающий от root, открывающий hostPort, монтирующий чувствительные директории хоста или использующий образ контейнера с известными критическими уязвимостями. Policy engine — Kyverno или OPA Gatekeeper — автоматически применяет организационные стандарты на этапе admission.

text

# Политика Kyverno: требовать, чтобы все контейнеры работали не от root
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-non-root
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-runasnonroot
    match:
      any:
      - resources:
          kinds: [Pod]
    validate:
      message: "Контейнеры должны работать не от root-пользователя."
      pattern:
        spec:
          containers:
          - securityContext:
              runAsNonRoot: true

Как выглядит хорошо управляемый общий кластер на самом деле

Разница между мультитенантным кластером, который работает, и тем, который незаметно создает проблемы, — в том, реализованы ли все уровни согласованно, а не частично. Вот чек-лист, который я использую при проверке среды общего кластера.

Namespace и маркировка:

  • Каждый namespace имеет метки team, environment и cost-centre.

  • Именование namespace следует единому паттерну по всему парку кластеров.

  • Lifecycle namespace управляется через Tenant CRD (Capsule) или аналог.

Идентификация и доступ:

  • RBAC-роли привязаны к namespace, а не к уровню кластера для команд разработки.

  • ClusterRoleBinding проверены и задокументированы.

  • RBAC интегрирован с вашим identity provider (Okta, Azure AD, Google Workspace).

Сетевое взаимодействие:

  • Default-deny NetworkPolicy присутствует в каждом тенантном namespace.

  • Межнеймспейсное взаимодействие явно разрешено там, где это требуется.

  • DNS egress явно разрешен.

Управление ресурсами:

  • ResourceQuota присутствует в каждом тенантном namespace.

  • LimitRange задает дефолтные запросы и лимиты.

  • Квоты установлены в 2–3 раза выше среднего потребления для учета всплесков.

Безопасность рабочей нагрузки:

  • Pod Security Standards с профилем restricted принудительно применяются в продакшен-namespace.

  • Policy engine (Kyverno или OPA Gatekeeper) запущен.

  • Сканирование образов контейнеров интегрировано в CI/CD-пайплайны.

Затраты и наблюдаемость:

  • Kubecost или OpenCost развернут и формирует атрибуцию по namespace.

  • Дашборды мониторинга учитывают тенантов — каждая команда видит свои метрики, не видя данных других команд.

  • Алерты настроены на уровне namespace, а не только на уровне кластера.

Общий кластер, прошедший этот чек-лист, — тот, о котором я готова рассказать команде безопасности. Кластер с пропущенными уровнями — это кластер с известными пробелами, которые могут превратиться в инциденты.

Заключительная мысль

Multitenancy — не продукт, который покупают, и не фича, которую включают. Это инженерная дисциплина — набор осознанных решений об изоляции, доступе, управлении ресурсами и наблюдаемости, которые вместе создают среду, где несколько команд могут безопасно использовать инфраструктуру совместно.

Компании, которые делают это правильно в 2026 году, не те, у кого самые изощренные инструменты, а те, кто правильно реализовал основы: проектирование namespace, RBAC, NetworkPolicies, квоты ресурсов — и последовательно строил поверх них. Такие инструменты, как vCluster, Capsule и Kyverno, ценны, но они усиливают хороший фундамент, а не заменяют его.

Компания с тридцатью двумя кластерами, с которой началась эта статья, к концу года консолидировалась до шести: один продакшен-кластер на крупный бизнес-домен, общий для всех команд, с надлежащими средствами контроля multitenancy. Затраты на control plane упали на восемьдесят процентов, нагрузка на дежурство платформенной команды резко снизилась, а позиция безопасности улучшилась — согласованные средства контроля, применяемые последовательно, надежнее несогласованных, применяемых в тридцати двух отдельных окружениях.

Этот результат доступен любой команде, готовой относиться к multitenancy как к инженерным инвестициям, которыми он и является.

Что еще почитать по теме

Эти статьи напрямую связаны с темами, от которых зависит multitenancy:

Комментарии (2)


  1. arsengush
    01.07.2026 08:00

    По сути всё упирается не в инструменты, а в дисциплину и базовые вещи RBAC, сеть, квоты. И да, почти все через это рано или поздно приходят к консолидации.


    1. xhumanoid
      01.07.2026 08:00

      И конечно же все верим что rolling update ничего нам не сломает, а etcd скейлится в бесконечность (к нулю) :)