Модуль 24. Безопасность Kubernetes
Цель: вывести платформу на предсказуемый базовый уровень безопасности (base hardening), чтобы не «горели» инциденты из-за лишних прав, «секретов в конфигмапах» и незамеченных уязвимых образов.
Что должно появиться после внедрения:
- RBAC по принципу наименьших прав, привязанный к ролям, а не к людям/подам «вообще».
- ServiceAccount per-app, короткоживущие токены, запрет «кучи кластер-админов».
- Pod Security Admission (уровень restricted на продуктивных ns) + обязательные securityContext.
- Секреты: шифрование «на диске» (encryption at rest), внешний источник правды (Vault/ESO/Secret Store CSI).
- Сканирование и подпись образов (Trivy/Grype + cosign), политика на входе (admission).
- Аудит и алерты на ключевые события (создание ClusterRole/RoleBinding, доступ к секретам, неподписанные/уязвимые образы).
Модель безопасности Kubernetes: о чём помнить всегда
- API-сервер — единая точка входа. Любые права выдаются через RBAC.
- ServiceAccount (SA) — «личность» пода. По умолчанию у пода есть SA и проецируется токен.
- Pod Security — «рамки» допустимых полей спеков (привилегии, capabilities, host* и т. п.).
- Секреты — объект Secret в etcd. По умолчанию — base64, не шифр. Нужно включать encryption at rest.
- Supply chain — образы из реестра, их подписи, уязвимости, SBoM/аттестации.
- Admission — «шлагбаум» на запись: mutating/validating (Kyverno/Gatekeeper, VerifyImage/cosign).
RBAC и ServiceAccounts: минимум, но правильно
Принципы
- Заводим роли на абстракции «роль приложения/команды/операции», а не «Петя/Вася».
- Role/RoleBinding для namespace-уровня, ClusterRole/ClusterRoleBinding — только если правда нужно кластерное.
- ServiceAccount per приложение, минимум прав, без automountServiceAccountToken: true по умолчанию (включать целево).
- Для CI/операторов — отдельные SA с чётко очерченными verbs/resources.
Мини-шаблон (идея)
# ServiceAccount для приложения apiVersion: v1 kind: ServiceAccount metadata: name: app-sa namespace: team-a automountServiceAccountToken: false # токен монтируем только где надо --- # Права только читать ConfigMap/Secret в своём ns kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: app-read-cm-secrets namespace: team-a rules: - apiGroups: [""] resources: ["configmaps","secrets"] verbs: ["get","list","watch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: app-rb namespace: team-a subjects: - kind: ServiceAccount name: app-sa roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: app-read-cm-secrets
Практические заметки
- Bound ServiceAccount Tokens (projected, короткоживущие) — включаем; не используем бесконечные токены секретов старого типа.
- Разделяем SA: deploy-sa (CI/CD), runtime-sa (само приложение).
- Логику выдачи временных облачных прав — через Workload Identity (в managed) или Vault (K8s auth).
Pod Security: PSA + securityContext по умолчанию
Pod Security Admission (PSA)
-
Лейблы на namespace:
pod-security.kubernetes.io/enforce=restricted
pod-security.kubernetes.io/audit=restricted
pod-security.kubernetes.io/warn=restricted - На prod-ns — enforce=restricted. На dev — можно baseline и warn restricted.
SecurityContext (обязательные поля)
- runAsNonRoot: true, runAsUser: <UID>, runAsGroup/fsGroup — фиксируем пользователя.
- readOnlyRootFilesystem: true (и tmp через emptyDir//tmp).
- allowPrivilegeEscalation: false, capabilities: drop: ["ALL"] (+add точечные при необходимости).
- seccompProfile: type: RuntimeDefault; AppArmor — по профилю.
Мини-фрагмент:
securityContext:
runAsNonRoot: true
runAsUser: 10001
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities: { drop: ["ALL"] }
seccompProfile: { type: RuntimeDefault }
Запрещаем: hostNetwork/hostPID/hostIPC, privileged: true, hostPath (кроме белого списка в DevOps-ns).
Секреты: где хранить и как выдавать
База
- Включить шифрование секретов в etcd (encryption at rest) с KMS-провайдером (облачный KMS или Vault-Transit).
- Доступ к Secret — только приложению (через SA и Role), а не людям с kubectl.
Внешний источник правды
- Vault + External Secrets Operator (ESO): секрет живёт во Vault, ESO синхронизирует в Secret (или монтирует через Secret Store CSI Driver).
- Secret Store CSI Driver (AWS/GCP/Azure/Vault): монтирование как файлов, не создавая Secret в etcd (минимум «следов»).
- Sealed Secrets (Bitnami) — если нужно хранить «зашифрованный Secret» в Git (GitOps-паттерн).
Динамические креды
- Vault DB secrets engine: под получает временные логины в БД (TTL/lease), авто-ревокация.
- Для S3/облаков — STS/Workload Identity: SA ↔ облачная роль, короткоживущие токены.
Антипаттерны: пароли в ConfigMap, «секреты в Helm values в Git», общие статические креды на год.
Supply chain: образы, подписи, уязвимости
Практика «по умолчанию»
- Внутренний реестр (с прокси-кешем) + allow-list регистров в политике.
- Скан уязвимостей в CI и на входе (Trivy/Grype/Clair). Fail релиз при высоких CVE без исключений.
- Подпись образов (cosign) и проверка в admission (Cosign/Policy Controller, Kyverno/Gatekeeper VerifyImage).
- SBOM (Syft) и аттестации (SLSA provenance) — хранить рядом с образом.
- Запрет :latest и неподписанных образов; имперсивное правило «только из доверенных реестров».
Мини-политики (идеи)
- Kyverno: «image registry must be in list», «tag not latest», «verify cosign signatures».
- Gatekeeper (OPA): «no privileged», «require seccomp/caps drop», «limits/requests required».
Кластерный «харднинг» (control plane и ноды)
- API-сервер: RBAC включён, анонимный доступ выключен, audit-лог включён и уходит в SIEM; Admission-плагины (PSA, NodeRestriction, ImagePolicyWebhook/VerifyImage).
- kubelet: authn/authz включены, readOnlyPort=0, RotateKubeletServerCertificate, запрет анонимного.
- etcd: TLS между членами, отдельные диски, шифрование секретов через KMS (см. выше).
- Обновления: своевременные патчи k8s/образов; следить за deprecations PSA/Admission.
- Ноды: минимальный базовый образ, отключены лишние сервисы, регулярные патчи ОС, auditd (по политике).
- Сеть: default-deny NetworkPolicy + egress-контур (см. Модуль 21).
- Реестр: токены доступа ограничены по времени/областям, webhook-проверки на подписи.
Наблюдаемость и аудит
- Алерты: создание/изменение ClusterRole/Binding, массовые LIST Secrets, события PSA (deny), VerifyImage failures, всплеск 5xx admission, скачки Forbidden в API.
- Дашборды: попытки доступа к секретам, доля неподписанных/уязвимых образов в deploy, распределение политик PSA «warn/deny».
- Логи: audit-лог API, логи admission-вебхуков, логи Vault/ESO/SecretStore CSI, сканеров образов.
Практика (лабораторка за 1–2 дня)
- RBAC/SA: завести app-sa для сервиса и выдать только чтение нужных ConfigMap/Secret в своём ns. Проверить попытку чтения «чужого» ns — Forbidden.
- PSA: на prod-ns поставить enforce=restricted. Попробовать задеплоить под c privileged: true — deny.
- Secrets: включить encryption at rest + создать Secret и убедиться по документации/тесту, что в etcd хранится шифротекст.
- Vault+ESO: завести секрет в Vault, синхронизировать в K8s через ESO; перевести приложение на чтение из секрет-тома.
- VerifyImage: подписать образ cosign sign, включить политику «только подписанные». Проверить, что неподписанный деплой — deny.
- Scan: подключить Trivy в CI и admission-скан «на входе»; зафейлить релиз с критическим CVE.
- Аудит: включить audit-лог и построить правило/алерт «создан ClusterRole с *» и «массовое чтение Secrets».
Риски и анти-паттерны
|
Риск |
Проявление |
Митигировать |
|---|---|---|
|
Чрезмерные права (cluster-admin всем) |
Любой под/человек может «всё» |
Ролевое моделирование, ревизия RBAC, deny-по-умолчанию, раздельные SA |
|
Секреты в ConfigMap/Git |
Утечки в репозитории/логах |
Только Secret, encryption at rest, Vault/ESO/CSI, Sealed Secrets |
|
Привилегированные поды |
Breakout на ноду, доступ к host |
PSA=restricted, deny hostPath/privileged, securityContext по умолчанию |
|
Неподписанные/уязвимые образы |
Эксплуатация CVE, подмена |
Скан в CI+admission, cosign verify, allow-list реестров |
|
Статические долгоживущие креды к БД |
Компрометация = полный доступ |
Vault dynamic creds, короткий TTL, ротация ключей |
|
Долгоживущие SA-токены |
Латентные утечки |
Projected tokens (короткие), automount=false, минимальные роли |
|
Нет аудита |
Инцидент незаметен |
Включить audit-лог, алерты на RBAC/Secrets/VerifyImage |
Чек-лист «готово к продакшену»
- Namespace’ы помечены PSA (enforce=restricted на prod).
- Каждый сервис запускается под своим SA, automount токена — false по умолчанию.
- RBAC минимален, ревизия ролей/биндингов — по расписанию.
- Encryption at rest включён; доступ к Secret’ам только по SA/RBAC.
- Vault/ESO или Secret Store CSI Driver внедрены; исключён «секрет-как-yaml».
- Включён image scanning (CI+admission) и verify image signatures (cosign).
- Политики Kyverno/Gatekeeper: no privileged, seccomp, caps drop, registry allow-list, no :latest.
- Audit-лог настроен, события утекают в SIEM; алерты на RBAC/Secret/VerifyImage.
- Документированы runbook’и: «секрет скомпрометирован», «неподписанный образ», «deny PSA», «под запросил привилегии».
Вопрос-ответ
В: Почему Secrets — не защита? Они же base64.
О: Base64 — это кодировка, не шифр. Включайте encryption at rest через KMS/Transit. Лучше вообще держать источник правды вне etcd (Vault/CSI).
В: Где хранить секреты в GitOps?
О: Sealed Secrets (шифр в Git, ключ у контроллера) или External Secrets Operator (Git хранит лишь «ссылку», а данные тянутся из Vault/SM).
В: Чем PSA отличается от PSP?
О: PSP удалён; PSA — встроенная простая проверка «baseline/restricted», а детальные правила делайте в Kyverno/Gatekeeper.
В: Как выдать приложению доступ к облаку «без ключей»?
О: Workload Identity (в managed-кластерe) или Vault K8s auth (SA-токен → краткоживущий токен на облако/DB).
В: Нужен ли WAF/IDS для кластера?
О: На «краю» — да (Ingress-WAF). Внутри кластера — сетевые политики, eBPF-наблюдаемость (Cilium/Hubble), алерты на подозрительную активность.
В: Что важнее: скан образов или подписи?
О: Оба. Подпись отвечает на «кто и как собрал?», скан — «что внутри?». В проде — и скан, и verify.
В: Можно ли выдать разработчикам kubectl-доступ в prod?
О: Только read-only по ролям, через аудитируемые пути (kubectl-подписки, SSO/OIDC), без exec в прод-поды (кроме SRE/он-колла по процедуре).
Безопасность Kubernetes — это не один «секретный» флаг, а дисциплина: минимальные права (RBAC/SA), жёсткие рамки Pod’ов (PSA/securityContext), секреты вне Git/etcd и supply-chain защита (скан + подписи). С этими четырьмя опорами вы снимаете 80–90% инцидентов «по умолчанию», а остальное — вопрос наблюдаемости и регулярной ревизии.



