Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad7050ca7d | ||
|
|
5525cc33ff | ||
| e4e5e06aec | |||
| 9f2c6932d7 | |||
|
|
cd94931c76 | ||
|
|
104bde49c4 | ||
|
|
b61571a858 | ||
| 13b9ca8a9f | |||
|
|
31bdc74c80 | ||
|
|
9f4801af68 | ||
|
|
63b33aaafb | ||
|
|
fb52d422ca | ||
|
|
deb0d5f0eb | ||
| 1613172dd6 | |||
| b7c36a5348 | |||
| 0037411aae | |||
| c23b51e2a5 | |||
| 448a994fd4 | |||
|
|
bfad13da2f | ||
|
|
f936f5ffb0 | ||
|
|
25b3536124 | ||
|
|
cdc2c34bca | ||
|
|
3b53a99371 | ||
|
|
aa3365cb0d | ||
|
|
7cf8b13f91 | ||
|
|
83bfd4e046 | ||
| 1c3525fc1b | |||
| a3fa7ba4c0 | |||
| 32e4cff59e | |||
| 4a46bb6626 | |||
| 34cbe7c79e | |||
|
|
ae911c7d38 | ||
|
|
bd4b6d4ea6 | ||
|
|
56ade56754 | ||
|
|
8a3540ead7 | ||
|
|
3dadb7a87a | ||
|
|
fc8ddcb511 | ||
| f5a217e793 | |||
| eeb27c6e29 | |||
| 0fb5374e06 | |||
| 0a81938175 | |||
| 84f2555494 | |||
| faa1dd2cac | |||
|
|
f4a19774a2 | ||
|
|
f39a907a87 | ||
| c401cf0dcb | |||
|
|
1d349b1a8c | ||
|
|
f6d4c2face | ||
|
|
6fda7834ce | ||
|
|
0d4befa985 | ||
|
|
9f263a97f3 | ||
| b6f164f85e | |||
| 5e10d54d67 | |||
| f190a6efa5 | |||
| 5bccce5815 | |||
| 0c696d3a3e | |||
|
|
385abf1092 | ||
|
|
3f7628cc54 | ||
| 2182c09031 | |||
|
|
e33eaa1db8 | ||
|
|
cb99195564 | ||
|
|
f5ea728d29 | ||
| f86336741b | |||
| 4448188464 | |||
|
|
af56004006 | ||
| af112cfffe | |||
|
|
03eb83b362 |
@ -4,6 +4,8 @@ include:
|
||||
|
||||
stages:
|
||||
- build
|
||||
- slices
|
||||
- slices-publish
|
||||
|
||||
variables:
|
||||
RELEASE_NAME: iac-offline
|
||||
@ -33,3 +35,31 @@ build_offline_mirror:
|
||||
- docker push ${IMAGE_NAME}
|
||||
- docker push ${CR}/${RELEASE_NAME}:latest
|
||||
timeout: 30m
|
||||
|
||||
generate_slice_jobs:
|
||||
stage: slices
|
||||
image: ${CR}/infra/slice-builder:1.0.0
|
||||
tags:
|
||||
- build
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG =~ /^v?(?:\d+\.){2}\d+$/
|
||||
variables:
|
||||
GIT_DEPTH: "1"
|
||||
script:
|
||||
- python3 ci/publish-slice.py generate --release "$CI_COMMIT_TAG" --commit "$CI_COMMIT_SHA" --out slices-pipeline.yml
|
||||
- cat slices-pipeline.yml
|
||||
artifacts:
|
||||
paths:
|
||||
- slices-pipeline.yml
|
||||
|
||||
publish_contour_slices:
|
||||
stage: slices-publish
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG =~ /^v?(?:\d+\.){2}\d+$/
|
||||
needs:
|
||||
- generate_slice_jobs
|
||||
trigger:
|
||||
include:
|
||||
- artifact: slices-pipeline.yml
|
||||
job: generate_slice_jobs
|
||||
strategy: depend
|
||||
|
||||
38
CLAUDE.md
38
CLAUDE.md
@ -25,11 +25,13 @@
|
||||
|
||||
| Путь | Что |
|
||||
|---|---|
|
||||
| `clusters/` | 10 точек входа Flux — **источник истины «что где раскатано»** |
|
||||
| `infrastructure/` | 36 платформенных компонентов |
|
||||
| `apps/` | 37 прикладных сервисов |
|
||||
| `docs/apps/` | 35 mermaid-диаграмм по сервисам + `README.md` с доменной группировкой |
|
||||
| `clusters/` | 17 точек входа Flux + шаблон `contour` — **источник истины «что где раскатано»** |
|
||||
| `infrastructure/` | 44 платформенных компонента |
|
||||
| `apps/` | 39 прикладных сервисов |
|
||||
| `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` | ранбук поднятия закрытого контура |
|
||||
| `ci/`, `.gitlab-ci.yml`, `Dockerfile` | на тег `vX.Y.Z`: образ офлайн-зеркала `iac-offline` и публикация «слайсов» контуров (см. ниже) |
|
||||
| `README.md` | mermaid-мегакарта платформы, структура репозитория, инструкции по добавлению app / infra / кластера |
|
||||
| `IAC-CATALOG.md` | каталог всего `infra/*`; §5 — про этот репозиторий |
|
||||
| `inventory.yaml` | сгенерированный снимок прода: 59 namespace → kind → имена |
|
||||
@ -38,15 +40,18 @@
|
||||
|
||||
**Кластер.** `clusters/<cluster>/kustomization.yaml` — плоский список `../../apps/<app>/<cluster>`. Инфраструктура подключается двумя разными способами:
|
||||
|
||||
- `d8-ugmk-prod` — прямо в корневом kustomization как `../../infrastructure/<comp>/d8-ugmk-prod`;
|
||||
- `brusnika-prod`, `brusnika-stage` — через `clusters/<c>/infrastructure/kustomization.yaml`, который ссылается на оверлеи `../../../infrastructure/<comp>/<c>` (`base` + патч HelmRelease + сопутствующие манифесты компонента);
|
||||
- `wb` — через `clusters/wb/infrastructure/kustomization.yaml`, который ссылается на `../../../infrastructure/<comp>` (резолвится в `base`), а различия лежат в `clusters/wb/infrastructure/patches/*.yaml`.
|
||||
- `d8-ugmk-prod`, `sarex-contour`, `ugok`, `uralkal`, `vad` — прямо в корневом kustomization как `../../infrastructure/<comp>/<c>`;
|
||||
- `brusnika-prod`, `brusnika-stage`, `vk-infra`, `vk-prod` — через `clusters/<c>/infrastructure/kustomization.yaml`, который ссылается на оверлеи `../../../infrastructure/<comp>/<c>` (`base` + патч HelmRelease + сопутствующие манифесты компонента);
|
||||
- `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`.
|
||||
|
||||
**Инфра-компонент.** `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` |
|
||||
| Что реально в проде по namespace | `inventory.yaml` |
|
||||
| Где лежит исходный код приложения | `IAC-CATALOG.md` §5.3.8 |
|
||||
| Что попадёт в слайс контура | `python3 ci/build-slice.py` по `clusters/<c>` (логика сбора — там же) |
|
||||
| Переменные шаблонного контура | `${...}` в `infrastructure/*/contour-template`; значения — ConfigMap `contour-vars` в кластере, не в репозитории |
|
||||
|
||||
## Ловушки
|
||||
|
||||
- **`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`.
|
||||
- **Мегадиаграмма в `README.md` идеализирована** — рисована руками, показывает все приложения на одной Postgres и все фронтенды за `control-interface`. Проверяемые источники — env-переменные и istio-config.
|
||||
- **`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).
|
||||
- **Имена namespace расходятся между источниками**: `inventory.yaml` использует суффикс (`flows-prod`), `apps/` — голое имя (`flows`).
|
||||
- **17 оверлеев приложений не подключены ни к одному кластеру** — мёртвый код.
|
||||
- **Нет диаграмм** в `docs/apps/` для `iam`, `auth-flow`, `ams-sync`.
|
||||
- **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`.
|
||||
- **`vk-prod` маршрутизирует в namespace с суффиксом `-prod`** (`eav-prod`, `pm-prod`, `inspections-prod`), а приложений из `apps/` в этом кластере нет: сервисы раскатываются не этим репозиторием.
|
||||
- **Имена namespace расходятся между источниками**: `inventory.yaml` и `vk-prod` используют суффикс (`flows-prod`), `apps/` — голое имя (`flows`).
|
||||
- **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`.
|
||||
- Самые центральные сервисы по числу входящих ссылок: `documentations` (~85), `processing` / `workflow` (~76), `django` (~53), `eav` (~47), `resources` (~44), `bim` (~39), `flows` (~38). Менять их конфигурацию — дороже всего.
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: debug
|
||||
image: cr.yandex/crp3ccidau046kdj8g9q/mc-files:dev9
|
||||
image: cr.yandex/crp3ccidau046kdj8g9q/mc-files:dev5
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ["/bin/sh", "-c", "while true; do sleep 3600; done"]
|
||||
imagePullSecrets:
|
||||
|
||||
@ -8,6 +8,9 @@ spec:
|
||||
values:
|
||||
services:
|
||||
backend:
|
||||
deployment:
|
||||
replicaCount:
|
||||
_default: 2
|
||||
envs:
|
||||
- name: ALLOWED_HOSTS
|
||||
value:
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -36,7 +36,7 @@ spec:
|
||||
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings-amqp:prod_3ab263be
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings-amqp:prod_9dea5b64
|
||||
pullPolicy:
|
||||
_default: IfNotPresent
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ spec:
|
||||
enabled: false
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/documentations:prod_179e518c
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/documentations:prod_89c8039a
|
||||
pullPolicy:
|
||||
_default: IfNotPresent
|
||||
service:
|
||||
@ -89,6 +89,9 @@ spec:
|
||||
- name: POSTGRES_POOL_SIZE
|
||||
value:
|
||||
_default: "20"
|
||||
- name: CDE_API_ENABLED
|
||||
value:
|
||||
_default: "false"
|
||||
- name: USE_LEGACY_BIM_FLOW
|
||||
value:
|
||||
_default: "true"
|
||||
@ -236,6 +239,9 @@ spec:
|
||||
- name: VALKEY_PORT
|
||||
value:
|
||||
_default: "6379"
|
||||
- name: CDE_API_ENABLED
|
||||
value:
|
||||
_default: "false"
|
||||
podAnnotations:
|
||||
_default:
|
||||
traffic.sidecar.istio.io/excludeOutboundPorts: "8200"
|
||||
|
||||
@ -97,6 +97,9 @@ spec:
|
||||
- name: PUBLIC_LINK_FOLDER_CONNECTOR_ENABLED
|
||||
value:
|
||||
_default: "true"
|
||||
- name: CDE_API_ENABLED
|
||||
value:
|
||||
_default: "false"
|
||||
- name: USE_ZITADEL
|
||||
value:
|
||||
_default: "1"
|
||||
@ -223,6 +226,9 @@ spec:
|
||||
- name: VALKEY_PORT
|
||||
value:
|
||||
_default: "6379"
|
||||
- name: CDE_API_ENABLED
|
||||
value:
|
||||
_default: "false"
|
||||
podAnnotations:
|
||||
_default:
|
||||
traffic.sidecar.istio.io/excludeOutboundPorts: "8200"
|
||||
|
||||
@ -37,7 +37,7 @@ spec:
|
||||
name:
|
||||
_default: pdf-markings-amqp
|
||||
replicaCount:
|
||||
_default: 1
|
||||
_default: 2
|
||||
port:
|
||||
_default: 8000
|
||||
command:
|
||||
@ -64,7 +64,7 @@ spec:
|
||||
enabled: false
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings-amqp:prod_3ab263be
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings-amqp:prod_9dea5b64
|
||||
pullPolicy:
|
||||
_default: IfNotPresent
|
||||
service:
|
||||
|
||||
@ -156,3 +156,6 @@ spec:
|
||||
- name: VALKEY_PORT
|
||||
value:
|
||||
_default: "6379"
|
||||
- name: CDE_API_ENABLED
|
||||
value:
|
||||
_default: "false"
|
||||
|
||||
@ -144,3 +144,6 @@ spec:
|
||||
- name: VALKEY_PORT
|
||||
value:
|
||||
_default: "6379"
|
||||
- name: CDE_API_ENABLED
|
||||
value:
|
||||
_default: "false"
|
||||
|
||||
@ -8,6 +8,10 @@ spec:
|
||||
values:
|
||||
services:
|
||||
backend:
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings:contour_ce9ed6d7
|
||||
|
||||
envs:
|
||||
- name: MARKS_APP__LOG_LEVEL
|
||||
value:
|
||||
@ -33,8 +37,6 @@ spec:
|
||||
value:
|
||||
_default: "true"
|
||||
|
||||
# Временно: в образе нет CA УГМК для s3.uralmine.com (INFRA-3034).
|
||||
# Вернуть "true" после монтирования CA и AWS_CA_BUNDLE.
|
||||
- name: MARKS_S3__SSL_VERIFY
|
||||
value:
|
||||
_default: "false"
|
||||
|
||||
@ -36,7 +36,7 @@ spec:
|
||||
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/documentations:prod_98a23ef5
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/documentations:prod_0be18f51
|
||||
pullPolicy:
|
||||
_default: IfNotPresent
|
||||
|
||||
@ -134,6 +134,10 @@ spec:
|
||||
- name: POSTGRES_POOL_SIZE
|
||||
value:
|
||||
_default: "20"
|
||||
|
||||
- name: CDE_API_ENABLED
|
||||
value:
|
||||
_default: "false"
|
||||
|
||||
- name: ZITADEL_ACCOUNT
|
||||
value:
|
||||
|
||||
@ -36,7 +36,7 @@ spec:
|
||||
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/documentations-api-files:prod_3f19a21d
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/documentations-api-files:prod_fef3add2
|
||||
pullPolicy:
|
||||
_default: IfNotPresent
|
||||
|
||||
@ -137,6 +137,10 @@ spec:
|
||||
- name: API_ADDRESS
|
||||
value:
|
||||
_default: "0.0.0.0:8080"
|
||||
|
||||
- name: CDE_API_ENABLED
|
||||
value:
|
||||
_default: "false"
|
||||
|
||||
- name: API_ADDRESS_FILE
|
||||
value:
|
||||
|
||||
@ -36,7 +36,7 @@ spec:
|
||||
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings-amqp:prod_3ab263be
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/pdf-markings-amqp:prod_9dea5b64
|
||||
pullPolicy:
|
||||
_default: IfNotPresent
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ data:
|
||||
|
||||
# DEBUG SETTINGS START
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
DEBUG = True
|
||||
DEBUG = False
|
||||
ALLOWED_HOSTS = ['*']
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# DEBUG SETTINGS END
|
||||
|
||||
@ -9,6 +9,8 @@ spec:
|
||||
services:
|
||||
backend:
|
||||
deployment:
|
||||
replicaCount:
|
||||
_default: 2
|
||||
args:
|
||||
_default:
|
||||
- |
|
||||
|
||||
@ -1,33 +1,5 @@
|
||||
---
|
||||
# ВНИМАНИЕ: data["production.py"] — одна строка, kustomize заменяет её ЦЕЛИКОМ,
|
||||
# поэтому здесь продублировано всё содержимое из
|
||||
# apps/issues/base/production-configmap.yaml (та же ловушка, что с envs).
|
||||
#
|
||||
# Зачем нужен этот патч:
|
||||
# production.py делает `from .base import *` (там всё через os.getenv), а затем
|
||||
# переприсваивает часть значений ХАРДКОДОМ — поэтому для этих переменных
|
||||
# ConfigMap ПОБЕЖДАЕТ env из HelmRelease, и правка env в оверлее
|
||||
# backend-s3.yaml/celery-s3.yaml сама по себе ни на что не влияет.
|
||||
#
|
||||
# INFRA-3005 (основная причина зависания экспорта в Excel):
|
||||
# в base хардкодом WORKFLOWS_HOST/WORKFLOWS_URL = workflows-api-service.workflow
|
||||
# — такого сервиса в УГМК нет. celery собирает xlsx, затем
|
||||
# ExportFinishedNotification → issues/mailing.py:122 делает POST на
|
||||
# {WORKFLOWS_HOST}/internal/v1/companies/{id}/workflows и падает с
|
||||
# ConnectionError (Name or service not known) — задача фейлится, фронт не
|
||||
# получает завершения и крутит загрузку бесконечно. Тем же путём с 26.08
|
||||
# падали ВСЕ уведомления (send_notification_on_create/on_update/
|
||||
# to_new_responsible/on_bulk_update, ~1770 ошибок).
|
||||
#
|
||||
# Отличия от base:
|
||||
# - WORKFLOWS_HOST / WORKFLOWS_URL → backend-svc.processing (через os.getenv,
|
||||
# чтобы env из оверлея снова начал работать)
|
||||
# - SAREX_API → https://sarex.uralmine.com (в base зашит https://srx.wb.ru)
|
||||
# - CORS/CSRF origins → https://sarex.uralmine.com (в base только lk.srx.wb.ru)
|
||||
# - убраны хардкоды KAFKA_USERNAME/KAFKA_PASSWORD/DJANGO_TOKEN и чужой
|
||||
# дефолт KAFKA_HOST: в УГМК всё это приходит из Vault
|
||||
# (см. podAnnotations в backend-s3.yaml / celery-s3.yaml / kafka-app.yaml)
|
||||
# - BASE_AERO_URL оставлен внутренним — он server-to-server
|
||||
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
@ -146,9 +118,9 @@ data:
|
||||
|
||||
CORS_ALLOW_ALL_ORIGINS = True
|
||||
ENABLE_MAILGUN=False
|
||||
SMTP_PORT=465
|
||||
SMTP_HOST="mail.rwb.ru"
|
||||
EMAIL_FROM="sarex@rwb.ru"
|
||||
SMTP_PORT=587
|
||||
SMTP_HOST="post.uralmine.com"
|
||||
EMAIL_FROM="sarex@uralmine.com"
|
||||
|
||||
CORS_ALLOW_METHODS = [
|
||||
"DELETE",
|
||||
|
||||
@ -12,7 +12,6 @@ data:
|
||||
|
||||
# DEBUG SETTINGS START
|
||||
# -----------------------------------------------------------------------------
|
||||
DEBUG = True
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
TEST_MODE = False
|
||||
@ -40,7 +39,7 @@ data:
|
||||
|
||||
# DEBUG SETTINGS START
|
||||
# -----------------------------------------------------------------------------
|
||||
DEBUG = True
|
||||
DEBUG = False
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
REVIEW_HOST='http://backend-service.flows.svc.cluster.local:8000'
|
||||
|
||||
@ -147,6 +147,28 @@ spec:
|
||||
value:
|
||||
_default: "/api/v1"
|
||||
|
||||
- name: KAFKA_ENABLE
|
||||
value:
|
||||
_default: "True"
|
||||
|
||||
- name: KAFKA_BOOTSTRAP_SERVERS
|
||||
value:
|
||||
_default: '["wb-prod-kafka-bootstrap.kafka.svc.cluster.local:9093"]'
|
||||
|
||||
- name: KAFKA_SECURITY_PROTOCOL
|
||||
value:
|
||||
_default: "SSL"
|
||||
|
||||
- name: KAFKA_SSL_CAFILE
|
||||
value:
|
||||
_default: "/usr/local/share/ca-certificates/kafka.crt"
|
||||
|
||||
# Обязан совпадать с SETTINGS_TOPICS["planning"] в
|
||||
# apps/message-hub/wb/message-hub.yaml
|
||||
- name: KAFKA_TOPICS
|
||||
value:
|
||||
_default: '{"planning": "message-hub-prod"}'
|
||||
|
||||
commitSha: ""
|
||||
gitlabUri: ""
|
||||
gitlabJobUrl: ""
|
||||
|
||||
@ -141,6 +141,26 @@ spec:
|
||||
value:
|
||||
_default: "/api/v1"
|
||||
|
||||
- name: KAFKA_ENABLE
|
||||
value:
|
||||
_default: "True"
|
||||
|
||||
- name: KAFKA_BOOTSTRAP_SERVERS
|
||||
value:
|
||||
_default: '["wb-prod-kafka-bootstrap.kafka.svc.cluster.local:9093"]'
|
||||
|
||||
- name: KAFKA_SECURITY_PROTOCOL
|
||||
value:
|
||||
_default: "SSL"
|
||||
|
||||
- name: KAFKA_SSL_CAFILE
|
||||
value:
|
||||
_default: "/usr/local/share/ca-certificates/kafka.crt"
|
||||
|
||||
- name: KAFKA_TOPICS
|
||||
value:
|
||||
_default: '{"planning": "message-hub-prod"}'
|
||||
|
||||
commitSha: ""
|
||||
gitlabUri: ""
|
||||
gitlabJobUrl: ""
|
||||
|
||||
@ -142,6 +142,10 @@ spec:
|
||||
value:
|
||||
_default: "0"
|
||||
|
||||
- name: IGNORE_RESOURCES
|
||||
value:
|
||||
_default: "True"
|
||||
|
||||
- name: DJANGO_HOST
|
||||
value:
|
||||
_default: "http://backend.django.svc.cluster.local:8000"
|
||||
|
||||
@ -8,6 +8,9 @@ spec:
|
||||
values:
|
||||
services:
|
||||
backend:
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/workflows-engine:contour_7d2cd329
|
||||
deployment:
|
||||
resources:
|
||||
requests:
|
||||
|
||||
@ -29,7 +29,7 @@ spec:
|
||||
enabled: true
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/workspaces-v2-frontend:contour_a72e3265
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/workspaces-v2-frontend:contour_2da2a00e
|
||||
pullPolicy:
|
||||
_default: IfNotPresent
|
||||
deployment:
|
||||
|
||||
@ -8,6 +8,9 @@ spec:
|
||||
values:
|
||||
services:
|
||||
frontend:
|
||||
image:
|
||||
name:
|
||||
_default: cr.yandex/crp3ccidau046kdj8g9q/workspaces-v2-frontend:contour_1b5d64e4
|
||||
deployment:
|
||||
replicaCount:
|
||||
_default: 1
|
||||
@ -36,7 +36,7 @@ spec:
|
||||
|
||||
image:
|
||||
name:
|
||||
_default: 10.4.10.187:80/library/workspaces-v2-frontend:contour_07373a45
|
||||
_default: 10.4.10.187:80/library/workspaces-v2-frontend:contour_1b5d64e4
|
||||
pullPolicy:
|
||||
_default: IfNotPresent
|
||||
|
||||
|
||||
163
ci/build-slice.py
Normal file
163
ci/build-slice.py
Normal file
@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import io
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
from pathlib import Path, PurePosixPath
|
||||
|
||||
import yaml
|
||||
|
||||
FLUX_KUSTOMIZATION = "kustomize.toolkit.fluxcd.io"
|
||||
KUSTOMIZATION_FILES = ("kustomization.yaml", "kustomization.yml", "Kustomization")
|
||||
|
||||
|
||||
class SliceError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def is_remote(ref: str) -> bool:
|
||||
return "://" in ref or ref.startswith(("git@", "github.com/", "gitlab.com/"))
|
||||
|
||||
|
||||
def kustomization_file(directory: Path) -> Path | None:
|
||||
for name in KUSTOMIZATION_FILES:
|
||||
candidate = directory / name
|
||||
if candidate.is_file():
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def local_refs(doc: dict) -> list[str]:
|
||||
refs = []
|
||||
refs += doc.get("resources") or []
|
||||
refs += doc.get("components") or []
|
||||
refs += doc.get("patchesStrategicMerge") or []
|
||||
refs += [p["path"] for p in doc.get("patches") or [] if isinstance(p, dict) and "path" in p]
|
||||
for key in ("configMapGenerator", "secretGenerator"):
|
||||
for gen in doc.get(key) or []:
|
||||
for entry in (gen.get("files") or []) + (gen.get("envs") or []):
|
||||
refs.append(entry.split("=", 1)[-1])
|
||||
if gen.get("env"):
|
||||
refs.append(gen["env"])
|
||||
return [r for r in refs if isinstance(r, str)]
|
||||
|
||||
|
||||
def flux_paths(path: Path) -> list[str]:
|
||||
try:
|
||||
docs = list(yaml.safe_load_all(path.read_text()))
|
||||
except yaml.YAMLError:
|
||||
return []
|
||||
return [
|
||||
d["spec"]["path"]
|
||||
for d in docs
|
||||
if isinstance(d, dict)
|
||||
and str(d.get("apiVersion", "")).startswith(FLUX_KUSTOMIZATION)
|
||||
and d.get("kind") == "Kustomization"
|
||||
and d.get("spec", {}).get("path")
|
||||
]
|
||||
|
||||
|
||||
def collect(repo: Path, start: str) -> tuple[set[PurePosixPath], list[str]]:
|
||||
repo = repo.resolve()
|
||||
files: set[PurePosixPath] = set()
|
||||
entries: list[str] = []
|
||||
seen_dirs: set[Path] = set()
|
||||
|
||||
def rel(p: Path) -> PurePosixPath:
|
||||
try:
|
||||
return PurePosixPath(p.resolve().relative_to(repo).as_posix())
|
||||
except ValueError:
|
||||
raise SliceError(f"reference outside the repository: {p}")
|
||||
|
||||
def add_file(p: Path):
|
||||
r = rel(p)
|
||||
if r in files:
|
||||
return
|
||||
files.add(r)
|
||||
if p.suffix in (".yaml", ".yml"):
|
||||
for fp in flux_paths(p):
|
||||
visit_dir(repo / fp, entry=True)
|
||||
|
||||
def visit_dir(d: Path, entry: bool = False):
|
||||
d = d.resolve()
|
||||
if d in seen_dirs:
|
||||
return
|
||||
seen_dirs.add(d)
|
||||
kfile = kustomization_file(d)
|
||||
if kfile is None:
|
||||
raise SliceError(f"no kustomization.yaml in {rel(d)}")
|
||||
if entry:
|
||||
entries.append(str(rel(d)))
|
||||
add_file(kfile)
|
||||
doc = yaml.safe_load(kfile.read_text()) or {}
|
||||
for ref in local_refs(doc):
|
||||
if is_remote(ref):
|
||||
raise SliceError(f"remote reference {ref} in {rel(kfile)}")
|
||||
target = (d / ref)
|
||||
if target.is_dir():
|
||||
visit_dir(target)
|
||||
elif target.is_file():
|
||||
add_file(target)
|
||||
else:
|
||||
raise SliceError(f"reference {ref} in {rel(kfile)} does not exist")
|
||||
|
||||
visit_dir(repo / start, entry=True)
|
||||
return files, sorted(set(entries))
|
||||
|
||||
|
||||
def write_tar(repo: Path, files: set[PurePosixPath], out: Path):
|
||||
buf = io.BytesIO()
|
||||
with tarfile.open(fileobj=buf, mode="w", format=tarfile.PAX_FORMAT) as tar:
|
||||
for f in sorted(files):
|
||||
data = (repo / f).read_bytes()
|
||||
info = tarfile.TarInfo(str(f))
|
||||
info.size = len(data)
|
||||
info.mode = 0o644
|
||||
info.mtime = 0
|
||||
info.uid = info.gid = 0
|
||||
info.uname = info.gname = ""
|
||||
tar.addfile(info, io.BytesIO(data))
|
||||
out.write_bytes(buf.getvalue())
|
||||
|
||||
|
||||
def kustomize_build(path: Path) -> bytes:
|
||||
p = subprocess.run(["kubectl", "kustomize", str(path)], capture_output=True)
|
||||
if p.returncode != 0:
|
||||
raise SliceError(f"kustomize build {path} failed: {p.stderr.decode().strip()}")
|
||||
return p.stdout
|
||||
|
||||
|
||||
def verify(repo: Path, out: Path, entries: list[str]):
|
||||
import tempfile
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
with tarfile.open(out) as tar:
|
||||
tar.extractall(tmp, filter="data")
|
||||
for e in entries:
|
||||
if kustomize_build(repo / e) != kustomize_build(Path(tmp) / e):
|
||||
raise SliceError(f"kustomize build of {e} differs between slice and full repository")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("contour")
|
||||
ap.add_argument("--repo", default=".")
|
||||
ap.add_argument("--out", required=True)
|
||||
ap.add_argument("--no-verify", action="store_true")
|
||||
args = ap.parse_args()
|
||||
repo = Path(args.repo).resolve()
|
||||
out = Path(args.out)
|
||||
try:
|
||||
files, entries = collect(repo, f"clusters/{args.contour}")
|
||||
write_tar(repo, files, out)
|
||||
if not args.no_verify:
|
||||
verify(repo, out, entries)
|
||||
except SliceError as e:
|
||||
print(f"slice {args.contour}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
print(f"slice {args.contour}: {len(files)} files, entry points: {', '.join(entries)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
217
ci/publish-slice.py
Normal file
217
ci/publish-slice.py
Normal file
@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import base64
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
spec = importlib.util.spec_from_file_location("build_slice", Path(__file__).with_name("build-slice.py"))
|
||||
bs = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(bs)
|
||||
|
||||
REGISTRY_HOST = "cr.yandex"
|
||||
SLICE_REGISTRY = "crpct2b2lsmao4nm0cjk"
|
||||
CONFIG_TYPE = "application/vnd.sarex.slice.config.v1+json"
|
||||
LAYER_TYPE = "application/vnd.oci.image.layer.v1.tar"
|
||||
MANIFEST_TYPE = "application/vnd.oci.image.manifest.v1+json"
|
||||
JOB_IMAGE = "${CR}/infra/slice-builder:1.0.0"
|
||||
|
||||
|
||||
class PublishError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def digest(data: bytes) -> str:
|
||||
return "sha256:" + hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def list_contours(repo: Path) -> list[str]:
|
||||
return sorted(p.parent.name for p in repo.glob("clusters/*/kustomization.yaml"))
|
||||
|
||||
|
||||
def child_pipeline(contours: list[str], release: str, commit: str) -> str:
|
||||
jobs: dict = {"stages": ["slices"]}
|
||||
for c in contours:
|
||||
jobs[f"slice {c}"] = {
|
||||
"stage": "slices",
|
||||
"image": JOB_IMAGE,
|
||||
"tags": ["build"],
|
||||
"allow_failure": True,
|
||||
"variables": {"GIT_DEPTH": "1"},
|
||||
"script": [
|
||||
"printf '%s' \"$SLICES_PUSHER_KEY\" | base64 -d > /tmp/slices-key.json",
|
||||
f"python3 ci/publish-slice.py publish --contour {c} --release {release} --commit {commit} --key-file /tmp/slices-key.json",
|
||||
],
|
||||
"after_script": ["rm -f /tmp/slices-key.json"],
|
||||
}
|
||||
if not contours:
|
||||
jobs["no contours"] = {"stage": "slices", "image": JOB_IMAGE, "tags": ["build"], "script": ["echo 'no clusters/*/kustomization.yaml found'"]}
|
||||
return yaml.safe_dump(jobs, sort_keys=False, allow_unicode=False)
|
||||
|
||||
|
||||
def build_manifest(layer: bytes, annotations: dict[str, str]) -> tuple[bytes, bytes]:
|
||||
config = b"{}"
|
||||
manifest = {
|
||||
"schemaVersion": 2,
|
||||
"mediaType": MANIFEST_TYPE,
|
||||
"config": {"mediaType": CONFIG_TYPE, "digest": digest(config), "size": len(config)},
|
||||
"layers": [{
|
||||
"mediaType": LAYER_TYPE,
|
||||
"digest": digest(layer),
|
||||
"size": len(layer),
|
||||
"annotations": {"org.opencontainers.image.title": "slice.tar"},
|
||||
}],
|
||||
"annotations": dict(sorted(annotations.items())),
|
||||
}
|
||||
return config, json.dumps(manifest, sort_keys=True, separators=(",", ":")).encode()
|
||||
|
||||
|
||||
class Registry:
|
||||
def __init__(self, username: str, password: str):
|
||||
self.base = f"https://{REGISTRY_HOST}"
|
||||
self.basic = "Basic " + base64.b64encode(f"{username}:{password}".encode()).decode()
|
||||
self.tokens: dict[str, str] = {}
|
||||
|
||||
def _send(self, method, url, data=None, headers=None):
|
||||
req = urllib.request.Request(url, data=data, method=method, headers=headers or {})
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=60) as r:
|
||||
return r.status, dict(r.headers), r.read()
|
||||
except urllib.error.HTTPError as e:
|
||||
return e.code, dict(e.headers), e.read()
|
||||
|
||||
def _token(self, challenge: str, scope: str) -> str:
|
||||
params = dict(re.findall(r'(\w+)="([^"]*)"', challenge))
|
||||
realm = params.pop("realm")
|
||||
params["scope"] = scope
|
||||
status, _, body = self._send("GET", f"{realm}?{urllib.parse.urlencode(params)}", headers={"Authorization": self.basic})
|
||||
if status != 200:
|
||||
raise PublishError(f"registry auth failed: HTTP {status}")
|
||||
payload = json.loads(body)
|
||||
return payload.get("token") or payload.get("access_token")
|
||||
|
||||
def request(self, method, repo, path, data=None, headers=None):
|
||||
scope = f"repository:{repo}:pull,push"
|
||||
url = path if path.startswith("http") else f"{self.base}/v2/{repo}/{path}"
|
||||
headers = dict(headers or {})
|
||||
if scope in self.tokens:
|
||||
headers["Authorization"] = f"Bearer {self.tokens[scope]}"
|
||||
status, h, body = self._send(method, url, data, headers)
|
||||
if status == 401:
|
||||
challenge = {k.lower(): v for k, v in h.items()}.get("www-authenticate", "")
|
||||
self.tokens[scope] = self._token(challenge, scope)
|
||||
headers["Authorization"] = f"Bearer {self.tokens[scope]}"
|
||||
status, h, body = self._send(method, url, data, headers)
|
||||
return status, {k.lower(): v for k, v in h.items()}, body
|
||||
|
||||
def current_layer(self, repo: str) -> str | None:
|
||||
status, _, body = self.request("GET", repo, "manifests/current", headers={"Accept": MANIFEST_TYPE})
|
||||
if status == 404:
|
||||
return None
|
||||
if status != 200:
|
||||
raise PublishError(f"{repo}:current: HTTP {status}")
|
||||
return json.loads(body)["layers"][0]["digest"]
|
||||
|
||||
def put_blob(self, repo: str, data: bytes) -> bool:
|
||||
d = digest(data)
|
||||
if self.request("HEAD", repo, f"blobs/{d}")[0] == 200:
|
||||
return False
|
||||
status, h, _ = self.request("POST", repo, "blobs/uploads/")
|
||||
if status != 202:
|
||||
raise PublishError(f"blob upload to {repo}: HTTP {status}")
|
||||
location = h["location"]
|
||||
if location.startswith("/"):
|
||||
location = self.base + location
|
||||
sep = "&" if "?" in location else "?"
|
||||
status, _, _ = self.request("PUT", repo, f"{location}{sep}digest={d}", data, {"Content-Type": "application/octet-stream"})
|
||||
if status != 201:
|
||||
raise PublishError(f"blob upload to {repo}: HTTP {status}")
|
||||
return True
|
||||
|
||||
def push(self, repo: str, tags: list[str], layer: bytes, annotations: dict[str, str]) -> bool:
|
||||
config, manifest = build_manifest(layer, annotations)
|
||||
self.put_blob(repo, config)
|
||||
uploaded = self.put_blob(repo, layer)
|
||||
for tag in tags:
|
||||
status, _, body = self.request("PUT", repo, f"manifests/{tag}", manifest, {"Content-Type": MANIFEST_TYPE})
|
||||
if status != 201:
|
||||
raise PublishError(f"{repo}:{tag}: HTTP {status} {body[:200]!r}")
|
||||
return uploaded
|
||||
|
||||
|
||||
def log(msg: str):
|
||||
print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True)
|
||||
|
||||
|
||||
def publish(repo: Path, contour: str, release: str, commit: str, key_file: Path) -> int:
|
||||
target = f"{SLICE_REGISTRY}/{contour}-iac"
|
||||
log(f"contour {contour}, source iac@{commit[:8]}, release {release}")
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
out = Path(tmp) / "slice.tar"
|
||||
files, entries = bs.collect(repo, f"clusters/{contour}")
|
||||
log(f"collected {len(files)} files, entry points: {', '.join(entries)}")
|
||||
bs.write_tar(repo, files, out)
|
||||
bs.verify(repo, out, entries)
|
||||
log(f"verified: kustomize build of {len(entries)} entry point(s) identical to full repository")
|
||||
layer = out.read_bytes()
|
||||
new = digest(layer)
|
||||
log(f"slice size {len(layer)} bytes, digest {new}")
|
||||
registry = Registry("json_key", key_file.read_text())
|
||||
current = registry.current_layer(f"{target}")
|
||||
changed = current != new
|
||||
log(f"registry {REGISTRY_HOST}/{target}, current " + (current or "absent") + (", content changed" if changed else ", content unchanged"))
|
||||
tags = [commit[:8], release] + (["current"] if changed else [])
|
||||
uploaded = registry.push(target, tags, layer, {
|
||||
"org.opencontainers.image.source": "iac",
|
||||
"org.opencontainers.image.revision": commit,
|
||||
"org.opencontainers.image.version": release,
|
||||
"org.opencontainers.image.created": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"io.sarex.slice.contour": contour,
|
||||
"io.sarex.slice.kind": "iac",
|
||||
})
|
||||
log(f"layer {'uploaded' if uploaded else 'already in registry'}, tags pushed: {', '.join(tags)}")
|
||||
except (bs.SliceError, PublishError) as e:
|
||||
log(f"FAILED: {e}")
|
||||
return 1
|
||||
log("done")
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
sub = ap.add_subparsers(dest="cmd", required=True)
|
||||
gen = sub.add_parser("generate")
|
||||
gen.add_argument("--repo", default=".")
|
||||
gen.add_argument("--release", required=True)
|
||||
gen.add_argument("--commit", required=True)
|
||||
gen.add_argument("--out", required=True)
|
||||
pub = sub.add_parser("publish")
|
||||
pub.add_argument("--repo", default=".")
|
||||
pub.add_argument("--contour", required=True)
|
||||
pub.add_argument("--release", required=True)
|
||||
pub.add_argument("--commit", required=True)
|
||||
pub.add_argument("--key-file", required=True)
|
||||
args = ap.parse_args()
|
||||
repo = Path(args.repo).resolve()
|
||||
if args.cmd == "generate":
|
||||
contours = list_contours(repo)
|
||||
Path(args.out).write_text(child_pipeline(contours, args.release, args.commit))
|
||||
log(f"{len(contours)} contours: {', '.join(contours)}")
|
||||
return 0
|
||||
return publish(repo, args.contour, args.release, args.commit, Path(args.key_file))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
93
ci/tests/test_build_slice.py
Normal file
93
ci/tests/test_build_slice.py
Normal file
@ -0,0 +1,93 @@
|
||||
import importlib.util
|
||||
import tarfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
spec = importlib.util.spec_from_file_location("build_slice", Path(__file__).parents[1] / "build-slice.py")
|
||||
bs = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(bs)
|
||||
|
||||
|
||||
def put(root: Path, rel: str, text: str):
|
||||
p = root / rel
|
||||
p.parent.mkdir(parents=True, exist_ok=True)
|
||||
p.write_text(text)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def repo(tmp_path):
|
||||
put(tmp_path, "clusters/a/kustomization.yaml", "resources:\n - ./flux-system\n - ./layers.yaml\n")
|
||||
put(tmp_path, "clusters/a/flux-system/kustomization.yaml", "resources:\n - gotk-sync.yaml\n")
|
||||
put(tmp_path, "clusters/a/flux-system/gotk-sync.yaml",
|
||||
"apiVersion: kustomize.toolkit.fluxcd.io/v1\nkind: Kustomization\nspec:\n path: ./clusters/a\n")
|
||||
put(tmp_path, "clusters/a/layers.yaml",
|
||||
"apiVersion: kustomize.toolkit.fluxcd.io/v1\nkind: Kustomization\nspec:\n path: ./layers/a/00-vault\n")
|
||||
put(tmp_path, "layers/a/00-vault/kustomization.yaml", "resources:\n - ../../../infrastructure/vault/contour-template\n")
|
||||
put(tmp_path, "infrastructure/vault/contour-template/kustomization.yaml",
|
||||
"resources:\n - ../base\npatches:\n - path: vault.yaml\n")
|
||||
put(tmp_path, "infrastructure/vault/contour-template/vault.yaml", "kind: HelmRelease\n")
|
||||
put(tmp_path, "infrastructure/vault/base/kustomization.yaml", "resources:\n - helmrelease.yaml\n")
|
||||
put(tmp_path, "infrastructure/vault/base/helmrelease.yaml", "kind: HelmRelease\n")
|
||||
put(tmp_path, "infrastructure/vault/base/unused.yaml", "kind: ConfigMap\n")
|
||||
put(tmp_path, "infrastructure/vault/uralkal/kustomization.yaml", "resources:\n - ../base\n")
|
||||
put(tmp_path, "clusters/b/kustomization.yaml", "resources:\n - ../../infrastructure/vault/uralkal\n")
|
||||
return tmp_path
|
||||
|
||||
|
||||
def test_slice_follows_flux_paths_and_skips_foreign(repo):
|
||||
files, entries = bs.collect(repo, "clusters/a")
|
||||
names = {str(f) for f in files}
|
||||
assert "infrastructure/vault/base/helmrelease.yaml" in names
|
||||
assert "infrastructure/vault/contour-template/vault.yaml" in names
|
||||
assert "layers/a/00-vault/kustomization.yaml" in names
|
||||
assert not any("uralkal" in n or n.startswith("clusters/b") for n in names)
|
||||
assert "infrastructure/vault/base/unused.yaml" not in names
|
||||
assert entries == ["clusters/a", "layers/a/00-vault"]
|
||||
|
||||
|
||||
def test_remote_reference_stops_build(repo):
|
||||
put(repo, "clusters/a/kustomization.yaml", "resources:\n - https://github.com/x/y//z\n")
|
||||
with pytest.raises(bs.SliceError, match="remote reference"):
|
||||
bs.collect(repo, "clusters/a")
|
||||
|
||||
|
||||
def test_dangling_reference_stops_build(repo):
|
||||
put(repo, "clusters/a/kustomization.yaml", "resources:\n - ./missing.yaml\n")
|
||||
with pytest.raises(bs.SliceError, match="does not exist"):
|
||||
bs.collect(repo, "clusters/a")
|
||||
|
||||
|
||||
def test_tar_is_byte_identical_across_runs(repo, tmp_path_factory):
|
||||
files, _ = bs.collect(repo, "clusters/a")
|
||||
out1 = tmp_path_factory.mktemp("o") / "s.tar"
|
||||
out2 = tmp_path_factory.mktemp("o") / "s.tar"
|
||||
bs.write_tar(repo, files, out1)
|
||||
(repo / "clusters/a/layers.yaml").touch()
|
||||
bs.write_tar(repo, files, out2)
|
||||
assert out1.read_bytes() == out2.read_bytes()
|
||||
with tarfile.open(out1) as t:
|
||||
assert all(m.mtime == 0 for m in t.getmembers())
|
||||
|
||||
|
||||
|
||||
pspec = importlib.util.spec_from_file_location("publish_slice", Path(__file__).parents[1] / "publish-slice.py")
|
||||
ps = importlib.util.module_from_spec(pspec)
|
||||
pspec.loader.exec_module(ps)
|
||||
|
||||
|
||||
def test_every_cluster_with_kustomization_is_a_contour(tmp_path):
|
||||
put(tmp_path, "clusters/stand/kustomization.yaml", "resources: []\n")
|
||||
put(tmp_path, "clusters/vad/kustomization.yaml", "resources: []\n")
|
||||
put(tmp_path, "clusters/contour/apps.yaml", "kind: Kustomization\n")
|
||||
assert ps.list_contours(tmp_path) == ["stand", "vad"]
|
||||
|
||||
|
||||
def test_child_pipeline_has_one_job_per_contour():
|
||||
doc = yaml.safe_load(ps.child_pipeline(["stand", "vad"], "3.9.68", "abcdef1234"))
|
||||
jobs = {k: v for k, v in doc.items() if k != "stages"}
|
||||
assert sorted(jobs) == ["slice stand", "slice vad"]
|
||||
assert all(j["allow_failure"] for j in jobs.values())
|
||||
assert "--contour vad --release 3.9.68 --commit abcdef1234" in jobs["slice vad"]["script"][1]
|
||||
assert all(ord(ch) < 128 for ch in ps.child_pipeline(["stand"], "1.0.0", "a" * 40))
|
||||
14
clusters/stand/00-vault/helm-repositories.yaml
Normal file
14
clusters/stand/00-vault/helm-repositories.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: yc-oci-charts
|
||||
namespace: flux-system
|
||||
spec:
|
||||
type: oci
|
||||
interval: 10m0s
|
||||
url: ${CHART_REPO:=oci://cr.yandex/crp3ccidau046kdj8g9q/charts}
|
||||
secretRef:
|
||||
name: ${CHART_REPO_SECRET:=yc-cr-auth}
|
||||
certSecretRef:
|
||||
name: chart-repo-ca
|
||||
5
clusters/stand/00-vault/kustomization.yaml
Normal file
5
clusters/stand/00-vault/kustomization.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ./helm-repositories.yaml
|
||||
- ../../../infrastructure/vault/contour-template
|
||||
7
clusters/stand/10-mesh/kustomization.yaml
Normal file
7
clusters/stand/10-mesh/kustomization.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../../../infrastructure/istio-base/contour-template
|
||||
- ../../../infrastructure/istio-pilot/contour-template
|
||||
- ../../../infrastructure/istio-gateway/contour-template
|
||||
- ../../../infrastructure/cert-manager/contour-template
|
||||
6
clusters/stand/20-data/kustomization.yaml
Normal file
6
clusters/stand/20-data/kustomization.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../../../infrastructure/postgresql/contour-template
|
||||
- ../../../infrastructure/kafka/contour-template
|
||||
- ../../../infrastructure/rabbitmq/contour-template
|
||||
5
clusters/stand/30-platform/kustomization.yaml
Normal file
5
clusters/stand/30-platform/kustomization.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../../../infrastructure/zitadel/contour-template
|
||||
- ../../../infrastructure/camunda/contour-template
|
||||
4
clusters/stand/40-routing/kustomization.yaml
Normal file
4
clusters/stand/40-routing/kustomization.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../../../infrastructure/istio-config/contour-template
|
||||
6440
clusters/stand/flux-system/gotk-components.yaml
Normal file
6440
clusters/stand/flux-system/gotk-components.yaml
Normal file
File diff suppressed because it is too large
Load Diff
25
clusters/stand/flux-system/gotk-sync.yaml
Normal file
25
clusters/stand/flux-system/gotk-sync.yaml
Normal file
@ -0,0 +1,25 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: flux-system
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 1m0s
|
||||
ref:
|
||||
branch: main
|
||||
url: http://gitea.gitea.svc:3000/infra/iac.git
|
||||
secretRef:
|
||||
name: flux-system
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: flux-system
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m0s
|
||||
path: ./clusters/stand
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
13
clusters/stand/flux-system/kustomization.yaml
Normal file
13
clusters/stand/flux-system/kustomization.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- gotk-components.yaml
|
||||
- gotk-sync.yaml
|
||||
patches:
|
||||
- target:
|
||||
kind: Deployment
|
||||
name: kustomize-controller
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/containers/0/args/-
|
||||
value: --feature-gates=CancelHealthCheckOnNewRevision=true
|
||||
5
clusters/stand/kustomization.yaml
Normal file
5
clusters/stand/kustomization.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ./flux-system
|
||||
- ./layers.yaml
|
||||
93
clusters/stand/layers.yaml
Normal file
93
clusters/stand/layers.yaml
Normal file
@ -0,0 +1,93 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: 00-vault
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m0s
|
||||
timeout: 10m0s
|
||||
path: ./clusters/stand/00-vault
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
name: contour-vars
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: 10-mesh
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m0s
|
||||
timeout: 15m0s
|
||||
path: ./clusters/stand/10-mesh
|
||||
prune: true
|
||||
wait: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
name: contour-vars
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: 20-data
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m0s
|
||||
timeout: 20m0s
|
||||
path: ./clusters/stand/20-data
|
||||
prune: true
|
||||
wait: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
name: contour-vars
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: 30-platform
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m0s
|
||||
timeout: 35m0s
|
||||
path: ./clusters/stand/30-platform
|
||||
prune: true
|
||||
wait: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
name: contour-vars
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: 40-routing
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m0s
|
||||
timeout: 10m0s
|
||||
path: ./clusters/stand/40-routing
|
||||
prune: true
|
||||
wait: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
name: contour-vars
|
||||
@ -12,3 +12,4 @@ resources:
|
||||
- ../../../infrastructure/kb/vk-infra
|
||||
- ../../../infrastructure/gitlab-runner/vk-infra
|
||||
- ../../../infrastructure/nexus/vk-infra
|
||||
- ../../../infrastructure/outline/vk-infra
|
||||
|
||||
354
infrastructure/camunda/contour-template/camunda.yaml
Normal file
354
infrastructure/camunda/contour-template/camunda.yaml
Normal file
@ -0,0 +1,354 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: camunda
|
||||
namespace: camunda
|
||||
spec:
|
||||
dependsOn: []
|
||||
interval: 5m
|
||||
timeout: 30m
|
||||
waitStrategy:
|
||||
name: legacy
|
||||
postRenderers:
|
||||
- kustomize:
|
||||
patches:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: batch
|
||||
version: v1
|
||||
kind: Job
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: camunda-connectors
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: camunda-identity
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: camunda-operate
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: camunda-optimize
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: camunda-tasklist
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: camunda-zeebe-gateway
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: camunda-zeebe
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: processing
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
value: processing
|
||||
effect: NoSchedule
|
||||
values:
|
||||
global:
|
||||
vault:
|
||||
enabled: true
|
||||
role: camunda-contour
|
||||
authPath: auth/kubernetes
|
||||
secrets:
|
||||
postgresql:
|
||||
path: secrets/data/camunda/identity-db
|
||||
keys:
|
||||
password: password
|
||||
postgresPassword: password
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
identity:
|
||||
auth:
|
||||
publicIssuerUrl: "https://${HOST_CAMUNDA_KEYCLOAK}/auth/realms/camunda-platform"
|
||||
identity:
|
||||
redirectUrl: "https://${HOST_CAMUNDA_IDENTITY}"
|
||||
operate:
|
||||
redirectUrl: "https://${HOST_CAMUNDA}"
|
||||
tasklist:
|
||||
redirectUrl: "https://${HOST_CAMUNDA_TASKLIST}"
|
||||
optimize:
|
||||
redirectUrl: "https://${HOST_CAMUNDA_OPTIMIZE}"
|
||||
identityPostgresql:
|
||||
enabled: false
|
||||
auth:
|
||||
usePasswordFiles: true
|
||||
primary:
|
||||
automountServiceAccountToken: true
|
||||
persistence:
|
||||
size: 10Gi
|
||||
storageClass: ${STORAGE_CLASS}
|
||||
identityKeycloak:
|
||||
externalDatabase:
|
||||
host: pg-host.storage.svc.cluster.local
|
||||
port: 5432
|
||||
user: bn_keycloak
|
||||
database: bitnami_keycloak
|
||||
password: ""
|
||||
existingSecret: ""
|
||||
existingSecretPasswordKey: password
|
||||
postgresql:
|
||||
enabled: false
|
||||
auth:
|
||||
usePasswordFiles: true
|
||||
primary:
|
||||
automountServiceAccountToken: true
|
||||
persistence:
|
||||
size: 10Gi
|
||||
storageClass: ${STORAGE_CLASS}
|
||||
vaultEnv:
|
||||
enabled: true
|
||||
role: camunda-contour
|
||||
authPath: auth/kubernetes
|
||||
envFiles:
|
||||
KEYCLOAK_ADMIN_PASSWORD:
|
||||
path: secrets/data/camunda/keycloak-admin
|
||||
key: admin-password
|
||||
KEYCLOAK_PASSWORD:
|
||||
path: secrets/data/camunda/keycloak-admin
|
||||
key: admin-password
|
||||
KEYCLOAK_DATABASE_PASSWORD:
|
||||
path: secrets/data/camunda/keycloak-db
|
||||
key: password
|
||||
global:
|
||||
storageClass: ${STORAGE_CLASS}
|
||||
tolerations: []
|
||||
elasticsearch:
|
||||
sysctlImage:
|
||||
registry: cr.yandex
|
||||
repository: crp3ccidau046kdj8g9q/contour/camunda/os-shell
|
||||
tag: 12-debian-12-r32
|
||||
pullSecrets:
|
||||
- regcred
|
||||
master:
|
||||
replicaCount: 1
|
||||
podAntiAffinityPreset: soft
|
||||
persistence:
|
||||
size: 10Gi
|
||||
storageClass: ${STORAGE_CLASS}
|
||||
tolerations: []
|
||||
metrics:
|
||||
enabled: false
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
prometheusRule:
|
||||
enabled: false
|
||||
tolerations: []
|
||||
camundaCanary:
|
||||
enabled: false
|
||||
prometheusServiceMonitor:
|
||||
enabled: false
|
||||
console:
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
tolerations: []
|
||||
zeebe:
|
||||
clusterSize: "1"
|
||||
partitionCount: "1"
|
||||
replicationFactor: "1"
|
||||
pvcStorageClassName: ${STORAGE_CLASS}
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
tolerations: []
|
||||
zeebeGateway:
|
||||
replicas: 1
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
tolerations: []
|
||||
identity:
|
||||
fullURL: "https://${HOST_CAMUNDA_IDENTITY}"
|
||||
externalDatabase:
|
||||
enabled: true
|
||||
host: pg-host.storage.svc.cluster.local
|
||||
port: 5432
|
||||
username: identity
|
||||
database: identity
|
||||
password: ""
|
||||
existingSecret: ""
|
||||
existingSecretPasswordKey: password
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
tolerations: []
|
||||
operate:
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
serviceAccount:
|
||||
automountServiceAccountToken: true
|
||||
tolerations: []
|
||||
tasklist:
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
serviceAccount:
|
||||
automountServiceAccountToken: true
|
||||
tolerations: []
|
||||
optimize:
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
serviceAccount:
|
||||
automountServiceAccountToken: true
|
||||
tolerations: []
|
||||
executionIdentity:
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
tolerations: []
|
||||
webModeler:
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
restapi:
|
||||
tolerations: []
|
||||
webapp:
|
||||
tolerations: []
|
||||
websockets:
|
||||
tolerations: []
|
||||
connectors:
|
||||
image:
|
||||
pullSecrets:
|
||||
- name: regcred
|
||||
serviceAccount:
|
||||
automountServiceAccountToken: true
|
||||
tolerations: []
|
||||
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: camunda.yaml
|
||||
@ -0,0 +1,25 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: cert-manager
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
interval: 5m
|
||||
timeout: 10m
|
||||
values:
|
||||
controller:
|
||||
image:
|
||||
registry: cr.yandex/crp3ccidau046kdj8g9q/cert-manager
|
||||
repository: cert-manager
|
||||
acmesolver:
|
||||
image:
|
||||
registry: cr.yandex/crp3ccidau046kdj8g9q/cert-manager
|
||||
repository: acmesolver
|
||||
webhook:
|
||||
image:
|
||||
registry: cr.yandex/crp3ccidau046kdj8g9q/cert-manager
|
||||
repository: cert-manager-webhook
|
||||
cainjector:
|
||||
image:
|
||||
registry: cr.yandex/crp3ccidau046kdj8g9q/cert-manager
|
||||
repository: cainjector
|
||||
@ -0,0 +1,28 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: cert-manager.yaml
|
||||
- target:
|
||||
group: cert-manager.io
|
||||
version: v1
|
||||
kind: ClusterIssuer
|
||||
name: letsencrypt-issuer
|
||||
patch: |-
|
||||
$patch: delete
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-issuer
|
||||
- target:
|
||||
group: cert-manager.io
|
||||
version: v1
|
||||
kind: ClusterIssuer
|
||||
name: letsencrypt-issuer-istio
|
||||
patch: |-
|
||||
$patch: delete
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-issuer-istio
|
||||
@ -0,0 +1,4 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
117
infrastructure/istio-config/contour-template/istio-config.yaml
Normal file
117
infrastructure/istio-config/contour-template/istio-config.yaml
Normal file
@ -0,0 +1,117 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: istio-config
|
||||
namespace: default
|
||||
spec:
|
||||
dependsOn: []
|
||||
interval: 5m
|
||||
timeout: 10m
|
||||
values:
|
||||
global:
|
||||
env: contour
|
||||
environments:
|
||||
contour:
|
||||
istio:
|
||||
gateways:
|
||||
platform:
|
||||
name: platform-gateway
|
||||
namespace: default
|
||||
selector:
|
||||
istio: ingressgateway
|
||||
servers:
|
||||
- hosts:
|
||||
- ${HOST_LOGIN}
|
||||
- ${HOST_CAMUNDA}
|
||||
- ${HOST_CAMUNDA_IDENTITY}
|
||||
- ${HOST_CAMUNDA_KEYCLOAK}
|
||||
- ${HOST_CAMUNDA_OPTIMIZE}
|
||||
- ${HOST_CAMUNDA_TASKLIST}
|
||||
- ${HOST_RABBITMQ}
|
||||
tls:
|
||||
credentialName: istio-ingress-tls
|
||||
virtualServices:
|
||||
zitadel:
|
||||
name: zitadel-virt-service
|
||||
namespace: default
|
||||
hosts:
|
||||
- ${HOST_LOGIN}
|
||||
gateways:
|
||||
- default/platform-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: zitadel-idp-contour.zitadel.svc.cluster.local
|
||||
port: 8080
|
||||
camunda-operate:
|
||||
name: camunda-operate-virt-service
|
||||
namespace: default
|
||||
hosts:
|
||||
- ${HOST_CAMUNDA}
|
||||
gateways:
|
||||
- default/platform-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: camunda-operate.camunda.svc.cluster.local
|
||||
port: 80
|
||||
camunda-identity:
|
||||
name: camunda-identity-virt-service
|
||||
namespace: default
|
||||
hosts:
|
||||
- ${HOST_CAMUNDA_IDENTITY}
|
||||
gateways:
|
||||
- default/platform-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: camunda-identity.camunda.svc.cluster.local
|
||||
port: 80
|
||||
camunda-keycloak:
|
||||
name: camunda-keycloak-virt-service
|
||||
namespace: default
|
||||
hosts:
|
||||
- ${HOST_CAMUNDA_KEYCLOAK}
|
||||
gateways:
|
||||
- default/platform-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: camunda-keycloak.camunda.svc.cluster.local
|
||||
port: 80
|
||||
camunda-optimize:
|
||||
name: camunda-optimize-virt-service
|
||||
namespace: default
|
||||
hosts:
|
||||
- ${HOST_CAMUNDA_OPTIMIZE}
|
||||
gateways:
|
||||
- default/platform-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: camunda-optimize.camunda.svc.cluster.local
|
||||
port: 80
|
||||
camunda-tasklist:
|
||||
name: camunda-tasklist-virt-service
|
||||
namespace: default
|
||||
hosts:
|
||||
- ${HOST_CAMUNDA_TASKLIST}
|
||||
gateways:
|
||||
- default/platform-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: camunda-tasklist.camunda.svc.cluster.local
|
||||
port: 80
|
||||
rabbitmq:
|
||||
name: rabbitmq-virt-service
|
||||
namespace: default
|
||||
hosts:
|
||||
- ${HOST_RABBITMQ}
|
||||
gateways:
|
||||
- default/platform-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: rabbitmq.rabbitmq.svc.cluster.local
|
||||
port: 15672
|
||||
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: istio-config.yaml
|
||||
@ -58,6 +58,18 @@ spec:
|
||||
renewBefore: 360h0m0s
|
||||
privateKey:
|
||||
rotationPolicy: Always
|
||||
srx-ui-kit-tls:
|
||||
dnsNames:
|
||||
- srx-ui-kit.infra.sarex.tech
|
||||
- srx-ui-kit-stage.infra.sarex.tech
|
||||
issuerRef:
|
||||
name: letsencrypt-issuer-istio
|
||||
kind: ClusterIssuer
|
||||
spec:
|
||||
duration: 2160h0m0s
|
||||
renewBefore: 360h0m0s
|
||||
privateKey:
|
||||
rotationPolicy: Always
|
||||
nexus-tls:
|
||||
dnsNames:
|
||||
- nexus.infra.sarex.tech
|
||||
@ -80,6 +92,28 @@ spec:
|
||||
renewBefore: 360h0m0s
|
||||
privateKey:
|
||||
rotationPolicy: Always
|
||||
wiki-tls:
|
||||
dnsNames:
|
||||
- wiki.sarex.space
|
||||
issuerRef:
|
||||
name: letsencrypt-issuer-istio
|
||||
kind: ClusterIssuer
|
||||
spec:
|
||||
duration: 2160h0m0s
|
||||
renewBefore: 360h0m0s
|
||||
privateKey:
|
||||
rotationPolicy: Always
|
||||
goalert-tls:
|
||||
dnsNames:
|
||||
- goalert.infra.sarex.io
|
||||
issuerRef:
|
||||
name: letsencrypt-issuer-istio
|
||||
kind: ClusterIssuer
|
||||
spec:
|
||||
duration: 2160h0m0s
|
||||
renewBefore: 360h0m0s
|
||||
privateKey:
|
||||
rotationPolicy: Always
|
||||
istio:
|
||||
gateways:
|
||||
vault:
|
||||
@ -104,6 +138,18 @@ spec:
|
||||
tls:
|
||||
credentialName: kb-tls
|
||||
mode: SIMPLE
|
||||
srx-ui-kit:
|
||||
name: srx-ui-kit-gateway
|
||||
namespace: istio-system
|
||||
selector:
|
||||
istio: ingressgateway
|
||||
servers:
|
||||
- hosts:
|
||||
- srx-ui-kit.infra.sarex.tech
|
||||
- srx-ui-kit-stage.infra.sarex.tech
|
||||
tls:
|
||||
credentialName: srx-ui-kit-tls
|
||||
mode: SIMPLE
|
||||
nexus:
|
||||
name: nexus-gateway
|
||||
namespace: istio-system
|
||||
@ -126,6 +172,28 @@ spec:
|
||||
tls:
|
||||
credentialName: idp-tls
|
||||
mode: SIMPLE
|
||||
wiki:
|
||||
name: wiki-gateway
|
||||
namespace: istio-system
|
||||
selector:
|
||||
istio: ingressgateway
|
||||
servers:
|
||||
- hosts:
|
||||
- wiki.sarex.space
|
||||
tls:
|
||||
credentialName: wiki-tls
|
||||
mode: SIMPLE
|
||||
goalert:
|
||||
name: goalert-gateway
|
||||
namespace: istio-system
|
||||
selector:
|
||||
istio: ingressgateway
|
||||
servers:
|
||||
- hosts:
|
||||
- goalert.infra.sarex.io
|
||||
tls:
|
||||
credentialName: goalert-tls
|
||||
mode: SIMPLE
|
||||
virtualServices:
|
||||
vault-virt-service:
|
||||
namespace: istio-system
|
||||
@ -149,6 +217,28 @@ spec:
|
||||
prefix: /
|
||||
service: kb-service.kb.svc.cluster.local
|
||||
port: 80
|
||||
srx-ui-kit-virt-service:
|
||||
namespace: istio-system
|
||||
hosts:
|
||||
- srx-ui-kit.infra.sarex.tech
|
||||
gateways:
|
||||
- istio-system/srx-ui-kit-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: universal-static-site-srx-ui-kit-pages.gitlab-pages-srx-ui-kit.svc.cluster.local
|
||||
port: 80
|
||||
srx-ui-kit-stage-virt-service:
|
||||
namespace: istio-system
|
||||
hosts:
|
||||
- srx-ui-kit-stage.infra.sarex.tech
|
||||
gateways:
|
||||
- istio-system/srx-ui-kit-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: universal-static-site-srx-ui-kit-stage-pages.gitlab-pages-srx-ui-kit-stage.svc.cluster.local
|
||||
port: 80
|
||||
nexus-virt-service:
|
||||
namespace: istio-system
|
||||
hosts:
|
||||
@ -171,3 +261,25 @@ spec:
|
||||
prefix: /
|
||||
service: idp.zitadel.svc.cluster.local
|
||||
port: 8080
|
||||
wiki-virt-service:
|
||||
namespace: istio-system
|
||||
hosts:
|
||||
- wiki.sarex.space
|
||||
gateways:
|
||||
- istio-system/wiki-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: outline.outline.svc.cluster.local
|
||||
port: 80
|
||||
goalert-virt-service:
|
||||
namespace: istio-system
|
||||
hosts:
|
||||
- goalert.infra.sarex.io
|
||||
gateways:
|
||||
- istio-system/goalert-gateway
|
||||
routes:
|
||||
- path:
|
||||
prefix: /
|
||||
service: goalert.goalert.svc.cluster.local
|
||||
port: 8081
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: ingressgateway
|
||||
namespace: istio-system
|
||||
spec:
|
||||
interval: 5m
|
||||
timeout: 10m
|
||||
dependsOn:
|
||||
- name: istio-base
|
||||
namespace: istio-system
|
||||
- name: istiod
|
||||
namespace: istio-system
|
||||
values:
|
||||
_internal_defaults_do_not_set:
|
||||
replicaCount: ${GATEWAY_REPLICAS}
|
||||
service:
|
||||
type: ClusterIP
|
||||
nodeSelector:
|
||||
sarex.io/gateway: "true"
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchLabels:
|
||||
istio: ingressgateway
|
||||
topologyKey: kubernetes.io/hostname
|
||||
tolerations:
|
||||
- key: node-role.kubernetes.io/control-plane
|
||||
operator: Exists
|
||||
effect: NoSchedule
|
||||
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: istio-gateway.yaml
|
||||
12
infrastructure/istio-pilot/contour-template/istio-pilot.yaml
Normal file
12
infrastructure/istio-pilot/contour-template/istio-pilot.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: istiod
|
||||
namespace: istio-system
|
||||
spec:
|
||||
interval: 5m
|
||||
timeout: 10m
|
||||
values:
|
||||
global:
|
||||
imagePullSecrets:
|
||||
- regcred
|
||||
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: istio-pilot.yaml
|
||||
73
infrastructure/kafka/contour-template/kafka.yaml
Normal file
73
infrastructure/kafka/contour-template/kafka.yaml
Normal file
@ -0,0 +1,73 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: kafka
|
||||
namespace: kafka
|
||||
spec:
|
||||
interval: 5m
|
||||
timeout: 10m
|
||||
postRenderers:
|
||||
- kustomize:
|
||||
patches:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
namespace: kafka
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: generic
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value: []
|
||||
values:
|
||||
global:
|
||||
imagePullSecrets:
|
||||
- regcred
|
||||
defaultStorageClass: ${STORAGE_CLASS}
|
||||
image:
|
||||
pullSecrets:
|
||||
- regcred
|
||||
controller:
|
||||
replicaCount: 1
|
||||
automountServiceAccountToken: true
|
||||
persistence:
|
||||
size: 8Gi
|
||||
storageClass: ${STORAGE_CLASS}
|
||||
overrideConfiguration:
|
||||
offsets.topic.replication.factor: 1
|
||||
transaction.state.log.replication.factor: 1
|
||||
transaction.state.log.min.isr: 1
|
||||
default.replication.factor: 1
|
||||
min.insync.replicas: 1
|
||||
broker:
|
||||
replicaCount: 0
|
||||
automountServiceAccountToken: true
|
||||
listeners:
|
||||
client:
|
||||
protocol: SASL_PLAINTEXT
|
||||
sslClientAuth: "none"
|
||||
provisioning:
|
||||
enabled: false
|
||||
sasl:
|
||||
managedExistingSecret:
|
||||
enabled: false
|
||||
existingSecret: ""
|
||||
enabledMechanisms: PLAIN,SCRAM-SHA-512
|
||||
interBrokerMechanism: PLAIN
|
||||
controllerMechanism: PLAIN
|
||||
client:
|
||||
users: []
|
||||
passwords: ""
|
||||
tls:
|
||||
type: PEM
|
||||
vault:
|
||||
enabled: true
|
||||
role: kafka
|
||||
authPath: auth/kubernetes
|
||||
secretPath: secrets/data/kafka/bootstrap
|
||||
clusterIdKey: clusterId
|
||||
interBrokerPasswordKey: interBrokerPassword
|
||||
controllerPasswordKey: controllerPassword
|
||||
6
infrastructure/kafka/contour-template/kustomization.yaml
Normal file
6
infrastructure/kafka/contour-template/kustomization.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: kafka.yaml
|
||||
6
infrastructure/outline/vk-infra/kustomization.yaml
Normal file
6
infrastructure/outline/vk-infra/kustomization.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- valkey.yaml
|
||||
- outline.yaml
|
||||
6
infrastructure/outline/vk-infra/namespace.yaml
Normal file
6
infrastructure/outline/vk-infra/namespace.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: outline
|
||||
labels:
|
||||
istio-injection: enabled
|
||||
139
infrastructure/outline/vk-infra/outline.yaml
Normal file
139
infrastructure/outline/vk-infra/outline.yaml
Normal file
@ -0,0 +1,139 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: outline
|
||||
namespace: outline
|
||||
spec:
|
||||
interval: 10m
|
||||
timeout: 10m
|
||||
chart:
|
||||
spec:
|
||||
chart: outline
|
||||
version: "0.1.0"
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: yc-oci-charts
|
||||
namespace: flux-system
|
||||
interval: 10m
|
||||
install:
|
||||
remediation:
|
||||
retries: 3
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: 3
|
||||
dependsOn:
|
||||
- name: istiod
|
||||
namespace: istio-system
|
||||
- name: outline-valkey
|
||||
namespace: outline
|
||||
values:
|
||||
universal-chart:
|
||||
global:
|
||||
env: infra
|
||||
image:
|
||||
name:
|
||||
infra: cr.yandex/crp3ccidau046kdj8g9q/outlinewiki/outline:1.12.0
|
||||
envs:
|
||||
- name: NODE_ENV
|
||||
value:
|
||||
_default: production
|
||||
- name: URL
|
||||
value:
|
||||
_default: https://wiki.sarex.space
|
||||
- name: PORT
|
||||
value:
|
||||
_default: "3000"
|
||||
- name: WEB_CONCURRENCY
|
||||
value:
|
||||
_default: "1"
|
||||
# TLS терминируется на istio ingressgateway
|
||||
- name: FORCE_HTTPS
|
||||
value:
|
||||
_default: "false"
|
||||
- name: ENABLE_UPDATES
|
||||
value:
|
||||
_default: "false"
|
||||
- name: LOG_LEVEL
|
||||
value:
|
||||
_default: info
|
||||
- name: PGSSLMODE
|
||||
value:
|
||||
_default: disable
|
||||
- name: FILE_STORAGE
|
||||
value:
|
||||
_default: s3
|
||||
- name: AWS_REGION
|
||||
value:
|
||||
_default: ru-msk
|
||||
- name: AWS_S3_UPLOAD_BUCKET_URL
|
||||
value:
|
||||
_default: https://hb.ru-msk.vkcloud-storage.ru
|
||||
- name: AWS_S3_UPLOAD_BUCKET_NAME
|
||||
value:
|
||||
_default: sarex-wiki
|
||||
- name: AWS_S3_FORCE_PATH_STYLE
|
||||
value:
|
||||
_default: "true"
|
||||
- name: AWS_S3_ACL
|
||||
value:
|
||||
_default: private
|
||||
# VK Object Storage документирует presigned PUT; presigned POST не описан
|
||||
- name: AWS_S3_UPLOAD_METHOD
|
||||
value:
|
||||
_default: put
|
||||
- name: OIDC_DISPLAY_NAME
|
||||
value:
|
||||
_default: Sarex IAM
|
||||
- name: OIDC_AUTH_URI
|
||||
value:
|
||||
_default: https://iam.sarex.io/oauth/v2/authorize
|
||||
- name: OIDC_TOKEN_URI
|
||||
value:
|
||||
_default: https://iam.sarex.io/oauth/v2/token
|
||||
- name: OIDC_USERINFO_URI
|
||||
value:
|
||||
_default: https://iam.sarex.io/oidc/v1/userinfo
|
||||
- name: OIDC_LOGOUT_URI
|
||||
value:
|
||||
_default: https://iam.sarex.io/oidc/v1/end_session
|
||||
- name: OIDC_USERNAME_CLAIM
|
||||
value:
|
||||
_default: preferred_username
|
||||
- name: OIDC_SCOPES
|
||||
value:
|
||||
_default: openid profile email offline_access
|
||||
# SMTP подключается отдельным шагом: добавить SMTP_HOST, SMTP_PORT,
|
||||
# SMTP_FROM_EMAIL сюда и SMTP_USERNAME, SMTP_PASSWORD в secretEnvs.
|
||||
secretEnvs:
|
||||
- name: SECRET_KEY
|
||||
secretName:
|
||||
_default: outline
|
||||
secretKey: SECRET_KEY
|
||||
- name: UTILS_SECRET
|
||||
secretName:
|
||||
_default: outline
|
||||
secretKey: UTILS_SECRET
|
||||
- name: DATABASE_URL
|
||||
secretName:
|
||||
_default: outline-postgresql
|
||||
secretKey: url
|
||||
- name: REDIS_URL
|
||||
secretName:
|
||||
_default: outline
|
||||
secretKey: REDIS_URL
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
secretName:
|
||||
_default: outline
|
||||
secretKey: AWS_ACCESS_KEY_ID
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
secretName:
|
||||
_default: outline
|
||||
secretKey: AWS_SECRET_ACCESS_KEY
|
||||
- name: OIDC_CLIENT_ID
|
||||
secretName:
|
||||
_default: outline
|
||||
secretKey: OIDC_CLIENT_ID
|
||||
- name: OIDC_CLIENT_SECRET
|
||||
secretName:
|
||||
_default: outline
|
||||
secretKey: OIDC_CLIENT_SECRET
|
||||
62
infrastructure/outline/vk-infra/valkey.yaml
Normal file
62
infrastructure/outline/vk-infra/valkey.yaml
Normal file
@ -0,0 +1,62 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: outline-valkey
|
||||
namespace: outline
|
||||
spec:
|
||||
interval: 10m
|
||||
timeout: 10m
|
||||
chart:
|
||||
spec:
|
||||
chart: valkey
|
||||
version: "0.1.0"
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: yc-oci-charts
|
||||
namespace: flux-system
|
||||
interval: 10m
|
||||
install:
|
||||
remediation:
|
||||
retries: 3
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: 3
|
||||
values:
|
||||
fullnameOverride: outline-valkey
|
||||
image:
|
||||
registry: cr.yandex
|
||||
repository: crp3ccidau046kdj8g9q/valkey/valkey
|
||||
tag: 8.0.2-debian-12-r6
|
||||
global:
|
||||
imagePullSecrets:
|
||||
- istio-registry-secret
|
||||
security:
|
||||
allowInsecureImages: true
|
||||
architecture: standalone
|
||||
auth:
|
||||
enabled: true
|
||||
sentinel: false
|
||||
existingSecret: outline-valkey
|
||||
existingSecretPasswordKey: valkey-password
|
||||
# Outline хранит в Valkey очереди фоновых задач и состояние websocket.
|
||||
# Персистентность не нужна, вытеснение ключей недопустимо для очередей.
|
||||
commonConfiguration: |-
|
||||
appendonly no
|
||||
save ""
|
||||
maxmemory 256mb
|
||||
maxmemory-policy noeviction
|
||||
primary:
|
||||
podAnnotations:
|
||||
sidecar.istio.io/inject: "false"
|
||||
nodeSelector:
|
||||
sarex.io/pool: svc
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 384Mi
|
||||
persistence:
|
||||
enabled: false
|
||||
metrics:
|
||||
enabled: false
|
||||
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: postgresql.yaml
|
||||
104
infrastructure/postgresql/contour-template/postgresql.yaml
Normal file
104
infrastructure/postgresql/contour-template/postgresql.yaml
Normal file
@ -0,0 +1,104 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: postgresql
|
||||
namespace: postgresql
|
||||
spec:
|
||||
interval: 5m
|
||||
timeout: 2h
|
||||
|
||||
install:
|
||||
timeout: 2h
|
||||
remediation:
|
||||
retries: 3
|
||||
|
||||
upgrade:
|
||||
timeout: 2h
|
||||
remediation:
|
||||
retries: 3
|
||||
|
||||
values:
|
||||
global:
|
||||
security:
|
||||
allowInsecureImages: true
|
||||
defaultStorageClass: ${STORAGE_CLASS}
|
||||
postgresql:
|
||||
auth:
|
||||
username: ""
|
||||
database: ""
|
||||
secretKeys:
|
||||
userPasswordKey: "postgres-password"
|
||||
auth:
|
||||
username: ""
|
||||
database: ""
|
||||
secretKeys:
|
||||
userPasswordKey: "postgres-password"
|
||||
image:
|
||||
registry: cr.yandex/crp3ccidau046kdj8g9q
|
||||
repository: contour/postgresql
|
||||
tag: 17.0.7
|
||||
pullPolicy: Always
|
||||
metrics:
|
||||
enabled: false
|
||||
prometheusRule:
|
||||
enabled: false
|
||||
primary:
|
||||
automountServiceAccountToken: true
|
||||
containerSecurityContext:
|
||||
readOnlyRootFilesystem: false
|
||||
persistence:
|
||||
storageClass: ${STORAGE_CLASS}
|
||||
size: 20Gi
|
||||
customLivenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
successThreshold: 1
|
||||
failureThreshold: 6
|
||||
customReadinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
successThreshold: 1
|
||||
failureThreshold: 6
|
||||
customStartupProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
successThreshold: 1
|
||||
failureThreshold: 6
|
||||
nodeSelector:
|
||||
dedicated: generic
|
||||
tolerations: []
|
||||
contour:
|
||||
enabled: true
|
||||
adminUser: "postgres"
|
||||
vault:
|
||||
enabled: true
|
||||
role: postgresql-zitadel
|
||||
authPath: auth/kubernetes
|
||||
secretPath: secrets/data/postgresql-zitadel/admin
|
||||
secretKey: postgres-password
|
||||
usersSecretPath: secrets/data/zitadel/postgresql
|
||||
sharedPreloadLibraries: "timescaledb,pg_stat_statements"
|
||||
databases:
|
||||
- name: zitadel
|
||||
user: zitadel
|
||||
passwordKey: password
|
||||
extensions: []
|
||||
restoreFromDump: false
|
||||
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: rabbitmq.yaml
|
||||
104
infrastructure/rabbitmq/contour-template/rabbitmq.yaml
Normal file
104
infrastructure/rabbitmq/contour-template/rabbitmq.yaml
Normal file
@ -0,0 +1,104 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: rabbitmq
|
||||
namespace: rabbitmq
|
||||
spec:
|
||||
interval: 5m
|
||||
timeout: 10m
|
||||
postRenderers:
|
||||
- kustomize:
|
||||
patches:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
namespace: rabbitmq
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: generic
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value: []
|
||||
- target:
|
||||
group: cert-manager.io
|
||||
version: v1
|
||||
kind: Certificate
|
||||
namespace: gateway
|
||||
name: rmq-tls
|
||||
patch: |-
|
||||
$patch: delete
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: rmq-tls
|
||||
namespace: gateway
|
||||
- target:
|
||||
group: networking.istio.io
|
||||
version: v1beta1
|
||||
kind: Gateway
|
||||
namespace: gateway
|
||||
name: rmq-gateway
|
||||
patch: |-
|
||||
$patch: delete
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: rmq-gateway
|
||||
namespace: gateway
|
||||
- target:
|
||||
group: networking.istio.io
|
||||
version: v1
|
||||
kind: VirtualService
|
||||
namespace: rabbitmq
|
||||
name: rmq-virt-service
|
||||
patch: |-
|
||||
$patch: delete
|
||||
apiVersion: networking.istio.io/v1
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: rmq-virt-service
|
||||
namespace: rabbitmq
|
||||
values:
|
||||
global:
|
||||
security:
|
||||
allowInsecureImages: true
|
||||
virtualService: null
|
||||
gateway: null
|
||||
certificate: null
|
||||
metrics:
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
default:
|
||||
enabled: false
|
||||
perObject:
|
||||
enabled: false
|
||||
detailed:
|
||||
enabled: false
|
||||
extraServiceMonitors: []
|
||||
replicaCount: 1
|
||||
resources:
|
||||
requests:
|
||||
memory: 1Gi
|
||||
persistence:
|
||||
storageClass: ${STORAGE_CLASS}
|
||||
size: 10Gi
|
||||
auth:
|
||||
securePassword: true
|
||||
enableLoopbackUser: false
|
||||
existingPasswordSecret: ""
|
||||
vault:
|
||||
enabled: true
|
||||
role: rabbitmq
|
||||
authPath: auth/kubernetes
|
||||
secretPath: secrets/data/rabbitmq/auth
|
||||
usernameKey: username
|
||||
passwordKey: password
|
||||
advancedConfiguration: |-
|
||||
[
|
||||
{rabbit, [
|
||||
{loopback_users, []}
|
||||
]}
|
||||
].
|
||||
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
|
||||
6
infrastructure/vault/contour-template/kustomization.yaml
Normal file
6
infrastructure/vault/contour-template/kustomization.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: vault.yaml
|
||||
110
infrastructure/vault/contour-template/vault.yaml
Normal file
110
infrastructure/vault/contour-template/vault.yaml
Normal file
@ -0,0 +1,110 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: vault
|
||||
namespace: vault
|
||||
spec:
|
||||
interval: 5m
|
||||
timeout: 10m
|
||||
install:
|
||||
disableWait: true
|
||||
upgrade:
|
||||
disableWait: true
|
||||
postRenderers:
|
||||
- kustomize:
|
||||
patches:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
namespace: vault
|
||||
name: vault-vault-contour
|
||||
patch: |-
|
||||
- op: replace
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: generic
|
||||
- op: replace
|
||||
path: /spec/template/spec/tolerations
|
||||
value: []
|
||||
values:
|
||||
global:
|
||||
namespace: vault
|
||||
imagePullSecrets:
|
||||
- name: regcred
|
||||
backup:
|
||||
enabled: false
|
||||
injector:
|
||||
nodeSelector:
|
||||
dedicated: generic
|
||||
tolerations: []
|
||||
server:
|
||||
includeConfigAnnotation: true
|
||||
nodeSelector:
|
||||
dedicated: generic
|
||||
tolerations: []
|
||||
dataStorage:
|
||||
size: 10Gi
|
||||
storageClass: ${STORAGE_CLASS}
|
||||
volumes:
|
||||
- name: unseal-keys
|
||||
secret:
|
||||
secretName: vault-unseal-keys
|
||||
optional: true
|
||||
defaultMode: 0440
|
||||
extraContainers:
|
||||
- name: unsealer
|
||||
image: cr.yandex/crp3ccidau046kdj8g9q/vault/vault:1.21.2
|
||||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
- name: VAULT_ADDR
|
||||
value: http://127.0.0.1:8200
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
while true; do
|
||||
if vault status >/dev/null 2>&1; then
|
||||
:
|
||||
else
|
||||
rc=$?
|
||||
if [ "$rc" -eq 2 ]; then
|
||||
if [ -s /vault/unseal-keys/key1 ] && [ -s /vault/unseal-keys/key2 ] && [ -s /vault/unseal-keys/key3 ]; then
|
||||
for k in key1 key2 key3; do
|
||||
vault operator unseal "$(cat /vault/unseal-keys/$k)" >/dev/null 2>&1 || echo "unseal call failed"
|
||||
done
|
||||
if vault status >/dev/null 2>&1; then echo "unsealed"; else echo "still sealed"; fi
|
||||
else
|
||||
echo "sealed, keys not mounted"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
volumeMounts:
|
||||
- name: unseal-keys
|
||||
mountPath: /vault/unseal-keys
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 16Mi
|
||||
limits:
|
||||
memory: 64Mi
|
||||
ha:
|
||||
replicas: 1
|
||||
raft:
|
||||
config: |
|
||||
ui = true
|
||||
|
||||
listener "tcp" {
|
||||
tls_disable = 1
|
||||
address = "[::]:8200"
|
||||
cluster_address = "[::]:8201"
|
||||
}
|
||||
|
||||
storage "raft" {
|
||||
path = "/vault/data"
|
||||
}
|
||||
|
||||
service_registration "kubernetes" {}
|
||||
@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- path: zitadel.yaml
|
||||
168
infrastructure/zitadel/contour-template/zitadel.yaml
Normal file
168
infrastructure/zitadel/contour-template/zitadel.yaml
Normal file
@ -0,0 +1,168 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: zitadel
|
||||
namespace: zitadel
|
||||
spec:
|
||||
interval: 5m
|
||||
timeout: 10m
|
||||
dependsOn:
|
||||
- name: postgresql
|
||||
namespace: postgresql
|
||||
postRenderers:
|
||||
- kustomize:
|
||||
patches:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: zitadel-idp-contour
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: generic
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value: []
|
||||
- op: replace
|
||||
path: /spec/template/metadata/annotations/vault.hashicorp.com~1agent-inject-template-zitadel-vault-config.yaml
|
||||
value: |-
|
||||
{{- with secret "secrets/data/zitadel/postgresql" -}}
|
||||
Database:
|
||||
postgres:
|
||||
User:
|
||||
Password: |-
|
||||
{{ index .Data.data "password" }}
|
||||
Admin:
|
||||
Password: |-
|
||||
{{ index .Data.data "password" }}
|
||||
FirstInstance:
|
||||
Org:
|
||||
Human:
|
||||
Password: |-
|
||||
{{ index .Data.data "humanPassword" }}
|
||||
{{- end -}}
|
||||
- target:
|
||||
group: batch
|
||||
version: v1
|
||||
kind: Job
|
||||
name: zitadel-idp-contour-init
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: generic
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value: []
|
||||
- op: replace
|
||||
path: /spec/template/metadata/annotations/vault.hashicorp.com~1agent-inject-template-zitadel-vault-config.yaml
|
||||
value: |-
|
||||
{{- with secret "secrets/data/zitadel/postgresql" -}}
|
||||
Database:
|
||||
postgres:
|
||||
User:
|
||||
Password: |-
|
||||
{{ index .Data.data "password" }}
|
||||
Admin:
|
||||
Password: |-
|
||||
{{ index .Data.data "password" }}
|
||||
FirstInstance:
|
||||
Org:
|
||||
Human:
|
||||
Password: |-
|
||||
{{ index .Data.data "humanPassword" }}
|
||||
{{- end -}}
|
||||
- target:
|
||||
group: batch
|
||||
version: v1
|
||||
kind: Job
|
||||
name: zitadel-idp-contour-setup
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/nodeSelector
|
||||
value:
|
||||
dedicated: generic
|
||||
- op: add
|
||||
path: /spec/template/spec/tolerations
|
||||
value: []
|
||||
- op: replace
|
||||
path: /spec/template/metadata/annotations/vault.hashicorp.com~1agent-inject-template-zitadel-vault-config.yaml
|
||||
value: |-
|
||||
{{- with secret "secrets/data/zitadel/postgresql" -}}
|
||||
Database:
|
||||
postgres:
|
||||
User:
|
||||
Password: |-
|
||||
{{ index .Data.data "password" }}
|
||||
Admin:
|
||||
Password: |-
|
||||
{{ index .Data.data "password" }}
|
||||
FirstInstance:
|
||||
Org:
|
||||
Human:
|
||||
Password: |-
|
||||
{{ index .Data.data "humanPassword" }}
|
||||
{{- end -}}
|
||||
values:
|
||||
zitadel:
|
||||
configmapConfig:
|
||||
ExternalDomain: ${HOST_LOGIN}
|
||||
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:
|
||||
enabled: false
|
||||
postgresqlSecret:
|
||||
create: false
|
||||
vault:
|
||||
enabled: true
|
||||
role: zitadel
|
||||
authPath: auth/kubernetes
|
||||
secretPath: secrets/data/zitadel/postgresql
|
||||
secretKey: password
|
||||
kvVersion: 2
|
||||
fileName: zitadel-vault-config.yaml
|
||||
serviceAccount:
|
||||
create: true
|
||||
name: zitadel-idp-contour
|
||||
replicaCount: 1
|
||||
pdb:
|
||||
enabled: false
|
||||
env:
|
||||
- name: ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED
|
||||
value: "false"
|
||||
- name: ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_VERIFIERS
|
||||
value: "bcrypt,pbkdf2"
|
||||
- name: ZITADEL_MACHINE_IDENTIFICATION_HOSTNAME_ENABLED
|
||||
value: "true"
|
||||
- name: ZITADEL_DATABASE_POSTGRES_HOST
|
||||
value: "postgresql.postgresql.svc.cluster.local"
|
||||
- name: ZITADEL_DATABASE_POSTGRES_PORT
|
||||
value: "5432"
|
||||
- name: ZITADEL_DATABASE_POSTGRES_USER_USERNAME
|
||||
value: "zitadel"
|
||||
- name: ZITADEL_DATABASE_POSTGRES_ADMIN_EXISTINGDATABASE
|
||||
value: "zitadel"
|
||||
- name: ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME
|
||||
value: "zitadel"
|
||||
- name: ZITADEL_DATABASE_POSTGRES_DATABASE
|
||||
value: "zitadel"
|
||||
- name: ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE
|
||||
value: "disable"
|
||||
- name: ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE
|
||||
value: "disable"
|
||||
- name: ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_USERNAME
|
||||
value: "zitadel-admin"
|
||||
- name: ZITADEL_DEFAULTINSTANCE_ORG_NAME
|
||||
value: "Sarex"
|
||||
Loading…
Reference in New Issue
Block a user