diff --git a/TOOLS/ARCHITECTURE.md b/TOOLS/ARCHITECTURE.md index 622657f..92557ae 100644 --- a/TOOLS/ARCHITECTURE.md +++ b/TOOLS/ARCHITECTURE.md @@ -203,6 +203,30 @@ resource "nubes_postgres_user" "user1" { role = "app_user" } +#### Subresource-born secrets (principle) + +Some `create_user` operations generate a password on the platform side and store it +in the PARENT instance's `vault_secrets`; the subresource's `Create` does not read it +back, and the parent's `vault_secrets` (Computed) refreshes only on `Read`. Result: in a +single `apply`, the password is unavailable right after `create_user` (accessing +`vault_secrets["users"]` fails with `Invalid index`). + +**Principle:** a secret born in a subresource operation must become an OUTPUT of that +subresource at the end of its `Create`; consumers read `nubes__.`, +never the parent's `vault_secrets`. + +**Rule:** this is service-specific DATA, never logic (see Exception Registry below): +the flag «user password is platform-generated, decrypt from parent vault, secret name X» +comes from the service YAML spec, exactly like `suspend_on_destroy_default`. The shared +subresource template (`TOOLS/resource-generator/internal/templates/subresource.go`) only +adds a conditional block gated on that flag — no service name is hardcoded there. + +Per-service fact (from specs): +- PostgreSQL (`90_postgres.yaml`): `create_user` has NO `password` input → password is + platform-generated into `vault_secrets["users"]` → NEEDS the output. +- MariaDB (`115_mariadb.yaml`): `create_user` TAKES `password` as input (sensitive) → + the password is already in the manifest (`nubes_mariadb_user.x.password`) → output NOT needed. + ### Redeploy (inline action) Services with `redeploy` operation get a `git_revision` field in the main resource. @@ -292,6 +316,13 @@ services. Service-specific deviations are of two kinds: |---|---|---| | `serviceSpecificDocExamples` | `TOOLS/docs-generator/internal/writers/writers.go` | per-service doc examples, gated on service name + required state/vault keys | +3. **Subresource-born secrets** — a platform-generated user password available only after + `create_user` (see «Subresource-born secrets» under «Subresource Resources»). The + generator flag «user password is platform-generated; read from parent vault secret X» + is declared in the service YAML spec — add the field to the spec's struct in + `TOOLS/resource-generator/internal/types/types.go` and wire it in + `TOOLS/resource-generator/internal/loader/loader.go`, NOT as `svc.Name == "..."` logic. + Rules: - Key by stable service NAME (slug), never by raw numeric ID. diff --git a/docs/60_strategy/provider_philosophy.md b/docs/60_strategy/provider_philosophy.md index e175de6..224eaed 100644 --- a/docs/60_strategy/provider_philosophy.md +++ b/docs/60_strategy/provider_philosophy.md @@ -48,41 +48,8 @@ To prevent "bad applies" and incomplete infrastructure states, the provider will - Изменение ключевых параметров подресурса => ресурс заменяется. - Это соответствует возможностям API и сохраняет корректность состояния Terraform. -### Секреты, рождаемые операцией подресурса (принцип и практика) - -**Проблема (наблюдаемая, 2026-10-01):** у части сервисов секрет (пароль пользователя -БД) **генерируется платформой** внутри операции `create_user`, а доступен он не в -выходе подресурса, а в `vault_secrets` **родительского инстанса**. При этом -`vault_secrets` родителя — `Computed`-атрибут, который обновляется только в `Read` -родителя (перечитывание облака на refresh/повторном apply), а **не** в конце -`Create` подресурса. Следствие: внутри одного `apply` после `create_user` пароль -нельзя прочитать — `vault_secrets["users"]` ещё пуст, и обращение к нему даёт -`Invalid index`. - -**Принцип (правило для генератора):** секрет, который порождает операция -подресурса, должен становиться **выходом самого подресурса** сразу по завершении -его `Create`, а не читаться потребителем из родителя. Потребитель берёт пароль -из `nubes__..password`, и зависимость по графу Терраформа -автоматически разносит создание по времени. - -**Как это «прописано для postgres», а не хардкод в шаблоне.** В общий шаблон -подресурса (`TOOLS/resource-generator/internal/templates/subresource.go`) НЕ -зашивается имя сервиса. Признак «у этого подресурса-пользователя пароль -генерируется платформой» должен приходить из **данных спека** (YAML), как уже -сделано для `suspend_on_destroy_default` / `adopt_existing_on_create_default` -(раздел 7). В шаблоне появится условный блок, срабатывающий только при наличии -этого признака. - -**Различия сервисов (факт из спеков):** - -| Сервис | Пароль пользователя | Что нужно | -|---|---|---| -| PostgreSQL (90) | генерирует платформа → `vault_secrets["users"]` | выход пароля у `postgres_user` из Vault по завершении `create_user` | -| MariaDB (115) | задаёт САМ пользователь (входной параметр `password` в `create_user`) | ничего — пароль уже в манифесте, `nubes_mariadb_user.x.password` | - -Вывод: фича «выход пароля» нужна только подресурсам, у которых `create_user` -**не** принимает пароль на входе (то есть где он auto-generated). Хардкодить -перечень сервисов в шаблоне запрещено — признак декларируется в YAML-спеке сервиса. +> Секреты, рождаемые операцией подресурса (пароль пользователя, авто-генерируемый +> в `create_user`), описаны в `TOOLS/ARCHITECTURE.md` → «Subresource-born secrets». ## 7. Каноничная lifecycle-логика для сервисов с suspend/resume