iac/infrastructure/security-audit
2026-11-01 22:02:54 +03:00
..
base Add audit collector HelmRelease for security-audit namespace to process and export kube-apiserver audit logs, including Kafka and Vault integration 2026-11-01 22:02:54 +03:00
uralkal Add audit collector HelmRelease for security-audit namespace to process and export kube-apiserver audit logs, including Kafka and Vault integration 2026-11-01 22:02:54 +03:00
kustomization.yaml Add audit collector HelmRelease for security-audit namespace to process and export kube-apiserver audit logs, including Kafka and Vault integration 2026-11-01 22:02:54 +03:00
README.md Add audit collector HelmRelease for security-audit namespace to process and export kube-apiserver audit logs, including Kafka and Vault integration 2026-11-01 22:02:54 +03:00

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 вернётся.

Предусловия подключения в контуре

  1. Аудит 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 есть на всех мастерах.

  2. 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 -- bash
    
    cat > /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
    
  3. Vault (secrets/ — KV v2):

    • секрет secrets/data/security-audit/kafka с ключами username, password, ca_crt; ca_crt — содержимое ca.crt из Secret kafka/kafka-kafka-contour-tls (CA генерирует чарт kafka-contour, срок 365 дней; при перевыпуске обновить и здесь);
    • политика read на secrets/data/security-audit/kafka;
    • роль security-audit в auth/kubernetes: bound SA audit-collector, namespace security-audit, политика выше.

    Заводится в infra/terraform, ветка contour, модуль vault-platform-secrets (роли vault_kubernetes_auth_backend_role, KV-секреты).

  4. Образ cr.yandex/crp3ccidau046kdj8g9q/opentelemetry-collector/opentelemetry-collector-contrib:0.121.0-amd64 доступен в registry контура (тот же, что дефолт чарта opentelemetry-collector-prod 0.117.1), regcred есть в namespace security-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. (контекст выводится автоматически).