diff --git a/infrastructure/security-audit/README.md b/infrastructure/security-audit/README.md index 5535571..2309e7b 100644 --- a/infrastructure/security-audit/README.md +++ b/infrastructure/security-audit/README.md @@ -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=/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/` | оба коллектора, 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 diff --git a/infrastructure/security-audit/base/kustomization.yaml b/infrastructure/security-audit/base/kustomization.yaml index 16a474e..476f75a 100644 --- a/infrastructure/security-audit/base/kustomization.yaml +++ b/infrastructure/security-audit/base/kustomization.yaml @@ -8,6 +8,10 @@ resources: - authorizationpolicy-access-collector.yaml - helmrelease-collector.yaml - helmrelease-access-collector.yaml + - 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. diff --git a/infrastructure/security-audit/base/processor-configmap.yaml b/infrastructure/security-audit/base/processor-configmap.yaml new file mode 100644 index 0000000..59dc8d1 --- /dev/null +++ b/infrastructure/security-audit/base/processor-configmap.yaml @@ -0,0 +1,62 @@ +# Конфиг 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) + + 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 + + # Срок хранения обеспечивает ILM бакета; processor только проверяет правила при старте. + retention: + days: 90 + prefixes: [events/, changes/] + check_on_start: true + + http: + host: 0.0.0.0 + port: 8000 # /healthz, /readyz, /metrics + + stream: + flush_interval: 5m + flush_max_rows: 10000 + flush_timeout: 30s # меньше kafka.rebalance_timeout + max_flush_failures: 30 diff --git a/infrastructure/security-audit/base/processor-deployment.yaml b/infrastructure/security-audit/base/processor-deployment.yaml new file mode 100644 index 0000000..29523a4 --- /dev/null +++ b/infrastructure/security-audit/base/processor-deployment.yaml @@ -0,0 +1,73 @@ +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 образа. + image: cr.yandex/crp3ccidau046kdj8g9q/k8s-audit-processor:394b6f9d + 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} diff --git a/infrastructure/security-audit/base/processor-networkpolicy.yaml b/infrastructure/security-audit/base/processor-networkpolicy.yaml new file mode 100644 index 0000000..03e9cdc --- /dev/null +++ b/infrastructure/security-audit/base/processor-networkpolicy.yaml @@ -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} diff --git a/infrastructure/security-audit/base/processor-serviceaccount.yaml b/infrastructure/security-audit/base/processor-serviceaccount.yaml new file mode 100644 index 0000000..50cc866 --- /dev/null +++ b/infrastructure/security-audit/base/processor-serviceaccount.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: audit-processor + labels: + app.kubernetes.io/name: audit-processor diff --git a/infrastructure/security-audit/uralkal/kustomization.yaml b/infrastructure/security-audit/uralkal/kustomization.yaml index b805ff9..4a3c098 100644 --- a/infrastructure/security-audit/uralkal/kustomization.yaml +++ b/infrastructure/security-audit/uralkal/kustomization.yaml @@ -31,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