gen(subresource): выход password для авто-генерируемого пароля пользователя
Проблема: у части сервисов пароль пользователя генерирует платформа и кладёт его в
секрет Vault РОДИТЕЛЬСКОГО инстанса. vault_secrets родителя — Computed и обновляется
только при его Read, поэтому внутри одного apply после create_user пароль недоступен
(Invalid index). Из-за этого в pg/outputs.tf приходилось читать vault_secrets кластера,
а стенду требовались два apply.
Решение: подресурс-пользователь отдаёт пароль СВОИМ выходом сразу после create_user.
- types.go: GenSubresource.VaultUserPassword (признак из данных спека);
- loader.go: признак = подресурс user + у сервиса есть vault-выходы + create_user
принимает username и НЕ принимает password; имя сервиса нигде не проверяется;
- templates/subresource.go: поле модели + Computed/Sensitive атрибут password,
чтение Vault родителя в Create (GetInstanceStateDetails + GetInstanceVaultSecrets)
и перенос уже полученного пароля в Update (чтобы Computed-атрибут не стал unknown);
- resources_core/subresource_user_password.go: ExtractUserPassword — разбор
{"<username>":{"password":"..."}} с безопасным возвратом пустой строки;
- writers: регрессионный тест «фича включена/выключена».
Проверено генерацией и сборкой test-стенда: выход получили 4 подресурса
(postgres_user, kafka_user, clickhouse_user, mongodb_user); mariadb_user НЕ затронут
(там пароль входной); k8s_*_user и vc_org_user не затронуты (пользователь
адресуется не через username). go test ./... — ok, go build — чисто.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package resources_core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ExtractUserPassword вытаскивает пароль пользователя из JSON-значения секрета Vault
|
||||
// родительского инстанса.
|
||||
//
|
||||
// ЗАЧЕМ: у части сервисов (проверено на postgres) платформа САМА генерирует пароль
|
||||
// в операции create_user и кладёт его в секрет Vault родителя. Формат значения
|
||||
// (проверено через GET /instances/<uid>/vault/users):
|
||||
//
|
||||
// {"<username>": {"password": "<пароль>"}}
|
||||
//
|
||||
// Подресурс обязан вернуть этот пароль СВОИМ выходом сразу после create_user, иначе
|
||||
// потребитель не сможет получить его в том же apply (vault_secrets родителя — Computed
|
||||
// и обновляется только при Read родителя). См. TOOLS/ARCHITECTURE.md,
|
||||
// раздел «Subresource-born secrets».
|
||||
//
|
||||
// Возвращает "" без ошибки, если пользователя в секрете нет или пароль отсутствует:
|
||||
// это не фатально (пароль остаётся неизвестным до следующего чтения) и не должно
|
||||
// ломать create.
|
||||
func ExtractUserPassword(secretJSON string, username string) (string, error) {
|
||||
raw := strings.TrimSpace(secretJSON)
|
||||
if raw == "" {
|
||||
return "", nil
|
||||
}
|
||||
name := strings.TrimSpace(username)
|
||||
if name == "" {
|
||||
return "", fmt.Errorf("пустое имя пользователя для поиска пароля в Vault")
|
||||
}
|
||||
|
||||
// Основной формат: {"<username>": {"password": "..."}}.
|
||||
var byUser map[string]struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(raw), &byUser); err == nil {
|
||||
if entry, ok := byUser[name]; ok && strings.TrimSpace(entry.Password) != "" {
|
||||
return strings.TrimSpace(entry.Password), nil
|
||||
}
|
||||
// Регистр имени может отличаться (платформа нормализует его сама).
|
||||
for key, entry := range byUser {
|
||||
if strings.EqualFold(strings.TrimSpace(key), name) && strings.TrimSpace(entry.Password) != "" {
|
||||
return strings.TrimSpace(entry.Password), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Упрощённый формат: {"password": "..."} — единственный пользователь в секрете.
|
||||
var flat struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(raw), &flat); err == nil {
|
||||
if strings.TrimSpace(flat.Password) != "" {
|
||||
return strings.TrimSpace(flat.Password), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
Reference in New Issue
Block a user