| .. | ||
| base | ||
| uralkal | ||
| kustomization.yaml | ||
| README.md | ||
security-audit
Сбор журнала аудита kube-apiserver с мастеров в Kafka-топик security.k8s-audit.
Одно сообщение — одно событие аудита в JSON (encoding: raw, без OTLP-обёртки), обогащённое полями sarex_*.
Дальнейшие этапы (processor → MinIO/Parquet) — отдельными компонентами.
С observability-коллектором (infrastructure/opentelemetry-collector) не связан: отдельный релиз, namespace и конфиг.
| Оверлей | Статус |
|---|---|
uralkal |
манифесты готовы, в clusters/uralkal не подключён |
Что делает коллектор
DaemonSet audit-collector-agent на узлах node-role.kubernetes.io/control-plane. Он читает
/var/log/audit/kube-apiserver-audit*.log (текущий и ротированные файлы), позиции хранит в /var/lib/otelcol-audit
(hostPath), туда же складывает дисковую очередь отправки.
Обработка (transform/audit):
- вырезание шума:
metadata.managedFieldsи аннотацияkubectl.kubernetes.io/last-applied-configurationвrequestObject/responseObject; - маскирование: значения параметров
password|passwd|pwd|token|secret|api_key|api-keyвrequestURI(token=abc→token=***), сама командаexecне маскируется; - классификация — поля ниже. Правила применяются по порядку, последнее подходящее побеждает.
| Поле | Значение | Условие |
|---|---|---|
sarex_contour |
имя контура | env CONTOUR из оверлея |
sarex_dry_run |
true / false |
requestURI содержит dryRun=All |
sarex_action |
read |
verb ∈ get, list |
mutate |
verb ∈ create, update, patch, delete, deletecollection |
|
status |
objectRef.subresource == status |
|
interactive |
objectRef.subresource ∈ exec, attach, portforward |
|
sarex_outcome |
applied |
код 2xx, не dry-run |
dry_run |
код 2xx, dry-run | |
denied_authn |
401 | |
denied_authz |
403 и authorization.k8s.io/decision=forbid |
|
denied_admission |
4xx при decision=allow, кроме 404/409/422 |
|
invalid |
422 | |
conflict |
409 | |
not_found |
404 | |
error |
5xx | |
sarex_actor_type |
human |
по умолчанию |
serviceaccount |
system:serviceaccount:* |
|
controller |
system:serviceaccount:kube-system:*, system:kube-*, system:apiserver |
|
node |
system:node:* |
|
gitops |
system:serviceaccount:flux-system:* |
watch не попадает ни в одну категорию sarex_action: поле не выставляется.
Надёжность доставки: required_acks: -1, дисковая очередь (sending_queue.storage), бесконечные ретраи. При
заполненной очереди срабатывает backpressure на filelog, чтение файла приостанавливается. Данные теряются,
только если файл успеет уйти из ротации (10 × 100 МБ) раньше, чем Kafka вернётся.
Предусловия подключения в контуре
-
Аудит apiserver включён (INFRA-3057): флаги
--audit-policy-file,--audit-log-path=/var/log/audit/kube-apiserver-audit.log,--audit-log-maxsize=100,--audit-log-maxbackup=10. Каталог/var/log/auditесть на всех мастерах. -
Kafka: топик и SCRAM-пользователь.
- Топик
security.k8s-audit: 1 партиция,retention.ms=259200000(3 суток),max.message.bytes=5242880, RF по контуру (вuralkalодин controller → RF 1). - Пользователь
security-audit(SCRAM-SHA-512). ACL не нужны.
Заводится terraform'ом:
infra/terraform, веткаcontour, модульkafka-topics-incluster, блокenvironments.<контур>вinfrastructure.yaml. Если нужно вручную — из пода контроллера, через внутренний листенер (INTERNAL, 9094,SASL_PLAINTEXT/PLAIN,inter_broker_user):kubectl -n kafka exec -it kafka-kafka-contour-controller-0 -c kafka -- bashcat > /tmp/admin.properties <<EOF security.protocol=SASL_PLAINTEXT sasl.mechanism=PLAIN sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="inter_broker_user" password="$(cat /vault/secrets/kafka-inter-broker-password)"; EOF B=localhost:9094 kafka-topics.sh --bootstrap-server $B --command-config /tmp/admin.properties --create \ --topic security.k8s-audit --partitions 1 --replication-factor 1 \ --config retention.ms=259200000 --config max.message.bytes=5242880 kafka-configs.sh --bootstrap-server $B --command-config /tmp/admin.properties --alter \ --entity-type users --entity-name security-audit \ --add-config 'SCRAM-SHA-512=[iterations=4096,password=<пароль>]' rm /tmp/admin.properties - Топик
-
Vault (
secrets/— KV v2):- секрет
secrets/data/security-audit/kafkaс ключамиusername,password,ca_crt;ca_crt— содержимоеca.crtиз Secretkafka/kafka-kafka-contour-tls(CA генерирует чартkafka-contour, срок 365 дней; при перевыпуске обновить и здесь); - политика
readнаsecrets/data/security-audit/kafka; - роль
security-auditвauth/kubernetes: bound SAaudit-collector, namespacesecurity-audit, политика выше.
Заводится в
infra/terraform, веткаcontour, модульvault-platform-secrets(ролиvault_kubernetes_auth_backend_role, KV-секреты). - секрет
-
Образ
cr.yandex/crp3ccidau046kdj8g9q/opentelemetry-collector/opentelemetry-collector-contrib:0.121.0-amd64доступен в registry контура (тот же, что дефолт чартаopentelemetry-collector-prod0.117.1),regcredесть в namespacesecurity-audit.
Подключение
Отдельным MR после выполнения предусловий — добавить в clusters/uralkal/kustomization.yaml:
- ../../infrastructure/security-audit/uralkal
dependsOn в оверлее ждёт HelmRelease kafka/kafka и vault/vault.
Проверка после подключения
- DaemonSet
security-audit/audit-collector-agentтолько на мастерах, все подыReady:kubectl -n security-audit get pods -o wide. - В логах коллектора нет ошибок:
kubectl -n security-audit logs ds/audit-collector-agent -c opentelemetry-collector-prod. - События в топике (из пода контроллера Kafka, с
admin.propertiesвыше):kafka-console-consumer.sh --bootstrap-server localhost:9094 --consumer.config /tmp/admin.properties --topic security.k8s-audit --max-messages 5. kubectl create secret generic audit-probe --from-literal=k=v→ событие сobjectRef.resource=secretsуровняMetadata, безrequestObject/responseObject.- Рестарт пода коллектора (
kubectl delete pod) → нет дублей и пропусков: сверитьauditIDв топике с файлом журнала на мастере за интервал рестарта.
Известное ограничение
Значения env с паролями внутри requestObject / responseObject workload-ресурсов на уровне RequestResponse
коллектор не маскирует: OTTL плохо работает с массивами (spec.containers[].env[]). Маскирование будет в processor'е.
До его готовности не повышать уровень для workload-ресурсов выше Request в контурах, где пароли могут быть в env.
Проверить перед подключением
Сверено по репозиторию и чартам 01.11.2026, доступа к кластеру не было.
| Что | Результат | Как проверено |
|---|---|---|
Образ и command.name |
.../opentelemetry-collector/opentelemetry-collector-contrib:0.121.0-amd64, otelcol-contrib |
дефолт values.yaml чарта opentelemetry-collector-prod 0.117.1 (appVersion 0.120.0, тег образа 0.121.0); otelcol-contrib components в образе: filelog, transform, kafka, file_storage, health_check, memory_limiter, batch есть |
| Синтаксис kafka exporter | для 0.121.0 корректен (topic/encoding наверху, auth.tls) |
otelcol-contrib validate в том же образе — OK |
| Kafka Service и порт | kafka-kafka-contour.kafka.svc.cluster.local:9092, SASL_SSL (не kafka.kafka...) |
helm template чарта kafka-contour 0.1.15 с values uralkal; тот же адрес у apps/*/uralkal |
| CA Kafka | Secret kafka/kafka-kafka-contour-tls, ключ ca.crt (helm genCA, 365 дней) |
шаблон tls-secret.yaml чарта; apps/issues/uralkal монтирует его же |
Kafka 4.0.0 и protocol_version: 2.8.0 |
совместимо (Kafka 4 требует ≥ 2.1) | appVersion чарта kafka-contour |
| Vault | HelmRelease vault/vault; injector ходит на http://vault-vault-contour.vault.svc:8200 |
infrastructure/vault/uralkal, helm template vault-contour 0.2.3 |
| Узлы мастеров | метка и taint node-role.kubernetes.io/control-plane |
так же сажается istio-gateway/uralkal |
| Рендер чарта | нет hostPort, Service, ClusterRole; nodeSelector/tolerations/securityContext как заданы |
helm template 0.117.1 с values из собранного HelmRelease |
Логика transform |
5 тестовых событий классифицированы верно, token=***, managedFields вырезаны |
запуск коллектора локально в том же образе с file-экспортёром вместо kafka |
Остаётся открытым:
TODO(verify)nodelocaldns (169.254.25.10) в NetworkPolicy: в репозитории не подтверждается. При дефолте kubespray включён, если нет — правило безвредно.- Некритичные предупреждения 0.121.0:
service::telemetry::metrics::addressустарел (так же во всех коллекторах репо); OTTL-пути без префиксаlog.(контекст выводится автоматически).