Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad7050ca7d | ||
|
|
5525cc33ff | ||
| e4e5e06aec | |||
| 9f2c6932d7 | |||
|
|
cd94931c76 | ||
|
|
104bde49c4 | ||
|
|
b61571a858 | ||
| 13b9ca8a9f | |||
|
|
31bdc74c80 | ||
|
|
9f4801af68 |
38
CLAUDE.md
38
CLAUDE.md
@ -25,11 +25,13 @@
|
|||||||
|
|
||||||
| Путь | Что |
|
| Путь | Что |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `clusters/` | 10 точек входа Flux — **источник истины «что где раскатано»** |
|
| `clusters/` | 17 точек входа Flux + шаблон `contour` — **источник истины «что где раскатано»** |
|
||||||
| `infrastructure/` | 36 платформенных компонентов |
|
| `infrastructure/` | 44 платформенных компонента |
|
||||||
| `apps/` | 37 прикладных сервисов |
|
| `apps/` | 39 прикладных сервисов |
|
||||||
| `docs/apps/` | 35 mermaid-диаграмм по сервисам + `README.md` с доменной группировкой |
|
| `docs/apps/` | 34 mermaid-диаграммы по сервисам + `README.md` с доменной группировкой |
|
||||||
|
| `docs/architecture/` | модель контура в ArchiMate + скрипты-сканеры (`scan_calls.py`, `scan_contour.py`) и сборка (`build_archimate.py`); реальные значения инсталляций сюда не кладутся, только `*.example.json` |
|
||||||
| `docs/closed-contour-deployment.md` | ранбук поднятия закрытого контура |
|
| `docs/closed-contour-deployment.md` | ранбук поднятия закрытого контура |
|
||||||
|
| `ci/`, `.gitlab-ci.yml`, `Dockerfile` | на тег `vX.Y.Z`: образ офлайн-зеркала `iac-offline` и публикация «слайсов» контуров (см. ниже) |
|
||||||
| `README.md` | mermaid-мегакарта платформы, структура репозитория, инструкции по добавлению app / infra / кластера |
|
| `README.md` | mermaid-мегакарта платформы, структура репозитория, инструкции по добавлению app / infra / кластера |
|
||||||
| `IAC-CATALOG.md` | каталог всего `infra/*`; §5 — про этот репозиторий |
|
| `IAC-CATALOG.md` | каталог всего `infra/*`; §5 — про этот репозиторий |
|
||||||
| `inventory.yaml` | сгенерированный снимок прода: 59 namespace → kind → имена |
|
| `inventory.yaml` | сгенерированный снимок прода: 59 namespace → kind → имена |
|
||||||
@ -38,15 +40,18 @@
|
|||||||
|
|
||||||
**Кластер.** `clusters/<cluster>/kustomization.yaml` — плоский список `../../apps/<app>/<cluster>`. Инфраструктура подключается двумя разными способами:
|
**Кластер.** `clusters/<cluster>/kustomization.yaml` — плоский список `../../apps/<app>/<cluster>`. Инфраструктура подключается двумя разными способами:
|
||||||
|
|
||||||
- `d8-ugmk-prod` — прямо в корневом kustomization как `../../infrastructure/<comp>/d8-ugmk-prod`;
|
- `d8-ugmk-prod`, `sarex-contour`, `ugok`, `uralkal`, `vad` — прямо в корневом kustomization как `../../infrastructure/<comp>/<c>`;
|
||||||
- `brusnika-prod`, `brusnika-stage` — через `clusters/<c>/infrastructure/kustomization.yaml`, который ссылается на оверлеи `../../../infrastructure/<comp>/<c>` (`base` + патч HelmRelease + сопутствующие манифесты компонента);
|
- `brusnika-prod`, `brusnika-stage`, `vk-infra`, `vk-prod` — через `clusters/<c>/infrastructure/kustomization.yaml`, который ссылается на оверлеи `../../../infrastructure/<comp>/<c>` (`base` + патч HelmRelease + сопутствующие манифесты компонента);
|
||||||
- `wb` — через `clusters/wb/infrastructure/kustomization.yaml`, который ссылается на `../../../infrastructure/<comp>` (резолвится в `base`), а различия лежат в `clusters/wb/infrastructure/patches/*.yaml`.
|
- `wb`, `yc-cps-prod`, `yc-infra-prod`, `yc-k8s-test-02` — через `clusters/<c>/infrastructure/kustomization.yaml`, который ссылается на `../../../infrastructure/<comp>` (резолвится в `base`), а различия лежат в `clusters/<c>/infrastructure/patches/*.yaml`;
|
||||||
|
- `stand` — послойно: `layers.yaml` объявляет Flux-`Kustomization` `00-vault → 10-mesh → 20-data → 30-platform → 40-routing` (каталоги `clusters/stand/<NN>-<layer>/`). Слои ссылаются на оверлеи `infrastructure/<comp>/contour-template`, а значения контура (`${STORAGE_CLASS}`, `${HOST_*}`, `${GATEWAY_REPLICAS}`) Flux подставляет через `postBuild.substituteFrom` из ConfigMap `contour-vars`.
|
||||||
|
|
||||||
Кластеры: `brusnika-prod`, `brusnika-stage`, `d8-ugmk-prod`, `wb`, `yc-cps-prod`, `yc-ecp`, `yc-infra-prod`, `yc-k8s-test`, `yc-k8s-test-02`, `contour`.
|
Кластеры с приложениями: `asterus`, `brusnika-prod`, `brusnika-stage`, `d8-ugmk-prod`, `sarex-contour`, `ugok`, `uralkal`, `vad`, `wb`, `yc-ecp`, `yc-k8s-test`. Только инфраструктура: `stand`, `vk-infra`, `vk-prod`, `yc-cps-prod`, `yc-infra-prod`, `yc-k8s-test-02`. Шаблон: `contour`.
|
||||||
|
|
||||||
**Приложение.** `apps/<app>/base/` — по одному `.yaml` на процесс (`backend.yaml`, `celery.yaml`, `frontend.yaml`) плюс `namespace.yaml`; оверлеи в `apps/<app>/<cluster>/`. Namespace = имя приложения. Рядом с манифестами лежит документация: `CONFIGURATION.md` (все env-переменные и откуда берутся), `ENDPOINTS.md` (исходящие HTTP-вызовы), `openapi.yaml` (входящий контракт), `.env.example`. Если процессов несколько — файлы с префиксом процесса: `api.ENDPOINTS.md`, `pdm.CONFIGURATION.md`, `frontend.CONFIGURATION.md`.
|
**Приложение.** `apps/<app>/base/` — по одному `.yaml` на процесс (`backend.yaml`, `celery.yaml`, `frontend.yaml`) плюс `namespace.yaml`; оверлеи в `apps/<app>/<cluster>/`. Namespace = имя приложения. Рядом с манифестами лежит документация: `CONFIGURATION.md` (все env-переменные и откуда берутся), `ENDPOINTS.md` (исходящие HTTP-вызовы), `openapi.yaml` (входящий контракт), `.env.example`. Если процессов несколько — файлы с префиксом процесса: `api.ENDPOINTS.md`, `pdm.CONFIGURATION.md`, `frontend.CONFIGURATION.md`.
|
||||||
|
|
||||||
**Инфра-компонент.** `infrastructure/<comp>/base/` + оверлеи `<comp>/<cluster>/`. Корневой `infrastructure/<comp>/kustomization.yaml` всегда указывает просто на `base`. Чарты идут с суффиксом контура: `vault-contour`, `keycloak-contour`, `postgresql-contour` и — внимание — `idp-contour` это Zitadel.
|
**Инфра-компонент.** `infrastructure/<comp>/base/` + оверлеи `<comp>/<cluster>/`. Корневой `infrastructure/<comp>/kustomization.yaml` всегда указывает просто на `base`. Оверлей `contour-template` (есть у vault, istio-*, cert-manager, postgresql, kafka, rabbitmq, zitadel, camunda, istio-config) — параметризованный `${VAR}`, а не привязанный к конкретному кластеру. Чарты идут с суффиксом контура: `vault-contour`, `keycloak-contour`, `postgresql-contour` и — внимание — `idp-contour` это Zitadel.
|
||||||
|
|
||||||
|
**Слайсы.** На тег `vX.Y.Z` `ci/publish-slice.py generate` создаёт child-pipeline с отдельной джобой на каждый `clusters/*/kustomization.yaml`. Джоба вызывает `ci/build-slice.py`: тот обходит дерево Kustomize от `clusters/<c>` и упаковывает только нужные файлы в tar. Результат публикуется как OCI-артефакт `cr.yandex/crpct2b2lsmao4nm0cjk/<c>-iac:<tag>` (media type `application/vnd.sarex.slice.config.v1+json`). Так закрытый контур получает только свой срез. Тесты — `ci/tests/test_build_slice.py`.
|
||||||
|
|
||||||
## Где искать конкретное
|
## Где искать конкретное
|
||||||
|
|
||||||
@ -62,18 +67,23 @@
|
|||||||
| Тег образа в контуре | `apps/<app>/<cluster>/*.yaml`, поле `image.tag` |
|
| Тег образа в контуре | `apps/<app>/<cluster>/*.yaml`, поле `image.tag` |
|
||||||
| Что реально в проде по namespace | `inventory.yaml` |
|
| Что реально в проде по namespace | `inventory.yaml` |
|
||||||
| Где лежит исходный код приложения | `IAC-CATALOG.md` §5.3.8 |
|
| Где лежит исходный код приложения | `IAC-CATALOG.md` §5.3.8 |
|
||||||
|
| Что попадёт в слайс контура | `python3 ci/build-slice.py` по `clusters/<c>` (логика сбора — там же) |
|
||||||
|
| Переменные шаблонного контура | `${...}` в `infrastructure/*/contour-template`; значения — ConfigMap `contour-vars` в кластере, не в репозитории |
|
||||||
|
|
||||||
## Ловушки
|
## Ловушки
|
||||||
|
|
||||||
- **`dsinv/`** — оверлей есть у 25 приложений, но `clusters/dsinv/` не существует. Это материализованный снимок живого контура WB, а не источник деплоя. Развёрнутым не считать.
|
- **`dsinv/`** — оверлей есть у 25 приложений, но `clusters/dsinv/` не существует. Это материализованный снимок живого контура WB, а не источник деплоя. Развёрнутым не считать.
|
||||||
- **Две несовместимые конвенции оверлеев** (`IAC-CATALOG.md` §5.3.4). `d8-ugmk-prod`, `yc-k8s-test`, `dsinv` наследуют `base` и патчат его. `brusnika-prod`, `brusnika-stage`, `yc-ecp` — полные копии HelmRelease, которые молча дрейфуют от base. Правка `base` на них не влияет.
|
- **Две несовместимые конвенции оверлеев** (`IAC-CATALOG.md` §5.3.4). `d8-ugmk-prod`, `yc-k8s-test`, `vad`, `uralkal`, `sarex-contour`, `dsinv` наследуют `base` и патчат его. `brusnika-prod`, `brusnika-stage`, `yc-ecp`, `asterus` — полные копии HelmRelease, которые молча дрейфуют от base. Правка `base` на них не влияет. **`wb` (4 из 27) и `ugok` (9 из 33) смешанные** — проверяйте `resources:` конкретного оверлея; в `ugok` причина обычно указана комментарием в его `kustomization.yaml`.
|
||||||
|
- **`asterus` подключён почти пустым**: оверлеи есть у 26 приложений, но в `clusters/asterus/kustomization.yaml` активен только `auth-flow`, остальные закомментированы. Инфраструктуры в кластере нет.
|
||||||
|
- **Слайс публикуется для каждого `clusters/*/kustomization.yaml`** — в том числе для тестовых и инфраструктурных кластеров. Новая папка в `clusters/` с этим файлом автоматически станет слайсом на следующем теге. У `contour` такого файла нет, поэтому для него слайс не собирается.
|
||||||
- **`IAC-CATALOG.md` — снимок на 05.08.2026** и по составу приложений на контур уже расходится с реальностью (там у `wb` ноль приложений, фактически 26 оверлеев). Всегда сверяться с `clusters/*/kustomization.yaml`.
|
- **`IAC-CATALOG.md` — снимок на 05.08.2026** и по составу приложений на контур уже расходится с реальностью (там у `wb` ноль приложений, фактически 26 оверлеев). Всегда сверяться с `clusters/*/kustomization.yaml`.
|
||||||
- **Мегадиаграмма в `README.md` идеализирована** — рисована руками, показывает все приложения на одной Postgres и все фронтенды за `control-interface`. Проверяемые источники — env-переменные и istio-config.
|
- **Мегадиаграмма в `README.md` идеализирована** — рисована руками, показывает все приложения на одной Postgres и все фронтенды за `control-interface`. Проверяемые источники — env-переменные и istio-config.
|
||||||
- **`clusters/contour/` — не кластер, а шаблон**: в нём нет `flux-system`, только `apps.yaml`, `infrastructure.yaml`, `helm-repositories.yaml`.
|
- **`clusters/contour/` — не кластер, а шаблон**: в нём нет `flux-system`, только `apps.yaml`, `infrastructure.yaml`, `helm-repositories.yaml`.
|
||||||
- **Path-роутинг виден в репозитории только у `d8-ugmk-prod` и `yc-ecp`.** В Brusnika и WB весь прикладной трафик уходит одним правилом в `nginx-service.global-ingress` / `yet-another-nginx-service.global-ingress`, а разводка по путям происходит вне репозитория. Через Istio там публикуются только платформенные UI (Gitea, Grafana, OpenObserve, Superset, Vault, Zitadel, Camunda, MinIO).
|
- **Path-роутинг лежит в `infrastructure/istio-config/<c>/` у большинства контуров, но не у WB.** В `clusters/wb/infrastructure/patches/istio-config.yaml` через Istio публикуются только платформенные UI (Gitea, Grafana, OpenObserve, Superset, Vault, GoAlert), а прикладной трафик разводится вне репозитория. В Brusnika схема смешанная: часть путей идёт напрямую в сервисы, остальное — одним правилом в `yet-another-nginx-service.global-ingress`.
|
||||||
- **Имена namespace расходятся между источниками**: `inventory.yaml` использует суффикс (`flows-prod`), `apps/` — голое имя (`flows`).
|
- **`vk-prod` маршрутизирует в namespace с суффиксом `-prod`** (`eav-prod`, `pm-prod`, `inspections-prod`), а приложений из `apps/` в этом кластере нет: сервисы раскатываются не этим репозиторием.
|
||||||
- **17 оверлеев приложений не подключены ни к одному кластеру** — мёртвый код.
|
- **Имена namespace расходятся между источниками**: `inventory.yaml` и `vk-prod` используют суффикс (`flows-prod`), `apps/` — голое имя (`flows`).
|
||||||
- **Нет диаграмм** в `docs/apps/` для `iam`, `auth-flow`, `ams-sync`.
|
- **66 оверлеев приложений не подключены ни к одному кластеру**: 25 — `dsinv`, 25 — закомментированные в `asterus`, остальные 16 — мёртвый код (в основном `brusnika-prod`, плюс `bi`/`iam` в `wb` и `yc-k8s-test`).
|
||||||
|
- **Нет диаграмм** в `docs/apps/` для `ams-sync`, `auth-flow`, `bi`, `iam`, `premises`.
|
||||||
- **Чистые фронтенды без бэкенда в этом репозитории**: `auth-flow`, `control-interface`, `cross-section`, `document-link`, `prescriptions`, `projects`, `remarks`, `reviews`, `stamp-verification`. Бэкенд `projects` живёт в `planning/projects-backend`.
|
- **Чистые фронтенды без бэкенда в этом репозитории**: `auth-flow`, `control-interface`, `cross-section`, `document-link`, `prescriptions`, `projects`, `remarks`, `reviews`, `stamp-verification`. Бэкенд `projects` живёт в `planning/projects-backend`.
|
||||||
- Самые центральные сервисы по числу входящих ссылок: `documentations` (~85), `processing` / `workflow` (~76), `django` (~53), `eav` (~47), `resources` (~44), `bim` (~39), `flows` (~38). Менять их конфигурацию — дороже всего.
|
- Самые центральные сервисы по числу входящих ссылок: `documentations` (~85), `processing` / `workflow` (~76), `django` (~53), `eav` (~47), `resources` (~44), `bim` (~39), `flows` (~38). Менять их конфигурацию — дороже всего.
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,9 @@ spec:
|
|||||||
values:
|
values:
|
||||||
services:
|
services:
|
||||||
backend:
|
backend:
|
||||||
|
deployment:
|
||||||
|
replicaCount:
|
||||||
|
_default: 2
|
||||||
envs:
|
envs:
|
||||||
- name: ALLOWED_HOSTS
|
- name: ALLOWED_HOSTS
|
||||||
value:
|
value:
|
||||||
|
|||||||
@ -18,7 +18,7 @@ data:
|
|||||||
|
|
||||||
# DEBUG SETTINGS START
|
# DEBUG SETTINGS START
|
||||||
# ---------------------------------------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
DEBUG = True
|
DEBUG = False
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
# ---------------------------------------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
# DEBUG SETTINGS END
|
# DEBUG SETTINGS END
|
||||||
|
|||||||
@ -9,6 +9,8 @@ spec:
|
|||||||
services:
|
services:
|
||||||
backend:
|
backend:
|
||||||
deployment:
|
deployment:
|
||||||
|
replicaCount:
|
||||||
|
_default: 2
|
||||||
args:
|
args:
|
||||||
_default:
|
_default:
|
||||||
- |
|
- |
|
||||||
|
|||||||
@ -7,6 +7,8 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
type: oci
|
type: oci
|
||||||
interval: 10m0s
|
interval: 10m0s
|
||||||
url: oci://cr.yandex/crp3ccidau046kdj8g9q/charts
|
url: ${CHART_REPO:=oci://cr.yandex/crp3ccidau046kdj8g9q/charts}
|
||||||
secretRef:
|
secretRef:
|
||||||
name: yc-cr-auth
|
name: ${CHART_REPO_SECRET:=yc-cr-auth}
|
||||||
|
certSecretRef:
|
||||||
|
name: chart-repo-ca
|
||||||
@ -1,4 +1,5 @@
|
|||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
resources:
|
resources:
|
||||||
|
- ./helm-repositories.yaml
|
||||||
- ../../../infrastructure/vault/contour-template
|
- ../../../infrastructure/vault/contour-template
|
||||||
|
|||||||
@ -2,5 +2,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
|||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
resources:
|
resources:
|
||||||
- ./flux-system
|
- ./flux-system
|
||||||
- ./helm-repositories.yaml
|
|
||||||
- ./layers.yaml
|
- ./layers.yaml
|
||||||
|
|||||||
@ -61,7 +61,7 @@ metadata:
|
|||||||
namespace: flux-system
|
namespace: flux-system
|
||||||
spec:
|
spec:
|
||||||
interval: 10m0s
|
interval: 10m0s
|
||||||
timeout: 20m0s
|
timeout: 35m0s
|
||||||
path: ./clusters/stand/30-platform
|
path: ./clusters/stand/30-platform
|
||||||
prune: true
|
prune: true
|
||||||
wait: true
|
wait: true
|
||||||
|
|||||||
@ -6,7 +6,9 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 15m
|
timeout: 30m
|
||||||
|
waitStrategy:
|
||||||
|
name: legacy
|
||||||
postRenderers:
|
postRenderers:
|
||||||
- kustomize:
|
- kustomize:
|
||||||
patches:
|
patches:
|
||||||
|
|||||||
153
infrastructure/security-audit/README.md
Normal file
153
infrastructure/security-audit/README.md
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
# 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`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n kafka exec -it kafka-kafka-contour-controller-0 -c kafka -- bash
|
||||||
|
```
|
||||||
|
|
||||||
|
```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`:
|
||||||
|
|
||||||
|
```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.` (контекст выводится автоматически).
|
||||||
242
infrastructure/security-audit/base/helmrelease-collector.yaml
Normal file
242
infrastructure/security-audit/base/helmrelease-collector.yaml
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: audit-collector
|
||||||
|
namespace: security-audit
|
||||||
|
spec:
|
||||||
|
interval: 10m
|
||||||
|
timeout: 10m
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: opentelemetry-collector-prod
|
||||||
|
version: "0.117.1"
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: yc-oci-charts
|
||||||
|
namespace: flux-system
|
||||||
|
interval: 10m
|
||||||
|
install:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
upgrade:
|
||||||
|
remediation:
|
||||||
|
retries: 3
|
||||||
|
values:
|
||||||
|
mode: daemonset
|
||||||
|
fullnameOverride: audit-collector
|
||||||
|
|
||||||
|
# Дефолт чарта 0.117.1 (appVersion 0.120.0), задан явно: contrib-сборка с filelog, transform,
|
||||||
|
# kafka exporter, file_storage, health_check, memory_limiter. Зеркало в registry контура — см. README.
|
||||||
|
image:
|
||||||
|
repository: cr.yandex/crp3ccidau046kdj8g9q/opentelemetry-collector/opentelemetry-collector-contrib
|
||||||
|
tag: "0.121.0-amd64"
|
||||||
|
command:
|
||||||
|
name: otelcol-contrib
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: regcred
|
||||||
|
|
||||||
|
# Только мастера: журнал аудита есть только там.
|
||||||
|
nodeSelector:
|
||||||
|
node-role.kubernetes.io/control-plane: ""
|
||||||
|
tolerations:
|
||||||
|
- key: node-role.kubernetes.io/control-plane
|
||||||
|
operator: Exists
|
||||||
|
effect: NoSchedule
|
||||||
|
rollout:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
|
||||||
|
# Доступ к Kubernetes API коллектору не нужен.
|
||||||
|
clusterRole:
|
||||||
|
create: false
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
name: audit-collector # = роль Vault security-audit, bound SA
|
||||||
|
presets:
|
||||||
|
logsCollection: {enabled: false}
|
||||||
|
hostMetrics: {enabled: false}
|
||||||
|
kubernetesAttributes: {enabled: false}
|
||||||
|
kubeletMetrics: {enabled: false}
|
||||||
|
kubernetesEvents: {enabled: false}
|
||||||
|
clusterMetrics: {enabled: false}
|
||||||
|
|
||||||
|
# В daemonset-режиме чарт вешает hostPort на OTLP/Jaeger/Zipkin: приёмники не нужны,
|
||||||
|
# а hostPort конфликтует с другими DaemonSet-коллекторами на тех же узлах.
|
||||||
|
ports:
|
||||||
|
otlp: {enabled: false}
|
||||||
|
otlp-http: {enabled: false}
|
||||||
|
jaeger-compact: {enabled: false}
|
||||||
|
jaeger-thrift: {enabled: false}
|
||||||
|
jaeger-grpc: {enabled: false}
|
||||||
|
zipkin: {enabled: false}
|
||||||
|
metrics: {enabled: false}
|
||||||
|
service:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Журнал аудита — 0600 root:root. Root нужен как владелец файла, capabilities не нужны.
|
||||||
|
podSecurityContext:
|
||||||
|
runAsUser: 0
|
||||||
|
runAsGroup: 0
|
||||||
|
seccompProfile: {type: RuntimeDefault}
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 0
|
||||||
|
runAsNonRoot: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
privileged: false
|
||||||
|
capabilities:
|
||||||
|
drop: [ALL]
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 50m, memory: 128Mi}
|
||||||
|
limits: {cpu: 500m, memory: 512Mi}
|
||||||
|
|
||||||
|
extraVolumes:
|
||||||
|
- name: audit-log
|
||||||
|
hostPath: {path: /var/log/audit, type: DirectoryOrCreate}
|
||||||
|
- name: otelcol-storage
|
||||||
|
hostPath: {path: /var/lib/otelcol-audit, type: DirectoryOrCreate}
|
||||||
|
extraVolumeMounts:
|
||||||
|
- {name: audit-log, mountPath: /var/log/audit, readOnly: true}
|
||||||
|
- {name: otelcol-storage, mountPath: /var/lib/otelcol-audit}
|
||||||
|
|
||||||
|
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.
|
||||||
|
# Полный конфиг вместо мержа с дефолтами чарта.
|
||||||
|
alternateConfig:
|
||||||
|
extensions:
|
||||||
|
health_check:
|
||||||
|
endpoint: ${env:MY_POD_IP}:13133
|
||||||
|
file_storage/audit:
|
||||||
|
directory: /var/lib/otelcol-audit
|
||||||
|
compaction:
|
||||||
|
on_start: true
|
||||||
|
directory: /var/lib/otelcol-audit
|
||||||
|
|
||||||
|
receivers:
|
||||||
|
filelog/audit:
|
||||||
|
include:
|
||||||
|
- /var/log/audit/kube-apiserver-audit*.log # текущий и ротированные (lumberjack)
|
||||||
|
start_at: beginning
|
||||||
|
storage: file_storage/audit # позиции чтения переживают рестарт
|
||||||
|
max_log_size: 8MiB # дефолт 1MiB режет RequestResponse
|
||||||
|
poll_interval: 1s
|
||||||
|
include_file_name: false
|
||||||
|
operators:
|
||||||
|
- type: json_parser
|
||||||
|
parse_to: body
|
||||||
|
|
||||||
|
processors:
|
||||||
|
memory_limiter:
|
||||||
|
check_interval: 1s
|
||||||
|
limit_mib: 400
|
||||||
|
spike_limit_mib: 100
|
||||||
|
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
|
||||||
|
# --- маскирование (п.23): значения, а не сама команда exec ---
|
||||||
|
- replace_pattern(body["requestURI"], "(?i)(password|passwd|pwd|token|secret|api[_-]?key)(=|%3D)[^&]*", "$$1$$2***")
|
||||||
|
# --- обогащение ---
|
||||||
|
- set(body["sarex_contour"], "${env:CONTOUR}")
|
||||||
|
- set(body["sarex_dry_run"], IsMatch(body["requestURI"], "[?&]dryRun=All"))
|
||||||
|
# --- действие ---
|
||||||
|
- set(body["sarex_action"], "read") where body["verb"] == "get" or body["verb"] == "list"
|
||||||
|
- set(body["sarex_action"], "mutate") where body["verb"] == "create" or body["verb"] == "update" or body["verb"] == "patch" or body["verb"] == "delete" or body["verb"] == "deletecollection"
|
||||||
|
- set(body["sarex_action"], "status") where body["objectRef"]["subresource"] == "status"
|
||||||
|
- set(body["sarex_action"], "interactive") where IsMatch(body["objectRef"]["subresource"], "^(exec|attach|portforward)$")
|
||||||
|
# --- исход ---
|
||||||
|
- set(body["sarex_outcome"], "applied") where body["responseStatus"]["code"] >= 200 and body["responseStatus"]["code"] < 300 and body["sarex_dry_run"] == false
|
||||||
|
- set(body["sarex_outcome"], "dry_run") where body["responseStatus"]["code"] >= 200 and body["responseStatus"]["code"] < 300 and body["sarex_dry_run"] == true
|
||||||
|
- set(body["sarex_outcome"], "denied_authn") where body["responseStatus"]["code"] == 401
|
||||||
|
- set(body["sarex_outcome"], "denied_authz") where body["responseStatus"]["code"] == 403 and body["annotations"]["authorization.k8s.io/decision"] == "forbid"
|
||||||
|
- set(body["sarex_outcome"], "denied_admission") where body["responseStatus"]["code"] >= 400 and body["responseStatus"]["code"] < 500 and body["annotations"]["authorization.k8s.io/decision"] == "allow" and body["responseStatus"]["code"] != 404 and body["responseStatus"]["code"] != 409 and body["responseStatus"]["code"] != 422
|
||||||
|
- set(body["sarex_outcome"], "invalid") where body["responseStatus"]["code"] == 422
|
||||||
|
- set(body["sarex_outcome"], "conflict") where body["responseStatus"]["code"] == 409
|
||||||
|
- set(body["sarex_outcome"], "not_found") where body["responseStatus"]["code"] == 404
|
||||||
|
- set(body["sarex_outcome"], "error") where body["responseStatus"]["code"] >= 500
|
||||||
|
# --- субъект (порядок важен: сначала общее, потом частное) ---
|
||||||
|
- set(body["sarex_actor_type"], "human")
|
||||||
|
- set(body["sarex_actor_type"], "serviceaccount") where IsMatch(body["user"]["username"], "^system:serviceaccount:")
|
||||||
|
- set(body["sarex_actor_type"], "controller") where IsMatch(body["user"]["username"], "^system:serviceaccount:kube-system:") or IsMatch(body["user"]["username"], "^system:(kube-|apiserver)")
|
||||||
|
- set(body["sarex_actor_type"], "node") where IsMatch(body["user"]["username"], "^system:node:")
|
||||||
|
- set(body["sarex_actor_type"], "gitops") where IsMatch(body["user"]["username"], "^system:serviceaccount:flux-system:")
|
||||||
|
batch:
|
||||||
|
send_batch_size: 500
|
||||||
|
send_batch_max_size: 1000
|
||||||
|
timeout: 2s
|
||||||
|
|
||||||
|
exporters:
|
||||||
|
kafka/audit:
|
||||||
|
brokers:
|
||||||
|
- ${env:KAFKA_BROKERS}
|
||||||
|
protocol_version: 2.8.0
|
||||||
|
topic: security.k8s-audit
|
||||||
|
encoding: raw # в сообщение — только body (JSON события), без OTLP-обёртки
|
||||||
|
auth:
|
||||||
|
sasl:
|
||||||
|
mechanism: SCRAM-SHA-512
|
||||||
|
username: ${file:/vault/secrets/kafka-username}
|
||||||
|
password: ${file:/vault/secrets/kafka-password}
|
||||||
|
tls:
|
||||||
|
insecure: false
|
||||||
|
ca_file: /vault/secrets/kafka-ca.crt
|
||||||
|
producer:
|
||||||
|
required_acks: -1
|
||||||
|
compression: zstd
|
||||||
|
max_message_bytes: 5242880
|
||||||
|
sending_queue:
|
||||||
|
enabled: true
|
||||||
|
storage: file_storage/audit # очередь на диске: Kafka недоступна → данные не теряются
|
||||||
|
queue_size: 10000
|
||||||
|
num_consumers: 2
|
||||||
|
retry_on_failure:
|
||||||
|
enabled: true
|
||||||
|
initial_interval: 5s
|
||||||
|
max_interval: 60s
|
||||||
|
max_elapsed_time: 0 # повторять бесконечно; при полной очереди — backpressure на filelog
|
||||||
|
|
||||||
|
service:
|
||||||
|
extensions: [health_check, file_storage/audit]
|
||||||
|
pipelines:
|
||||||
|
logs/audit:
|
||||||
|
receivers: [filelog/audit]
|
||||||
|
processors: [memory_limiter, transform/audit, batch]
|
||||||
|
exporters: [kafka/audit]
|
||||||
|
telemetry:
|
||||||
|
logs:
|
||||||
|
level: info
|
||||||
|
metrics:
|
||||||
|
address: ${env:MY_POD_IP}:8888
|
||||||
7
infrastructure/security-audit/base/kustomization.yaml
Normal file
7
infrastructure/security-audit/base/kustomization.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
namespace: security-audit
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- networkpolicy.yaml
|
||||||
|
- helmrelease-collector.yaml
|
||||||
10
infrastructure/security-audit/base/namespace.yaml
Normal file
10
infrastructure/security-audit/base/namespace.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: security-audit
|
||||||
|
labels:
|
||||||
|
# hostPath (/var/log/audit, чекпоинты) запрещён профилем baseline — нужен privileged.
|
||||||
|
pod-security.kubernetes.io/enforce: privileged
|
||||||
|
pod-security.kubernetes.io/warn: baseline
|
||||||
|
pod-security.kubernetes.io/audit: baseline
|
||||||
|
istio-injection: disabled
|
||||||
32
infrastructure/security-audit/base/networkpolicy.yaml
Normal file
32
infrastructure/security-audit/base/networkpolicy.yaml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Коллектору нужны только DNS, Kafka и Vault (агент-инжектор). Входящие — только health-check kubelet'а.
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: audit-collector
|
||||||
|
spec:
|
||||||
|
podSelector: {}
|
||||||
|
policyTypes: [Ingress, Egress]
|
||||||
|
ingress:
|
||||||
|
- ports:
|
||||||
|
- {port: 13133, protocol: TCP} # health_check (liveness/readiness)
|
||||||
|
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; TODO(verify): enable_nodelocaldns в контуре
|
||||||
|
ports:
|
||||||
|
- {port: 53, protocol: UDP}
|
||||||
|
- {port: 53, protocol: TCP}
|
||||||
|
- to:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels: {kubernetes.io/metadata.name: kafka}
|
||||||
|
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)
|
||||||
4
infrastructure/security-audit/kustomization.yaml
Normal file
4
infrastructure/security-audit/kustomization.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- base
|
||||||
18
infrastructure/security-audit/uralkal/audit-collector.yaml
Normal file
18
infrastructure/security-audit/uralkal/audit-collector.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: audit-collector
|
||||||
|
namespace: security-audit
|
||||||
|
spec:
|
||||||
|
dependsOn:
|
||||||
|
- name: kafka
|
||||||
|
namespace: kafka
|
||||||
|
- name: vault
|
||||||
|
namespace: vault
|
||||||
|
values:
|
||||||
|
extraEnvs:
|
||||||
|
- name: CONTOUR
|
||||||
|
value: uralkal
|
||||||
|
# Service bitnami-чарта kafka-contour (релиз kafka); тот же адрес у приложений apps/*/uralkal.
|
||||||
|
- name: KAFKA_BROKERS
|
||||||
|
value: kafka-kafka-contour.kafka.svc.cluster.local:9092
|
||||||
6
infrastructure/security-audit/uralkal/kustomization.yaml
Normal file
6
infrastructure/security-audit/uralkal/kustomization.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- ../base
|
||||||
|
patches:
|
||||||
|
- path: audit-collector.yaml
|
||||||
@ -110,6 +110,17 @@ spec:
|
|||||||
configmapConfig:
|
configmapConfig:
|
||||||
ExternalDomain: ${HOST_LOGIN}
|
ExternalDomain: ${HOST_LOGIN}
|
||||||
ExternalSecure: true
|
ExternalSecure: true
|
||||||
|
# IAM_OWNER service user for sarexctl phase zitadel-setup; the chart stores its key
|
||||||
|
# in secret zitadel/sarex-installer. Created only on the first instance setup.
|
||||||
|
FirstInstance:
|
||||||
|
Org:
|
||||||
|
Machine:
|
||||||
|
Machine:
|
||||||
|
Username: sarex-installer
|
||||||
|
Name: sarexctl
|
||||||
|
MachineKey:
|
||||||
|
ExpirationDate: "2099-01-01T00:00:00Z"
|
||||||
|
Type: 1
|
||||||
debug:
|
debug:
|
||||||
enabled: false
|
enabled: false
|
||||||
postgresqlSecret:
|
postgresqlSecret:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user