Введение: почему безопасность Kubernetes требует особого внимания
Kubernetes управляет контейнерами на тысячах узлов, и каждая ошибка в настройке доступа открывает путь к компрометации всего кластера. По данным CNCF, число production-кластеров растет на 28% ежегодно, а вместе с ними растет и число атак на cloud-native инфраструктуру. Злоумышленники ищут открытые API, избыточные права и секреты в открытом виде.
Безопасность кластера держится на трех опорах: контроль доступа, сетевая сегментация и защита чувствительных данных. Если RBAC настроен с избыточными правами, NetworkPolicies отсутствуют, а секреты лежат в base64, кластер уязвим. В этом руководстве вы настроите каждую из этих областей на практике: создадите роли с минимальными привилегиями, изолируете сетевой трафик между сервисами и выстроите безопасное хранение секретов. В конце получите готовый чек-лист для аудита.
Материал адресован администраторам и DevOps-инженерам, которые отвечают за безопасность контейнерных платформ. Все команды и YAML-манифесты проверены на Kubernetes 1.30 и совместимы с актуальными версиями.
RBAC: детальное разделение прав доступа
RBAC (Role-Based Access Control) определяет, кто и что может делать в кластере. Без него любой пользователь с доступом к API получает права администратора. Настройка RBAC снижает риск несанкционированных действий и ограничивает ущерб при компрометации учетной записи.
Основные понятия RBAC: Role, ClusterRole, Binding
Role действует в пределах одного namespace. ClusterRole работает на уровне всего кластера. Разница принципиальна: Role не может выдать права на узлы, PersistentVolumes или другие cluster-scoped ресурсы.
Binding связывает субъектов с ролями. RoleBinding применяет Role к пользователям, группам или ServiceAccount в конкретном namespace. ClusterRoleBinding применяет ClusterRole ко всему кластеру. Субъектами могут быть пользователи, группы и ServiceAccount.
Пример Role, которая разрешает чтение подов в namespace development:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]Связывание этой роли с ServiceAccount команды разработки:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-pod-reader
namespace: development
subjects:
- kind: ServiceAccount
name: dev-team
namespace: development
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.ioПошаговая настройка RBAC для команды разработки
Сценарий: команда разработки должна управлять подами в своем namespace development, но не иметь доступа к другим namespace и cluster-scoped ресурсам.
Шаг 1. Создайте namespace и ServiceAccount:
kubectl create namespace development
kubectl create serviceaccount dev-team -n developmentШаг 2. Создайте Role с правами на управление подами, деплойментами и сервисами:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: dev-full-access
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]Шаг 3. Создайте RoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-full-access-binding
namespace: development
subjects:
- kind: ServiceAccount
name: dev-team
namespace: development
roleRef:
kind: Role
name: dev-full-access
apiGroup: rbac.authorization.k8s.ioШаг 4. Проверьте доступ:
kubectl auth can-i create pods --as=system:serviceaccount:development:dev-team -n development
# yes
kubectl auth can-i create pods --as=system:serviceaccount:development:dev-team -n production
# noКоманда kubectl auth can-i показывает, какие действия разрешены для конкретного субъекта. Это основной инструмент проверки RBAC.
Лучшие практики RBAC
Используйте группы для управления доступом, а не отдельные привязки для каждого пользователя. Привязывайте роли к группам через ClusterRoleBinding с указанием группы в subjects. Это упрощает управление при росте команды.
Избегайте использования cluster-admin для повседневных задач. Выдавайте cluster-admin только при начальной настройке кластера и для аварийного восстановления. Для регулярной работы создавайте роли с минимальными правами.
Регулярно аудируйте роли. Команда kubectl get rolebindings --all-namespaces показывает все привязки. Ищите субъектов с правами на delete, update для критичных ресурсов. Подробнее об аудите RBAC читайте в руководстве по аудиту безопасности Kubernetes.
Принцип наименьших привилегий работает так: если команде не нужны права на удаление, не выдавайте их. Лучше добавить права позже, чем удалять после инцидента.
NetworkPolicies: сегментация сетевого трафика
По умолчанию все поды в кластере могут общаться друг с другом. Это удобно для разработки, но опасно для production: если атакующий получит доступ к одному поду, он сможет атаковать все остальные. NetworkPolicies ограничивают сетевые взаимодействия на уровне подов.
Как работают NetworkPolicies: селекторы и правила
NetworkPolicy использует podSelector для выбора подов, к которым применяется политика. policyTypes указывает, какие направления трафика контролируются: Ingress, Egress или оба. Правила ingress и egress определяют, от кого и куда разрешен трафик.
Пример политики, которая разрешает входящий трафик только от подов с меткой app=frontend:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080Если в namespace нет ни одной NetworkPolicy, весь трафик разрешен. Первая политика с podSelector, который выбирает все поды (пустой matchLabels), запускает режим default deny.
Практические примеры: изоляция приложений
Пример 1. Default deny для всего namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- EgressЭта политика блокирует весь входящий и исходящий трафик для всех подов в namespace production. После ее применения нужно явно разрешать каждый легитимный поток.
Пример 2. Разрешение трафика от ingress controller:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-ingress
namespace: production
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443Пример 3. Разрешение egress только к определенному внешнему ресурсу:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-to-db
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5432Выбор CNI-плагина с поддержкой NetworkPolicies
NetworkPolicy - это API-объект, но его применяет CNI-плагин. Не все CNI поддерживают политики. Calico, Cilium и Weave Net реализуют полную поддержку NetworkPolicy. Flannel не поддерживает политики без дополнительных компонентов.
Calico - проверенное решение для production-кластеров, поддерживает NetworkPolicy и расширенные сетевые политики. Cilium использует eBPF и предлагает более высокую производительность и наблюдаемость. Weave Net проще в настройке, но менее распространен в крупных кластерах. Выбор зависит от требований к производительности и функциональности. Для большинства сценариев Calico или Cilium - оптимальный выбор.
Управление секретами: от нативных Secrets до внешних систем
Секреты содержат пароли, токены, ключи API. Их компрометация дает атакующему доступ к базам данных, внешним сервисам и внутренним системам. Управление секретами требует отдельного подхода.
Проблемы нативных Kubernetes Secrets
Нативные Secrets хранятся в etcd в base64. Base64 - это кодирование, а не шифрование. Любой, кто получит доступ к etcd или к объекту Secret через API, сможет декодировать данные. По умолчанию etcd не шифрует данные на диске.
Доступ к Secret через API означает доступ к данным. Если у пользователя есть права get на secrets в namespace, он видит все пароли этого namespace. Это создает риск при избыточных RBAC-правах. Подробнее о работе с нативными Secrets читайте в полном руководстве по Kubernetes Secrets.
Sealed Secrets: шифрование секретов для GitOps
Sealed Secrets решает проблему хранения секретов в Git. Вы шифруете секрет с помощью kubeseal, получаете манифест SealedSecret, который можно безопасно коммитить в репозиторий. Расшифровать его может только контроллер Sealed Secrets в кластере.
Установка контроллера:
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.27.1/controller.yamlШифрование секрета:
kubectl create secret generic db-password --from-literal=password=MySecret123 -n production --dry-run=client -o yaml | kubeseal --format yaml > sealed-secret.yamlПолученный sealed-secret.yaml можно коммитить в Git. Контроллер в кластере расшифрует его и создаст обычный Secret. Приватный ключ хранится только в кластере, что делает манифест бесполезным для посторонних.
Интеграция с HashiCorp Vault
HashiCorp Vault централизует управление секретами: хранение, ротацию, аудит и доступ. Интеграция с Kubernetes позволяет синхронизировать секреты из Vault в Kubernetes Secrets или монтировать их напрямую через CSI driver.
Практичный способ - External Secrets Operator. Он создает Kubernetes Secrets из секретов Vault по расписанию. Установка:
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespaceНастройка SecretStore для подключения к Vault:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: production
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
auth:
kubernetes:
mountPath: "kubernetes"
role: "k8s-role"Создание ExternalSecret для синхронизации:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: "1h"
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: db/password
property: valueПреимущества Vault: автоматическая ротация, детальный аудит, единое хранилище для всех кластеров. Сравнение нативных Secrets и внешних систем читайте в статье о выборе хранилища секретов.
Шифрование Secrets at rest
Даже при использовании внешних систем нативные Secrets остаются в etcd. Включите шифрование at rest, чтобы защитить их на диске.
Создайте файл EncryptionConfiguration:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret:
- identity: {} Передайте файл в kube-apiserver через флаг --encryption-provider-config. После включения шифрования все новые секреты будут зашифрованы. Существующие секреты нужно пересоздать: kubectl get secrets --all-namespaces -o json | kubectl replace -f -.
Сохраните резервную копию ключа шифрования. Потеря ключа означает невозможность расшифровать секреты.
Чек-лист аудита безопасности кластера
Этот чек-лист поможет проверить соответствие требованиям и выявить уязвимости. Выполняйте его регулярно, минимум раз в квартал или после значительных изменений в кластере.
Проверка RBAC
- Выполните kubectl get clusterrolebindings и найдите всех субъектов с cluster-admin. Их должно быть минимальное количество.
- Выполните kubectl auth can-i --list --as=system:serviceaccount:default:default для проверки прав сервисного аккаунта по умолчанию.
- Проверьте, что нет RoleBinding, которые выдают права на secrets для широкого круга пользователей.
- Используйте kubectl get rolebindings --all-namespaces -o yaml и ищите подозрительные привязки.
Проверка NetworkPolicies
- Убедитесь, что в каждом production-namespace есть default deny политика.
- Проверьте, что CNI-плагин поддерживает NetworkPolicy: kubectl get pods -n kube-system | grep calico или cilium.
- Протестируйте доступ между подами: kubectl exec -it pod-a -- curl pod-b. Если доступ есть, а политика запрещает, CNI не применяет политики.
- Проверьте, что egress-трафик ограничен там, где это необходимо.
Проверка управления секретами
- Проверьте, включено ли шифрование at rest: kubectl get secrets --all-namespaces -o json | grep -c "aescbc". Если 0, шифрование не работает.
- Убедитесь, что секреты не хранятся в образах: сканируйте образы на наличие паролей и ключей.
- Проверьте, что секреты не закоммичены в Git в открытом виде.
- Если используются внешние системы, проверьте настройки ротации и аудита.
Дополнительные проверки
- Примените Pod Security Standards: kubectl label namespace production pod-security.kubernetes.io/enforce=restricted.
- Проверьте версии компонентов: kubectl version. Обновляйте Kubernetes минимум раз в 6 месяцев.
- Настройте аудит API server и проверяйте логи на подозрительные действия.
- Сканируйте образы на уязвимости с помощью Trivy или Grype.
- Запустите kube-bench для проверки соответствия CIS Benchmark.
Полный план аудита безопасности с готовыми командами читайте в практическом плане аудита IT-инфраструктуры.
Заключение
Безопасность Kubernetes - это три уровня: RBAC ограничивает доступ, NetworkPolicies сегментируют сеть, управление секретами защищает чувствительные данные. Каждый уровень требует настройки и регулярной проверки.
Начните с RBAC: создайте роли с минимальными привилегиями, избегайте cluster-admin, используйте группы. Затем примените NetworkPolicies: включите default deny в production-namespace и явно разрешите легитимный трафик. Защитите секреты: включите шифрование at rest, используйте Sealed Secrets для GitOps или интегрируйтесь с Vault через External Secrets Operator.
Безопасность - непрерывный процесс. Запускайте чек-лист аудита регулярно, обновляйте компоненты, сканируйте образы. Каждая проверка снижает риск компрометации. Для углубленного изучения настройки RBAC читайте практическое руководство по RBAC, а для настройки аудита API server - руководство по аудиту безопасности.