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>
Factory > Doc > Runbooks > Nouvelle application web
Mettre en service une nouvelle application web
Last Updated: 2026-05-31 Status: ✅ Procédure courante Related: Conventions de nommage · Checklist · ADR CI/CD · ADR Vault
C'est quoi ?
Ce runbook décrit, de zéro, comment faire vivre une nouvelle application web sur la plateforme Arcodange. Le pattern est GitOps : l'app habite son propre dépôt Gitea, sa base de données et ses accès Vault sont provisionnés par Terraform/OpenTofu, et ArgoCD déploie son chart Helm dans un namespace dédié. Les identifiants Postgres ne sont jamais écrits en clair : ils sont générés à la volée par Vault et injectés dans le pod par le Vault Secrets Operator (VSO).
La mécanique est répartie sur trois dépôts — le dépôt plateforme factory, le dépôt des services partagés tools, et le nouveau dépôt de l'app — avec des dépendances d'ordre strictes (voir plus bas). Les exemples de référence sont erp (image publique + DB) et webapp (image maison + DB).
Sert à :
- Créer un dépôt Gitea et son squelette (
chart/,iac/,.gitea/workflows/). - Provisionner la base de données, son rôle propriétaire, et les accès Vault (statiques + dynamiques).
- Déployer l'app via ArgoCD et l'exposer derrière Traefik (interne
.labou public.fr+ CrowdSec).
Carte de bout en bout
%%{init: {'theme': 'base'}}%%
flowchart TB
classDef step fill:#2563eb,stroke:#1e40af,color:#fff
classDef plat fill:#059669,stroke:#047857,color:#fff
classDef gitops fill:#7c3aed,stroke:#6d28d9,color:#fff
classDef run fill:#b45309,stroke:#92400e,color:#fff
REPO["1 · Dépôt Gitea<br>arcodange-org/‹app›"]:::step
DB["2 · factory/postgres/iac<br>base ‹app› + rôle ‹app›_role"]:::plat
VAULT["3 · tools/hashicorp-vault/iac<br>gitea_cicd_‹app› + policies ‹app› / ‹app›-ops"]:::plat
CONTENT["4·5·6 · chart/ + iac/ + .gitea/<br>push → CI build image & tofu apply"]:::step
ARGO["7 · factory/argocd/values.yaml<br>→ Application ArgoCD (ns ‹app›)"]:::gitops
POD["Runtime · Pod(SA ‹app›) → VSO → Vault<br>creds/‹app› → pgbouncer.tools → base ‹app›"]:::run
REPO --> DB
REPO --> VAULT
DB --> CONTENT
VAULT --> CONTENT
CONTENT --> ARGO
ARGO --> POD
Ordre des opérations (le point le plus important)
Important
Les étapes ne sont pas interchangeables. Le rôle JWT de CI
gitea_cicd_<app>(étape 3) et le rôle Postgres<app>_role(étape 2) doivent exister avant que la CI Terraform de l'app (étape 6 appliquant l'étape 5) ne s'exécute — sinon l'authentification Vault de la CI échoue, ou le moduleapp_rolesn'a pas de<app>_roleà qui rattacher les credentials dynamiques.
[01] Dépôt Gitea sous arcodange-org (hérite les secrets CI d'org)
│
├──> [02] factory/postgres/iac → base <app> + <app>_role + user_lookup()
│
└──> [03] tools/hashicorp-vault/iac → gitea_cicd_<app> (JWT CI) + policies <app> / <app>-ops
│ (02 et 03 indépendants entre eux, mais TOUS DEUX avant 05)
▼
[04+05+06] Contenu du dépôt : chart/ + iac/ + .gitea/workflows/ (+ Dockerfile)
│ push → CI « dockerimage » build l'image · CI « vault » applique iac/
│ → creds/<app> (rôle DB dynamique) + rôle K8s <app> + secrets KV
▼
[07] factory/argocd/values.yaml → ArgoCD crée l'Application → déploie le chart dans le namespace <app>
▼
Runtime : Pod(SA <app>) → VSO → VaultAuth(role <app>) → creds/<app>
→ user PG dynamique héritant de <app>_role → pgbouncer.tools → base <app>
Prérequis plateforme (déjà en place)
Ces fondations existent et ne sont pas à refaire pour chaque app :
| Brique | Où | Rôle |
|---|---|---|
Mounts Vault kvv2, postgres, transit, auth kubernetes |
tools/hashicorp-vault/iac/main.tf |
Moteurs de secrets + auth K8s |
Connexion Vault→Postgres (via pgbouncer.tools, user credentials_editor) |
idem | Permet à Vault d'émettre des users PG dynamiques |
Rôle JWT de bootstrap gitea_cicd + app OAuth2 Gitea (gitea_app_id) |
gitea_oidc_auth.yml |
Échange OIDC Gitea → JWT Vault dans la CI |
Bot tofu_module_reader (clé SSH dans kvv1/gitea/tofu_module_reader) |
factory/iac/gitea_tofu_ci_user.tf |
Laisse la CI cloner le module partagé tools en SSH |
Secrets Actions d'organisation (HOMELAB_CA_CERT, vault_oauth__sh_b64, PACKAGES_TOKEN) |
org Gitea arcodange-org |
Hérités par tout dépôt de l'org |
Index des étapes
| # | Page | Ce qu'on y fait | Statut |
|---|---|---|---|
| — | Conventions de nommage | Le nom <app> réutilisé à l'identique partout (à lire en premier) |
✅ |
| 01 | Dépôt Gitea | Créer le dépôt sous arcodange-org + squelette |
✅ |
| 02 | Base de données | factory/postgres/iac → base <app> + rôle <app>_role |
✅ |
| 03 | Vault plateforme | tools/hashicorp-vault/iac → gitea_cicd_<app> + policies |
✅ |
| 04 | Chart Helm | Le chart de l'app (DB via pgbouncer, secrets VSO, ingress) | ✅ |
| 05 | Terraform de l'app | iac/ → module app_roles (creds dynamiques + rôle K8s) |
✅ |
| 06 | Workflows CI | .gitea/workflows/ : tofu apply + build image |
✅ |
| 07 | Enregistrement ArgoCD | factory/argocd/values.yaml → Application + déploiement |
✅ |
| 08 | Checklist | Récapitulatif ordonné + definition of done | ✅ |
Légende de statut
✅ actif · 🟡 dégradé/beta · 🔴 critique/EOL · ⚠️ problème connu · ❌ désactivé
Comment éditer ce runbook
- Ajouter une page → la créer depuis le template tree-docs adéquat et ajouter sa ligne dans l'index ci-dessus.
- Garder les liens croisés bidirectionnels → toute dépendance citée dans une page (
Upstream/Downstream) doit avoir sa réciproque sur l'autre page. - Mettre à jour
Last Updated:ci-dessus après tout changement de structure. - Les exemples cités (
erp,webapp) sont vivants : revérifier les snippets contre le code réel avant de s'y fier aveuglément.