Cozystack изначально находится в защищённом положении, и цифры это подтверждают: 54 контроля CIS проходят на кластере, который никто специально не настраивал для теста. Операционная система узла неизменяемая и не имеет оболочки, привилегированные рабочие нагрузки отклоняются на этапе допуска, все проверки etcd проходят, а тенанты изначально имеют сетевую изоляцию.
Эта страница публикует полный прогон, а не только выгодную его часть. Необработанный отчёт kube-bench также перечисляет два десятка ошибок, и полезная работа заключается в том, чтобы их различить: большинство из них — это бенчмарк, ищущий файлы, которых неизменяемый узел не хранит, или проверяющий флаг, который заменили более новые релизы Kubernetes. Четыре ошибки заслуживают внимания, и каждая рассмотрена ниже с объяснением причин.
Именно в этой сортировке смысл. Передать аудитору неаннотированный отчёт kube-bench хуже, чем не передать вообще ничего: они видят красные строки, а вы проводите встречу, объясняя архитектуру, а не безопасность.
CIS Kubernetes Benchmark v1.12, выполненный kube-bench на Cozystack v1.6 на Kubernetes v1.34.3. Проверки control plane выполнялись на узле control-plane, проверки worker — на worker-узле.
Область охвата: это управляющий кластер (management cluster) — узлы Talos и control plane Kubernetes, на котором работает сам Cozystack. Кластеры Kubernetes тенантов не охвачены этими цифрами. Их control plane — это Deployment-ы Kamaji со своими флагами API-сервера и своим etcd, поэтому разделы 1, 2 и 3 для них нужно оценивать отдельно. Если кластеры тенантов входят в область вашей оценки, запросите также и этот прогон.
| Раздел | Пройдено | Провалено | Предупреждение |
|---|---|---|---|
| 1 — Конфигурация безопасности control plane | 29 | 22 | 9 |
| 2 — Конфигурация узла etcd | 7 | 0 | 0 |
| 3 — Конфигурация control plane | 1 | 0 | 4 |
| 4 — Конфигурация безопасности worker-узла | 17 | 2 | 6 |
| 5 — Политики Kubernetes | 0 | 0 | 34 |
| Итого | 54 | 24 | 53 |
Раздел 2 стоит отметить особо: проходят все проверки флагов etcd — клиентские и пировые
сертификаты, --client-cert-auth, отсутствие --auto-tls. Единственная ошибка, связанная с
etcd, находится в разделе 1 и касается владельца каталога данных; она рассмотрена ниже.
Пятнадцать из двадцати четырёх ошибок — это проверки файлов: прав доступа и владения
манифестами подов API-сервера, controller manager, scheduler и etcd, а также admin.conf,
scheduler.conf и controller-manager.conf.
Каждая из них сообщает пустое значение. Посмотрите на узел, и станет понятно почему:
# /etc/kubernetes на control-plane узле Talos
bootstrap-kubeconfig
kubeconfig-kubelet
kubelet.yaml
manifests/ <- пусто
pki/
Каталог manifests существует, но пуст: Talos формирует поды control plane из собственной
конфигурации в /system, а не из файлов, которые редактирует администратор, а
/etc/kubernetes/manifests оставлен для статических подов, которые вы сами решите
добавить. Административные kubeconfig-файлы, которые ищет бенчмарк — admin.conf,
scheduler.conf, controller-manager.conf — отсутствуют вовсе, потому что учётные данные
выдаются через API Talos, а не хранятся на диске.
Проверьте это на своём собственном узле, а не принимайте на веру:
talosctl -n <control-plane-ip> list -l /etc/kubernetes /etc/kubernetes/manifests
Честная трактовка не «пятнадцать контролей провалены», а «пятнадцать контролей неприменимы,
а риск, для управления которым они существуют — злоумышленник или ошибка, изменяющие
конфигурацию control plane на диске — обрабатывается неизменяемостью, а не режимами доступа
к файлам». Одна проверка из той же группы, 1.1.12, проваливается по другой причине. Каталог
данных etcd существует и доступен для чтения — проверка 1.1.11 подтверждает режим 0700, —
но etcd работает от имени root, на узле Talos нет системной учётной записи etcd, и
сканирующий контейнер не может преобразовать числового владельца в имя. Цель контроля —
ограничить, кто может читать каталог данных etcd — достигнута; буквальное владение
etcd:etcd, которое требуется, не может существовать в системе без учётных записей
пользователей.
Проверки 1.2.6, 1.2.7 и 1.2.8 требуют, чтобы флаг --authorization-mode не включал
AlwaysAllow и включал Node и RBAC. Kubernetes 1.30 представил файл структурированной
конфигурации авторизации, и Talos использует его, поэтому флаг отсутствует, и проверки
проваливаются.
Сама конфигурация — это именно то, что требует бенчмарк:
apiVersion: apiserver.config.k8s.io/v1beta1
kind: AuthorizationConfiguration
authorizers:
- name: node
type: Node
- name: rbac
type: RBAC
Оба авторизатора включены, а AlwaysAllow нигде нет. Это не случай запуска устаревшего
бенчмарка: CIS v1.12 — текущая редакция, охватывающая Kubernetes с 1.32 по 1.34, а
структурированная авторизация достигла статуса общедоступности в 1.32. Контроль просто
по-прежнему проверяет флаг, которого современный соответствующий кластер имеет полное право
не иметь. Ожидайте больше подобных ложных срабатываний. Опровергнуть их — значит прочитать
конфигурацию, а не перезапускать инструмент.
Проверка 4.1.1 требует файл сервиса kubelet, который Talos не использует. Проверка 4.3.1
требует, чтобы эндпоинт метрик kube-proxy был привязан к localhost — а kube-proxy привязывать
не к чему: Cozystack запускает Cilium с включённым kube-proxy-replacement, поэтому
компонент, на который направлена проверка, просто не установлен. Риск, о котором писался
контроль, никуда не исчез — он переместился на собственные порты метрик и проверки состояния
агента Cilium на каждом узле, которые бенчмарк вообще не рассматривает. Привяжите их к
внутреннему адресу узла и закройте межсетевым экраном так же, как вы бы поступили с
kube-proxy.
Четыре ошибки проходят через эту сортировку. Ни одна из них не экзотична, и все четыре — это настройки в конфигурации машины Talos, а не изменения платформы.
Три из четырёх — это осознанные решения разработчиков платформы, а не недосмотр, и знание причин полезнее, чем знание самого результата.
| Проверка | Что это означает | Как к этому относиться |
|---|---|---|
1.2.5 — не задан --kubelet-certificate-authority | API-сервер предъявляет клиентский сертификат kubelet, но не проверяет серверный сертификат kubelet по CA | Осознанное решение: на bare metal нет службы метаданных для выпуска и распространения серверных сертификатов kubelet. Устранение этого означает создание такого механизма |
1.3.7 — controller manager --bind-address=0.0.0.0 | Защищённый порт (10257) слушает на всех интерфейсах, а не только на loopback, и предоставляет только метрики. Метрики требуют аутентификации и авторизации; /healthz, /readyz и /livez — нет | Осознанное решение: так сегодня собираются метрики. Более чистый вариант — loopback плюс авторизующий прокси перед ним |
1.4.2 — scheduler --bind-address=0.0.0.0 | То же самое, на порту 10259 | Как выше |
1.2.30 — --service-account-extend-token-expiration не установлен в false | Расширенный срок жизни токена служебной учётной записи остаётся включённым — параметр совместимости для старых клиентов | Не осознанное решение — значение по умолчанию просто никогда не менялось |
Если ваш аудитор считает что-либо из этого находкой, ответ — компенсирующий контроль плюс план, а не отказ. Первые три требуют день-два инженерной работы для полного устранения; четвёртая — это флаг. Далее о том, что реально требуется для их устранения.
Одно предостережение перед действиями с 1.2.5: сам флаг — это не решение, и сам по себе он
всё ломает. По умолчанию kubelet предоставляет самоподписанный сертификат, поэтому
API-сервер, которому сказано проверять его по CA, теряет возможность выполнять kubectl logs, exec, port-forward или metrics-server. Устранение этого контроля — это изменение
из трёх частей: включить serverTLSBootstrap на kubelet, запустить подписывающий орган,
который одобряет CSR серверных сертификатов kubelet, и только затем установить
--kubelet-certificate-authority. Сделайте это на тестовом кластере и проверьте kubectl logs на каждом узле, прежде чем считать задачу выполненной.
Рекомендуемое бенчмарком решение для 1.3.7 и 1.4.2 — --bind-address=127.0.0.1, и его
буквальное применение имеет свою цену: Prometheus опрашивает controller manager и scheduler
на разных узлах, и эндпоинты только на loopback перестают быть доступными для опроса.
Соразмерный ответ — оставить адрес привязки как есть, закрыть порты 10257 и 10259 для всех,
кроме пути мониторинга, с помощью межсетевого экрана входящего трафика Talos, и
зафиксировать это как компенсирующий контроль, а не как пройденную проверку.
Прежде чем отключать расширенный срок действия токена, следите за
serviceaccount_stale_tokens_total на API-сервере: пока значение выше нуля, что-то всё ещё
зависит от режима совместимости.
Все четыре настройки находятся в конфигурации машины Talos, которую вы применяете при установке — Cozystack не генерирует её за вас, что также объясняет, почему тот же прогон на вашем кластере может отличаться. Проверьте, что реально работает у вас, прежде чем что-либо менять:
talosctl -n <control-plane-ip> get authorizationconfig -o yaml
Проверка 3.2.2 — «убедитесь, что политика аудита охватывает ключевые проблемы безопасности» — это ручная проверка, поэтому kube-bench сообщает предупреждение и переходит дальше. Её стоит выполнить вручную.
На рассматриваемом кластере политика аудита установлена на level: Metadata. Это фиксирует,
кто что и когда вызвал, но не тела запросов или ответов. Для повседневной работы это разумное
значение по умолчанию; для режима, требующего восстановления того, что действительно
изменилось — требование 10.2.1 PCI DSS, например — этого само по себе недостаточно.
Устоите перед очевидным решением. Повышение всего до RequestResponse записывает тела всех
запросов в журнал аудита, а эти тела содержат значения Secret, токены и любые персональные
данные, которые ваши пользователи разместили в аннотациях. Журнал перестаёт быть записью
доступа и становится второй копией данных, которые он должен защищать — теперь в файле с
другим сроком хранения, другим контролем доступа и, вполне возможно, другой областью
соответствия. Собственная эталонная политика Kubernetes сохраняет Secret и ConfigMap на
уровне Metadata именно по этой причине.
Работоспособный вариант — по ресурсам. Логируйте привязки ролей, конфигурации webhook и
политику допуска на уровне RequestResponse, потому что знание того, что там изменилось —
это и есть цель; храните Secret на уровне Metadata, потому что знать, что Secret был
прочитан, полезно, а знать его содержимое — это риск. Решите это разделение осознанно и
запишите почему — аудитор гораздо охотнее примет обоснованную политику, чем максимальную.
См.
страницу PCI DSS о том, как журналирование аудита вписывается в
программу соответствия в целом.
Предупреждения — это ручные проверки: бенчмарк не может их решить, поэтому это должен сделать человек. Тридцать четыре из них относятся к разделу 5 — RBAC, Pod Security и сетевые политики, и на несколько уже даёт ответ то, как Cozystack строит тенанта:
baseline и предупреждает на уровне restricted.
Это отвечает на проверки раздела 5.2 о привилегированных контейнерах, пространствах имён
хоста и hostPath — но не на те, что касаются запуска от имени root, сброшенных возможностей
и профилей seccomp, для которых нужен restricted — всего одна метка пространства имёнget secrets. Читайте это как принцип наименьших
привилегий на уровне API-поверхности, а не как границу конфиденциальности: любой, кто может
запланировать рабочую нагрузку в пространстве имён, может смонтировать секреты этого
пространства имён в подОстальные предупреждения — клиентские сертификаты и токены служебных учётных записей, используемые как учётные данные пользователя, в частности — зависят от того, как вы управляете кластером, а не от того, как он поставляется.
Перед запуском важно сделать две вещи правильно. Явно передавайте --benchmark — иначе
kube-bench выбирает его на основе обнаруженной версии Kubernetes, а другой выбор даёт другой
набор проверок и другие итоги. И зафиксируйте образ: latest не является доказательством, и
аудитор имеет право спросить, какая версия какого инструмента создала отчёт.
Создайте пространство имён, разрешающее доступ к хосту, запустите задание, прочитайте вывод:
kubectl create namespace kube-bench
kubectl label namespace kube-bench pod-security.kubernetes.io/enforce=privileged
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench-master
namespace: kube-bench
spec:
backoffLimit: 1
template:
spec:
hostPID: true
nodeName: <your-control-plane-node>
restartPolicy: Never
containers:
- name: kube-bench
image: docker.io/aquasec/kube-bench:v0.12.0 # зафиксируйте версию или digest
command: ["kube-bench"]
args:
- "run"
- "--benchmark"
- "cis-1.12"
- "--targets"
- "master,controlplane,etcd,policies"
- "--json"
volumeMounts:
- { name: var-lib-etcd, mountPath: /var/lib/etcd, readOnly: true }
- { name: var-lib-kubelet, mountPath: /var/lib/kubelet, readOnly: true }
- { name: etc-kubernetes, mountPath: /etc/kubernetes, readOnly: true }
- { name: usr-bin, mountPath: /usr/local/mount-from-host/bin, readOnly: true }
volumes:
- { name: var-lib-etcd, hostPath: { path: /var/lib/etcd } }
- { name: var-lib-kubelet, hostPath: { path: /var/lib/kubelet } }
- { name: etc-kubernetes, hostPath: { path: /etc/kubernetes } }
- { name: usr-bin, hostPath: { path: /usr/bin } }
Для проверок worker-узла запустите то же задание на worker-узле с --targets node и убрав
монтирование etcd.
Относитесь к этому заданию так, как оно и есть: привилегированный, короткоживущий
диагностический инструмент. Оно работает с hostPID, в пространстве имён, где применение
Pod Security отключено, и монтирует /var/lib/kubelet — которое содержит клиентский ключ
kubelet узла и проецируемые токены служебных учётных записей всех подов на этом узле. Любой,
кто может выполнить exec в этот под, наследует идентичность узла. Поэтому запускайте его в
пространстве имён, доступном только администраторам кластера, никогда внутри тенанта,
добавьте automountServiceAccountToken: false в спецификацию пода, соберите JSON и удалите
пространство имён, как только получите результат:
kubectl delete namespace kube-bench
Исключение, которое требуется этому заданию из допуска, осознанное и временное — оно ничего не меняет в применении политик в пространствах имён, где реально работают рабочие нагрузки.
У бенчмарка нет вердикта «пройдено/не пройдено» — это список контролей, а соответствие — это суждение о конкретном кластере. В приведённом выше прогоне 54 контроля пройдены, а четыре отклонения стоит устранить. Из оставшихся двадцати пятнадцать проверяют режимы файлов на неизменяемом узле, три проверяют флаг, который заменила структурированная авторизация, одна требует файл модуля kubelet, которому Talos не находит применения, а одна требует kube-proxy, который заменил Cilium.
Потому что большинство проверок раздела 1.1 проверяет права доступа и владение файлами в
/etc/kubernetes, а Talos не хранит таких файлов. Контроли предполагают кластер kubeadm, где
администратор может редактировать манифесты на диске. Риск, на который эти контроли
направлены, обрабатывается иначе, а не игнорируется.
Да, и вам стоит это сделать. Манифест выше — тот же, что использовался для этой страницы. Запустите его на своём кластере перед оценкой и храните вывод вместе с заметками о том, какие ошибки архитектурные.
Не сам по себе. Неаннотированный отчёт вызывает больше вопросов, чем даёт ответов. Работает отчёт плюс сопоставление: для каждой ошибки — является ли она реальным отклонением, контролем, реализованным иначе, или проверкой, которая не применима — именно это и есть данная страница.
Эта страница описывает Cozystack v1.6 на Kubernetes v1.34.3, наблюдаемый на одном эталонном кластере — только управляющем кластере — измеренный с помощью CIS Kubernetes Benchmark v1.12 через kube-bench 18 августа 2026 года. Ваша установка может отличаться, особенно в конфигурации машины Talos, которая задаёт многие из рассмотренных здесь настроек. Эта страница носит информационный характер, а не является оценкой или сертификацией.