Архитектура управления секретами в Codegen Orchestrator разделяет ответственности между Оркестратором и Пользовательскими проектами.
Мы выделяем три уровня секретов, которые имеют разные модели жизненного цикла и хранения.
| Уровень | Описание | Примеры | Владелец | Хранение (Master) | Использование |
|---|---|---|---|---|---|
| L1. Platform | Инфраструктурные ключи самого Оркестратора | GH_APP_PRIVATE_KEY, POSTGRES_URL, OPENAI_API_KEY, CLOUDFLARE_API_TOKEN |
DevOps Оркестратора | K8s Secrets / .env |
Внедряются в контейнеры сервисов (Worker, API, Infra) |
| L2. Project | Секреты для запуска сгенерированных приложений | TELEGRAM_BOT_TOKEN, STRIPE_KEY |
Пользователь | GitHub Repository Secrets (в репо проекта) | CI/CD пайплайны (service_template), Ansible |
| L3. User | Личные ключи пользователя для провайдеров (Future) | User's Cloudflare Key, AWS Key | Пользователь | Encrypted DB Table (user_vault) |
Infra Service (для провижининга от имени юзера) |
Эти секреты необходимы для функционирования самой платформы.
- Storage: Переменные окружения.
- Access: Читаются при старте сервисов (
os.getenv). - Repo: Хранятся в
.env(локально) или в Secret Manager платформы хостинга.
Ключевой момент: Секреты зашифрованы at rest в PostgreSQL (Fernet encryption).
- Storage:
project.config.secrets(JSONB) — все значения зашифрованы Fernet-токенами (gAAAAA...). - Encryption:
shared/crypto.py—SecretsCipherчитаетSECRETS_ENCRYPTION_KEYиз env.encrypt_dict/decrypt_dictшифруют/дешифруют все значения в dict. - Graceful degradation: При расшифровке plaintext-значений (legacy) — warning в лог, значение возвращается as-is. При следующей записи мигрирует в encrypted (encrypt-on-write).
- Lifecycle:
- Пользователь вводит токен (например, Telegram Token) через PO в Telegram.
- PO tool
set_project_secret→ atomic merge viaPOST /projects/{id}/config/secrets(server-sideSELECT FOR UPDATElocking, handles concurrent writes). - DevOps subgraph
SecretResolverNode→ decrypt from DB → resolve → encrypt → save back via atomic merge.
- Usage:
- Secrets доступны в расшифрованном виде только в runtime (при вызове
decrypt_dict) - В БД всегда зашифрованы — даже при прямом SELECT видны только Fernet-токены
- Secrets доступны в расшифрованном виде только в runtime (при вызове
Если пользователю нужно провижить ресурсы на своём аккаунте (например, VPS на его DigitalOcean).
- Storage: Таблица
user_vault(user_id, key, encrypted_value). - Encryption: Symmetric Key Encryption (AES-GCM), ключ шифрования — это L1 Secret (
VAULT_MASTER_KEY). - Usage: Infra Service расшифровывает "на лету" перед вызовом провайдера (Terraform/Ansible).
The infra-service is responsible for preparing the "bare metal". It uses L1 Secrets only.
- SSH Key: Uses Orchestrator's L1 Private Key to connect to servers.
- Provider Keys: API keys for Time4VPS/DigitalOcean (L1).
It does NOT handle Project (L2) secrets. It does not deploy applications.
Application deployment is fully delegated to GitHub Actions. This allows secure usage of L2 secrets without exposing them to the Orchestrator's backend.
- DOTENV trick: Orchestrator collects ALL env vars → builds
.envcontent → base64-encodes → stores as single GitHub SecretDOTENV. The deploy workflow decodes and writes the file. No per-variable enumeration needed. - Secret Injection (two stages):
- Scaffolder: Sets
REGISTRY_URL,REGISTRY_USER,REGISTRY_PASSWORDimmediately after repo creation (before first CI push) - DeployerNode: Sets 9 secrets total —
DOTENV,DEPLOY_HOST,DEPLOY_USER,DEPLOY_SSH_KEY,DEPLOY_PORT,PROJECT_NAME,REGISTRY_URL,REGISTRY_USER,REGISTRY_PASSWORD
- Scaffolder: Sets
- CI workflow (
ci.yml, on push): lint → test → build images → push to self-hosted Docker registry - Deploy workflow (
deploy.yml, onworkflow_dispatchfrom Orchestrator): SCP compose files → write.envfrom DOTENV → pull images →docker compose up
Privilege Separation:
- Infra Service: Can create/destroy servers (Root access via Ansible). Cannot see App Secrets.
- GitHub Actions: Can deploy apps (SSH User access). Can access App Secrets. Cannot destroy servers.
Docker Registry: Self-hosted (registry:2) behind Caddy with TLS and basic auth. CI pushes images there, deploy pulls from there. GHCR is not used (GitHub App tokens cannot create org packages).
- User creates Project → Orchestrator creates GitHub Repo + sets registry secrets (
REGISTRY_*). - User provides Bot Token → PO tool
set_project_secret→ encrypted in DB (Fernet). - Infra Service provisions Server → Uses L1 Keys (Time4VPS API) for server setup. Ansible playbooks for Docker/firewall/users.
- Scaffolder pushes code → CI (
ci.yml, auto on push) → builds Docker images → pushes to self-hosted registry. - Orchestrator triggers deploy → DevOps subgraph: environment-contract resolution → DOTENV → GitHub Secrets →
workflow_dispatch deploy.yml→ pull images from registry →docker compose up. - Feature deploy → Developer pushes → CI passes → GitHub webhook → API →
deploy:queue→ re-resolve env → deploy.