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:
2026-05-31 17:22:30 +02:00
parent 54b3092305
commit 8330d82225
14 changed files with 1048 additions and 3 deletions

View File

@@ -0,0 +1,96 @@
[Factory](../../../README.md) > [Doc](../../README.md) > [Runbooks](../README.md) > [Nouvelle application web](README.md) > **5. Terraform de l'app**
# 5. Le Terraform de l'application
> **Status:** ✅ Active
> **Upstream:** [2. Base de données](02-database.md), [3. Vault plateforme](03-vault-platform.md)
> **Downstream:** [4. Chart Helm](04-helm-chart.md), [6. Workflows CI](06-ci-workflows.md)
> **Related:** [Conventions de nommage](conventions.md)
---
## Summary
Le `iac/` du dépôt déclare les ressources Vault **propres à l'app** : un rôle Postgres dynamique (`postgres/creds/<app>`), un rôle d'authentification Kubernetes (`<app>`), et les secrets de config KV. Le gros du travail est fait par un **module partagé** (`app_roles`, dans `tools`) ; le dépôt se contente de l'appeler avec son nom et d'ajouter ses secrets spécifiques.
## Les trois fichiers
### `providers.tf` — s'authentifier à Vault avec le rôle CI de l'app
```hcl
terraform {
required_providers {
vault = { source = "vault", version = "4.4.0" }
}
}
provider "vault" {
address = "https://vault.arcodange.lab"
auth_login_jwt { # JWT fourni par la CI via TERRAFORM_VAULT_AUTH_JWT
mount = "gitea_jwt"
role = "gitea_cicd_<app>" # ← créé à l'étape 3 ; DOIT exister avant le 1er apply
}
}
```
### `backend.tf` — état distant sur GCS, préfixe par app
```hcl
terraform {
backend "gcs" {
bucket = "arcodange-tf"
prefix = "<app>/main" # ← un préfixe d'état dédié par app
}
}
```
### `main.tf` — appeler le module partagé + secrets de l'app
```hcl
module "app_roles" {
source = "git::ssh://git@192.168.1.202:2222/arcodange-org/tools.git//hashicorp-vault/iac/modules/app_roles?depth=1&ref=main"
name = "<app>"
# database = "<autre>" # optionnel ; par défaut = name
}
# Exemple : secrets de config statiques de l'app, écrits dans kvv2/<app>/config
resource "vault_kv_secret_v2" "config" {
mount = module.app_roles.mount_paths.kvv2 # "kvv2"
name = format("%sconfig", module.app_roles.kvv2_path_prefix) # "<app>/config"
data_json = jsonencode({
# … clés propres à l'app (ex. erp : DOLI_ADMIN_LOGIN/PASSWORD, DOLI_INSTANCE_UNIQUE_ID) …
})
}
```
## Ce que le module `app_roles` crée
[`modules/app_roles/main.tf`](https://gitea.arcodange.lab/arcodange-org/tools/src/branch/main/hashicorp-vault/iac/modules/app_roles/main.tf) :
| Ressource | Effet |
|---|---|
| `vault_database_secret_backend_role``postgres/creds/<app>` | À chaque demande : `CREATE ROLE "…" LOGIN PASSWORD … VALID UNTIL … ; GRANT <app>_role TO "…"`. Le user éphémère **hérite** de `<app>_role` (donc des droits sur la base). À la révocation : `REASSIGN OWNED … TO <app>_role` + `REVOKE`. |
| `vault_kubernetes_auth_backend_role``<app>` | Lie le SA `<app>` du namespace `<app>` aux policies `default` + `<app>` (TTL 3600 s). C'est ce que `VaultAuth` cible (étape 4). |
Sorties utiles : `mount_paths` (`{k8s, pg, kvv2}`), `kvv2_path_prefix` (`<app>/`), `name`, `database`.
## Dépendances (à respecter)
> [!IMPORTANT]
> Ce Terraform **suppose** que deux choses existent déjà :
> - le rôle Postgres `<app>_role` (créé à l'[étape 2](02-database.md)) — sinon le `GRANT <app>_role TO …` du rôle dynamique est invalide ;
> - le rôle JWT `gitea_cicd_<app>` et la policy `<app>` (créés à l'[étape 3](03-vault-platform.md)) — sinon l'authentification du provider échoue / le rôle K8s ne peut référencer la policy.
>
> Ce `iac/` est appliqué par la CI de l'app, voir [étape 6](06-ci-workflows.md). Ne pas pousser ce dossier avant d'avoir appliqué les étapes 2 et 3.
## Notes / contraintes
- Le module est récupéré **en SSH** via le bot `tofu_module_reader` (cf. [étape 1](01-gitea-repo.md)) ; `?ref=main&depth=1` épingle la branche et limite le clone.
- L'état est isolé par `prefix = "<app>/main"` : pas de collision entre apps dans le bucket `arcodange-tf`.
- `erp` et `webapp` montrent deux variantes : `erp` passe par `module "app_roles"` ; `webapp` inline encore les ressources (`vault_database_secret_backend_role` + `vault_kubernetes_auth_backend_role`) — préférer le module pour une nouvelle app.
## Related
- [2. Base de données](02-database.md) — fournit `<app>_role`.
- [3. Vault plateforme](03-vault-platform.md) — fournit `gitea_cicd_<app>` et la policy `<app>`.
- [4. Chart Helm](04-helm-chart.md) — consomme `postgres/creds/<app>`, le rôle K8s `<app>` et `kvv2/<app>/config`.
- [6. Workflows CI](06-ci-workflows.md) — applique ce `iac/`.