SOGOMS v1.0.7 - 2FA obligatoire et Infrastructure Management

Phase 17g - Double Authentification:
- TOTP avec Google Authenticator/Authy
- QR code pour enrôlement
- Codes de backup (10 codes usage unique)
- Page /admin/security pour gestion 2FA
- Page /admin/users avec Reset 2FA (super_admin)
- 2FA obligatoire pour rôles configurés

Phase 21 - Infrastructure Management:
- SQLite pour données infra (/data/infra.db)
- SSH Pool avec reconnexion auto
- Gestion Incus (list, start, stop, restart, sync)
- Gestion Nginx (test, reload, deploy, sync, certbot)
- Interface admin /admin/infra
- Formulaire ajout serveur
- Page détail serveur avec containers et sites

Fichiers créés:
- internal/infra/ (db, models, migrations, repository, ssh, incus, nginx)
- cmd/sogoms/admin/totp.go
- cmd/sogoms/admin/handlers_2fa.go
- cmd/sogoms/admin/handlers_infra.go
- Templates: 2fa_*, security, users, infra, server_*

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-26 21:21:11 +01:00
parent 1274400b08
commit 0b1977e0c4
37 changed files with 4976 additions and 148 deletions

306
TODO.md
View File

@@ -362,6 +362,54 @@ users:
email: pierre@example.com
```
### 17g. Double Authentification (2FA) - OBLIGATOIRE
**Prérequis de sécurité** : l'accès à l'admin SOGOMS doit être protégé par 2FA.
- [x] Package Go `github.com/pquerna/otp` pour TOTP
- [x] Package Go `github.com/skip2/go-qrcode` pour QR codes
- [x] Stockage 2FA dans admin_users.yaml (two_fa_enabled, two_fa_secret, backup_codes)
- [x] Enrôlement TOTP :
- [x] Page `/admin/2fa/setup` : configuration 2FA
- [x] Génération secret TOTP (base32, 160 bits)
- [x] Affichage QR code pour scan (Google Auth, Authy, etc.)
- [x] Saisie code de vérification pour activer
- [x] Génération 10 codes de backup format XXXX-XXXX (usage unique)
- [x] Login avec 2FA :
- [x] Après password valide → page saisie code TOTP (`/admin/2fa/verify`)
- [x] Validation code TOTP (fenêtre ±30s)
- [x] Option "code de backup" si téléphone perdu
- [x] Session marquée `TwoFAVerified`
- [ ] Fallback Email OTP :
- [ ] Si TOTP non configuré → envoi code 6 chiffres par email
- [ ] Code valide 10 minutes, usage unique
- [ ] Utilise sogoms-smtp existant
- [x] Politique :
- [x] 2FA obligatoire pour rôles configurés (`required_roles`)
- [x] 2FA optionnel pour autres rôles
- [x] Forcer configuration 2FA à la première connexion si requis
- [x] Recovery :
- [x] Reset 2FA par super_admin (page `/admin/users`)
- [x] Audit log des actions 2FA (2fa_reset loggé)
- [x] Page `/admin/security` : gestion 2FA utilisateur
- [x] Page `/admin/users` : liste utilisateurs + bouton Reset 2FA (super_admin)
- [x] Config admin_users.yaml :
```yaml
two_fa:
enabled: true
issuer_name: "SOGOMS Admin"
required_roles: [super_admin]
users:
- username: pierre
password_hash: "$2a$12$..."
role: super_admin
email: pierre@example.com
two_fa_enabled: true
two_fa_secret: "BASE32SECRET..."
backup_codes: ["$2a$...", ...] # bcrypt hashed
```
## Hors scope V1
- sogorch (orchestrateur scénarios)
@@ -424,6 +472,264 @@ Note : le bouton "Scanner la base" (19b) fait office d'Update Schema.
- [ ] JWT secret : auto-généré (openssl rand -base64 32)
- [ ] Permissions fichiers : 600
## Phase 20 : Soft Delete
Objectif : supporter la suppression logique pour les tables ayant un champ `deleted_at`.
### 20a. Détection lors du scan DB
- [x] Introspection : détecter colonne `deleted_at` (TIMESTAMP ou DATETIME)
- [x] Schema.yaml : ajouter propriété `soft_delete: true` sur la table
- [x] Affichage admin : indicateur visuel tables avec soft delete (*)
### 20b. Comportement DELETE
- [x] Route DELETE : UPDATE `deleted_at = NOW()` au lieu de DELETE physique
- [x] Queries YAML : support soft_delete via schema
- [x] Réponse API : retourner `affected_rows` comme avant
- [x] Support paramètre `raw` dans sogoms-db pour expressions SQL brutes
### 20c. Filtrage automatique SELECT
- [x] Routes list/show : ajouter `WHERE deleted_at IS NULL` automatiquement
- [x] Schema-driven : BuildListQuery/BuildShowQuery avec filtre soft delete
- [x] Queries YAML : fonction addSoftDeleteFilter() pour injection automatique
- [ ] Option `include_deleted: true` pour voir les supprimés (admin)
### 20d. Restauration (optionnel)
- [ ] Route `POST /api/{resource}/{id}/restore` : remet `deleted_at = NULL`
- [ ] Permission spécifique pour restauration
- [ ] Logging de l'action restore
### 20e. Purge définitive (optionnel)
- [ ] Route `DELETE /api/{resource}/{id}/purge` : suppression physique
- [ ] Permission admin requise
- [ ] Confirmation double (paramètre `force=true`)
### 20f. Cascade Soft Delete
- [x] Détecter les tables enfants via FK (ex: tasks.project_id → projects)
- [x] Lors du soft delete parent, soft delete automatique des enfants
- [x] Récursion : petits-enfants supprimés avant enfants (depth-first)
- [x] Option `cascade: true` dans schema.yaml (auto-détecté lors du scan)
- [x] Auto-détection : cascade activé si parent a soft_delete ET enfants avec soft_delete
- [ ] Logging des suppressions en cascade
---
## Phase 21 : Infrastructure Management
Objectif : piloter depuis l'admin SOGOMS les configurations Nginx, serveurs et containers Incus.
### 21a. Modèle de données
- [x] Table `servers` : id, name, host (IP/hostname), vpn_ip, ssh_port, ssh_user, ssh_key_file, has_incus, has_nginx, status
- [x] Table `containers` : id, server_id, name, incus_name, ip, vpn_ip, image, status (running/stopped/unknown)
- [x] Table `nginx_configs` : id, server_id, domain, type, template, upstream, ssl_enabled, config_content, status
- [x] Table `app_bindings` : id, app_id, container_id, nginx_config_id, server_id, type
- [x] Stockage : SQLite local `/data/infra.db` (flag `-infra-db`)
- [x] Migration : auto-création tables au démarrage (`internal/infra/migrations.go`)
### 21b. SSH Pool (intégré dans sogoms-admin)
- [x] `internal/infra/ssh.go` : client SSH avec pool de connexions
- [x] Pool de connexions SSH vers serveurs configurés
- [x] Reconnexion automatique en cas de perte (isAlive check)
- [x] Méthodes SSH :
- [x] `Exec` / `ExecSimple` : exécute commande sur serveur
- [x] `WriteFile` / `ReadFile` : lecture/écriture fichiers distants
- [x] `CopyFile` / `CopyFrom` : copie fichiers local ↔ distant
- [x] `StreamExec` : exécution avec streaming stdout/stderr
- [x] Config : clé SSH stockée dans SQLite (chemin fichier)
- [x] Sécurité : accès restreint super_admin uniquement
### 21c. Gestion Incus (containers)
- [x] `internal/infra/incus.go` : méthodes Incus via SSH
- [x] Action `ListIncusContainers` : liste containers (`incus list --format json`)
- [ ] Action `incus_create` : crée un container (image, nom, config)
- [x] Action `StartIncusContainer` : démarre un container
- [x] Action `StopIncusContainer` : arrête un container (graceful)
- [x] Action `RestartIncusContainer` : redémarre un container
- [ ] Action `incus_delete` : supprime un container (avec confirmation)
- [x] Action `ExecInContainer` : exécute une commande dans un container
- [ ] Action `incus_copy` : copie un container (backup/clone)
- [ ] Action `incus_move` : migre un container vers un autre serveur
- [ ] Action `incus_snapshot` : crée un snapshot
- [x] Sync : synchronisation containers Incus → base SQLite
- [ ] Templates : images préconfigurées (alpine-sogoms, alpine-node, alpine-nginx)
- [ ] Réseau : attribution IP automatique ou manuelle
### 21d. Gestion Nginx
- [x] `internal/infra/nginx.go` : méthodes Nginx via SSH
- [ ] Templates Nginx dans `config/nginx-templates/`
- [ ] `frontend.conf.tmpl` : proxy vers container frontend
- [ ] `api.conf.tmpl` : proxy vers sogoway (local ou distant via VPN)
- [ ] `admin.conf.tmpl` : proxy vers sogoms-admin
- [ ] `ssl.conf.tmpl` : config SSL commune (Let's Encrypt)
- [x] Action `GenerateNginxProxyConfig` : génère config proxy standard
- [x] Action `DeployNginxSite` : écrire + activer + recharger
- [x] Action `TestNginxConfig` : `nginx -t` sur le serveur cible
- [x] Action `ReloadNginx` : `systemctl reload nginx` sur le serveur cible
- [x] Action `ListNginxSites` : liste sites-available/enabled
- [x] Action `EnableNginxSite` / `DisableNginxSite` : gestion liens symboliques
- [x] Action `DeleteNginxSite` : supprime une config
- [x] Sync : synchronisation sites Nginx → base SQLite
- [x] Gestion Let's Encrypt : `RequestSSLCertificate` via certbot
- [ ] Rollback : sauvegarde config avant modification
### 21e. Interface Admin
- [x] Page `/admin/infra` : dashboard infrastructure (liste serveurs, stats)
- [x] Lien "Infra" dans header (super_admin only)
- [x] Section Serveurs :
- [x] Liste serveurs avec statut (online/offline/unknown)
- [x] Badges Incus/Nginx pour services disponibles
- [x] Bouton test connexion SSH
- [x] Formulaire ajout serveur (nom, host, vpn_ip, ssh_user, ssh_key_file, port)
- [x] Page détail serveur : containers, configs nginx
- [x] Bouton suppression serveur
- [x] Section Containers :
- [x] Liste containers par serveur
- [x] Statut (running/stopped/unknown)
- [x] Actions : start, stop, restart
- [x] Bouton sync depuis Incus
- [ ] Formulaire création container (serveur, image, nom, IP)
- [ ] Logs container (dernières lignes)
- [x] Section Nginx :
- [x] Liste sites par serveur/domaine
- [x] Statut : active/inactive
- [x] Bouton sync depuis serveur
- [x] Bouton reload Nginx
- [ ] Éditeur config (lecture seule ou édition avancée)
- [ ] Historique déploiements
- [ ] Section Apps :
- [ ] Vue unifiée : app → container frontend + config nginx + API sogoms
- [ ] Wizard création app complète (voir 21f)
**⚠️ À TESTER** : Interface infra déployée, valider fonctionnement avec serveur réel.
### 21f. Orchestration (Workflows)
Workflows automatisés pour opérations complexes.
- [ ] Workflow `app_create_full` : création app complète
1. Créer container frontend sur serveur cible
2. Configurer container (packages, user, etc.)
3. Générer config Nginx frontend
4. Générer config Nginx API (proxy vers sogoway)
5. Déployer configs Nginx
6. Créer config app SOGOMS (`config/apps/{app}/`)
7. Recharger sogoway
- [ ] Workflow `app_migrate` : migration app vers autre serveur
1. Snapshot container source
2. Copier vers serveur destination
3. Mettre à jour configs Nginx
4. Basculer DNS (notification)
5. Supprimer ancien container (optionnel)
- [ ] Workflow `ssl_setup` : configuration SSL
1. Vérifier DNS pointe vers serveur
2. Exécuter certbot
3. Mettre à jour config Nginx
4. Recharger Nginx
- [ ] Logging : toutes étapes loggées dans sogoms-logs
- [ ] Rollback : annulation automatique si échec
### 21g. API Interne
Endpoints admin pour piloter l'infrastructure.
- [ ] `GET /admin/api/infra/servers` : liste serveurs
- [ ] `POST /admin/api/infra/servers` : ajoute serveur
- [ ] `DELETE /admin/api/infra/servers/{id}` : supprime serveur
- [ ] `POST /admin/api/infra/servers/{id}/test` : teste connexion
- [ ] `GET /admin/api/infra/containers` : liste containers (tous serveurs)
- [ ] `GET /admin/api/infra/containers/{server_id}` : containers d'un serveur
- [ ] `POST /admin/api/infra/containers` : crée container
- [ ] `POST /admin/api/infra/containers/{id}/start` : démarre
- [ ] `POST /admin/api/infra/containers/{id}/stop` : arrête
- [ ] `DELETE /admin/api/infra/containers/{id}` : supprime
- [ ] `GET /admin/api/infra/nginx` : liste configs nginx
- [ ] `POST /admin/api/infra/nginx/generate` : génère config
- [ ] `POST /admin/api/infra/nginx/deploy` : déploie config
- [ ] `POST /admin/api/infra/nginx/reload/{server_id}` : reload nginx
- [ ] `POST /admin/api/infra/workflows/{name}` : lance workflow
### 21h. Configuration exemple
```yaml
# /secrets/infra_servers.yaml
servers:
- name: IN3
host: 195.154.80.116
vpn_ip: 11.1.2.1
ssh_user: root
ssh_key_file: /secrets/ssh_in3_key
ssh_port: 22
type: host
incus: true
- name: IN4
host: 195.154.xx.xx
vpn_ip: 11.1.2.14
ssh_user: root
ssh_key_file: /secrets/ssh_in4_key
ssh_port: 22
type: host
incus: true
# Templates Nginx
nginx:
templates_dir: /config/nginx-templates
certbot_email: admin@sogoms.com
```
```nginx
# config/nginx-templates/api.conf.tmpl
server {
server_name {{.Domain}};
location /api/ {
proxy_pass http://{{.ApiUpstream}};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
{{if .SSLEnabled}}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/{{.Domain}}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{.Domain}}/privkey.pem;
{{else}}
listen 80;
{{end}}
}
```
### 21i. Sécurité
- [ ] Clés SSH : fichiers séparés dans `/secrets/`, permissions 600
- [ ] Accès : super_admin uniquement pour toutes opérations infra
- [ ] Audit : toutes actions loggées (qui, quoi, quand, serveur)
- [ ] Rate limiting : max 10 opérations/minute par user
- [ ] Confirmation : double confirmation pour actions destructives (delete container)
- [ ] Isolation : sogoms-infra tourne avec user dédié
### 21j. Dépendances
- Phase 17 (Admin UI) ✅
- Phase 19 (Création App) ✅
- Accès SSH aux serveurs (clés à configurer)
- Incus installé sur les serveurs hôtes
- [x] Package Go : `golang.org/x/crypto/ssh`
- [x] Package Go : `github.com/mattn/go-sqlite3`
---
## Phase 18 : Application Geosector (Janvier-Février 2026)
Migration de l'API PHP 8.3 existante vers SOGOMS pour l'application Flutter (Web + mobiles).