Compare commits

..

18 Commits

Author SHA1 Message Date
emelinda
df3840e70d remove {topic: security.k8s-audit, kind: k8s_audit} 2026-11-07 20:27:40 +03:00
emelinda
772cef5cef security-audit: fix pipelines placement in processor config — top-level key
config.Pipelines is a root-level key in k8s-audit; nested under kafka: it
was ignored and the service fell back to the single kafka.topic fallback.
2026-11-07 20:18:47 +03:00
emelinda
d0bed7033a security-audit: enable mesh-access pipeline, audit-processor pinned by digest
Config: pipelines security.k8s-audit (k8s_audit) + security.mesh-access
(mesh_access); kafka.topic kept for rollback (pre-pipelines image ignores
the pipelines key). Image pinned to digest sha256:56a23bec… (k8s-audit@05a186a,
pipelines support) per repo policy п.38. Kafka ACL and MinIO policy need no
changes (no ACLs; bucket user has s3:* on the whole bucket). Companion
terraform change: ILM rule expire-mesh-access-90d.
2026-11-07 20:12:54 +03:00
emelinda
a2da49804a security-audit: audit-processor 47297469, flush_interval 1m
Bump processor image and deliver events to MinIO within a minute
(more small parquet files; compaction is stage 3 of k8s-audit).
2026-11-07 18:46:32 +03:00
emelinda
ff931e1708 security-audit: audit-processor flush_interval 5m -> 1m
Deliver audit events to MinIO within a minute for near-real-time
investigation; trade-off is more small parquet files (compaction
is planned in stage 3 of k8s-audit).
2026-11-07 18:07:36 +03:00
emelinda
a6a176d6c5 security-audit: audit-processor af50e663, drop retention config section
New image removes the bucket lifecycle check (retention is owned by terraform
minio-buckets lifecycle_rules), so the retention section is dropped from the
processor config map.
2026-11-07 17:24:47 +03:00
emelinda
a60b171bea security-audit: IsMap guards in transform/audit delete_key statements
Some events (e.g. deletecollection) carry requestObject as a slice, not a map:
indexing it with "metadata" failed with "unable to resolve an integer index in
slice" and spammed the collector log (error_mode: ignore — events were not lost).
IsMap chains rely on OTTL short-circuit `and` evaluation (verified against
v0.121 sources).
2026-11-07 16:23:46 +03:00
emelinda
cf2689aea0 security-audit: fix filter/audit config key — log_record (singular), filterprocessor 0.121
The processor rejected "log_records": LogFilters.LogConditions is mapstructure
"log_record" in v0.121 (collector failed to start: failed to get config).
2026-11-07 16:00:24 +03:00
emelinda
0b8318f547 security-audit: drop flux-system read polling from apiserver audit pipeline
filter/audit in audit-collector drops get/list/watch events from
system:serviceaccount:flux-system:* (helm/kustomize/source controllers polling
fluxcd resources every few seconds — the bulk of the topic volume). GitOps
mutations are kept: they are the actual trail of cluster changes.
2026-11-07 15:45:37 +03:00
emelinda
508f18d2a5 Merge remote-tracking branch 'origin/master' 2026-11-07 14:54:15 +03:00
emelinda
1960ef495c security-audit: add audit-processor — ship apiserver audit from Kafka to MinIO (Parquet)
base/processor-*.yaml: Deployment (1 replica, image k8s-audit-processor:394b6f9d),
ConfigMap with config.yaml, ServiceAccount, NetworkPolicy (DNS, kafka:9092,
external MinIO 10.133.0.245:9000). Contour-specific values for uralkal are set
via env patch in the overlay (K8S_AUDIT_*), same pattern as the collectors.
Credentials reuse the static Secrets (security-audit-kafka, kafka-ca,
security-audit-minio) via a projected volume at /vault/secrets.

app.env=stand: the contour's external MinIO has no TLS, so strict validation
(minio.secure) would fail. log.s3_echo=true is temporary for flow verification
(per security req. 20: disable after debugging).
2026-11-07 14:54:08 +03:00
491c0462cd ++ proctmp only uralkal 2026-11-07 11:37:41 +03:00
aa0ba4097c ++ engine low proctmp 2026-11-07 11:22:11 +03:00
emelinda
9cb62ea9f0 security-audit: nil-guards в transform/audit — удаление managedFields/annotations
У части событий requestObject есть, а metadata/annotations в нём nil —
statement падал с "expected pcommon.Map but got nil" и засорял лог
(error_mode: ignore, события не терялись).
2026-11-06 18:03:30 +03:00
emelinda
d4bbc5fd14 security-audit: отложить события Zitadel — отключить Job idp-actions-bootstrap
PAT machine user'а security-audit-bootstrap не заведён (ни Vault-роль, ни статический
Secret), Job не сможет настроить Target/Execution'ы. Пайплайн logs/idp в access-collector
оставлен и инертен: без Target'а Zitadel ничего не отправляет. Обратное включение:
раскомментировать idp-actions-bootstrap в base/kustomization.yaml и его патч в оверлее
uralkal, добавить ключ zitadel_pat в Secret security-audit-kafka.
2026-11-06 17:34:05 +03:00
emelinda
3162679524 security-audit: креды Kafka и PAT Zitadel — из статических Secret'ов вместо Vault Agent
В контуре uralkal роли Vault (security-audit, security-audit-bootstrap) не заведены.
Коллекторы и Job idp-actions-bootstrap монтируют Secret'ы namespace (security-audit-kafka,
kafka-ca) projected volume'ом в /vault/secrets под теми же именами файлов — конфиг
коллекторов (${file:...}, ca_file) не меняется. Из NetworkPolicy убран egress в Vault,
из оверлея uralkal — dependsOn на HelmRelease vault.
2026-11-06 17:22:20 +03:00
emelinda
f0014c5d00 uralkal: подключить security-audit — аудит apiserver, журнал доступа шлюза, события Zitadel
DaemonSet audit-collector на control-plane (журнал kube-apiserver → security.k8s-audit),
Deployment access-collector (OTLP :4317 — журнал доступа ingress-шлюза → security.mesh-access,
webhookevent :8088 — события Zitadel Actions v2 → security.idp-events, otlp :4319 — журнал
аудита Vault → security.vault-audit), Job idp-actions-bootstrap (Target + Execution'ы в Zitadel),
NetworkPolicy/AuthorizationPolicy, EnvoyFilter strip-audit-headers и Telemetry шлюза
на провайдер audit-access (уже раскатан в istio-pilot/uralkal).

Предусловия выполнены вне репозитория: аудит apiserver на мастерах (INFRA-3057),
топики security.* и SCRAM-пользователь в Kafka, бакет security-audit в MinIO,
секреты и роли Vault (terraform, vault-platform-secrets).
2026-11-06 16:47:32 +03:00
emelinda
509926a108 uralkal: отключить postgres-tls-test и istio-mtls-check от кластера
Оверлеи убраны из clusters/uralkal/kustomization.yaml, манифесты
apps/postgres-tls-test/ и infrastructure/istio-mtls-check/ сохранены
для возможного повторного подключения.
2026-11-06 15:35:36 +03:00
17 changed files with 317 additions and 110 deletions

View File

@ -36,7 +36,7 @@ spec:
image:
name:
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings-amqp:prod_9fb418db
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings-amqp:prod_9dea5b64
pullPolicy:
_default: IfNotPresent

View File

@ -10,7 +10,7 @@ spec:
backend:
image:
name:
_default: cr.yandex/crp3ccidau046kdj8g9q/workflows-engine:contour_7d2cd329
_default: cr.yandex/crp3ccidau046kdj8g9q/workflows-engine:contour_8a50dd85
deployment:
resources:
requests:

View File

@ -19,3 +19,19 @@ patches:
target:
kind: HelmRelease
name: frontend
- target:
kind: HelmRelease
name: engine-low
patch: |-
- op: add
path: /spec/values/services/backend/envs/-
value:
name: JOB_TMP_HOST_PATH
value:
_default: "/mnt/proctmp"
- op: add
path: /spec/values/services/backend/envs/-
value:
name: JOB_TMP_HOST_PATH_IMAGE
value:
_default: "e57-to-las"

View File

@ -17,6 +17,7 @@ resources:
- ../../infrastructure/trino/uralkal
- ../../infrastructure/istio-config/uralkal
- ../../infrastructure/s3-proxy/uralkal
- ../../infrastructure/security-audit/uralkal
- ../../apps/reviews/uralkal
- ../../apps/remarks/uralkal
@ -54,8 +55,6 @@ resources:
- ../../apps/pm/uralkal
- ../../apps/message-hub/uralkal
- ../../apps/cde/uralkal
- ../../apps/postgres-tls-test/uralkal
- ../../infrastructure/istio-mtls-check/base
patches:
- target:

View File

@ -10,21 +10,24 @@
| журнал аудита Vault | sidecar `audit-shipper` в подах Vault → `access-collector`, pipeline `logs/vault` | `security.vault-audit` |
Одно сообщение — одна запись в JSON (`encoding: raw`, без OTLP-обёртки), обогащённая полями `sarex_*`.
Дальнейшие этапы (processor → MinIO/Parquet) — отдельными компонентами.
Processor (`audit-processor`, образ `k8s-audit-processor` из `infra/k8s-audit`) читает топик
`security.k8s-audit` и пишет события в MinIO (Parquet, `events/contour=<c>/dt=…/hour=…`). Его манифесты —
`base/processor-*.yaml`, контур-специфика (CONTOUR, брокеры, endpoint MinIO, `log.s3_echo`) — env-патчем
в оверлее. Секреты — те же статические Secret'ы, что у коллекторов, плюс `security-audit-minio`.
С observability-коллектором (`infrastructure/opentelemetry-collector`) не связан: отдельный релиз, namespace и конфиг.
| Каталог | Что | Namespace |
|---|---|---|
| `base/` | оба коллектора, NetworkPolicy, AuthorizationPolicy, Namespace | `security-audit` |
| `base/idp-actions-bootstrap/` | Job настройки Target/Execution'ов в Zitadel, скрипт и список событий | `security-audit` |
| `base/` | оба коллектора, audit-processor, NetworkPolicy, AuthorizationPolicy, Namespace | `security-audit` |
| `base/idp-actions-bootstrap/` | Job настройки Target/Execution'ов в Zitadel, скрипт и список событий (**сейчас отключён** в `base/kustomization.yaml` — отложено, нет PAT) | `security-audit` |
| `mesh/` | EnvoyFilter и Telemetry шлюза; без `namespace` в kustomization, селектор шлюза — заглушка | `istio-system` |
| `uralkal/` | оверлей: `base` + `mesh`, селектор шлюза, Kafka, `dependsOn` | — |
| `uralkal/` | оверлей: `base` + `mesh`, селектор шлюза, Kafka, `dependsOn`, env audit-processor'а | — |
| `../vault/uralkal-audit/` | Vault-часть журнала аудита Vault: оверлей поверх `vault/uralkal` (не подключён) | `vault` |
| Оверлей | Статус |
|---|---|
| `uralkal` | манифесты готовы, **в `clusters/uralkal` не подключён** |
| `uralkal` | подключён в `clusters/uralkal` |
## Журнал аудита kube-apiserver
@ -104,16 +107,13 @@ DaemonSet `audit-collector-agent` на узлах `node-role.kubernetes.io/contr
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` **и** `access-collector`, namespace
`security-audit`, политика выше.
Заводится в `infra/terraform`, ветка `contour`, модуль `vault-platform-secrets` (роли `vault_kubernetes_auth_backend_role`,
KV-секреты).
3. **Креды Kafka — статические Secret'ы** в namespace `security-audit` (роли в Vault не заведены, агент-инжектор
не используется):
- Secret `security-audit-kafka` с ключами `username`, `password` (SCRAM-пользователь `security-audit`);
- Secret `kafka-ca` с ключом `ca.crt` — содержимое `ca.crt` из Secret `kafka/kafka-kafka-contour-tls`
(CA генерирует чарт `kafka-contour`, срок 365 дней; при перевыпуске обновить и здесь).
Оба монтируются projected volume'ом в `/vault/secrets` под именами `kafka-username`, `kafka-password`,
`kafka-ca.crt` — конфиг коллекторов (`${file:...}`, `ca_file`) не меняется.
4. **Образ** `cr.yandex/crp3ccidau046kdj8g9q/opentelemetry-collector/opentelemetry-collector-contrib:0.121.0-amd64`
доступен в registry контура (тот же, что дефолт чарта `opentelemetry-collector-prod` 0.117.1), `regcred` есть в
namespace `security-audit`.
@ -126,7 +126,7 @@ DaemonSet `audit-collector-agent` на узлах `node-role.kubernetes.io/contr
- ../../infrastructure/security-audit/uralkal
```
`dependsOn` в оверлее ждёт HelmRelease `kafka/kafka` и `vault/vault`.
`dependsOn` в оверлее ждёт HelmRelease `kafka/kafka`.
Порядок: сначала должен раскататься провайдер `audit-access` в istiod (`infrastructure/istio-pilot/uralkal/istio-pilot.yaml`,
применяется сразу, как только попадёт в master: кластер его уже подключает). Telemetry из `mesh/` ссылается на этот провайдер по имени. Проверка:
@ -260,9 +260,8 @@ spec:
Метка `istio-injection: disabled` отключила бы инъекцию совсем, даже по метке пода.
- `PeerAuthentication` в репозитории нет, поэтому режим PERMISSIVE. Шлюз шлёт в коллектор по auto-mTLS (оба в mesh),
коллектор в Kafka — тоже через mTLS (`kafka` в mesh), внутри остаётся `SASL_SSL`.
- Vault Agent (`agent-init-first`, pre-populate) + istio-proxy: по паттерну контура (`apps/bi`, `apps/bim`, `apps/cde`…)
`traffic.sidecar.istio.io/excludeOutboundPorts: "8200"`. Init-агент ходит в Vault мимо iptables-перехвата,
даже если `istio-init` отработал раньше.
- Креды Kafka — статические Secret'ы (projected volume в `/vault/secrets`), Vault Agent не используется:
роли `security-audit` в Vault контура нет.
- `holdApplicationUntilProxyStarts`: kafka exporter подключается к брокерам на старте и без готового proxy падает.
- `istio-init` требует `NET_ADMIN`/`NET_RAW`: enforce `privileged` это разрешает, профиль `warn: baseline` даст
предупреждения при создании подов — ожидаемо.
@ -382,8 +381,8 @@ HTTP-probe на pilot-agent `:15020`, а тот ходит в приложени
- **Mesh.** Job в mesh (`sidecar.istio.io/inject=true`, `holdApplicationUntilProxyStarts`). В конце скрипт вызывает
`POST 127.0.0.1:15020/quitquitquit`, istio-proxy завершается, под — `Completed`. STRICT mTLS у Zitadel сейчас нет, но
Job к нему готов.
- **Vault:** роль `security-audit-bootstrap`, `secrets/data/security-audit/zitadel-bootstrap` → `pat` →
`/vault/secrets/zitadel-pat`; `excludeOutboundPorts: 8200` — паттерн контура.
- **PAT:** статический Secret в namespace `security-audit` (роли в Vault нет), монтируется в
`/vault/secrets/zitadel-pat`; имя Secret'а и ключа — в `job.yaml`, сверить с созданным в контуре.
- **Скрипт** (`files/idp-actions-bootstrap.sh`, POSIX sh) идемпотентен:
1. ждёт `/debug/ready` (10 попыток × 15 с);
2. печатает все типы событий инстанса (`known: …`, `POST /admin/v1/events/types/_search`);
@ -405,10 +404,8 @@ HTTP-probe на pilot-agent `:15020`, а тот ходит в приложени
- Топик `security.idp-events`: 3 партиции, `retention.ms=259200000`, RF по контуру, тем же путём, что остальные
топики. Пользователь `security-audit`, ACL не нужны.
- Сервисный пользователь Zitadel `security-audit-bootstrap` (machine user) с ролью `IAM_OWNER` на инстансе.
Нужны `action.target.read/write/delete`, `action.execution.read/write`, `events.read`. Его PAT — во Vault
`secrets/data/security-audit/zitadel-bootstrap`, ключ `pat`.
- Роль Vault `security-audit-bootstrap` в `auth/kubernetes`: bound SA `idp-actions-bootstrap`, namespace `security-audit`,
политика `read` на `secrets/data/security-audit/zitadel-bootstrap`.
Нужны `action.target.read/write/delete`, `action.execution.read/write`, `events.read`. Его PAT — ключ
в статическом Secret'е namespace `security-audit` (см. `base/idp-actions-bootstrap/job.yaml`).
- Feature flag не нужен: в v4.12.2 `actions` в `/v2/features/instance` удалён (reserved), Actions v2 включены всегда.
Проверка API изнутри кластера (ожидается `"https://login.sarex.local.uralkali.com"`):

View File

@ -118,31 +118,24 @@ spec:
sidecar.istio.io/inject: "true"
# Kafka exporter подключается к брокерам на старте: без готового istio-proxy коллектор упадёт.
proxy.istio.io/config: '{"holdApplicationUntilProxyStarts": true}'
# Паттерн контура для Vault + sidecar (apps/*/base): трафик агента к Vault мимо istio-proxy.
traffic.sidecar.istio.io/excludeOutboundPorts: "8200"
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-init-first: "true"
vault.hashicorp.com/agent-pre-populate-only: "true"
vault.hashicorp.com/agent-requests-cpu: "25m"
vault.hashicorp.com/agent-limits-cpu: "100m"
vault.hashicorp.com/auth-path: auth/kubernetes
vault.hashicorp.com/role: security-audit
# Многострочные шаблоны — см. helmrelease-collector.yaml (toYaml | tpl в чарте).
vault.hashicorp.com/agent-inject-secret-kafka-username: secrets/data/security-audit/kafka
vault.hashicorp.com/agent-inject-template-kafka-username: |-
{{ "{{- with secret \"secrets/data/security-audit/kafka\" -}}" }}
{{ "{{ .Data.data.username }}" }}
{{ "{{- end -}}" }}
vault.hashicorp.com/agent-inject-secret-kafka-password: secrets/data/security-audit/kafka
vault.hashicorp.com/agent-inject-template-kafka-password: |-
{{ "{{- with secret \"secrets/data/security-audit/kafka\" -}}" }}
{{ "{{ .Data.data.password }}" }}
{{ "{{- end -}}" }}
vault.hashicorp.com/agent-inject-secret-kafka-ca.crt: secrets/data/security-audit/kafka
vault.hashicorp.com/agent-inject-template-kafka-ca.crt: |-
{{ "{{- with secret \"secrets/data/security-audit/kafka\" -}}" }}
{{ "{{ .Data.data.ca_crt }}" }}
{{ "{{- end -}}" }}
# Креды Kafka — статические Secret'ы namespace (роли security-audit в Vault нет).
# Те же пути /vault/secrets/..., что читает конфиг: ${file:...} и ca_file.
extraVolumes:
- name: kafka-secrets
projected:
sources:
- secret:
name: security-audit-kafka
items:
- {key: username, path: kafka-username}
- {key: password, path: kafka-password}
- secret:
name: kafka-ca
items:
- {key: ca.crt, path: kafka-ca.crt}
extraVolumeMounts:
- {name: kafka-secrets, mountPath: /vault/secrets, readOnly: true}
# Контур-специфичное (CONTOUR, KAFKA_BROKERS) задаётся в оверлее через extraEnvs.
alternateConfig:

View File

@ -51,7 +51,7 @@ spec:
create: false
serviceAccount:
create: true
name: audit-collector # = роль Vault security-audit, bound SA
name: audit-collector # bound SA роли Vault security-audit — если вернёмся на Vault Agent
presets:
logsCollection: {enabled: false}
hostMetrics: {enabled: false}
@ -96,39 +96,31 @@ spec:
hostPath: {path: /var/log/audit, type: DirectoryOrCreate}
- name: otelcol-storage
hostPath: {path: /var/lib/otelcol-audit, type: DirectoryOrCreate}
# Креды Kafka — статические Secret'ы namespace (роли security-audit в Vault нет).
# Projected volume складывает оба Secret'а в /vault/secrets под теми же именами файлов,
# что читает конфиг: ${file:/vault/secrets/kafka-username|kafka-password}, ca_file=kafka-ca.crt.
- name: kafka-secrets
projected:
sources:
- secret:
name: security-audit-kafka
items:
- {key: username, path: kafka-username}
- {key: password, path: kafka-password}
- secret:
name: kafka-ca
items:
- {key: ca.crt, path: kafka-ca.crt}
extraVolumeMounts:
- {name: audit-log, mountPath: /var/log/audit, readOnly: true}
- {name: otelcol-storage, mountPath: /var/lib/otelcol-audit}
- {name: kafka-secrets, mountPath: /vault/secrets, readOnly: true}
# Метка исключает под из webhook'а инъекции Istio ещё до мутации (namespace без istio-injection).
podLabels:
sidecar.istio.io/inject: "false"
podAnnotations:
sidecar.istio.io/inject: "false"
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-init-first: "true"
vault.hashicorp.com/agent-pre-populate-only: "true"
vault.hashicorp.com/agent-requests-cpu: "25m"
vault.hashicorp.com/agent-limits-cpu: "100m"
vault.hashicorp.com/auth-path: auth/kubernetes
vault.hashicorp.com/role: security-audit
# Чарт рендерит podAnnotations через toYaml | tpl: однострочный шаблон toYaml переносит,
# и литерал {{ "..." }} рвётся. Поэтому по строке на действие (block scalar не переносится).
vault.hashicorp.com/agent-inject-secret-kafka-username: secrets/data/security-audit/kafka
vault.hashicorp.com/agent-inject-template-kafka-username: |-
{{ "{{- with secret \"secrets/data/security-audit/kafka\" -}}" }}
{{ "{{ .Data.data.username }}" }}
{{ "{{- end -}}" }}
vault.hashicorp.com/agent-inject-secret-kafka-password: secrets/data/security-audit/kafka
vault.hashicorp.com/agent-inject-template-kafka-password: |-
{{ "{{- with secret \"secrets/data/security-audit/kafka\" -}}" }}
{{ "{{ .Data.data.password }}" }}
{{ "{{- end -}}" }}
vault.hashicorp.com/agent-inject-secret-kafka-ca.crt: secrets/data/security-audit/kafka
vault.hashicorp.com/agent-inject-template-kafka-ca.crt: |-
{{ "{{- with secret \"secrets/data/security-audit/kafka\" -}}" }}
{{ "{{ .Data.data.ca_crt }}" }}
{{ "{{- end -}}" }}
# Контур-специфичное (CONTOUR, KAFKA_BROKERS) задаётся в оверлее через extraEnvs.
# Полный конфиг вместо мержа с дефолтами чарта.
@ -160,16 +152,28 @@ spec:
check_interval: 1s
limit_mib: 400
spike_limit_mib: 100
# Отрезание шума до transform и Kafka: бесконечные опросы Flux-контроллеров
# (helm/kustomize/source: get/list/watch на ресурсах fluxcd). Мутации GitOps
# (create/update/patch/delete) остаются — они и есть след изменений через GitOps.
# Фильтр намеренно узкий: чтения других акторов (kube-system, операторы) не трогаем.
filter/audit:
error_mode: ignore
logs:
# Ключ именно log_record (singular) — так в filterprocessor 0.121 (config.go).
# Запись отбрасывается, если любое условие истинно.
log_record:
- 'IsMatch(body["user"]["username"], "^system:serviceaccount:flux-system:") and (body["verb"] == "get" or body["verb"] == "list" or body["verb"] == "watch")'
transform/audit:
error_mode: ignore
log_statements:
- context: log
statements:
# --- объём и шум ---
- delete_key(body["requestObject"]["metadata"], "managedFields") where body["requestObject"] != nil
- delete_key(body["responseObject"]["metadata"], "managedFields") where body["responseObject"] != nil
- delete_key(body["requestObject"]["metadata"]["annotations"], "kubectl.kubernetes.io/last-applied-configuration") where body["requestObject"] != nil
- delete_key(body["responseObject"]["metadata"]["annotations"], "kubectl.kubernetes.io/last-applied-configuration") where body["responseObject"] != nil
# --- объём и шум (guard'ы IsMap: у части событий requestObject — массив или без metadata/annotations;
# and в OTTL short-circuit, поэтому индексация вглубь выполняется только для map) ---
- delete_key(body["requestObject"]["metadata"], "managedFields") where IsMap(body["requestObject"]) and IsMap(body["requestObject"]["metadata"])
- delete_key(body["responseObject"]["metadata"], "managedFields") where IsMap(body["responseObject"]) and IsMap(body["responseObject"]["metadata"])
- delete_key(body["requestObject"]["metadata"]["annotations"], "kubectl.kubernetes.io/last-applied-configuration") where IsMap(body["requestObject"]) and IsMap(body["requestObject"]["metadata"]) and IsMap(body["requestObject"]["metadata"]["annotations"])
- delete_key(body["responseObject"]["metadata"]["annotations"], "kubectl.kubernetes.io/last-applied-configuration") where IsMap(body["responseObject"]) and IsMap(body["responseObject"]["metadata"]) and IsMap(body["responseObject"]["metadata"]["annotations"])
# --- маскирование (п.23): значения, а не сама команда exec ---
- replace_pattern(body["requestURI"], "(?i)(password|passwd|pwd|token|secret|api[_-]?key)(=|%3D)[^&]*", "$$1$$2***")
# --- обогащение ---
@ -236,7 +240,7 @@ spec:
pipelines:
logs/audit:
receivers: [filelog/audit]
processors: [memory_limiter, transform/audit, batch]
processors: [memory_limiter, filter/audit, transform/audit, batch]
exporters: [kafka/audit]
telemetry:
logs:

View File

@ -19,19 +19,6 @@ spec:
annotations:
sidecar.istio.io/inject: "true"
proxy.istio.io/config: '{"holdApplicationUntilProxyStarts": true}'
traffic.sidecar.istio.io/excludeOutboundPorts: "8200" # Vault мимо istio-proxy (паттерн контура)
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-init-first: "true"
vault.hashicorp.com/agent-pre-populate-only: "true"
vault.hashicorp.com/agent-requests-cpu: "25m"
vault.hashicorp.com/agent-limits-cpu: "100m"
vault.hashicorp.com/auth-path: auth/kubernetes
vault.hashicorp.com/role: security-audit-bootstrap
vault.hashicorp.com/agent-inject-secret-zitadel-pat: secrets/data/security-audit/zitadel-bootstrap
vault.hashicorp.com/agent-inject-template-zitadel-pat: |-
{{- with secret "secrets/data/security-audit/zitadel-bootstrap" -}}
{{ .Data.data.pat }}
{{- end -}}
spec:
serviceAccountName: idp-actions-bootstrap
restartPolicy: Never
@ -82,6 +69,7 @@ spec:
- {name: script, mountPath: /scripts, readOnly: true}
- {name: events, mountPath: /config, readOnly: true}
- {name: tmp, mountPath: /tmp}
- {name: zitadel-pat, mountPath: /vault/secrets, readOnly: true}
volumes:
- {name: tools, emptyDir: {sizeLimit: 16Mi}}
- {name: tmp, emptyDir: {medium: Memory, sizeLimit: 16Mi}} # заголовки с PAT — только в памяти
@ -89,3 +77,10 @@ spec:
configMap: {name: idp-actions-bootstrap-script}
- name: events
configMap: {name: idp-actions-bootstrap-events}
# PAT machine user'а security-audit-bootstrap — статический Secret (роли в Vault нет).
# TODO(verify): имя Secret'а и ключа сверить с созданным в контуре; скрипт читает PAT_FILE=/vault/secrets/zitadel-pat.
- name: zitadel-pat
secret:
secretName: security-audit-kafka
items:
- {key: zitadel_pat, path: zitadel-pat}

View File

@ -8,4 +8,12 @@ resources:
- authorizationpolicy-access-collector.yaml
- helmrelease-collector.yaml
- helmrelease-access-collector.yaml
- idp-actions-bootstrap
- processor-serviceaccount.yaml
- processor-configmap.yaml
- processor-deployment.yaml
- processor-networkpolicy.yaml
# События Zitadel отложены: нет PAT machine user'а security-audit-bootstrap (роли в Vault нет,
# статический Secret не заведён). Обратное включение: раскомментировать здесь и патч
# idp-actions-bootstrap.yaml в оверлее uralkal, добавить ключ zitadel_pat в Secret.
# Пайплайн logs/idp в access-collector при этом инертен: без Job Target в Zitadel не создаётся.
# - idp-actions-bootstrap

View File

@ -1,4 +1,5 @@
# Коллектору нужны только DNS, Kafka и Vault (агент-инжектор). Входящие — только health-check kubelet'а.
# Коллектору нужны только DNS и Kafka. Входящие — только health-check kubelet'а.
# (Раньше был egress в Vault для агента-инжектора; креды — статические Secret'ы.)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@ -25,8 +26,3 @@ spec:
ports:
# client-листенер SASL_SSL: bootstrap kafka-kafka-contour и advertised-адреса подов controller-headless
- {port: 9092, protocol: TCP}
- to:
- namespaceSelector:
matchLabels: {kubernetes.io/metadata.name: vault}
ports:
- {port: 8200, protocol: TCP} # vault-vault-contour.vault.svc:8200 (AGENT_INJECT_VAULT_ADDR)

View File

@ -0,0 +1,63 @@
# Конфиг audit-processor (образ k8s-audit-processor, CONFIG_PATH=/etc/k8s-audit/config.yaml).
# Контур-специфичные значения (contour, kafka.brokers, minio.endpoint, app.env, log.s3_echo)
# задаёт оверлей через env K8S_AUDIT_* — см. uralkal/kustomization.yaml.
apiVersion: v1
kind: ConfigMap
metadata:
name: audit-processor-config
labels:
app.kubernetes.io/name: audit-processor
data:
config.yaml: |
contour: "" # K8S_AUDIT_CONTOUR
app:
name: audit-processor
env: dev # K8S_AUDIT_APP_ENV
log:
level: info
output: stdout
add_source: false
access_log: true
audit_events: false # поток ИБ не идёт в прикладные логи (п.20)
s3_echo: false # K8S_AUDIT_LOG_S3_ECHO; только отладка (п.20)
# Пайплайны чтения: один consumer group вычитывает все топики списка.
# Ключ верхнего уровня (config.Pipelines), НЕ внутри kafka.
# kafka.topic НЕ удалять — без pipelines (откат на старый образ) читается он.
pipelines:
# - {topic: security.k8s-audit, kind: k8s_audit}
- {topic: security.mesh-access, kind: mesh_access}
kafka:
brokers: [] # K8S_AUDIT_KAFKA_BROKERS
topic: security.k8s-audit
group: security-audit-processor
start_from: earliest # latest перескочил бы события после разрыва offset'ов
session_timeout: 45s
rebalance_timeout: 60s
tls:
enabled: true
ca_file: /vault/secrets/kafka-ca.crt
sasl:
mechanism: SCRAM-SHA-512
username_file: /vault/secrets/kafka-username
password_file: /vault/secrets/kafka-password
minio:
endpoint: "" # K8S_AUDIT_MINIO_ENDPOINT
bucket: security-audit
secure: false # внешний MinIO контура — plain HTTP (ServiceEntry minio.uralkal.external)
access_key_file: /vault/secrets/minio-access-key
secret_key_file: /vault/secrets/minio-secret-key
http:
host: 0.0.0.0
port: 8000 # /healthz, /readyz, /metrics
stream:
flush_interval: 1m # как часто сбрасывать буфер в MinIO (и коммитить offset'ы)
flush_max_rows: 10000 # или раньше, при стольких строках
flush_timeout: 30s # меньше kafka.rebalance_timeout
max_flush_failures: 30

View File

@ -0,0 +1,74 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: audit-processor
labels:
app.kubernetes.io/name: audit-processor
spec:
replicas: 1 # consumer group: партиция security.k8s-audit одна, вторая реплика была бы standby
selector:
matchLabels:
app.kubernetes.io/name: audit-processor
template:
metadata:
labels:
app.kubernetes.io/name: audit-processor
# Без sidecar: в Kafka процессор ходит напрямую SASL_SSL (как audit-collector),
# во внешний MinIO — мимо mesh (ServiceEntry, HTTP).
sidecar.istio.io/inject: "false"
annotations:
sidecar.istio.io/inject: "false"
spec:
serviceAccountName: audit-processor
imagePullSecrets:
- name: regcred
securityContext:
seccompProfile: {type: RuntimeDefault}
containers:
- name: audit-processor
# Образ FROM scratch, USER 65534; CONFIG_PATH=/etc/k8s-audit/config.yaml — в ENTRYPOINT образа.
# Digest, а не тег (п.38): релиз с поддержкой pipelines (k8s-audit@05a186a).
image: cr.yandex/crp3ccidau046kdj8g9q/k8s-audit-processor@sha256:56a23bec64fe6abdabebbc67806c4d5677486dca5ad5aac01b17db09d768bc72
ports:
- {name: http, containerPort: 8000}
readinessProbe:
httpGet: {path: /readyz, port: http}
periodSeconds: 10
livenessProbe:
httpGet: {path: /healthz, port: http}
periodSeconds: 20
resources:
requests: {cpu: 50m, memory: 128Mi}
limits: {cpu: 500m, memory: 512Mi}
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
volumeMounts:
- {name: config, mountPath: /etc/k8s-audit, readOnly: true}
# Те же Secret'ы и имена файлов, что у коллекторов (плюс ключи MinIO).
- {name: secrets, mountPath: /vault/secrets, readOnly: true}
volumes:
- name: config
configMap: {name: audit-processor-config}
- name: secrets
projected:
sources:
- secret:
name: security-audit-kafka
items:
- {key: username, path: kafka-username}
- {key: password, path: kafka-password}
- secret:
name: kafka-ca
items:
- {key: ca.crt, path: kafka-ca.crt}
- secret:
name: security-audit-minio
items:
- {key: access_key, path: minio-access-key}
- {key: secret_key, path: minio-secret-key}

View File

@ -0,0 +1,34 @@
# Процессору нужны: Kafka (чтение топика), внешний MinIO (запись Parquet), DNS.
# Входящие — только пробы и метрики (:8000). Складывается с общей политикой audit-collector
# (podSelector {}): её правила DNS и Kafka дублировать не обязательно, но оставляем автономность.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: audit-processor
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: audit-processor
policyTypes: [Ingress, Egress]
ingress:
- ports:
- {port: 8000, protocol: TCP} # /healthz, /readyz (kubelet), /metrics
egress:
- to:
- namespaceSelector:
matchLabels: {kubernetes.io/metadata.name: kube-system}
podSelector:
matchLabels: {k8s-app: kube-dns}
- ipBlock: {cidr: 169.254.25.10/32} # nodelocaldns kubespray
ports:
- {port: 53, protocol: UDP}
- {port: 53, protocol: TCP}
- to:
- namespaceSelector:
matchLabels: {kubernetes.io/metadata.name: kafka}
ports:
- {port: 9092, protocol: TCP} # client-листенер SASL_SSL
- to:
- ipBlock: {cidr: 10.133.0.245/32} # внешний MinIO контура (minio.uralkal.external)
ports:
- {port: 9000, protocol: TCP}

View File

@ -0,0 +1,6 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: audit-processor
labels:
app.kubernetes.io/name: audit-processor

View File

@ -7,8 +7,6 @@ spec:
dependsOn:
- name: kafka
namespace: kafka
- name: vault
namespace: vault
values:
extraEnvs:
- name: CONTOUR

View File

@ -7,8 +7,6 @@ spec:
dependsOn:
- name: kafka
namespace: kafka
- name: vault
namespace: vault
values:
extraEnvs:
- name: CONTOUR

View File

@ -6,7 +6,8 @@ resources:
patches:
- path: audit-collector.yaml
- path: access-collector.yaml
- path: idp-actions-bootstrap.yaml
# События Zitadel отложены (нет PAT); включать вместе с idp-actions-bootstrap в base/kustomization.yaml.
# - path: idp-actions-bootstrap.yaml
# Селектор ingress-шлюза (HelmRelease istio-system/ingressgateway): replace, а не merge —
# merge-patch CRD оставил бы и заглушку security-audit/gateway.
- target:
@ -30,3 +31,28 @@ patches:
- op: replace
path: /spec/ingress/0/from/0/podSelector/matchLabels
value: {istio: ingressgateway}
# Контур-специфика audit-processor (Kafka → MinIO/Parquet).
- target:
kind: Deployment
name: audit-processor
patch: |-
- op: add
path: /spec/template/spec/containers/0/env
value:
- name: K8S_AUDIT_CONTOUR
value: uralkal
# MinIO контура — внешний, без TLS: strict-валидация (app.env ∉ dev/local/stand)
# не пройдёт по minio.secure. Послабления стенда при этом используются только здесь:
# Kafka по-прежнему TLS+SASL, start_from earliest.
- name: K8S_AUDIT_APP_ENV
value: stand
# Отладочное эхо записанных в S3 событий в stdout. Только на время запуска (п.20):
# после проверки потока выключить (false) и убрать комментарий.
- name: K8S_AUDIT_LOG_S3_ECHO
value: "true"
# Service чарта kafka-contour; тот же адрес у коллекторов и приложений.
- name: K8S_AUDIT_KAFKA_BROKERS
value: kafka-kafka-contour.kafka.svc.cluster.local:9092
# Внешний MinIO (ServiceEntry minio.uralkal.external в istio-config).
- name: K8S_AUDIT_MINIO_ENDPOINT
value: 10.133.0.245:9000