docs(runbooks): add "new web app" setup runbook under doc/runbooks/
Document, as a tree-docs tree, the end-to-end procedure to stand up a new web application on the Arcodange platform — a mechanic spread across the factory, tools and app repos with non-trivial ordering dependencies. Covers: Gitea repo creation (org-secret inheritance), Postgres DB + owner role (factory/postgres/iac), platform Vault declaration (gitea_cicd_<app> + policies, tools/hashicorp-vault/iac), the app Helm chart (VSO dynamic secrets via pgbouncer), the app Terraform (app_roles module), the CI workflows (tofu apply + image build, incl. the copy-pasted role pitfall), and ArgoCD registration (factory/argocd/values.yaml). Adds a naming- conventions concept page and an ordered checklist. Wires the legacy doc/adr "setup hello world web app" item and the factory README to the runbook. New docs live under doc/ (singular) per the PR #8 convention. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
93
doc/runbooks/new-web-app/02-database.md
Normal file
93
doc/runbooks/new-web-app/02-database.md
Normal file
@@ -0,0 +1,93 @@
|
||||
[Factory](../../../README.md) > [Doc](../../README.md) > [Runbooks](../README.md) > [Nouvelle application web](README.md) > **2. Base de données**
|
||||
|
||||
# 2. Provisionner la base de données
|
||||
|
||||
> **Status:** ✅ Active
|
||||
> **Upstream:** [1. Dépôt Gitea](01-gitea-repo.md)
|
||||
> **Downstream:** [5. Terraform de l'app](05-app-terraform.md)
|
||||
> **Related:** [3. Vault plateforme](03-vault-platform.md) · [4. Chart Helm](04-helm-chart.md) · [Conventions de nommage](conventions.md)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
La base de l'app et son **rôle propriétaire** `<app>_role` sont créés par un Terraform **côté plateforme** (`factory/postgres/iac`), pas dans le dépôt de l'app. On ajoute simplement le nom de l'app à une liste, et la CI de `factory` applique. L'app, elle, ne se connectera **jamais** avec un mot de passe statique : elle obtiendra des identifiants éphémères de Vault (cf. [étape 4](04-helm-chart.md)) qui héritent de `<app>_role`.
|
||||
|
||||
## Action
|
||||
|
||||
Ajouter `"<app>"` au set `applications` de [`factory/postgres/iac/terraform.tfvars`](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/postgres/iac/terraform.tfvars) :
|
||||
|
||||
```hcl
|
||||
applications = [
|
||||
"webapp",
|
||||
"erp",
|
||||
"crowdsec",
|
||||
"plausible",
|
||||
"dance-lessons-coach",
|
||||
"<app>", # ← ajouter
|
||||
]
|
||||
```
|
||||
|
||||
Puis pousser : la CI applique automatiquement (voir plus bas).
|
||||
|
||||
## Ce que ça crée
|
||||
|
||||
[`postgres/iac/main.tf`](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/postgres/iac/main.tf) itère `for_each` sur le set et crée, **par app** :
|
||||
|
||||
| Ressource | Nom | Rôle |
|
||||
|---|---|---|
|
||||
| `postgresql_role` | `<app>_role` | Rôle **non-login**, propriétaire de la base |
|
||||
| `postgresql_grant_role` | `<app>_role` → `credentials_editor` (WITH ADMIN OPTION) | Laisse Vault rattacher les users dynamiques à ce rôle |
|
||||
| `postgresql_database` | `<app>` | La base (owner `<app>_role`, `template0`, `alter_object_ownership`) |
|
||||
| `postgresql_function` | `user_lookup()` (dans la base `<app>`) | Authentification pgbouncer (lit `pg_shadow`) |
|
||||
| `postgresql_grant` | EXECUTE sur `user_lookup` → `pgbouncer_auth` | Autorise pgbouncer à résoudre les users |
|
||||
|
||||
Extrait clé :
|
||||
|
||||
```hcl
|
||||
resource "postgresql_role" "app_role" {
|
||||
for_each = var.applications
|
||||
name = "${each.value}_role"
|
||||
login = false # non-login : ne sert que de "porteur de droits"
|
||||
}
|
||||
resource "postgresql_database" "app_db" {
|
||||
for_each = var.applications
|
||||
name = each.value
|
||||
owner = postgresql_role.app_role[each.value].name
|
||||
template = "template0"
|
||||
alter_object_ownership = true
|
||||
}
|
||||
```
|
||||
|
||||
## Comment c'est appliqué
|
||||
|
||||
Le workflow [`factory/.gitea/workflows/postgres.yaml`](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/.gitea/workflows/postgres.yaml) se déclenche sur tout changement de `postgres/**/*.tf` ou `*.tfvars` :
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme': 'base'}}%%
|
||||
flowchart LR
|
||||
classDef ci fill:#059669,stroke:#047857,color:#fff
|
||||
classDef db fill:#2563eb,stroke:#1e40af,color:#fff
|
||||
PUSH["push tfvars"]:::ci --> JWT["OIDC Gitea → JWT Vault<br>(role gitea_cicd)"]:::ci
|
||||
JWT --> READ["lit kvv1/postgres/credentials<br>→ TF_VAR_postgres_*"]:::ci
|
||||
READ --> APPLY["tofu apply postgres/iac"]:::ci
|
||||
APPLY --> DB["base ‹app› + ‹app›_role"]:::db
|
||||
```
|
||||
|
||||
Le provider PostgreSQL pointe l'hôte `192.168.1.202` (`sslmode=disable`, `superuser=true`) et s'authentifie avec le compte `credentials_editor`, dont les identifiants sont dans Vault à `kvv1/postgres/credentials_editor/credentials`.
|
||||
|
||||
## Le modèle de connexion (à retenir)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> L'application **ne se connecte pas** directement à Postgres avec un user fixe. Elle vise **`pgbouncer.tools:5432`** et utilise des **users dynamiques courts** émis par Vault, qui héritent de `<app>_role` (donc des droits sur la base `<app>`). C'est l'étape 4 (chart + VSO) et l'étape 5 (rôle Vault `creds/<app>`) qui câblent ça. Ici, on ne fait qu'établir *la base et le rôle propriétaire*.
|
||||
|
||||
## Notes / contraintes
|
||||
|
||||
- `credentials_editor` est un compte unique partagé par toutes les apps, à fort privilège (il peut créer des rôles). Il sert aussi de compte de connexion au moteur Postgres de Vault (cf. [étape 3](03-vault-platform.md)).
|
||||
- La fonction `user_lookup()` est indispensable au mode `auth_query` de pgbouncer ; elle est `security_definer` et n'est exécutable que par `pgbouncer_auth`.
|
||||
|
||||
## Related
|
||||
|
||||
- [3. Vault plateforme](03-vault-platform.md) — la connexion Vault→Postgres réutilise `credentials_editor` ; à faire en parallèle.
|
||||
- [5. Terraform de l'app](05-app-terraform.md) — le module `app_roles` fait `GRANT <app>_role TO …` : il **exige** que `<app>_role` existe déjà (créé ici).
|
||||
- [4. Chart Helm](04-helm-chart.md) — où la connexion `pgbouncer.tools` + creds dynamiques est configurée.
|
||||
Reference in New Issue
Block a user