Set-OPS — moteur d'ecosystemes numeriques souverains (Alliance Boreale)
This commit is contained in:
commit
3dd3f43ad8
308 changed files with 13649 additions and 0 deletions
7
.ansible-lint
Normal file
7
.ansible-lint
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Les fichiers sous docs/ sont des REGISTRES DE DONNEES (consommes par Python),
|
||||
# pas du contenu Ansible : nomenclature alignee pour la lisibilite, serveurs.yml
|
||||
# genere par safe_dump. Les regles yaml d'ansible-lint ne s'y appliquent pas.
|
||||
exclude_paths:
|
||||
- docs/
|
||||
- instance/
|
||||
- exemples/
|
||||
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
*.retry
|
||||
# Instance (plan + inventaire) : depot separe, monte ici par symlink (modele A).
|
||||
/instance
|
||||
.vault-pass
|
||||
facts_cache/
|
||||
.ansible/
|
||||
*.vault
|
||||
*.vault.yml
|
||||
*.secret
|
||||
*.pem
|
||||
*.key
|
||||
*.p12
|
||||
*.pfx
|
||||
.env
|
||||
.env.*
|
||||
id_rsa
|
||||
id_ed25519
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.vscode/
|
||||
.idea/
|
||||
tmp/
|
||||
dist/
|
||||
*.tar
|
||||
*.tar.gz
|
||||
*.zip
|
||||
exemples/modeles/*/inventories/*/hosts*.yml
|
||||
690
AGENTS.md
Normal file
690
AGENTS.md
Normal file
|
|
@ -0,0 +1,690 @@
|
|||
# AGENTS.md — Set-OPS
|
||||
|
||||
## Rôle du dépôt
|
||||
|
||||
Ce dépôt contient les playbooks, rôles, inventaires et templates Ansible servant à construire, configurer, maintenir et documenter les serveurs d’un écosystème numérique souverain.
|
||||
|
||||
`Set-OPS` est le moteur global d’exploitation d’écosystèmes numériques souverains.
|
||||
|
||||
Le template Debian 13 Proxmox est seulement un sous-ensemble du dépôt. Le dépôt ne doit jamais être restructuré autour d’un seul besoin ponctuel.
|
||||
|
||||
---
|
||||
|
||||
## Mission et identité
|
||||
|
||||
Au-delà de l’exploitation, `Set-OPS` **définit et construit un écosystème numérique souverain** : une infrastructure interne auto-suffisante, sans dépendance SaaS, dont tous les piliers sont décrits en code et reliés entre eux.
|
||||
|
||||
Piliers de l’écosystème :
|
||||
|
||||
- identité — machines (PKI / certificats) et utilisateurs (annuaire + SSO) ;
|
||||
- confiance — autorité de certification interne (ACME) ;
|
||||
- nommage et adressage — DNS interne et nomenclature dérivable ;
|
||||
- données — bases relationnelles et cache, avec registre des connexions ;
|
||||
- communication — relais courriel interne ;
|
||||
- observabilité et supervision — métriques, journaux, tableaux de bord, supervision active ;
|
||||
- applicatif — services internes (forge, etc.) et couche web.
|
||||
|
||||
Propriétés visées, avec leurs nuances honnêtes :
|
||||
|
||||
- **Souverain / auto-suffisant** : c’est l’objectif. Aucune dépendance à un service externe pour la confiance, l’identité, le nom ou la communication. Cela justifie le choix de construire plutôt qu’assembler des SaaS.
|
||||
- **Déclaratif et convergent** : l’état voulu est décrit dans des registres machine-lisibles (`instance/plan/nomenclature.yml`, `docs/dependances-groupes.yml`, `instance/plan/bases-donnees.yml`) et appliqué par les groupes Ansible. Ces registres sont la **source unique de vérité**.
|
||||
- **Pas (encore) auto-réparé** : la convergence est pilotée par l’opérateur (GUI / CLI / `make`), pas une boucle fermée d’auto-remédiation.
|
||||
- **Définition avant déploiement** : une grande partie est planifiée et validée (`--syntax-check`, `ansible-lint`) mais pas encore exécutée contre des VM réelles. Ne jamais présenter un rôle non déployé comme « en production ».
|
||||
|
||||
Conséquence pour le travail : préserver la discipline qui tient l’ensemble — registres comme source unique, dépendances explicites, validation de chaque pièce, secrets hors dépôt. C’est ce qui empêche l’écosystème de devenir un objet ingérable. Le template Debian 13 reste la fondation (le moule des VM), pas la finalité.
|
||||
|
||||
---
|
||||
|
||||
## Le plan et la génération de l’inventaire (méta-classe)
|
||||
|
||||
`Set-OPS` se pilote par un **plan**, pas par l’édition directe de l’inventaire.
|
||||
L’inventaire Ansible est **généré** depuis le plan.
|
||||
|
||||
**RÈGLE D’OR : `instance/inventories/production/hosts.yml` est un artefact GÉNÉRÉ. Ne jamais l’éditer à la main.** On édite le *plan*, puis on régénère.
|
||||
|
||||
- L’**application** est l’entité pivot ; le **groupe** Ansible n’est qu’une capacité (le rôle appliqué), plus une cible de liaison.
|
||||
- Le plan vit dans des registres machine-lisibles : `instance/plan/serveurs.yml` (les VM), `instance/plan/applications.yml` (les services et leurs liens `requiert`/`utilise`/`expose`), `instance/plan/bases-donnees.yml`, `instance/plan/domaines.yml`, `instance/plan/nomenclature.yml`.
|
||||
- Génération : `make instancier` (génère + diff sémantique), `make instancier-appliquer` (régénère `hosts.yml`, refuse si le diff n’est pas vide — `FORCE=1` pour un changement intentionnel).
|
||||
- Flux : **éditer le plan → `make instancier` (revoir le diff) → `make instancier-appliquer` → déployer**. Via le GUI : vues **Serveurs** et **Applications**, puis « Appliquer le plan » (la vue Inventaire est en lecture seule).
|
||||
- VMID / IP / VLAN / passerelle sont **dérivés** de la `fonction` via la nomenclature ; les groupes d’une VM sont dérivés (socle + services des applications + intégrations + état).
|
||||
- Garde-fous : validateurs de registres, diff-vide, `node --check` du JS du GUI (`scripts/verifier_gui.py`, dans `make inventaire-verifier`), git comme filet.
|
||||
|
||||
Référence complète : **`docs/plan-et-generation.md`**.
|
||||
|
||||
**Plan de contrôle gelé en périmètre** : le GUI, le générateur, l'IPAM et la modélisation sont volontairement *maison* et **souverains**, mais leur périmètre est gelé. Ne pas y ajouter de fonctionnalités de type NetBox/AWX (RBAC, historique d'audit, détection de conflits IPAM, API riche) : le besoin réel d'une de ces fonctions est le **signal d'adopter l'outil mûr correspondant** (NetBox pour la source de vérité, AWX pour l'exécution), pas de le réimplémenter. Décision et seuils : **`docs/positionnement.md`**.
|
||||
|
||||
---
|
||||
|
||||
## Règle d’or IA
|
||||
|
||||
Un seul agent IA travaille dans ce dépôt à la fois.
|
||||
|
||||
- Soit Codex.
|
||||
- Soit Claude Code.
|
||||
- Jamais les deux simultanément.
|
||||
|
||||
Tout changement significatif doit être consigné dans `CHANGELOG.md`.
|
||||
|
||||
---
|
||||
|
||||
## Principes
|
||||
|
||||
1. Toujours lire l’existant avant de modifier.
|
||||
2. Ne jamais introduire de secret en clair.
|
||||
3. Ne jamais casser l’idempotence Ansible.
|
||||
4. Ne jamais exécuter d’action destructive sans confirmation explicite.
|
||||
5. Préférer la simplicité à l’ingénierie excessive.
|
||||
6. Documenter ce qui est utile à l’exploitation réelle.
|
||||
7. Préférer les correctifs ciblés aux régénérations massives.
|
||||
8. Ne jamais supposer qu’un rôle est complet sans l’avoir inspecté.
|
||||
9. Ne jamais déclarer un playbook prêt si la validation minimale échoue.
|
||||
10. **Impératif : Set-OPS doit rester pleinement exploitable par un humain SANS IA.** La doc, `make` et le GUI sont l’interface primaire et complète. Ne jamais introduire de fonctionnalité qui *exige* une IA pour s’en servir. L’IA n’assiste que le mainteneur pour faire évoluer l’outil — jamais l’utilisateur final. (Le bon étalon : un sysadmin humain réussit depuis la doc. `AGENTS.md`/`CLAUDE.md` ne font pas partie de l’outil livré.)
|
||||
|
||||
---
|
||||
|
||||
## Sécurité
|
||||
|
||||
Ne jamais commiter :
|
||||
|
||||
- mots de passe ;
|
||||
- clés privées SSH ;
|
||||
- tokens API ;
|
||||
- secrets non chiffrés ;
|
||||
- fichiers `.env` sensibles ;
|
||||
- certificats privés ;
|
||||
- backups réels ;
|
||||
- exports de production non anonymisés.
|
||||
|
||||
Les secrets doivent être gérés hors dépôt ou avec un mécanisme explicitement prévu, par exemple :
|
||||
|
||||
- Ansible Vault ;
|
||||
- fichier local non versionné ;
|
||||
- secret injecté hors dépôt ;
|
||||
- gestionnaire de secrets approuvé.
|
||||
|
||||
---
|
||||
|
||||
## Actions destructives
|
||||
|
||||
Toute action destructive doit exiger une variable explicite, par exemple :
|
||||
|
||||
```yaml
|
||||
confirm_destructive_action: true
|
||||
```
|
||||
|
||||
Sont considérées comme destructives ou risquées :
|
||||
|
||||
- modification bloquante de SSH ;
|
||||
- activation ou modification d’un pare-feu ;
|
||||
- suppression d’utilisateurs ;
|
||||
- suppression de paquets critiques ;
|
||||
- formatage disque ;
|
||||
- modification de partitions ;
|
||||
- redémarrage massif ;
|
||||
- purge de données ;
|
||||
- changement réseau pouvant couper l’accès ;
|
||||
- modification d’un hyperviseur Proxmox ;
|
||||
- opération sur stockage, iSCSI, ZFS ou Ceph.
|
||||
|
||||
Sans confirmation explicite, refuser l’exécution.
|
||||
|
||||
---
|
||||
|
||||
## Règle de modification du dépôt
|
||||
|
||||
Avant toute modification, exécuter ou demander l’équivalent de :
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
find . -maxdepth 3 -type f | sort
|
||||
```
|
||||
|
||||
Ne pas remplacer massivement l’arborescence sans demande explicite.
|
||||
|
||||
Avant de modifier un fichier, lire son contenu actuel.
|
||||
|
||||
Après modification, indiquer clairement :
|
||||
|
||||
- les fichiers créés ;
|
||||
- les fichiers modifiés ;
|
||||
- les commandes de validation exécutées ;
|
||||
- les tests non exécutés ;
|
||||
- les limites connues.
|
||||
|
||||
---
|
||||
|
||||
## Validation Ansible obligatoire
|
||||
|
||||
Avant de proposer un changement comme terminé, vérifier au minimum la syntaxe du playbook touché.
|
||||
|
||||
Exemple pour le template Debian 13 Proxmox :
|
||||
|
||||
```bash
|
||||
ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_preparer.yml --syntax-check
|
||||
```
|
||||
|
||||
Pour un autre playbook, remplacer le chemin par le playbook concerné.
|
||||
|
||||
Ne jamais déclarer un playbook prêt si `--syntax-check` échoue.
|
||||
|
||||
Si `ansible-lint` est disponible, l’utiliser :
|
||||
|
||||
```bash
|
||||
ansible-lint
|
||||
```
|
||||
|
||||
Si `ansible-lint` n’est pas disponible, le signaler clairement. Ne pas inventer un résultat.
|
||||
|
||||
---
|
||||
|
||||
## Règle pour les handlers Ansible
|
||||
|
||||
Chaque rôle qui utilise `notify` doit contenir son handler dans le rôle lui-même.
|
||||
|
||||
Exemple :
|
||||
|
||||
```text
|
||||
roles/ssh_baseline/tasks/main.yml
|
||||
roles/ssh_baseline/handlers/main.yml
|
||||
```
|
||||
|
||||
Ne pas dépendre d’un handler défini dans un autre rôle, sauf justification explicite.
|
||||
|
||||
Tout `notify` doit pointer vers un handler existant.
|
||||
|
||||
Commandes de vérification utiles :
|
||||
|
||||
```bash
|
||||
find roles -path '*/tasks/*.yml' -exec grep -H "notify:" {} \;
|
||||
find roles -path '*/handlers/main.yml' -print
|
||||
```
|
||||
|
||||
Avant de livrer un rôle, vérifier que chaque handler référencé existe réellement.
|
||||
|
||||
---
|
||||
|
||||
## Style Ansible attendu
|
||||
|
||||
Les playbooks doivent être :
|
||||
|
||||
- idempotents ;
|
||||
- lisibles ;
|
||||
- sobres ;
|
||||
- compatibles Debian 13 sauf exception documentée ;
|
||||
- testables avec `--check` autant que possible ;
|
||||
- sécuritaires par défaut ;
|
||||
- sans dépendances SaaS ou cloud inutiles.
|
||||
|
||||
Préférer les modules Ansible standards :
|
||||
|
||||
- `ansible.builtin.apt`
|
||||
- `ansible.builtin.template`
|
||||
- `ansible.builtin.copy`
|
||||
- `ansible.builtin.service`
|
||||
- `ansible.builtin.systemd`
|
||||
- `ansible.builtin.lineinfile`
|
||||
- `ansible.builtin.file`
|
||||
- `ansible.builtin.user`
|
||||
- `ansible.builtin.group`
|
||||
|
||||
Éviter `shell` et `command` sauf nécessité réelle.
|
||||
|
||||
Lorsqu’une commande shell est nécessaire, elle doit être encadrée avec les paramètres appropriés selon le cas :
|
||||
|
||||
- `changed_when`
|
||||
- `failed_when`
|
||||
- `creates`
|
||||
- `removes`
|
||||
|
||||
---
|
||||
|
||||
## Structure générale du dépôt
|
||||
|
||||
Le dépôt peut contenir progressivement :
|
||||
|
||||
```text
|
||||
inventories/
|
||||
playbooks/
|
||||
roles/
|
||||
templates/
|
||||
files/
|
||||
scripts/
|
||||
docs/
|
||||
```
|
||||
|
||||
Les playbooks peuvent être classés par domaine :
|
||||
|
||||
```text
|
||||
playbooks/
|
||||
├── groupes/
|
||||
├── maintenance/
|
||||
├── monitoring/
|
||||
├── networking/
|
||||
├── proxmox/
|
||||
├── modeles_vm/
|
||||
├── web/
|
||||
├── database/
|
||||
├── identity/
|
||||
├── backup/
|
||||
└── applications/
|
||||
```
|
||||
|
||||
Les rôles peuvent être ajoutés progressivement selon les besoins.
|
||||
|
||||
Ne pas créer de structure inutile uniquement pour donner une impression de complétude.
|
||||
|
||||
La conformité normale des VM déployées doit passer par `playbooks/groupes/`.
|
||||
|
||||
Ne pas maintenir en parallèle des playbooks de couches génériques comme `playbooks/socle/` ou `playbooks/durcissement/` lorsqu'un groupe opérationnel exprime déjà cet état voulu.
|
||||
|
||||
---
|
||||
|
||||
## Interface opérateur Makefile
|
||||
|
||||
Le `Makefile` est l'interface opérateur privilégiée pour les gestes courants.
|
||||
|
||||
Les commandes `make` doivent simplifier l'exploitation Ansible sans masquer les playbooks réellement exécutés.
|
||||
|
||||
Préférer quelques cibles claires et utiles :
|
||||
|
||||
- validation du dépôt ;
|
||||
- inspection des inventaires ;
|
||||
- ajout ou mise à jour d'un hôte dans un inventaire ;
|
||||
- association d'un hôte à ses groupes ;
|
||||
- déploiement ou remise en conformité d'un hôte ;
|
||||
- déploiement ou remise en conformité d'un groupe ;
|
||||
- préparation, vérification et nettoyage protégé d'un modèle de VM.
|
||||
|
||||
Ne pas multiplier les cibles `make` secondaires si elles ne correspondent pas à un geste réel d'exploitation.
|
||||
|
||||
Les cibles d'exploitation des VM doivent privilégier les groupes :
|
||||
|
||||
```text
|
||||
make deployer HOTE=web-01
|
||||
make deployer-groupe GROUPE=serveur_debian
|
||||
make hote-planifier HOTE=obs-01 VMID=94101 GROUPES="serveur_debian serveur_durci serveur_prometheus"
|
||||
```
|
||||
|
||||
Éviter les cibles parallèles qui réappliquent les mêmes rôles par couche, par exemple `make socle`, `make durcissement`, `make converger` ou `make deployer-vm`.
|
||||
|
||||
Toute cible `make` qui lance une action destructive ou risquée doit exiger une confirmation explicite.
|
||||
|
||||
---
|
||||
|
||||
## Convention groupes et playbooks
|
||||
|
||||
Chaque groupe opérationnel Ansible doit avoir un playbook homonyme dans `playbooks/groupes/`.
|
||||
|
||||
La convention attendue est :
|
||||
|
||||
```text
|
||||
groupe Ansible : serveur_debian
|
||||
playbook : playbooks/groupes/serveur_debian.yml
|
||||
```
|
||||
|
||||
L'appartenance aux groupes détermine les services, intégrations et politiques appliqués à une VM.
|
||||
|
||||
`playbooks/groupes/` est la source officielle de conformité pour les VM déployées.
|
||||
|
||||
Un playbook de groupe doit cibler son groupe homonyme, pas `all`, sauf justification explicite.
|
||||
|
||||
Les concepts comme socle Debian ou durcissement commun doivent être représentés par des groupes explicites :
|
||||
|
||||
```text
|
||||
serveur_debian -> socle commun Debian
|
||||
serveur_durci -> durcissement commun
|
||||
client_dns -> intégration cliente DNS
|
||||
client_pki -> intégration cliente PKI / ACME
|
||||
```
|
||||
|
||||
Ne pas dupliquer ces mêmes rôles dans des playbooks de couches séparés.
|
||||
|
||||
Quand un nouveau groupe opérationnel est ajouté :
|
||||
|
||||
- créer le playbook homonyme dans `playbooks/groupes/` ;
|
||||
- documenter son intention opérationnelle ;
|
||||
- déclarer ses dépendances causales dans `docs/dependances-groupes.yml` si son exécution requiert un autre service actif ;
|
||||
- prévoir les rôles nécessaires ;
|
||||
- valider au minimum sa syntaxe ;
|
||||
- l'ajouter aux facilités d'exploitation si l'opérateur doit l'utiliser directement.
|
||||
|
||||
---
|
||||
|
||||
## Cycle de vie et conformité des VM
|
||||
|
||||
Set-OPS doit gérer le cycle de vie complet des VM de l’instance :
|
||||
|
||||
```text
|
||||
VM Debian minimale
|
||||
→ goldenisation du template
|
||||
→ clonage
|
||||
→ identité initiale cloud-init
|
||||
→ conformité par groupes Ansible
|
||||
→ intégrations transversales
|
||||
→ conformité continue
|
||||
```
|
||||
|
||||
Le template est seulement la fondation. Les VM existantes et futures doivent converger vers l'état voulu par les playbooks de groupes.
|
||||
|
||||
Les rôles et playbooks doivent donc être conçus pour être relancés régulièrement, sans effet secondaire inutile.
|
||||
|
||||
Le groupe d'inventaire attendu pour les VM Debian gérées est :
|
||||
|
||||
```text
|
||||
serveur_debian
|
||||
```
|
||||
|
||||
Les groupes spécialisés doivent s'ajouter selon les besoins réels, par exemple :
|
||||
|
||||
```text
|
||||
client_dns
|
||||
client_pki
|
||||
client_ldap
|
||||
client_supervision
|
||||
client_metrique
|
||||
serveur_web_frontal
|
||||
serveur_postgresql
|
||||
serveur_prometheus
|
||||
```
|
||||
|
||||
Ne pas cibler `all` par défaut pour un playbook qui ne s'applique pas réellement à tous les hôtes.
|
||||
|
||||
---
|
||||
|
||||
## Services centraux et intégrations clientes
|
||||
|
||||
Pour chaque service d'infrastructure, distinguer deux responsabilités :
|
||||
|
||||
```text
|
||||
service serveur : installe et configure le service central
|
||||
intégration cliente : raccorde les VM au service central
|
||||
```
|
||||
|
||||
Exemples :
|
||||
|
||||
```text
|
||||
PowerDNS serveur → clients DNS / resolver / enregistrements
|
||||
step-ca serveur → confiance CA / ACME client
|
||||
LDAP serveur → SSSD / NSS / PAM client
|
||||
Keycloak serveur → intégrations OIDC applicatives
|
||||
Prometheus → node_exporter sur les VM
|
||||
Icinga2 → agent ou checks distants
|
||||
Grafana → datasources et dashboards côté plateforme
|
||||
```
|
||||
|
||||
Quand un nouveau service central est ajouté, prévoir aussi le ou les rôles clients nécessaires pour intégrer les VM existantes et futures.
|
||||
|
||||
Les dépendances entre groupes doivent être déclarées dans :
|
||||
|
||||
```text
|
||||
docs/dependances-groupes.yml
|
||||
```
|
||||
|
||||
Ces dépendances servent à refuser un déploiement lorsque les prérequis actifs sont absents et à préparer les futurs checks de supervision.
|
||||
|
||||
Les intégrations clientes doivent être :
|
||||
|
||||
- idempotentes ;
|
||||
- activables par inventaire ou variables ;
|
||||
- désactivées par défaut si leur dépendance centrale n'existe pas ;
|
||||
- documentées avec leurs prérequis ;
|
||||
- testables avec `--syntax-check` et, lorsque possible, `--check`.
|
||||
|
||||
Ne pas mettre les intégrations applicatives ou les agents spécialisés dans le golden template, sauf justification opérationnelle explicite.
|
||||
|
||||
---
|
||||
|
||||
## Variables et inventaires
|
||||
|
||||
Les variables de rôle doivent utiliser un préfixe correspondant au rôle.
|
||||
|
||||
Exemples :
|
||||
|
||||
```yaml
|
||||
ssh_durcissement_port: 22
|
||||
nftables_socle_enabled: false
|
||||
fail2ban_ssh_enabled: true
|
||||
```
|
||||
|
||||
Séparer clairement :
|
||||
|
||||
```text
|
||||
variables de template : construction du golden template
|
||||
variables de conformité : état voulu des VM déployées
|
||||
variables applicatives : services et rôles spécialisés
|
||||
```
|
||||
|
||||
Les variables de conformité ne doivent pas couper l'accès SSH, DNS ou réseau sans validation explicite.
|
||||
|
||||
Toute variable susceptible de provoquer une action destructive, bloquante ou irréversible doit exiger une confirmation explicite.
|
||||
|
||||
---
|
||||
|
||||
## Langue et nommage
|
||||
|
||||
La surface destinée à l'opérateur doit être en français.
|
||||
|
||||
À franciser :
|
||||
|
||||
- noms de groupes d'inventaire ;
|
||||
- cibles `make` ;
|
||||
- variables de commande maison ;
|
||||
- libellés et messages des scripts maison ;
|
||||
- noms des playbooks maison quand ils sont exposés à l'opérateur ;
|
||||
- documentation d'exploitation.
|
||||
|
||||
À ne pas franciser automatiquement :
|
||||
|
||||
- mots-clés Ansible (`hosts`, `roles`, `tasks`, `handlers`, `vars`, `become`) ;
|
||||
- noms de modules Ansible (`ansible.builtin.apt`, `ansible.builtin.template`, etc.) ;
|
||||
- conventions techniques imposées par un outil ;
|
||||
- noms de rôles existants, sauf demande explicite ou migration ciblée justifiée.
|
||||
|
||||
Les variables de rôle peuvent rester alignées sur le nom technique du rôle, mais elles doivent conserver un préfixe clair et stable.
|
||||
|
||||
Ne pas faire de renommage massif uniquement pour franciser si cela augmente le risque sans bénéfice opérationnel immédiat.
|
||||
|
||||
---
|
||||
|
||||
## Template Debian 13 Proxmox
|
||||
|
||||
Le template Debian 13 Proxmox doit rester un socle commun.
|
||||
|
||||
Il peut contenir :
|
||||
|
||||
- Debian minimal ;
|
||||
- SSH ;
|
||||
- sudo ;
|
||||
- compte technique `ansible` ;
|
||||
- sudo NOPASSWD pour `ansible` lorsque requis ;
|
||||
- `qemu-guest-agent` ;
|
||||
- `cloud-init` ;
|
||||
- `cloud-guest-utils` ;
|
||||
- chrony ;
|
||||
- outils de diagnostic de base ;
|
||||
- durcissement raisonnable ;
|
||||
- AppArmor ;
|
||||
- auditd ;
|
||||
- fail2ban SSH ;
|
||||
- unattended-upgrades ;
|
||||
- configuration journald ;
|
||||
- sysctl de sécurité ;
|
||||
- nftables installé et préparé, mais pas forcément activé.
|
||||
|
||||
Il ne doit pas contenir par défaut :
|
||||
|
||||
- NGINX ;
|
||||
- PostgreSQL ;
|
||||
- MariaDB ;
|
||||
- Docker ;
|
||||
- Podman ;
|
||||
- Redis ;
|
||||
- GitLab ;
|
||||
- Nextcloud ;
|
||||
- monitoring complet ;
|
||||
- agents applicatifs spécialisés ;
|
||||
- données propres à un clone ;
|
||||
- secrets ;
|
||||
- clés privées.
|
||||
|
||||
Les services spécialisés doivent être installés ensuite par des playbooks dédiés sur les clones.
|
||||
|
||||
---
|
||||
|
||||
## SSH
|
||||
|
||||
Le template Debian 13 Proxmox doit être construit avec un accès SSH par clé dès le départ.
|
||||
|
||||
Cloud-init doit injecter le `ciuser` et sa clé publique avant l'exécution d'Ansible.
|
||||
|
||||
État attendu :
|
||||
|
||||
```text
|
||||
PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
PubkeyAuthentication yes
|
||||
AuthenticationMethods publickey
|
||||
```
|
||||
|
||||
Ne pas lancer le playbook de préparation tant que l'accès SSH par clé au compte technique n'est pas confirmé.
|
||||
|
||||
Toute modification SSH doit valider la configuration avant rechargement :
|
||||
|
||||
```bash
|
||||
sshd -t
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pare-feu
|
||||
|
||||
Ne pas activer un pare-feu générique dans un template sans confirmation explicite.
|
||||
|
||||
Pour le template Debian 13, `nftables` peut être installé et préparé, mais rester désactivé par défaut.
|
||||
|
||||
L’activation du pare-feu doit être faite sur un clone ou sur un serveur final, avec des règles adaptées à son rôle.
|
||||
|
||||
---
|
||||
|
||||
## Cloud-init
|
||||
|
||||
Cloud-init sert à donner l’identité initiale d’un clone :
|
||||
|
||||
- hostname ;
|
||||
- utilisateur initial ;
|
||||
- clé SSH ;
|
||||
- adresse IP ;
|
||||
- passerelle ;
|
||||
- DNS ;
|
||||
- agrandissement de la partition racine.
|
||||
|
||||
Cloud-init ne doit pas remplacer Ansible pour la configuration applicative.
|
||||
|
||||
Séparation attendue :
|
||||
|
||||
```text
|
||||
Proxmox + cloud-init : identité initiale de la VM
|
||||
Set-OPS + Ansible : configuration réelle du serveur
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Nettoyage avant template
|
||||
|
||||
Le nettoyage final avant conversion en template doit être protégé par une confirmation explicite.
|
||||
|
||||
Exemple :
|
||||
|
||||
```bash
|
||||
ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_nettoyer.yml -e template_cleanup_confirm=true
|
||||
```
|
||||
|
||||
Le nettoyage peut inclure :
|
||||
|
||||
- `cloud-init clean --logs` ;
|
||||
- nettoyage du cache APT ;
|
||||
- rotation ou purge contrôlée des journaux ;
|
||||
- vidage de `/etc/machine-id` ;
|
||||
- remise en place du lien `/var/lib/dbus/machine-id` ;
|
||||
- suppression des historiques shell.
|
||||
|
||||
Ne jamais lancer ce nettoyage sur un serveur de production sans confirmation explicite.
|
||||
|
||||
---
|
||||
|
||||
## CHANGELOG
|
||||
|
||||
Chaque modification significative doit être inscrite dans `CHANGELOG.md`.
|
||||
|
||||
Format recommandé :
|
||||
|
||||
```markdown
|
||||
## YYYY-MM-DD
|
||||
|
||||
### Ajouté
|
||||
- ...
|
||||
|
||||
### Modifié
|
||||
- ...
|
||||
|
||||
### Corrigé
|
||||
- ...
|
||||
```
|
||||
|
||||
Les corrections de rôles, handlers, playbooks et templates doivent être consignées.
|
||||
|
||||
---
|
||||
|
||||
## Stabilisation des changements
|
||||
|
||||
Après une série cohérente de changements validés, recommander un commit propre avant de poursuivre vers un nouveau chantier.
|
||||
|
||||
Avant de recommander un commit :
|
||||
|
||||
- vérifier l'état Git ;
|
||||
- résumer les fichiers créés, modifiés, déplacés ou supprimés ;
|
||||
- indiquer les validations exécutées ;
|
||||
- signaler les validations non exécutées ;
|
||||
- mentionner les risques ou limites connus.
|
||||
|
||||
Ne pas créer de commit sans demande explicite.
|
||||
|
||||
---
|
||||
|
||||
## Comportement attendu de Codex
|
||||
|
||||
Avant de modifier :
|
||||
|
||||
1. Lire `AGENTS.md`.
|
||||
2. Lire `README.md`, `CHANGELOG.md` et `ansible.cfg` s’ils existent.
|
||||
3. Vérifier l’état Git.
|
||||
4. Inspecter les fichiers concernés.
|
||||
5. Identifier la portée exacte de la demande.
|
||||
6. Proposer le plus petit changement utile.
|
||||
7. Préserver les conventions existantes.
|
||||
|
||||
Après modification :
|
||||
|
||||
1. Résumer les fichiers créés ou modifiés.
|
||||
2. Indiquer les commandes de validation exécutées.
|
||||
3. Signaler clairement ce qui n’a pas été testé.
|
||||
4. Mettre à jour `CHANGELOG.md` si pertinent.
|
||||
5. Ne pas affirmer que c’est prêt si la validation a échoué.
|
||||
|
||||
---
|
||||
|
||||
## Philosophie
|
||||
|
||||
Set-OPS est un outil d’exploitation réelle, pas une démonstration technique.
|
||||
|
||||
Priorités :
|
||||
|
||||
- reproductibilité ;
|
||||
- sobriété ;
|
||||
- clarté ;
|
||||
- sécurité ;
|
||||
- maintenance ;
|
||||
- autonomie ;
|
||||
- résilience.
|
||||
|
||||
La complexité doit toujours être justifiée par un bénéfice opérationnel clair.
|
||||
21
CHANGELOG.md
Normal file
21
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-06-24 — Première publication publique
|
||||
|
||||
Première mise à disposition publique de **Set-OPS**, moteur Ansible d'écosystèmes
|
||||
numériques souverains sur Proxmox — offert à la communauté québécoise par
|
||||
l'**Alliance Boréale**, à la Saint-Jean-Baptiste 2026.
|
||||
|
||||
- **Moteur générique, piloté par un plan déclaratif** : on édite le plan
|
||||
(`instance/plan/*.yml`), l'inventaire Ansible se génère, les VM se clonent depuis
|
||||
un golden template Debian 13, les rôles s'appliquent par groupes. Tout passe par
|
||||
`make`, le GUI local et la documentation.
|
||||
- **Piliers d'un écosystème souverain** : socle Debian durci, AC/PKI interne, DNS
|
||||
interne, identité (LDAP + SSO), relais courriel, bases de données, observabilité,
|
||||
forge.
|
||||
- **Catalogue de modèles prêts à déployer** (`exemples/modeles/`) : un hébergeur
|
||||
copie un modèle, le renseigne à ses couleurs, et instancie.
|
||||
- **Souveraineté jusqu'au bout** : Set-OPS s'exploite entièrement à la main, sans
|
||||
aucune IA.
|
||||
|
||||
Pour démarrer : **`QUICKSTART.md`**.
|
||||
244
CLAUDE.md
Normal file
244
CLAUDE.md
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
# CLAUDE.md — Set-OPS
|
||||
|
||||
## Instruction principale
|
||||
|
||||
Claude Code doit lire et respecter `AGENTS.md` avant toute modification.
|
||||
|
||||
`AGENTS.md` est la source d’autorité principale du dépôt.
|
||||
|
||||
En cas de contradiction entre `CLAUDE.md` et `AGENTS.md`, suivre `AGENTS.md`.
|
||||
|
||||
---
|
||||
|
||||
## Rôle du dépôt
|
||||
|
||||
`Set-OPS` est le moteur Ansible global d’exploitation d’écosystèmes numériques souverains.
|
||||
|
||||
Le template Debian 13 Proxmox est seulement un sous-ensemble du dépôt. Ne pas restructurer tout le dépôt autour de ce seul chantier.
|
||||
|
||||
---
|
||||
|
||||
## Règle d’or IA
|
||||
|
||||
Un seul agent IA travaille dans ce dépôt à la fois.
|
||||
|
||||
- Soit Codex.
|
||||
- Soit Claude Code.
|
||||
- Jamais les deux simultanément.
|
||||
|
||||
---
|
||||
|
||||
## Avant toute modification
|
||||
|
||||
Exécuter ou demander l’équivalent de :
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
find . -maxdepth 3 -type f | sort
|
||||
```
|
||||
|
||||
Lire au minimum :
|
||||
|
||||
```text
|
||||
AGENTS.md
|
||||
README.md
|
||||
CHANGELOG.md
|
||||
ansible.cfg
|
||||
```
|
||||
|
||||
Lire aussi les fichiers directement concernés avant de les modifier.
|
||||
|
||||
Ne pas remplacer massivement l’arborescence sans demande explicite.
|
||||
|
||||
Préférer un correctif minimal ciblé.
|
||||
|
||||
---
|
||||
|
||||
## Validation Ansible obligatoire
|
||||
|
||||
Avant de dire qu’un changement est prêt, exécuter au minimum le `--syntax-check` du playbook touché.
|
||||
|
||||
Pour le template Debian 13 Proxmox :
|
||||
|
||||
```bash
|
||||
ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_preparer.yml --syntax-check
|
||||
```
|
||||
|
||||
Si `ansible-lint` est disponible :
|
||||
|
||||
```bash
|
||||
ansible-lint
|
||||
```
|
||||
|
||||
Si `ansible-lint` n’est pas disponible, le signaler clairement.
|
||||
|
||||
Ne jamais déclarer un playbook prêt si la validation échoue.
|
||||
|
||||
---
|
||||
|
||||
## Handlers Ansible
|
||||
|
||||
Chaque rôle qui utilise `notify` doit contenir son handler dans le rôle lui-même.
|
||||
|
||||
Exemple :
|
||||
|
||||
```text
|
||||
roles/ssh_baseline/tasks/main.yml
|
||||
roles/ssh_baseline/handlers/main.yml
|
||||
```
|
||||
|
||||
Commandes utiles :
|
||||
|
||||
```bash
|
||||
find roles -path '*/tasks/*.yml' -exec grep -H "notify:" {} \;
|
||||
find roles -path '*/handlers/main.yml' -print
|
||||
```
|
||||
|
||||
Avant de livrer un rôle, vérifier que chaque handler référencé existe réellement.
|
||||
|
||||
---
|
||||
|
||||
## Actions destructives
|
||||
|
||||
Toute action destructrice ou risquée doit exiger une confirmation explicite.
|
||||
|
||||
Exemple :
|
||||
|
||||
```yaml
|
||||
confirm_destructive_action: true
|
||||
```
|
||||
|
||||
Sont considérées risquées :
|
||||
|
||||
- modification bloquante de SSH ;
|
||||
- activation ou modification d’un pare-feu ;
|
||||
- suppression d’utilisateurs ;
|
||||
- suppression de paquets critiques ;
|
||||
- formatage disque ;
|
||||
- modification de partitions ;
|
||||
- redémarrage massif ;
|
||||
- purge de données ;
|
||||
- changement réseau pouvant couper l’accès ;
|
||||
- modification d’un hyperviseur Proxmox ;
|
||||
- opération sur stockage, iSCSI, ZFS ou Ceph.
|
||||
|
||||
Sans confirmation explicite, refuser l’exécution.
|
||||
|
||||
---
|
||||
|
||||
## Template Debian 13 Proxmox
|
||||
|
||||
Le template doit rester un socle commun.
|
||||
|
||||
Il peut contenir :
|
||||
|
||||
- Debian minimal ;
|
||||
- SSH ;
|
||||
- sudo ;
|
||||
- compte technique `ansible` ;
|
||||
- sudo NOPASSWD pour `ansible` lorsque requis ;
|
||||
- `qemu-guest-agent` ;
|
||||
- `cloud-init` ;
|
||||
- `cloud-guest-utils` ;
|
||||
- chrony ;
|
||||
- outils de diagnostic ;
|
||||
- hardening raisonnable ;
|
||||
- AppArmor ;
|
||||
- auditd ;
|
||||
- fail2ban SSH ;
|
||||
- unattended-upgrades ;
|
||||
- journald ;
|
||||
- sysctl de sécurité ;
|
||||
- nftables installé et préparé, mais non activé par défaut.
|
||||
|
||||
Il ne doit pas contenir par défaut :
|
||||
|
||||
- NGINX ;
|
||||
- PostgreSQL ;
|
||||
- MariaDB ;
|
||||
- Docker ;
|
||||
- Podman ;
|
||||
- Redis ;
|
||||
- GitLab ;
|
||||
- Nextcloud ;
|
||||
- monitoring complet ;
|
||||
- données propres à un clone ;
|
||||
- secrets ;
|
||||
- clés privées.
|
||||
|
||||
---
|
||||
|
||||
## SSH
|
||||
|
||||
Pendant la construction du template :
|
||||
|
||||
```text
|
||||
PasswordAuthentication yes
|
||||
PermitRootLogin no
|
||||
PubkeyAuthentication yes
|
||||
```
|
||||
|
||||
État cible après validation des clés SSH :
|
||||
|
||||
```text
|
||||
PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
PubkeyAuthentication yes
|
||||
```
|
||||
|
||||
Ne jamais désactiver l’authentification par mot de passe avant d’avoir confirmé que l’accès par clé fonctionne.
|
||||
|
||||
Toute modification SSH doit valider la configuration avant rechargement :
|
||||
|
||||
```bash
|
||||
sshd -t
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pare-feu
|
||||
|
||||
Ne pas activer un pare-feu générique dans le template sans confirmation explicite.
|
||||
|
||||
`nftables` peut être installé et préparé, mais rester désactivé dans le template.
|
||||
|
||||
L’activation doit être faite sur un clone ou un serveur final, avec des règles adaptées au rôle du serveur.
|
||||
|
||||
---
|
||||
|
||||
## Cloud-init
|
||||
|
||||
Cloud-init donne l’identité initiale d’un clone :
|
||||
|
||||
- hostname ;
|
||||
- utilisateur initial ;
|
||||
- clé SSH ;
|
||||
- IP ;
|
||||
- passerelle ;
|
||||
- DNS ;
|
||||
- agrandissement de la partition racine.
|
||||
|
||||
Cloud-init ne remplace pas Ansible.
|
||||
|
||||
Séparation attendue :
|
||||
|
||||
```text
|
||||
Proxmox + cloud-init : identité initiale de la VM
|
||||
Set-OPS + Ansible : configuration réelle du serveur
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Après modification
|
||||
|
||||
Répondre avec :
|
||||
|
||||
1. fichiers créés ;
|
||||
2. fichiers modifiés ;
|
||||
3. commandes de validation exécutées ;
|
||||
4. résultat des validations ;
|
||||
5. tests non exécutés ;
|
||||
6. limites connues ;
|
||||
7. entrée `CHANGELOG.md` ajoutée ou raison de l’absence d’entrée.
|
||||
|
||||
Ne pas dire que c’est prêt si ce n’est pas validé.
|
||||
235
LICENSE
Normal file
235
LICENSE
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
Set-OPS
|
||||
Copyright (C) 2026 Alliance Boréale
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>.
|
||||
478
Makefile
Normal file
478
Makefile
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
SHELL := /usr/bin/env bash
|
||||
|
||||
export ANSIBLE_HOME ?= $(CURDIR)/.ansible
|
||||
export ANSIBLE_LOCAL_TEMP ?= $(CURDIR)/.ansible/tmp
|
||||
export ANSIBLE_SSH_CONTROL_PATH_DIR ?= $(CURDIR)/.ansible/cp
|
||||
export ANSIBLE_SSH_ARGS ?= -F /dev/null -o ControlMaster=no
|
||||
|
||||
export SETOPS_INSTANCE ?= instance
|
||||
INVENTAIRE_LAB ?= $(SETOPS_INSTANCE)/inventories/lab/hosts.yml
|
||||
INVENTAIRE_PRODUCTION ?= $(SETOPS_INSTANCE)/inventories/production/hosts.yml
|
||||
FICHIER_INVENTAIRE ?= $(INVENTAIRE_PRODUCTION)
|
||||
FICHIER_DEPENDANCES ?= docs/dependances-groupes.yml
|
||||
GROUPE_MODELE ?= modeles_vm
|
||||
GROUPE_DEBIAN ?= serveur_debian
|
||||
GROUPE_HOTES_ACTIFS ?= hotes_actifs
|
||||
LIMITE ?= $(GROUPE_DEBIAN)
|
||||
HOTE ?=
|
||||
ADRESSE_IP ?=
|
||||
GROUPES ?= $(GROUPE_DEBIAN)
|
||||
GROUPE ?= $(GROUPE_DEBIAN)
|
||||
UTILISATEUR_ANSIBLE ?= ansible
|
||||
VMID_MODELE ?=
|
||||
VMID ?=
|
||||
NOEUD_PROXMOX ?=
|
||||
STOCKAGE_PROXMOX ?=
|
||||
FORMAT_DISQUE ?=
|
||||
TAILLE_DISQUE ?=
|
||||
DISQUE_PROXMOX ?=
|
||||
CIDR ?= 24
|
||||
PASSERELLE ?=
|
||||
DNS ?=
|
||||
DHCP ?= false
|
||||
CIUSER ?=
|
||||
CLE_SSH_PUBLIQUE ?=
|
||||
PONT_PROXMOX ?=
|
||||
VLAN ?=
|
||||
DEMARRER ?=
|
||||
CLONE_COMPLET ?=
|
||||
|
||||
CONFIRMER ?= false
|
||||
VERIFICATION ?= false
|
||||
DIFF ?= false
|
||||
ETIQUETTES ?=
|
||||
SAUTER_ETIQUETTES ?=
|
||||
VARIABLES ?=
|
||||
|
||||
OPTIONS_PLAYBOOK :=
|
||||
ifneq ($(LIMITE),)
|
||||
OPTIONS_PLAYBOOK += --limit $(LIMITE)
|
||||
endif
|
||||
ifeq ($(VERIFICATION),true)
|
||||
OPTIONS_PLAYBOOK += --check
|
||||
endif
|
||||
ifeq ($(DIFF),true)
|
||||
OPTIONS_PLAYBOOK += --diff
|
||||
endif
|
||||
ifneq ($(ETIQUETTES),)
|
||||
OPTIONS_PLAYBOOK += --tags $(ETIQUETTES)
|
||||
endif
|
||||
ifneq ($(SAUTER_ETIQUETTES),)
|
||||
OPTIONS_PLAYBOOK += --skip-tags $(SAUTER_ETIQUETTES)
|
||||
endif
|
||||
ifneq ($(VARIABLES),)
|
||||
OPTIONS_PLAYBOOK += -e $(VARIABLES)
|
||||
endif
|
||||
|
||||
PLAYBOOK_PREPARER_MODELE := playbooks/modeles_vm/debian13_proxmox_preparer.yml
|
||||
PLAYBOOK_VERIFIER_MODELE := playbooks/modeles_vm/debian13_proxmox_verifier.yml
|
||||
PLAYBOOK_NETTOYER_MODELE := playbooks/modeles_vm/debian13_proxmox_nettoyer.yml
|
||||
PLAYBOOK_VERIFIER_HOTE := playbooks/maintenance/verifier_hote_debian.yml
|
||||
PLAYBOOK_PROXMOX_CLONER_VM := playbooks/proxmox/cloner_vm_debian.yml
|
||||
DOSSIER_PLAYBOOKS_GROUPES := playbooks/groupes
|
||||
|
||||
.DEFAULT_GOAL := aide
|
||||
|
||||
.PHONY: ansible-runtime
|
||||
ansible-runtime:
|
||||
@mkdir -p "$(ANSIBLE_LOCAL_TEMP)"
|
||||
@mkdir -p "$(ANSIBLE_SSH_CONTROL_PATH_DIR)"
|
||||
|
||||
.PHONY: _instance-requise
|
||||
_instance-requise:
|
||||
@if [[ ! -f "$(SETOPS_INSTANCE)/plan/serveurs.yml" ]]; then \
|
||||
printf '%s\n' "Aucune instance configuree : '$(SETOPS_INSTANCE)/plan' introuvable."; \
|
||||
printf '%s\n' "Demarre avec QUICKSTART.md. En bref :"; \
|
||||
printf '%s\n' " cp -r exemples/modeles/<modele> ../mon-instance && ln -s ../mon-instance instance"; \
|
||||
printf '%s\n' " modeles disponibles : $$(ls exemples/modeles 2>/dev/null | grep -v '\.md' | tr '\n' ' ')"; \
|
||||
exit 2; \
|
||||
fi
|
||||
|
||||
.PHONY: aide
|
||||
aide:
|
||||
@printf '%s\n' 'Set-OPS — moteur d ecosystemes numeriques souverains'
|
||||
@printf '%s\n' ''
|
||||
@printf '%s\n' 'Nouveau ? -> QUICKSTART.md (de zero a ton ecosysteme sur Proxmox)'
|
||||
@printf '%s\n' 'Flux: editer le plan -> make instancier -> make instancier-appliquer -> make deployer'
|
||||
@printf '%s\n' ''
|
||||
@printf '%s\n' 'VM'
|
||||
@printf '%s\n' ' Creer une VM (VMID/IP/VLAN/passerelle lus dans le plan):'
|
||||
@printf '%s\n' ' make creer-vm HOTE=web-frontal-01'
|
||||
@printf '%s\n' ' Cloner seulement, sans passer par le plan:'
|
||||
@printf '%s\n' ' make cloner-vm HOTE=web-frontal-01 VMID=95301 VLAN=15 ADRESSE_IP=10.0.2.31 PASSERELLE=10.0.2.1'
|
||||
@printf '%s\n' ' Configurer Proxmox et le Vault API:'
|
||||
@printf '%s\n' ' make config'
|
||||
@printf '%s\n' ''
|
||||
@printf '%s\n' 'Hotes'
|
||||
@printf '%s\n' ' Planifier/modifier un hote: editer le plan, puis regenerer:'
|
||||
@printf '%s\n' ' editer instance/plan/serveurs.yml (ou la vue Serveurs du GUI)'
|
||||
@printf '%s\n' ' make instancier-appliquer'
|
||||
@printf '%s\n' ' Verifier un deploiement a blanc (dry-run):'
|
||||
@printf '%s\n' ' make verifier-deploiement HOTE=web-frontal-01'
|
||||
@printf '%s\n' ' Remettre un hote en conformite selon ses groupes:'
|
||||
@printf '%s\n' ' make deployer HOTE=web-frontal-01'
|
||||
@printf '%s\n' ' Afficher un hote:'
|
||||
@printf '%s\n' ' make hote-afficher HOTE=web-frontal-01'
|
||||
@printf '%s\n' ' Diagnostiquer:'
|
||||
@printf '%s\n' ' make verifier-hote LIMITE=web-frontal-01'
|
||||
@printf '%s\n' ''
|
||||
@printf '%s\n' 'Groupes'
|
||||
@printf '%s\n' ' Appliquer un groupe complet:'
|
||||
@printf '%s\n' ' make deployer-groupe GROUPE=serveur_debian'
|
||||
@printf '%s\n' ' Convention:'
|
||||
@printf '%s\n' ' groupe serveur_debian -> playbooks/groupes/serveur_debian.yml'
|
||||
@printf '%s\n' ''
|
||||
@printf '%s\n' 'Inventaires'
|
||||
@printf '%s\n' ' Graphe de production:'
|
||||
@printf '%s\n' ' make inventaire'
|
||||
@printf '%s\n' ' Graphe explicite:'
|
||||
@printf '%s\n' ' make inventaire-graphe FICHIER_INVENTAIRE=$(SETOPS_INSTANCE)/inventories/production/hosts.yml'
|
||||
@printf '%s\n' ' Verifier les inventaires:'
|
||||
@printf '%s\n' ' make inventaire-verifier'
|
||||
@printf '%s\n' ' Lister les donnees brutes:'
|
||||
@printf '%s\n' ' make inventaire-lister'
|
||||
@printf '%s\n' ' Interface locale de gestion:'
|
||||
@printf '%s\n' ' make inventaire-ui'
|
||||
@printf '%s\n' ''
|
||||
@printf '%s\n' 'Modele Debian 13 Proxmox'
|
||||
@printf '%s\n' ' Construire et verifier:'
|
||||
@printf '%s\n' ' make preparer-modele'
|
||||
@printf '%s\n' ' make verifier-modele'
|
||||
@printf '%s\n' ' Nettoyage final protege:'
|
||||
@printf '%s\n' ' make nettoyer-modele CONFIRMER=true'
|
||||
@printf '%s\n' ''
|
||||
@printf '%s\n' 'Validation'
|
||||
@printf '%s\n' ' make syntaxe'
|
||||
@printf '%s\n' ' make lint'
|
||||
@printf '%s\n' ' make verifier'
|
||||
@printf '%s\n' ''
|
||||
@printf '%s\n' 'Variables frequentes'
|
||||
@printf '%s\n' ' HOTE=web-frontal-01 GROUPE=serveur_debian GROUPES="serveur_debian serveur_durci"'
|
||||
@printf '%s\n' ' VMID=95301 VLAN=15 ADRESSE_IP=10.0.2.31 PASSERELLE=10.0.2.1'
|
||||
@printf '%s\n' ' FICHIER_INVENTAIRE=$(SETOPS_INSTANCE)/inventories/production/hosts.yml FICHIER_DEPENDANCES=docs/dependances-groupes.yml CONFIRMER=true'
|
||||
|
||||
.PHONY: lint
|
||||
lint: ansible-runtime
|
||||
ansible-lint
|
||||
|
||||
.PHONY: syntaxe syntaxe-modele syntaxe-nettoyage syntaxe-verification-modele syntaxe-verification-hote syntaxe-groupes syntaxe-proxmox
|
||||
syntaxe: syntaxe-modele syntaxe-verification-modele syntaxe-nettoyage syntaxe-verification-hote syntaxe-groupes syntaxe-proxmox
|
||||
|
||||
syntaxe-modele: ansible-runtime
|
||||
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_PREPARER_MODELE) --syntax-check
|
||||
|
||||
syntaxe-verification-modele: ansible-runtime
|
||||
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_VERIFIER_MODELE) --syntax-check
|
||||
|
||||
syntaxe-nettoyage: ansible-runtime
|
||||
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_NETTOYER_MODELE) --syntax-check
|
||||
|
||||
syntaxe-verification-hote: ansible-runtime
|
||||
ansible-playbook -i $(INVENTAIRE_PRODUCTION) $(PLAYBOOK_VERIFIER_HOTE) --syntax-check
|
||||
|
||||
syntaxe-groupes: ansible-runtime
|
||||
@for playbook in $(DOSSIER_PLAYBOOKS_GROUPES)/*.yml; do \
|
||||
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$$playbook" --syntax-check; \
|
||||
done
|
||||
|
||||
syntaxe-proxmox: ansible-runtime
|
||||
ansible-playbook -i localhost, $(PLAYBOOK_PROXMOX_CLONER_VM) --syntax-check
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
python3 scripts/tests/test_inventory_host.py
|
||||
|
||||
.PHONY: verifier
|
||||
verifier: lint test inventaire-verifier syntaxe
|
||||
|
||||
.PHONY: inventaire hote-planifier hote-ajouter hote-groupes hote-afficher appliquer deployer deployer-groupe cloner-vm creer-vm config inventaire-ui inventaire-verifier inventaire-lister inventaire-graphe inventaire-hote inventaire-lab inventaire-production
|
||||
inventaire: inventaire-production
|
||||
|
||||
config:
|
||||
python3 scripts/config_proxmox.py
|
||||
|
||||
inventaire-ui: _instance-requise
|
||||
python3 scripts/inventory_gui.py --inventaire $(FICHIER_INVENTAIRE)
|
||||
|
||||
hote-ajouter hote-planifier hote-groupes:
|
||||
@printf '%s\n' 'Cible depreciee: l inventaire est GENERE depuis le plan, il ne s edite plus a la main.'
|
||||
@printf '%s\n' 'Declare ou modifie l hote dans instance/plan/serveurs.yml (ou la vue Serveurs du GUI), puis :'
|
||||
@printf '%s\n' ' make instancier-appliquer'
|
||||
@printf '%s\n' '(creer-vm lit desormais VMID/IP/VLAN/passerelle directement dans l inventaire genere.)'
|
||||
@exit 2
|
||||
|
||||
hote-afficher: ansible-runtime
|
||||
@if [[ -z "$(HOTE)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) afficher --hote $(HOTE)
|
||||
|
||||
appliquer: ansible-runtime
|
||||
@if [[ -z "$(GROUPE)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec GROUPE=nom_groupe.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
@if [[ ! -f "$(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml" ]]; then \
|
||||
printf '%s\n' 'Refus: aucun playbook pour ce groupe: $(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml'; \
|
||||
exit 2; \
|
||||
fi
|
||||
python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) --dependances $(FICHIER_DEPENDANCES) verifier-dependances-groupe --groupe $(GROUPE)
|
||||
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml" --limit '$(GROUPE):&$(GROUPE_HOTES_ACTIFS)'
|
||||
|
||||
deployer: _instance-requise
|
||||
@set -e; \
|
||||
if [[ -z "$(HOTE)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) verifier-actif --hote $(HOTE); \
|
||||
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) --dependances $(FICHIER_DEPENDANCES) verifier-dependances-hote --hote $(HOTE); \
|
||||
playbooks="$$(python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) playbooks --hote $(HOTE) --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES))"; \
|
||||
if [[ -z "$$playbooks" ]]; then \
|
||||
printf '%s\n' 'Refus: aucun playbook applicable pour HOTE=$(HOTE).'; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
vault_chiffre="$$(grep -rlsIF '$$ANSIBLE_VAULT' $(SETOPS_INSTANCE)/inventories/production/group_vars 2>/dev/null | head -1 || true)"; \
|
||||
if [[ -n "$$vault_chiffre" && -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \
|
||||
if [[ -t 0 ]]; then \
|
||||
read -r -s -p 'Mot de passe du vault Ansible: ' mdp; echo; \
|
||||
vf="$$(mktemp)"; printf '%s' "$$mdp" > "$$vf"; chmod 600 "$$vf"; \
|
||||
export ANSIBLE_VAULT_PASSWORD_FILE="$$vf"; \
|
||||
trap 'rm -f "$$vf"' EXIT; \
|
||||
else \
|
||||
printf '%s\n' 'Refus: vault chiffre detecte mais aucun mot de passe (entree non interactive). Fournir ANSIBLE_VAULT_PASSWORD_FILE ou le champ vault de la GUI.'; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
fi; \
|
||||
$(MAKE) _verifier-acces-hote LIMITE="$(HOTE)"; \
|
||||
$(MAKE) _verifier-privileges-hote LIMITE="$(HOTE)"; \
|
||||
for playbook in $$playbooks; do \
|
||||
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$$playbook" --limit "$(HOTE)"; \
|
||||
done; \
|
||||
$(MAKE) verifier-hote LIMITE="$(HOTE)"
|
||||
|
||||
deployer-groupe:
|
||||
@if [[ -z "$(GROUPE)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec GROUPE=nom_groupe.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
$(MAKE) appliquer GROUPE="$(GROUPE)"
|
||||
|
||||
.PHONY: verifier-deploiement
|
||||
verifier-deploiement: ansible-runtime
|
||||
@set -e; \
|
||||
if [[ -z "$(HOTE)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) verifier-actif --hote $(HOTE); \
|
||||
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) --dependances $(FICHIER_DEPENDANCES) verifier-dependances-hote --hote $(HOTE); \
|
||||
playbooks="$$(python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) playbooks --hote $(HOTE) --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES))"; \
|
||||
if [[ -z "$$playbooks" ]]; then \
|
||||
printf '%s\n' 'Refus: aucun playbook applicable pour HOTE=$(HOTE).'; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
vault_chiffre="$$(grep -rlsIF '$$ANSIBLE_VAULT' $(SETOPS_INSTANCE)/inventories/production/group_vars 2>/dev/null | head -1 || true)"; \
|
||||
if [[ -n "$$vault_chiffre" && -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \
|
||||
if [[ -t 0 ]]; then \
|
||||
read -r -s -p 'Mot de passe du vault Ansible: ' mdp; echo; \
|
||||
vf="$$(mktemp)"; printf '%s' "$$mdp" > "$$vf"; chmod 600 "$$vf"; \
|
||||
export ANSIBLE_VAULT_PASSWORD_FILE="$$vf"; \
|
||||
trap 'rm -f "$$vf"' EXIT; \
|
||||
else \
|
||||
printf '%s\n' 'Refus: vault chiffre detecte mais aucun mot de passe (entree non interactive). Fournir ANSIBLE_VAULT_PASSWORD_FILE ou le champ vault de la GUI.'; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
fi; \
|
||||
for playbook in $$playbooks; do \
|
||||
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$$playbook" --limit "$(HOTE)" --check --diff; \
|
||||
done
|
||||
|
||||
cloner-vm: ansible-runtime
|
||||
@if [[ -z "$(HOTE)" || -z "$(VMID)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec HOTE=nom VMID=id_clone.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
@if [[ -z "$(VLAN)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec VLAN=id_vlan.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
@if ! [[ "$(VLAN)" =~ ^[0-9]+$$ ]] || (( 10#$(VLAN) < 1 || 10#$(VLAN) > 4094 )); then \
|
||||
printf '%s\n' 'Refus: VLAN doit etre un nombre entre 1 et 4094.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
@if [[ -n "$(CLE_SSH_PUBLIQUE)" && ! -f "$(CLE_SSH_PUBLIQUE)" ]]; then \
|
||||
printf '%s\n' 'Refus: cle publique SSH introuvable: $(CLE_SSH_PUBLIQUE)'; \
|
||||
exit 2; \
|
||||
fi
|
||||
@if [[ "$(DHCP)" != "true" && ( -z "$(ADRESSE_IP)" || -z "$(CIDR)" || -z "$(PASSERELLE)" ) ]]; then \
|
||||
printf '%s\n' 'Refus: fournir ADRESSE_IP, CIDR et PASSERELLE, ou utiliser DHCP=true.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
@ipconfig='ip=dhcp'; \
|
||||
if [[ "$(DHCP)" != "true" ]]; then \
|
||||
ipconfig='ip=$(ADRESSE_IP)/$(CIDR),gw=$(PASSERELLE)'; \
|
||||
fi; \
|
||||
extra_vars=( \
|
||||
-e proxmox_clone_nom="$(HOTE)" \
|
||||
-e proxmox_clone_vmid="$(VMID)" \
|
||||
-e proxmox_clone_ipconfig0="$$ipconfig" \
|
||||
); \
|
||||
[[ -n "$(VMID_MODELE)" ]] && extra_vars+=( -e proxmox_clone_vmid_modele="$(VMID_MODELE)" ); \
|
||||
[[ -n "$(NOEUD_PROXMOX)" ]] && extra_vars+=( -e proxmox_clone_noeud="$(NOEUD_PROXMOX)" ); \
|
||||
[[ -n "$(STOCKAGE_PROXMOX)" ]] && extra_vars+=( -e proxmox_clone_stockage="$(STOCKAGE_PROXMOX)" ); \
|
||||
[[ -n "$(FORMAT_DISQUE)" ]] && extra_vars+=( -e proxmox_clone_format="$(FORMAT_DISQUE)" ); \
|
||||
[[ -n "$(CLONE_COMPLET)" ]] && extra_vars+=( -e proxmox_clone_complet="$(CLONE_COMPLET)" ); \
|
||||
[[ -n "$(TAILLE_DISQUE)" ]] && extra_vars+=( -e proxmox_clone_taille_disque="$(TAILLE_DISQUE)" ); \
|
||||
[[ -n "$(DISQUE_PROXMOX)" ]] && extra_vars+=( -e proxmox_clone_disque="$(DISQUE_PROXMOX)" ); \
|
||||
[[ -n "$(DNS)" ]] && extra_vars+=( -e proxmox_clone_dns="$(DNS)" ); \
|
||||
[[ -n "$(CIUSER)" ]] && extra_vars+=( -e proxmox_clone_ciuser="$(CIUSER)" ); \
|
||||
[[ -n "$(CLE_SSH_PUBLIQUE)" ]] && extra_vars+=( -e proxmox_clone_cle_publique_fichier="$(CLE_SSH_PUBLIQUE)" ); \
|
||||
[[ -n "$(PONT_PROXMOX)" ]] && extra_vars+=( -e proxmox_clone_pont="$(PONT_PROXMOX)" ); \
|
||||
extra_vars+=( -e proxmox_clone_vlan="$(VLAN)" ); \
|
||||
[[ -n "$(DEMARRER)" ]] && extra_vars+=( -e proxmox_clone_demarrer="$(DEMARRER)" ); \
|
||||
vault_args=(); \
|
||||
vault_file="$(SETOPS_INSTANCE)/inventories/lab/group_vars/proxmox.vault.yml"; \
|
||||
if [[ -f "$$vault_file" ]]; then \
|
||||
read -r premiere_ligne < "$$vault_file" || true; \
|
||||
case "$$premiere_ligne" in \
|
||||
'$$ANSIBLE_VAULT'*) \
|
||||
if [[ -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \
|
||||
vault_args+=( --ask-vault-pass ); \
|
||||
fi; \
|
||||
;; \
|
||||
esac; \
|
||||
fi; \
|
||||
ansible-playbook -i localhost, $(PLAYBOOK_PROXMOX_CLONER_VM) "$${vault_args[@]}" "$${extra_vars[@]}"
|
||||
|
||||
creer-vm: _instance-requise
|
||||
@set -e; \
|
||||
if [[ -z "$(HOTE)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote (declare dans le plan).'; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
params="$$(python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) parametres-proxmox --hote $(HOTE))"; \
|
||||
eval "$$params"; \
|
||||
$(MAKE) cloner-vm \
|
||||
HOTE="$(HOTE)" \
|
||||
VMID="$$SETOPS_VMID" \
|
||||
ADRESSE_IP="$$SETOPS_IP" \
|
||||
CIDR="$$SETOPS_CIDR" \
|
||||
PASSERELLE="$$SETOPS_PASSERELLE" \
|
||||
VLAN="$$SETOPS_VLAN" \
|
||||
STOCKAGE_PROXMOX="$${SETOPS_STOCKAGE:-$(STOCKAGE_PROXMOX)}" \
|
||||
TAILLE_DISQUE="$${SETOPS_DISQUE:-$(TAILLE_DISQUE)}" \
|
||||
NOEUD_PROXMOX="$${SETOPS_NOEUD:-$(NOEUD_PROXMOX)}" \
|
||||
VMID_MODELE="$(VMID_MODELE)" \
|
||||
FORMAT_DISQUE="$(FORMAT_DISQUE)" \
|
||||
DISQUE_PROXMOX="$(DISQUE_PROXMOX)" \
|
||||
DNS="$(DNS)" \
|
||||
DHCP="$(DHCP)" \
|
||||
CIUSER="$(CIUSER)" \
|
||||
CLE_SSH_PUBLIQUE="$(CLE_SSH_PUBLIQUE)" \
|
||||
PONT_PROXMOX="$(PONT_PROXMOX)" \
|
||||
DEMARRER="$(DEMARRER)" \
|
||||
CLONE_COMPLET="$(CLONE_COMPLET)"
|
||||
|
||||
inventaire-verifier: ansible-runtime _instance-requise
|
||||
ansible-inventory -i $(INVENTAIRE_LAB) --list > /dev/null
|
||||
ansible-inventory -i $(INVENTAIRE_PRODUCTION) --list > /dev/null
|
||||
python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) verifier-playbooks --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES)
|
||||
python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) --dependances $(FICHIER_DEPENDANCES) verifier-dependances --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES)
|
||||
python3 scripts/verifier_gui.py
|
||||
python3 scripts/serveurs.py verifier
|
||||
python3 scripts/applications.py verifier
|
||||
python3 scripts/bases_donnees.py verifier
|
||||
python3 scripts/domaines.py verifier
|
||||
|
||||
.PHONY: bases bases-verifier domaines domaines-verifier applications applications-verifier applications-bootstrap serveurs serveurs-verifier serveurs-bootstrap
|
||||
serveurs:
|
||||
python3 scripts/serveurs.py lister
|
||||
|
||||
serveurs-verifier:
|
||||
python3 scripts/serveurs.py verifier
|
||||
|
||||
serveurs-bootstrap:
|
||||
python3 scripts/serveurs.py bootstrap
|
||||
|
||||
.PHONY: instancier instancier-appliquer
|
||||
instancier: _instance-requise
|
||||
python3 scripts/instancier.py generer
|
||||
python3 scripts/instancier.py comparer
|
||||
|
||||
instancier-appliquer: _instance-requise
|
||||
python3 scripts/instancier.py appliquer
|
||||
|
||||
bases:
|
||||
python3 scripts/bases_donnees.py lister
|
||||
|
||||
bases-verifier:
|
||||
python3 scripts/bases_donnees.py verifier
|
||||
|
||||
domaines:
|
||||
python3 scripts/domaines.py lister
|
||||
|
||||
domaines-verifier:
|
||||
python3 scripts/domaines.py verifier
|
||||
|
||||
applications:
|
||||
python3 scripts/applications.py lister
|
||||
|
||||
applications-verifier:
|
||||
python3 scripts/applications.py verifier
|
||||
|
||||
applications-bootstrap:
|
||||
python3 scripts/applications.py bootstrap
|
||||
|
||||
inventaire-lister: ansible-runtime
|
||||
ansible-inventory -i $(FICHIER_INVENTAIRE) --list
|
||||
|
||||
inventaire-graphe: ansible-runtime
|
||||
ansible-inventory -i $(FICHIER_INVENTAIRE) --graph
|
||||
|
||||
inventaire-hote: ansible-runtime
|
||||
@if [[ -z "$(HOTE)" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
ansible-inventory -i $(FICHIER_INVENTAIRE) --host $(HOTE)
|
||||
|
||||
inventaire-lab:
|
||||
$(MAKE) inventaire-graphe FICHIER_INVENTAIRE="$(INVENTAIRE_LAB)"
|
||||
|
||||
inventaire-production:
|
||||
$(MAKE) inventaire-graphe FICHIER_INVENTAIRE="$(INVENTAIRE_PRODUCTION)"
|
||||
|
||||
.PHONY: _verifier-acces-modele _verifier-privileges-modele preparer-modele verifier-modele nettoyer-modele
|
||||
_verifier-acces-modele: ansible-runtime
|
||||
ansible -i $(INVENTAIRE_LAB) $(GROUPE_MODELE) -m ping -e ansible_become=false
|
||||
|
||||
_verifier-privileges-modele: ansible-runtime
|
||||
ansible -i $(INVENTAIRE_LAB) $(GROUPE_MODELE) -b -m command -a "whoami"
|
||||
|
||||
preparer-modele: ansible-runtime _verifier-acces-modele _verifier-privileges-modele
|
||||
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_PREPARER_MODELE)
|
||||
|
||||
verifier-modele: ansible-runtime
|
||||
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_VERIFIER_MODELE)
|
||||
|
||||
nettoyer-modele: ansible-runtime
|
||||
@if [[ "$(CONFIRMER)" != "true" ]]; then \
|
||||
printf '%s\n' 'Refus: relancer avec CONFIRMER=true pour le nettoyage final du modele.'; \
|
||||
exit 2; \
|
||||
fi
|
||||
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_NETTOYER_MODELE) -e template_cleanup_confirm=true
|
||||
|
||||
.PHONY: _verifier-acces-hote _verifier-privileges-hote faits verifier-hote
|
||||
_verifier-acces-hote: ansible-runtime
|
||||
ansible -i $(INVENTAIRE_PRODUCTION) $(LIMITE) -m ping -e ansible_become=false
|
||||
|
||||
_verifier-privileges-hote: ansible-runtime
|
||||
ansible -i $(INVENTAIRE_PRODUCTION) $(LIMITE) -b -m command -a "whoami"
|
||||
|
||||
faits: ansible-runtime
|
||||
ansible -i $(INVENTAIRE_PRODUCTION) $(LIMITE) -m setup -a "filter=ansible_distribution*"
|
||||
|
||||
verifier-hote: ansible-runtime
|
||||
ansible-playbook -i $(INVENTAIRE_PRODUCTION) $(PLAYBOOK_VERIFIER_HOTE) $(OPTIONS_PLAYBOOK)
|
||||
104
QUICKSTART.md
Normal file
104
QUICKSTART.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# Démarrage rapide — de zéro à ton écosystème souverain
|
||||
|
||||
Tu débarques avec une **grappe Proxmox vierge** et tu veux monter ton écosystème
|
||||
numérique. Voici le chemin, de bout en bout. Set-OPS est le **moteur** ; tu vas
|
||||
créer **ton instance** à partir d'un modèle, puis déployer.
|
||||
|
||||
> Concepts en 10 s : tu **décris un plan** (quelles VM, quels services), le moteur
|
||||
> **génère l'inventaire**, et Ansible **déploie**. Tu n'édites jamais l'inventaire
|
||||
> à la main. Détails : `docs/plan-et-generation.md`.
|
||||
|
||||
## 0. Prérequis (à toi de fournir)
|
||||
- une **grappe Proxmox** où tu es admin (API activée) ;
|
||||
- une machine de pilotage Linux avec **Ansible**, **Python 3**, **make**, `git`
|
||||
(et `node` pour le garde-fou JS du GUI, optionnel) ;
|
||||
- un **token API Proxmox** ;
|
||||
- une **paire de clés SSH** (la publique ira dans les VM via cloud-init) ;
|
||||
- un **mot de passe Ansible Vault** (pour chiffrer tes secrets).
|
||||
|
||||
## 1. Cloner le moteur
|
||||
```bash
|
||||
git clone <url-de-Set-OPS> Set-OPS && cd Set-OPS
|
||||
```
|
||||
|
||||
## 2. Choisir un modèle et créer ton instance
|
||||
Les modèles sont dans `exemples/modeles/` (voir leur README). Choisis selon ton offre :
|
||||
`socle`, `presence-web`, `forge`, `identite`, `observabilite`, `integral`.
|
||||
|
||||
```bash
|
||||
cp -r exemples/modeles/presence-web ../mon-instance # ton instance, ailleurs
|
||||
ln -s ../mon-instance instance # le moteur la trouve via ce lien
|
||||
```
|
||||
*(Alternative au symlink : `export SETOPS_INSTANCE=../mon-instance`.)*
|
||||
|
||||
## 3. Renseigner ton instance (« tes couleurs »)
|
||||
- `instance/inventories/production/group_vars/all.yml` → **`domaine_interne`** (ex. `monorg.internal`) ;
|
||||
- `instance/plan/nomenclature.yml` → ton **supernet** (ex. `10.20.0.0/16`) ;
|
||||
- `instance/plan/domaines.yml` → ton **domaine public** ;
|
||||
- `instance/plan/serveurs.yml` → **placement Proxmox** (nœud, stockage, disque, mémoire, cœurs).
|
||||
|
||||
Tu peux aussi le faire dans le GUI plus tard (`make inventaire-ui`).
|
||||
|
||||
## 4. Configurer Proxmox et tes secrets
|
||||
```bash
|
||||
make config # renseigne API host/user/port, nœud, stockage, VMID du template...
|
||||
```
|
||||
Place ton **token API** et tes secrets dans le Vault de l'instance
|
||||
(`instance/inventories/lab/group_vars/proxmox.vault.yml`, à partir du `.example`,
|
||||
chiffré avec `ansible-vault`). Exporte ton mot de passe Vault, ex. :
|
||||
```bash
|
||||
export ANSIBLE_VAULT_PASSWORD_FILE=~/.config/setops-vault-pass
|
||||
```
|
||||
|
||||
## 5. Construire le golden template Debian 13 (UNE seule fois)
|
||||
Une grappe vierge n'a aucun template. Crée une VM **Debian 13 vanille**, rends-la
|
||||
joignable par Ansible, puis :
|
||||
```bash
|
||||
make preparer-modele # socle + durcissement + cloud-init + qemu-guest-agent...
|
||||
make verifier-modele
|
||||
make nettoyer-modele CONFIRMER=true
|
||||
```
|
||||
Convertis ensuite la VM en **template Proxmox** nommé `modele-debian13` (le nom de
|
||||
clone source par défaut). Détails et procédure : `docs/vm-lifecycle.md` et
|
||||
`docs/procedure-template-debian13-proxmox.md`.
|
||||
|
||||
## 6. Générer ton inventaire depuis le plan
|
||||
```bash
|
||||
make instancier # montre ce que le plan produit (diff)
|
||||
make instancier-appliquer FORCE=1 # 1re génération : écrit instance/inventories/production/hosts.yml
|
||||
```
|
||||
Tes hôtes sont là, en état `planifie`. `make serveurs` te montre leurs VMID/IP dérivés.
|
||||
|
||||
## 7. Créer les VM (clone du template + cloud-init)
|
||||
Pour chaque hôte — `creer-vm` lit ses VMID/IP/VLAN/passerelle directement dans
|
||||
l'inventaire généré (`make serveurs` te les montre) :
|
||||
```bash
|
||||
make creer-vm HOTE=infra-dns-01
|
||||
```
|
||||
*(Les valeurs de nœud/stockage/template viennent de `make config`. La création
|
||||
suit désormais le plan de bout en bout : un seul argument, `HOTE`.)*
|
||||
|
||||
## 8. Activer puis déployer
|
||||
Passe l'hôte en `etat: actif` dans `instance/plan/serveurs.yml`, régénère, déploie :
|
||||
```bash
|
||||
make instancier-appliquer
|
||||
make deployer HOTE=infra-dns-01 # configure l'hôte selon ses groupes
|
||||
# ou, par couche :
|
||||
make deployer-groupe GROUPE=serveur_postgresql
|
||||
```
|
||||
Les déploiements de groupe ne ciblent **que** les hôtes actifs.
|
||||
|
||||
## 9. Ensuite : tu vis dans le plan
|
||||
Édite le plan (GUI `make inventaire-ui`, ou les registres `instance/plan/`),
|
||||
`make instancier-appliquer`, `make deployer`. Tu ne touches jamais `hosts.yml`.
|
||||
|
||||
## Valider à tout moment
|
||||
```bash
|
||||
make inventaire-verifier # registres + inventaire + garde-fous
|
||||
make verifier # + ansible-lint + --syntax-check
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Ordre de mise en place des services : `docs/catalogue-services.md`. Modèle,
|
||||
registres et règle d'or : `docs/plan-et-generation.md` et `AGENTS.md`.
|
||||
171
README.md
Normal file
171
README.md
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
# Set-OPS — moteur d'écosystèmes numériques souverains
|
||||
|
||||
**Set-OPS est un moteur Ansible générique** qui permet à un hébergeur de **construire et exploiter un écosystème numérique souverain** — DNS interne, AC/PKI, identité (LDAP + SSO), relais courriel, bases de données, observabilité, applications — sur sa propre grappe **Proxmox**, à partir d'un **plan déclaratif**.
|
||||
|
||||
Le dépôt est le **moteur** (générique, partageable). Chaque déploiement réel est une **instance** (le plan + l'inventaire d'un hébergeur, dans son propre dépôt). Tu crées la tienne à partir d'un **modèle prêt à déployer** (`exemples/modeles/`).
|
||||
|
||||
> 👉 **Tu débarques avec une grappe Proxmox et tu veux monter ton écosystème ? Commence par [`QUICKSTART.md`](QUICKSTART.md).**
|
||||
|
||||
**Souveraineté jusqu'au bout : Set-OPS s'exploite entièrement à la main** — la doc, `make` et le GUI suffisent, **sans aucune IA**. L'outil libère de la dépendance aux géants ; il ne la remplace pas par une dépendance à une IA.
|
||||
|
||||
---
|
||||
|
||||
## Mission (la vision derrière l'outil)
|
||||
|
||||
`Set-OPS` ne se limite plus à l'exploitation : il **définit et construit un écosystème numérique souverain** — une infrastructure interne auto-suffisante, sans dépendance SaaS, décrite en code et pilotée par des registres machine-lisibles qui font office de **source unique de vérité** (`instance/plan/serveurs.yml`, `instance/plan/applications.yml`, `instance/plan/bases-donnees.yml`, `instance/plan/domaines.yml`, `instance/plan/nomenclature.yml`, `docs/dependances-groupes.yml`).
|
||||
|
||||
Piliers de l'écosystème :
|
||||
|
||||
- **identité** — machines (PKI / certificats) et utilisateurs (annuaire + SSO) ;
|
||||
- **confiance** — autorité de certification interne (ACME) ;
|
||||
- **nommage et adressage** — DNS interne et nomenclature dérivable ;
|
||||
- **données** — bases relationnelles et cache, avec registre des connexions ;
|
||||
- **communication** — relais courriel interne ;
|
||||
- **observabilité et supervision** — métriques, journaux, tableaux de bord, supervision active ;
|
||||
- **applicatif** — services internes (forge, etc.) et couche web.
|
||||
|
||||
L'état voulu est **déclaratif et convergent** (appliqué par les groupes Ansible), **souverain** par conception, mais **piloté par l'opérateur** (pas d'auto-remédiation : la boucle n'est pas fermée). Une grande partie est aujourd'hui *définie et validée* avant d'être déployée sur des VM réelles ; le template Debian 13 reste la fondation, pas la finalité.
|
||||
|
||||
Cadre et règles d'autorité : voir `AGENTS.md` (section « Mission et identité »).
|
||||
|
||||
## Le plan : on édite, l'inventaire se génère
|
||||
|
||||
`Set-OPS` se pilote par un **plan**, pas par l'édition directe de l'inventaire.
|
||||
`instance/inventories/production/hosts.yml` est **généré** depuis le plan — **ne pas l'éditer à la main**.
|
||||
|
||||
```
|
||||
éditer le PLAN → make instancier (revoir le diff) → make instancier-appliquer → make deployer
|
||||
```
|
||||
|
||||
- **Plan** : `instance/plan/serveurs.yml` (les VM), `instance/plan/applications.yml` (les services et leurs liens), `instance/plan/bases-donnees.yml`, `instance/plan/domaines.yml`, dérivés via `instance/plan/nomenclature.yml`.
|
||||
- **GUI** (`make inventaire-ui`) : vues **Serveurs** et **Applications** pour éditer, puis « Appliquer le plan » ; la vue **Inventaire** est en lecture seule.
|
||||
- VMID / IP / VLAN sont **dérivés** de la `fonction` ; les groupes d'une VM sont dérivés des applications qui y tournent.
|
||||
|
||||
Guide complet : **`docs/plan-et-generation.md`**.
|
||||
|
||||
## Portée transverse
|
||||
|
||||
Au-delà des piliers ci-dessus, le dépôt couvre des préoccupations transverses, communes à toutes les VM :
|
||||
|
||||
- templates de VM Proxmox (la fondation) ;
|
||||
- groupes de conformité et durcissement ;
|
||||
- maintenance ;
|
||||
- sauvegardes.
|
||||
|
||||
## Premier chantier
|
||||
|
||||
Template Debian 13 Proxmox :
|
||||
|
||||
```text
|
||||
playbooks/modeles_vm/debian13_proxmox_preparer.yml
|
||||
playbooks/modeles_vm/debian13_proxmox_verifier.yml
|
||||
playbooks/modeles_vm/debian13_proxmox_nettoyer.yml
|
||||
```
|
||||
|
||||
## Principe
|
||||
|
||||
Le template contient seulement le socle commun.
|
||||
|
||||
Les services spécialisés seront installés ensuite sur les clones :
|
||||
|
||||
- NGINX ;
|
||||
- PostgreSQL ;
|
||||
- MariaDB ;
|
||||
- Docker/Podman ;
|
||||
- monitoring complet ;
|
||||
- applications métier.
|
||||
|
||||
## Exploitation courante
|
||||
|
||||
Un `Makefile` fournit les commandes d'exploitation principales.
|
||||
|
||||
Afficher l'aide :
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
Valider le dépôt :
|
||||
|
||||
```bash
|
||||
make verifier
|
||||
```
|
||||
|
||||
Inspecter les inventaires :
|
||||
|
||||
```bash
|
||||
make inventaire
|
||||
make hote-afficher HOTE=web-frontal-01
|
||||
```
|
||||
|
||||
Ouvrir l'interface locale de gestion d'inventaire :
|
||||
|
||||
```bash
|
||||
make inventaire-ui
|
||||
```
|
||||
|
||||
Planifier une VM passe désormais par le **plan**, pas par l'édition de l'inventaire :
|
||||
|
||||
1. déclarer la VM dans `instance/plan/serveurs.yml` (vue **Serveurs** du GUI, ou `make serveurs`) — `fonction`, `etat`, placement ; VMID/IP/VLAN sont dérivés ;
|
||||
2. déclarer les services qui y tournent dans `instance/plan/applications.yml` (vue **Applications**) ;
|
||||
3. régénérer l'inventaire :
|
||||
|
||||
```bash
|
||||
make instancier # génère + diff sémantique (que va-t-il changer ?)
|
||||
make instancier-appliquer # régénère instance/inventories/production/hosts.yml
|
||||
```
|
||||
|
||||
Les anciennes commandes `make hote-planifier` / `hote-ajouter` / `hote-groupes` éditaient l'inventaire **directement** ; elles sont **supplantées** par le plan (l'inventaire est généré, ne pas l'éditer à la main).
|
||||
|
||||
Chaque groupe opérationnel doit avoir son playbook homonyme dans `playbooks/groupes/`.
|
||||
|
||||
La conformité normale des VM passe par ces playbooks de groupes. Les rôles de socle et de durcissement sont appliqués par `serveur_debian` et `serveur_durci`, pas par des playbooks de couches séparés.
|
||||
|
||||
Les groupes opérationnels avec des hôtes, comme `serveur_web_frontal` ou `client_dns`, sont validés contre `playbooks/groupes/` par les commandes d'inventaire.
|
||||
|
||||
Le catalogue des services et intégrations prévus est dans `docs/catalogue-services.md`.
|
||||
|
||||
Les dépendances causales entre groupes sont dans `docs/dependances-groupes.yml`.
|
||||
|
||||
Le runbook du DNS interne initial est dans `docs/dns-interne.md`.
|
||||
|
||||
La nomenclature des noms de VM et des VMID est dans `docs/nomenclature-vm.md`.
|
||||
|
||||
Créer un clone depuis le modèle Debian 13 via l'API Proxmox :
|
||||
|
||||
```bash
|
||||
make config
|
||||
make creer-vm HOTE=web-frontal-01 # VMID/IP/VLAN/passerelle lus dans le plan
|
||||
make deployer HOTE=web-frontal-01
|
||||
```
|
||||
|
||||
L'hôte doit d'abord être déclaré dans `instance/plan/serveurs.yml` et l'inventaire régénéré (`make instancier-appliquer`) : `creer-vm` ne prend que `HOTE`, le reste est dérivé.
|
||||
|
||||
Les valeurs Cloud-Init communes déjà présentes dans le modèle Proxmox sont héritées par les clones.
|
||||
|
||||
Préparer le golden template Debian 13 Proxmox :
|
||||
|
||||
```bash
|
||||
make preparer-modele
|
||||
make verifier-modele
|
||||
```
|
||||
|
||||
Le nettoyage final du template est protégé :
|
||||
|
||||
```bash
|
||||
make nettoyer-modele CONFIRMER=true
|
||||
```
|
||||
|
||||
Déployer ou remettre en conformité une VM Debian clonée depuis le template :
|
||||
|
||||
```bash
|
||||
make deployer HOTE=web-frontal-01
|
||||
```
|
||||
|
||||
Déployer ou remettre en conformité un groupe :
|
||||
|
||||
```bash
|
||||
make deployer-groupe GROUPE=serveur_debian
|
||||
```
|
||||
|
||||
Les déploiements de groupes ciblent automatiquement les hôtes actifs seulement.
|
||||
62
SOLUTION.md
Normal file
62
SOLUTION.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# La solution Set-OPS
|
||||
|
||||
## Décision
|
||||
|
||||
`Set-OPS` est le moteur Ansible global d’exploitation d’écosystèmes numériques souverains.
|
||||
|
||||
Le template Debian 13 Proxmox est seulement un chantier dans ce dépôt.
|
||||
|
||||
## Ce qu'on fait maintenant
|
||||
|
||||
On garde une seule structure simple :
|
||||
|
||||
```text
|
||||
inventories/
|
||||
playbooks/
|
||||
roles/
|
||||
docs/
|
||||
```
|
||||
|
||||
Les rôles sont nommés clairement, sans sous-arborescence complexe.
|
||||
|
||||
## Commande principale pour construire le template
|
||||
|
||||
```bash
|
||||
ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_preparer.yml --ask-pass --ask-become-pass
|
||||
```
|
||||
|
||||
Après que sudo sans mot de passe fonctionne :
|
||||
|
||||
```bash
|
||||
ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_preparer.yml
|
||||
```
|
||||
|
||||
## Vérification
|
||||
|
||||
```bash
|
||||
ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_verifier.yml
|
||||
```
|
||||
|
||||
## Nettoyage final avant conversion
|
||||
|
||||
```bash
|
||||
ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_nettoyer.yml -e template_cleanup_confirm=true
|
||||
```
|
||||
|
||||
Ensuite :
|
||||
|
||||
```bash
|
||||
sudo shutdown -h now
|
||||
```
|
||||
|
||||
Puis côté Proxmox :
|
||||
|
||||
```bash
|
||||
qm template VMID
|
||||
```
|
||||
|
||||
## Important
|
||||
|
||||
Le pare-feu `nftables` est installé et préparé, mais il n'est pas activé par défaut dans le template.
|
||||
|
||||
C'est volontaire pour éviter de couper SSH pendant la construction.
|
||||
13
ansible.cfg
Normal file
13
ansible.cfg
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[defaults]
|
||||
inventory = instance/inventories/lab/hosts.yml
|
||||
roles_path = roles
|
||||
filter_plugins = filter_plugins
|
||||
interpreter_python = auto_silent
|
||||
host_key_checking = False
|
||||
retry_files_enabled = False
|
||||
stdout_callback = default
|
||||
|
||||
[privilege_escalation]
|
||||
become = True
|
||||
become_method = sudo
|
||||
become_user = root
|
||||
197
docs/MISE-A-JOUR-CODEX-CLAUDE.md
Normal file
197
docs/MISE-A-JOUR-CODEX-CLAUDE.md
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
# Mise à jour pour Codex et Claude Code — Set-OPS
|
||||
|
||||
## État du dépôt
|
||||
|
||||
`Set-OPS` est le moteur Ansible global d’exploitation d’écosystèmes numériques souverains.
|
||||
|
||||
Il ne sert pas seulement à créer un template Proxmox. Il doit contenir progressivement les playbooks, rôles, inventaires et templates nécessaires à tous les systèmes d’une instance.
|
||||
|
||||
Le chantier en cours est le template Debian 13 Proxmox.
|
||||
|
||||
---
|
||||
|
||||
## Fichiers de gouvernance
|
||||
|
||||
Les fichiers suivants doivent être lus avant toute modification :
|
||||
|
||||
```text
|
||||
AGENTS.md
|
||||
CLAUDE.md
|
||||
README.md
|
||||
CHANGELOG.md
|
||||
ansible.cfg
|
||||
```
|
||||
|
||||
`AGENTS.md` est la source d’autorité principale.
|
||||
|
||||
---
|
||||
|
||||
## État fonctionnel visé pour le template Debian 13
|
||||
|
||||
Le template Debian 13 Proxmox doit contenir :
|
||||
|
||||
- Debian minimal ;
|
||||
- SSH ;
|
||||
- sudo ;
|
||||
- compte `ansible` ;
|
||||
- sudo NOPASSWD pour `ansible` ;
|
||||
- `qemu-guest-agent` ;
|
||||
- `cloud-init` ;
|
||||
- `cloud-guest-utils` ;
|
||||
- chrony ;
|
||||
- outils de diagnostic ;
|
||||
- AppArmor ;
|
||||
- auditd ;
|
||||
- fail2ban SSH ;
|
||||
- unattended-upgrades ;
|
||||
- journald ;
|
||||
- sysctl de sécurité ;
|
||||
- nftables installé et préparé, mais désactivé par défaut.
|
||||
|
||||
Il ne doit pas contenir :
|
||||
|
||||
- NGINX ;
|
||||
- PostgreSQL ;
|
||||
- MariaDB ;
|
||||
- Docker ;
|
||||
- Podman ;
|
||||
- Redis ;
|
||||
- GitLab ;
|
||||
- Nextcloud ;
|
||||
- monitoring complet ;
|
||||
- secrets ;
|
||||
- clés privées ;
|
||||
- données propres à un clone.
|
||||
|
||||
---
|
||||
|
||||
## Incident récent à corriger
|
||||
|
||||
Le playbook :
|
||||
|
||||
```text
|
||||
playbooks/modeles_vm/debian13_proxmox_preparer.yml
|
||||
```
|
||||
|
||||
a échoué sur un handler manquant :
|
||||
|
||||
```text
|
||||
ERROR! The requested handler 'Validate and reload ssh' was not found
|
||||
```
|
||||
|
||||
Le problème est relié à des rôles contenant :
|
||||
|
||||
```yaml
|
||||
notify: Validate and reload ssh
|
||||
```
|
||||
|
||||
sans handler local correspondant.
|
||||
|
||||
Rôles à vérifier en priorité :
|
||||
|
||||
```text
|
||||
roles/ssh_baseline/
|
||||
roles/ssh_durcissement/
|
||||
```
|
||||
|
||||
Chaque rôle utilisant `notify` doit avoir son propre fichier :
|
||||
|
||||
```text
|
||||
roles/<role>/handlers/main.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Correctif minimal attendu
|
||||
|
||||
Ne pas régénérer tout le dépôt.
|
||||
|
||||
Créer ou corriger :
|
||||
|
||||
```text
|
||||
roles/ssh_baseline/handlers/main.yml
|
||||
roles/ssh_durcissement/handlers/main.yml
|
||||
```
|
||||
|
||||
Contenu attendu :
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Valider la configuration SSH
|
||||
ansible.builtin.command: sshd -t
|
||||
changed_when: false
|
||||
listen: Validate and reload ssh
|
||||
|
||||
- name: Recharger SSH
|
||||
ansible.builtin.systemd:
|
||||
name: ssh
|
||||
state: reloaded
|
||||
listen: Validate and reload ssh
|
||||
```
|
||||
|
||||
Puis vérifier tous les `notify` :
|
||||
|
||||
```bash
|
||||
find roles -path '*/tasks/*.yml' -exec grep -H "notify:" {} \;
|
||||
find roles -path '*/handlers/main.yml' -print
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation obligatoire
|
||||
|
||||
Après correction :
|
||||
|
||||
```bash
|
||||
make syntax-template
|
||||
```
|
||||
|
||||
Puis relancer :
|
||||
|
||||
```bash
|
||||
make preparer-modele
|
||||
```
|
||||
|
||||
Puis vérifier :
|
||||
|
||||
```bash
|
||||
make verifier-modele
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Nettoyage final
|
||||
|
||||
Ne lancer le nettoyage final que lorsque la VM est validée :
|
||||
|
||||
```bash
|
||||
make nettoyer-modele CONFIRMER=true
|
||||
```
|
||||
|
||||
Ensuite seulement :
|
||||
|
||||
```bash
|
||||
sudo shutdown -h now
|
||||
```
|
||||
|
||||
Puis côté Proxmox :
|
||||
|
||||
```bash
|
||||
qm template VMID
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Règle de conduite
|
||||
|
||||
Ne pas faire de régénération massive.
|
||||
|
||||
Lire l’existant.
|
||||
|
||||
Corriger petit.
|
||||
|
||||
Valider.
|
||||
|
||||
Mettre à jour `CHANGELOG.md`.
|
||||
|
||||
Résumer clairement ce qui a été fait et ce qui n’a pas été testé.
|
||||
66
docs/architecture-set-ops.md
Normal file
66
docs/architecture-set-ops.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# Architecture Set-OPS
|
||||
|
||||
Set-OPS définit et construit l'écosystème numérique souverain. Il se
|
||||
pilote par un **plan** : l'inventaire Ansible (`instance/inventories/production/hosts.yml`)
|
||||
est **généré** depuis le plan, pas édité à la main.
|
||||
|
||||
- Modèle, registres, commandes et flux de travail : **`docs/plan-et-generation.md`**.
|
||||
- Règles d'autorité : **`AGENTS.md`** (sections « Mission et identité » et « Le plan et la génération de l'inventaire »).
|
||||
|
||||
## Entités du plan
|
||||
|
||||
```text
|
||||
serveur (VM) instance/plan/serveurs.yml fonction, état, placement, intégrations
|
||||
application instance/plan/applications.yml groupe (rôle), hôte, port, requiert, expose
|
||||
base instance/plan/bases-donnees.yml serveur de BD, base, propriétaire, secret (Vault), portée
|
||||
domaine (DNS) instance/plan/domaines.yml zone publique, autorité, edge
|
||||
nomenclature instance/plan/nomenclature.yml fonctions -> VMID / VLAN / IP (dérivés)
|
||||
```
|
||||
|
||||
L'**application** est l'entité pivot ; le **groupe** Ansible n'est qu'une capacité
|
||||
(le rôle appliqué). VMID / IP / VLAN et les appartenances de groupes sont **dérivés**.
|
||||
|
||||
## Rôles Ansible
|
||||
|
||||
Les rôles actifs sont conservés directement sous `roles/`.
|
||||
|
||||
Les sous-arborescences catégorielles de rôles ne doivent pas dupliquer un rôle actif. Un nouveau rôle doit être ajouté seulement lorsqu'un besoin opérationnel réel existe.
|
||||
|
||||
Les valeurs communes aux rôles doivent rester dans les defaults des rôles quand elles sont valables pour tous les environnements. Les inventaires ne doivent contenir que les politiques propres à leur contexte.
|
||||
|
||||
## Groupes et playbooks
|
||||
|
||||
Les groupes opérationnels de l'inventaire doivent correspondre à un playbook homonyme :
|
||||
|
||||
```text
|
||||
instance/inventories/production/hosts.yml
|
||||
serveur_debian
|
||||
|
||||
playbooks/groupes/serveur_debian.yml
|
||||
```
|
||||
|
||||
Cette relation rend l'exploitation lisible :
|
||||
|
||||
```text
|
||||
appartenance à un groupe
|
||||
→ playbook correspondant
|
||||
→ état voulu appliqué par Ansible
|
||||
```
|
||||
|
||||
Les groupes structurels ou vides peuvent exister, mais un groupe assigné à une VM de production doit avoir un playbook s'il exprime une intention de configuration.
|
||||
|
||||
## Cycle de vie VM
|
||||
|
||||
Le cycle de vie des VM est documenté dans :
|
||||
|
||||
```text
|
||||
docs/vm-lifecycle.md
|
||||
```
|
||||
|
||||
## Intégrations futures
|
||||
|
||||
Les intégrations transversales des VM sont documentées dans :
|
||||
|
||||
```text
|
||||
docs/integrations-vm.md
|
||||
```
|
||||
222
docs/catalogue-services.md
Normal file
222
docs/catalogue-services.md
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
# Catalogue des services
|
||||
|
||||
Ce document fixe les noms de groupes et de playbooks pour les prochains services.
|
||||
|
||||
La règle reste :
|
||||
|
||||
```text
|
||||
groupe opérationnel -> playbooks/groupes/<groupe>.yml
|
||||
```
|
||||
|
||||
Les playbooks ajoutés maintenant sont des points d'ancrage. Ils ne doivent pas installer un service tant que le rôle correspondant n'existe pas et que ses variables, secrets et prérequis sont documentés.
|
||||
|
||||
La nomenclature des VM et des VMID est documentée dans `docs/nomenclature-vm.md`.
|
||||
|
||||
Un service central peut partager un hôte avec d'autres services de la même fonction opérationnelle (plusieurs applications par VM). La relation stricte est entre groupe et playbook, pas entre groupe et VM.
|
||||
|
||||
> Modèle à jour : chaque service est une **application** (`instance/plan/applications.yml`). Voir `docs/plan-et-generation.md`.
|
||||
|
||||
## État d'implémentation des rôles
|
||||
|
||||
> **Mise à jour (2026-06-24).** La plupart des rôles ci-dessous **existent désormais** —
|
||||
> écrits et validés *en tant que code*, **pas encore éprouvés sur des VM réelles**. Le rôle
|
||||
> effectif porte le nom du **groupe** (`serveur_keycloak`, `client_pki`…), pas le nom court
|
||||
> de la colonne « Rôle » des tables.
|
||||
|
||||
**Implémentés** (`tasks` + `templates` + `handlers`, validés) : `serveur_step_ca`,
|
||||
`client_pki`, `serveur_powerdns`, `client_dns`, `serveur_openldap`, `client_ldap`,
|
||||
`serveur_keycloak`, `serveur_postgresql`, `serveur_redis`, `serveur_nginx`,
|
||||
`serveur_sendmail`, `client_smtp`, `serveur_prometheus`, `client_metrique`, `serveur_loki`,
|
||||
`client_journal`, `serveur_grafana`, `serveur_icinga`, `serveur_forgejo`. Plus le socle et
|
||||
le durcissement, appliqués par `serveur_debian` / `serveur_durci`.
|
||||
|
||||
**Échafaudages** (playbook-ancre `debug` « reste à définir », **sans rôle**) :
|
||||
`serveur_nextcloud`, `serveur_collabora`, `client_supervision`, `serveur_web_frontal`,
|
||||
`serveur_web_dorsal`. Les capacités *collaboration* et *couche web applicative* sont câblées
|
||||
par convention mais pas encore implémentées.
|
||||
|
||||
**Rôles-catégories inertes** (dossiers `roles/<x>/` réduits à un `README.md`, jamais câblés) :
|
||||
`applications`, `backup`, `database`, `identity`, `monitoring`, `proxmox`, `storage`, `web`.
|
||||
L'architecture réelle est **plate** (`serveur_*` / `client_*`) ; ces dossiers sont des
|
||||
vestiges d'un regroupement par catégorie abandonné — à supprimer ou réactiver lors d'une
|
||||
consolidation ultérieure.
|
||||
|
||||
## Services centraux
|
||||
|
||||
| Service | Groupe | Playbook | Rôle |
|
||||
| --- | --- | --- | --- |
|
||||
| Keycloak | `serveur_keycloak` | `playbooks/groupes/serveur_keycloak.yml` | `keycloak` |
|
||||
| OpenLDAP | `serveur_openldap` | `playbooks/groupes/serveur_openldap.yml` | `openldap` |
|
||||
| PostgreSQL | `serveur_postgresql` | `playbooks/groupes/serveur_postgresql.yml` | `postgresql` |
|
||||
| Loki | `serveur_loki` | `playbooks/groupes/serveur_loki.yml` | `loki` |
|
||||
| Plateforme Icinga | `serveur_icinga` | `playbooks/groupes/serveur_icinga.yml` | `icinga` |
|
||||
| Prometheus | `serveur_prometheus` | `playbooks/groupes/serveur_prometheus.yml` | `prometheus` |
|
||||
| Grafana | `serveur_grafana` | `playbooks/groupes/serveur_grafana.yml` | `grafana` |
|
||||
| Forgejo | `serveur_forgejo` | `playbooks/groupes/serveur_forgejo.yml` | `forgejo` |
|
||||
| Sendmail MTA | `serveur_sendmail` | `playbooks/groupes/serveur_sendmail.yml` | `sendmail` |
|
||||
| step-ca | `serveur_step_ca` | `playbooks/groupes/serveur_step_ca.yml` | `step_ca` |
|
||||
| PowerDNS | `serveur_powerdns` | `playbooks/groupes/serveur_powerdns.yml` | `serveur_powerdns` |
|
||||
| Redis | `serveur_redis` | `playbooks/groupes/serveur_redis.yml` | `redis` |
|
||||
| NGINX WAF et reverse proxy | `serveur_nginx` | `playbooks/groupes/serveur_nginx.yml` | `nginx` |
|
||||
| Nextcloud | `serveur_nextcloud` | `playbooks/groupes/serveur_nextcloud.yml` | `nextcloud` |
|
||||
| Collabora | `serveur_collabora` | `playbooks/groupes/serveur_collabora.yml` | `collabora` |
|
||||
|
||||
## Couche applicative web
|
||||
|
||||
La couche applicative web est distincte de l'edge `serveur_nginx` :
|
||||
|
||||
- `serveur_nginx` est l'edge : mandataire inverse, terminaison TLS, WAF ; il reçoit le trafic externe et le route.
|
||||
- `serveur_web_frontal` est la couche présentation web (UI, rendu, assets), servie *derrière* l'edge.
|
||||
- `serveur_web_dorsal` est la couche application web (API, traitement), consommée par les frontaux.
|
||||
|
||||
Le « web » de ces deux groupes est implicite par leur position derrière `serveur_nginx`. Le jour où un service dorsal n'est pas web (worker batch, file, démon), créer un groupe dédié plutôt que d'élargir `serveur_web_dorsal`.
|
||||
|
||||
| Couche | Groupe | Playbook | Rôle |
|
||||
| --- | --- | --- | --- |
|
||||
| Présentation web (frontends) | `serveur_web_frontal` | `playbooks/groupes/serveur_web_frontal.yml` | `web_frontaux` |
|
||||
| Application web (backends) | `serveur_web_dorsal` | `playbooks/groupes/serveur_web_dorsal.yml` | `web_dorsaux` |
|
||||
|
||||
Hôtes planifiés : `web-frontal-01` et `web-frontal-02` dans `serveur_web_frontal` ; `web-dorsal-01` dans `serveur_web_dorsal`. Aucun n'est encore actif (à créer puis activer).
|
||||
|
||||
Dépendance d'intégration prévue : `serveur_web_frontal` devra publier via `serveur_nginx` (règle « tout service exposé en HTTP(S) passe par l'edge »). Cette dépendance n'est pas encore déclarée dans `docs/dependances-groupes.yml` (les deux groupes sont vides) ; elle sera ajoutée avec le rôle `web_frontaux`, lorsque des frontaux actifs devront publier via l'edge.
|
||||
|
||||
## Hôtes planifiés
|
||||
|
||||
| Hôte | Services |
|
||||
| --- | --- |
|
||||
| `infra-pki-01` | step-ca |
|
||||
| `infra-edge-01` | NGINX WAF et reverse proxy |
|
||||
| `infra-mail-01` | Sendmail MTA |
|
||||
| `infra-dns-01` | PowerDNS |
|
||||
| `idm-01` | OpenLDAP, Keycloak |
|
||||
| `data-01` | PostgreSQL, Redis |
|
||||
| `obs-01` | Prometheus, Loki, Grafana |
|
||||
| `mon-01` | Plateforme Icinga : Icinga 2, Icinga Web 2, Icinga BPM |
|
||||
| `forge-01` | Forgejo |
|
||||
| `collab-01` | Nextcloud, Collabora |
|
||||
|
||||
## Intégrations clientes
|
||||
|
||||
| Intégration | Groupe | Playbook | Rôle |
|
||||
| --- | --- | --- | --- |
|
||||
| Résolution DNS interne | `client_dns` | `playbooks/groupes/client_dns.yml` | `client_dns` |
|
||||
| Confiance PKI / ACME | `client_pki` | `playbooks/groupes/client_pki.yml` | `client_pki` |
|
||||
| Authentification LDAP | `client_ldap` | `playbooks/groupes/client_ldap.yml` | `client_ldap` |
|
||||
| Supervision Icinga | `client_supervision` | `playbooks/groupes/client_supervision.yml` | `client_supervision` |
|
||||
| Métriques Prometheus | `client_metrique` | `playbooks/groupes/client_metrique.yml` | `client_metriques` |
|
||||
| Journaux vers Loki | `client_journal` | `playbooks/groupes/client_journal.yml` | `client_journaux` |
|
||||
| Relais SMTP | `client_smtp` | `playbooks/groupes/client_smtp.yml` | `client_smtp` |
|
||||
|
||||
## Ordre d'implémentation recommandé
|
||||
|
||||
L'ordre ci-dessous privilégie les dépendances structurantes avant les applications.
|
||||
|
||||
### Phase 1 - Fondations transversales
|
||||
|
||||
1. `serveur_powerdns`
|
||||
- Service central : DNS interne autoritaire et/ou résolution interne selon le design retenu.
|
||||
- Intégration à prévoir : `client_dns`.
|
||||
- Raison : les autres intégrations auront besoin de noms stables plutôt que d'adresses IP.
|
||||
|
||||
2. `serveur_step_ca`
|
||||
- Service central : autorité de certification interne et ACME.
|
||||
- Intégration à prévoir : `client_pki`.
|
||||
- Raison : les autres services auront besoin de certificats fiables avant d'être exposés proprement.
|
||||
|
||||
3. `serveur_nginx`
|
||||
- Service central : reverse proxy, terminaison TLS, publication HTTP(S), WAF.
|
||||
- Intégration à prévoir : publication des services HTTP derrière le proxy.
|
||||
- Raison : plusieurs services seront consommés par navigateur ou API et doivent passer par un point d'entrée cohérent.
|
||||
|
||||
4. `serveur_sendmail`
|
||||
- Service central : relais SMTP sortant.
|
||||
- Intégration à prévoir : `client_smtp`.
|
||||
- Raison : les notifications, réinitialisations de mot de passe et alertes doivent fonctionner tôt.
|
||||
|
||||
### Phase 2 - Données et identité
|
||||
|
||||
5. `serveur_postgresql`
|
||||
- Service central : base de données relationnelle partagée.
|
||||
- Intégration à prévoir : bases dédiées par application, comptes applicatifs et sauvegardes.
|
||||
- Raison : Keycloak, Grafana, Icinga Web 2, Forgejo et Nextcloud peuvent dépendre de PostgreSQL.
|
||||
|
||||
6. `serveur_openldap`
|
||||
- Service central : annuaire interne.
|
||||
- Intégration à prévoir : `client_ldap`.
|
||||
- Raison : l'identité Unix et l'annuaire doivent exister avant les intégrations d'authentification avancées.
|
||||
|
||||
7. `serveur_keycloak`
|
||||
- Service central : SSO/OIDC/SAML.
|
||||
- Intégration à prévoir : applications web derrière `serveur_nginx`.
|
||||
- Raison : les applications devraient être branchées au SSO dès leur arrivée plutôt qu'après coup.
|
||||
|
||||
### Phase 3 - Observabilité minimale
|
||||
|
||||
8. `serveur_prometheus`
|
||||
- Service central : métriques.
|
||||
- Intégration à prévoir : `client_metrique`.
|
||||
- Raison : les prochains services doivent être mesurables dès leur déploiement.
|
||||
|
||||
9. `serveur_loki`
|
||||
- Service central : journaux centralisés.
|
||||
- Intégration à prévoir : `client_journal`.
|
||||
- Raison : les journaux centralisés accélèrent le diagnostic des services suivants.
|
||||
|
||||
10. `serveur_grafana`
|
||||
- Service central : tableaux de bord.
|
||||
- Intégration à prévoir : datasources Prometheus et Loki, authentification Keycloak.
|
||||
- Raison : Grafana consolide les métriques et journaux après leur mise en place.
|
||||
|
||||
### Phase 4 - Supervision active
|
||||
|
||||
11. `serveur_icinga`
|
||||
- Service central : supervision active, interface web et vues métiers Icinga.
|
||||
- Composants prévus : Icinga 2, Icinga Web 2, Icinga BPM.
|
||||
- Intégrations à prévoir : `client_supervision`, PostgreSQL, NGINX, Keycloak si retenu.
|
||||
- Raison : ces composants forment une même capacité de supervision et gagnent à cohabiter sur `mon-01` au départ.
|
||||
|
||||
### Phase 5 - Services applicatifs internes
|
||||
|
||||
12. `serveur_redis`
|
||||
- Service central : cache et files internes.
|
||||
- Intégration à prévoir : Nextcloud et autres applications qui en ont besoin.
|
||||
- Raison : Redis est une dépendance applicative, pas une fondation globale.
|
||||
|
||||
13. `serveur_forgejo`
|
||||
- Service central : forge Git.
|
||||
- Intégration à prévoir : PostgreSQL, NGINX, Keycloak, SMTP, sauvegardes.
|
||||
- Raison : la forge devient plus utile après SSO, TLS, SMTP et observabilité.
|
||||
|
||||
14. `serveur_nextcloud`
|
||||
- Service central : collaboration fichiers.
|
||||
- Intégration à prévoir : PostgreSQL, Redis, NGINX, Keycloak, SMTP, sauvegardes.
|
||||
- Raison : Nextcloud dépend de plusieurs fondations et doit arriver après elles.
|
||||
|
||||
15. `serveur_collabora`
|
||||
- Service central : édition documentaire en ligne.
|
||||
- Intégration à prévoir : Nextcloud, NGINX, certificats.
|
||||
- Raison : Collabora est une extension de Nextcloud et doit venir après lui.
|
||||
|
||||
## Règles d'intégration
|
||||
|
||||
- Tout service exposé en HTTP(S) doit prévoir son intégration avec `serveur_nginx`.
|
||||
- Tout service avec authentification humaine doit prévoir son intégration avec `serveur_keycloak`, sauf justification contraire.
|
||||
- Tout service générant des alertes ou notifications doit prévoir `client_smtp`.
|
||||
- Toute VM de service doit rejoindre `client_metrique`, `client_journal` et `client_supervision` quand les services centraux correspondants existent.
|
||||
- Tout service utilisant un certificat interne doit dépendre de `client_pki`.
|
||||
- Tout rôle serveur doit documenter ses ports, secrets, sauvegardes, dépendances et groupes clients associés.
|
||||
|
||||
Les groupes clients peuvent être ajoutés aux VM existantes quand le service central correspondant est réellement disponible.
|
||||
|
||||
## Dépendances causales
|
||||
|
||||
Les dépendances exécutables sont déclarées dans `docs/dependances-groupes.yml`.
|
||||
|
||||
Le runbook DNS initial est dans `docs/dns-interne.md`.
|
||||
|
||||
Ce fichier sert à deux usages :
|
||||
|
||||
- bloquer le déploiement d'un groupe tant que ses prérequis actifs ne sont pas présents ;
|
||||
- fournir une source exploitable pour les futurs modèles de supervision.
|
||||
|
||||
Un hôte peut porter un groupe client à l'état planifié. Le déploiement est refusé tant que le groupe serveur requis n'a pas au moins un hôte actif.
|
||||
86
docs/dependances-groupes.yml
Normal file
86
docs/dependances-groupes.yml
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
groupes:
|
||||
client_dns:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_powerdns
|
||||
raison: "Les resolvers clients ne doivent pas pointer vers un service DNS absent."
|
||||
surveillance: "Verifier resolution interne et disponibilite du service DNS."
|
||||
|
||||
client_pki:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_step_ca
|
||||
raison: "La confiance CA et ACME client dependent de l'autorite interne."
|
||||
surveillance: "Verifier validite CA, emission ACME et expiration des certificats."
|
||||
|
||||
client_ldap:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_openldap
|
||||
raison: "La configuration NSS/PAM/SSSD depend de l'annuaire LDAP."
|
||||
surveillance: "Verifier bind LDAP, latence et expiration des certificats LDAP."
|
||||
|
||||
client_supervision:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_icinga
|
||||
raison: "Les agents ou checks clients doivent se rattacher a une plateforme Icinga active."
|
||||
surveillance: "Verifier enregistrement des hotes, fraicheur des checks et notifications."
|
||||
|
||||
client_metrique:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_prometheus
|
||||
raison: "Les exporters clients doivent etre collectes par Prometheus."
|
||||
surveillance: "Verifier targets Prometheus, scrape duration et erreurs de collecte."
|
||||
|
||||
client_journal:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_loki
|
||||
raison: "L'expedition des journaux depend du collecteur central Loki."
|
||||
surveillance: "Verifier ingestion Loki, retard et volume de journaux."
|
||||
|
||||
client_smtp:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_sendmail
|
||||
raison: "Les notifications locales doivent relayer vers un MTA actif."
|
||||
surveillance: "Verifier file d'attente, relais SMTP et echecs de livraison."
|
||||
|
||||
serveur_keycloak:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_postgresql
|
||||
raison: "Keycloak doit utiliser une base PostgreSQL geree."
|
||||
surveillance: "Verifier connexion base, etat realm et disponibilite OIDC."
|
||||
|
||||
serveur_grafana:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_prometheus
|
||||
- serveur_loki
|
||||
raison: "Grafana est utile comme interface aux metriques et journaux centraux."
|
||||
surveillance: "Verifier datasources Prometheus/Loki et authentification."
|
||||
|
||||
serveur_icinga:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_postgresql
|
||||
raison: "La plateforme Icinga Web/BPM depend d'une base relationnelle."
|
||||
surveillance: "Verifier moteur Icinga, base, interface web et notifications."
|
||||
|
||||
serveur_forgejo:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_postgresql
|
||||
- serveur_nginx
|
||||
- serveur_sendmail
|
||||
raison: "Forgejo depend d'une base, d'une publication HTTP(S) et du courriel."
|
||||
surveillance: "Verifier HTTP(S), base, files Git et envoi courriel."
|
||||
|
||||
serveur_nextcloud:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_postgresql
|
||||
- serveur_redis
|
||||
- serveur_nginx
|
||||
- serveur_sendmail
|
||||
raison: "Nextcloud depend d'une base, d'un cache, d'un frontal web et du courriel."
|
||||
surveillance: "Verifier jobs, base, Redis, HTTP(S), stockage et courriel."
|
||||
|
||||
serveur_collabora:
|
||||
requiert_groupes_actifs:
|
||||
- serveur_nextcloud
|
||||
- serveur_nginx
|
||||
raison: "Collabora est expose via le frontal web et integre a Nextcloud."
|
||||
surveillance: "Verifier connectivite Nextcloud, websocket et disponibilite HTTP(S)."
|
||||
90
docs/dns-interne.md
Normal file
90
docs/dns-interne.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# DNS interne
|
||||
|
||||
Le service DNS interne est la premiere capacite de plateforme.
|
||||
|
||||
## Groupes
|
||||
|
||||
```text
|
||||
serveur_powerdns -> service DNS central PowerDNS Authoritative
|
||||
client_dns -> integration cliente DNS
|
||||
```
|
||||
|
||||
`client_dns` depend de `serveur_powerdns` dans `docs/dependances-groupes.yml`.
|
||||
|
||||
## Zone initiale
|
||||
|
||||
La zone initiale est :
|
||||
|
||||
```text
|
||||
exemple.internal
|
||||
```
|
||||
|
||||
Elle est definie dans :
|
||||
|
||||
```text
|
||||
instance/inventories/production/group_vars/serveur_powerdns.yml
|
||||
```
|
||||
|
||||
## Enregistrement automatique
|
||||
|
||||
Le role `serveur_powerdns` genere la zone a partir de l'inventaire.
|
||||
|
||||
Les hotes qui remplissent ces conditions sont ajoutes automatiquement :
|
||||
|
||||
```text
|
||||
hote dans hotes_actifs
|
||||
ansible_host defini
|
||||
```
|
||||
|
||||
Exemple :
|
||||
|
||||
```text
|
||||
web-frontal-01 ansible_host=10.0.2.31
|
||||
-> web-frontal-01.exemple.internal A 10.0.2.31
|
||||
```
|
||||
|
||||
Les enregistrements additionnels explicites sont dans `serveur_powerdns_records`.
|
||||
|
||||
## Backend PowerDNS
|
||||
|
||||
Le premier jalon utilise le backend BIND de PowerDNS.
|
||||
|
||||
Raison :
|
||||
|
||||
- pas de dependance prematuree a PostgreSQL ;
|
||||
- zone lisible et generee par Ansible ;
|
||||
- idempotence simple ;
|
||||
- bon point de depart pour la supervision.
|
||||
|
||||
Quand `serveur_postgresql` sera stable, il sera possible de migrer vers un backend SQL si le besoin operationnel le justifie.
|
||||
|
||||
## Clients DNS
|
||||
|
||||
Le role `client_dns` valide :
|
||||
|
||||
- qu'un serveur `serveur_powerdns` actif existe ;
|
||||
- que la zone repond a une requete SOA ;
|
||||
- que le nom de l'hote existe dans la zone.
|
||||
|
||||
La modification du resolver local est protegee :
|
||||
|
||||
```yaml
|
||||
client_dns_apply: true
|
||||
client_dns_confirm: true
|
||||
```
|
||||
|
||||
Sans ces deux variables, le role valide les prerequis mais ne modifie pas `/etc/resolv.conf`.
|
||||
|
||||
Cette protection est volontaire : une mauvaise configuration DNS peut couper la resolution de noms.
|
||||
|
||||
## Surveillance a prevoir
|
||||
|
||||
Les premiers checks utiles :
|
||||
|
||||
- service `pdns` actif ;
|
||||
- port UDP/TCP 53 disponible ;
|
||||
- SOA de `exemple.internal` resoluble ;
|
||||
- enregistrement `ns1.exemple.internal` resoluble ;
|
||||
- enregistrements des hotes actifs presents ;
|
||||
- serial de zone attendu ;
|
||||
- latence de resolution.
|
||||
43
docs/integrations-vm.md
Normal file
43
docs/integrations-vm.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Intégrations futures des VM
|
||||
|
||||
Les serveurs centraux ne sont pas encore en place. Les rôles d'intégration doivent donc rester optionnels et désactivés par défaut tant que leurs dépendances n'existent pas.
|
||||
|
||||
## Séparation
|
||||
|
||||
```text
|
||||
Template Debian 13 Proxmox : socle commun minimal
|
||||
Cloud-init : identité initiale du clone
|
||||
Set-OPS + Ansible : configuration réelle du serveur
|
||||
```
|
||||
|
||||
Le template ne doit pas être modifié pour chaque nouveau serveur. Les intégrations sont appliquées après clonage selon les groupes d'inventaire et les playbooks dédiés.
|
||||
|
||||
## Domaines prévus
|
||||
|
||||
```text
|
||||
DNS interne : PowerDNS, résolveurs, enregistrements applicatifs
|
||||
PKI interne : step-ca, ACME, confiance CA locale
|
||||
Identité : LDAP, SSSD, Keycloak/OIDC selon le besoin
|
||||
Supervision : Icinga2 agent ou checks distants
|
||||
Métriques : Prometheus node_exporter
|
||||
Visualisation : Grafana côté plateforme centrale
|
||||
```
|
||||
|
||||
## Principes Ansible
|
||||
|
||||
- Chaque rôle d'intégration doit être désactivé par défaut.
|
||||
- Chaque variable de rôle doit utiliser le préfixe du rôle.
|
||||
- Les secrets ne doivent jamais être stockés en clair dans le dépôt.
|
||||
- Un rôle ne doit pas échouer si son intégration est désactivée.
|
||||
- Les playbooks applicatifs doivent être appliqués sur les clones, pas sur le template.
|
||||
- Les opérations pouvant couper l'accès réseau ou SSH doivent exiger une confirmation explicite.
|
||||
|
||||
## Ordre logique de construction
|
||||
|
||||
1. DNS interne.
|
||||
2. PKI interne et confiance CA.
|
||||
3. Identité système et applicative.
|
||||
4. Supervision et métriques.
|
||||
5. Visualisation et alerting.
|
||||
|
||||
Cet ordre reste indicatif. Les rôles doivent rester découplés pour permettre une adoption progressive.
|
||||
312
docs/modeles_vm/debian13-proxmox.md
Normal file
312
docs/modeles_vm/debian13-proxmox.md
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
# Golden template Debian 13 Proxmox
|
||||
|
||||
## Objet
|
||||
|
||||
Ce document justifie les ajouts appliqués par Set-OPS à une installation Debian 13 minimale pour obtenir le golden template Proxmox.
|
||||
|
||||
Le template doit rester un socle commun, clonable et sécuritaire. Il ne doit pas devenir un serveur applicatif ni intégrer des dépendances propres à un rôle final.
|
||||
|
||||
## État de départ
|
||||
|
||||
L'état de départ attendu est décrit dans :
|
||||
|
||||
```text
|
||||
docs/procedure-template-debian13-proxmox.md
|
||||
```
|
||||
|
||||
Résumé :
|
||||
|
||||
```text
|
||||
Debian 13 minimal
|
||||
aucun environnement graphique
|
||||
SSH installé
|
||||
partition EFI
|
||||
partition racine ext4
|
||||
pas de LVM
|
||||
pas de swap
|
||||
disque agrandissable
|
||||
CloudInit Drive Proxmox présent
|
||||
ciuser et clé SSH injectés par Cloud-Init
|
||||
aucun secret
|
||||
aucune donnée propre à un clone final
|
||||
```
|
||||
|
||||
## Runbook du playbook prepare
|
||||
|
||||
### Objectif
|
||||
|
||||
Le playbook `debian13_proxmox_preparer.yml` transforme une VM Debian 13 minimale en socle golden template.
|
||||
|
||||
Il installe les composants communs, configure l'accès Ansible, applique le durcissement template-safe et prépare la VM pour cloud-init.
|
||||
|
||||
Il ne fait pas le nettoyage final avant conversion en template.
|
||||
|
||||
### Prérequis côté VM
|
||||
|
||||
Avant de lancer le playbook, la VM doit respecter ces conditions :
|
||||
|
||||
```text
|
||||
Debian installé et démarré
|
||||
réseau fonctionnel
|
||||
SSH joignable depuis le poste Ansible
|
||||
CloudInit Drive présent côté Proxmox
|
||||
utilisateur Ansible initial injecté par Cloud-Init
|
||||
clé publique SSH injectée par Cloud-Init
|
||||
sudo ou accès root possible
|
||||
APT fonctionnel
|
||||
aucun rôle applicatif déjà installé
|
||||
VM destinée à devenir un template, pas un serveur de production
|
||||
```
|
||||
|
||||
Vérifications utiles depuis le poste Ansible :
|
||||
|
||||
```bash
|
||||
ssh ansible@10.0.2.99
|
||||
ansible -i instance/inventories/lab/hosts.yml modeles_vm -m ping
|
||||
ansible -i instance/inventories/lab/hosts.yml modeles_vm -m setup
|
||||
```
|
||||
|
||||
Adapter l'utilisateur et l'adresse IP selon `instance/inventories/lab/hosts.yml`.
|
||||
|
||||
### Prérequis côté dépôt
|
||||
|
||||
Avant l'exécution :
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
make syntax-template
|
||||
```
|
||||
|
||||
L'inventaire doit contenir la VM dans le groupe :
|
||||
|
||||
```text
|
||||
modeles_vm
|
||||
```
|
||||
|
||||
Les variables du template sont dans :
|
||||
|
||||
```text
|
||||
instance/inventories/lab/group_vars/modeles_vm.yml
|
||||
```
|
||||
|
||||
### Commande de préparation
|
||||
|
||||
Lancement lorsque l'accès par clé et sudo sont fonctionnels :
|
||||
|
||||
```bash
|
||||
make preparer-modele
|
||||
```
|
||||
|
||||
Le flux `make` suppose que SSH par clé et sudo NOPASSWD sont déjà fonctionnels pour `ansible`.
|
||||
|
||||
### Déroulement attendu
|
||||
|
||||
Le playbook :
|
||||
|
||||
1. vérifie que la cible est Debian ;
|
||||
2. avertit si la version majeure n'est pas Debian 13 ;
|
||||
3. installe les paquets communs ;
|
||||
4. active `qemu-guest-agent` ;
|
||||
5. installe et configure `cloud-init` ;
|
||||
6. configure le compte technique Ansible ;
|
||||
7. active la synchronisation du temps ;
|
||||
8. configure SSH ;
|
||||
9. applique le durcissement template-safe ;
|
||||
10. prépare nftables sans l'activer ;
|
||||
11. affiche le statut cloud-init.
|
||||
|
||||
### Résultat attendu
|
||||
|
||||
Une première exécution peut changer la VM.
|
||||
|
||||
Une relance sur une VM déjà préparée doit idéalement finir avec :
|
||||
|
||||
```text
|
||||
failed=0
|
||||
changed=0
|
||||
```
|
||||
|
||||
Un résultat `changed=0` à la relance est le signal que le playbook est idempotent dans l'état actuel.
|
||||
|
||||
### Erreurs fréquentes
|
||||
|
||||
| Symptôme | Cause probable | Action |
|
||||
| --- | --- | --- |
|
||||
| `UNREACHABLE` | IP, SSH, utilisateur ou clé SSH incorrecte. | Vérifier `instance/inventories/lab/hosts.yml`, cloud-init et tester `ssh`. |
|
||||
| échec `become` | Sudo NOPASSWD absent ou utilisateur non autorisé. | Corriger l'accès sudo initial, puis relancer `make preparer-modele`. |
|
||||
| échec APT | DNS, passerelle, miroir Debian ou verrou APT. | Vérifier réseau, DNS et processus APT en cours. |
|
||||
| erreur handler SSH | Handler manquant ou nom `notify` incohérent. | Vérifier les handlers du rôle SSH avant de relancer. |
|
||||
| avertissement Debian non 13 | La cible n'est pas Debian 13. | Ne pas convertir en template Debian 13 sans justification. |
|
||||
|
||||
### Point d'arrêt
|
||||
|
||||
Après `prepare`, ne pas convertir immédiatement la VM en template.
|
||||
|
||||
Exécuter d'abord :
|
||||
|
||||
```bash
|
||||
make verifier-modele
|
||||
```
|
||||
|
||||
Le playbook de vérification contrôle notamment Debian 13, les paquets requis, l'absence de swap actif, l'absence d'environnement graphique, les services de base, `nftables` désactivé, sudo NOPASSWD et le durcissement SSH effectif.
|
||||
|
||||
Le nettoyage final se lance seulement après validation complète :
|
||||
|
||||
```bash
|
||||
make nettoyer-modele CONFIRMER=true
|
||||
```
|
||||
|
||||
Ne pas lancer le cleanup final sur une VM encore en diagnostic ou sur un serveur final.
|
||||
|
||||
## Préparation Ansible
|
||||
|
||||
Le playbook applique les rôles suivants :
|
||||
|
||||
```text
|
||||
common_packages
|
||||
qemu_guest_agent
|
||||
cloud_init
|
||||
sudo_ansible
|
||||
chrony
|
||||
ssh_baseline
|
||||
systemd_ssh_auto
|
||||
motd
|
||||
hardening_packages
|
||||
sysctl_durcissement
|
||||
core_dumps
|
||||
unattended_upgrades
|
||||
apparmor
|
||||
auditd
|
||||
fail2ban_ssh
|
||||
journald
|
||||
ssh_durcissement
|
||||
nftables_socle
|
||||
```
|
||||
|
||||
## Justification des ajouts
|
||||
|
||||
| Rôle | Ajout ou changement | Justification | Limite volontaire |
|
||||
| --- | --- | --- | --- |
|
||||
| `common_packages` | Installe les outils système et diagnostic de base. | Permet l'administration locale, le dépannage réseau, l'exécution fiable d'Ansible et les opérations de maintenance courantes. | Aucun service applicatif spécialisé n'est installé. |
|
||||
| `qemu_guest_agent` | Installe et active `qemu-guest-agent`. | Donne à Proxmox une visibilité propre sur l'état de la VM et facilite les opérations d'arrêt, IP reporting et gestion depuis l'hyperviseur. | Ne remplace pas la supervision applicative. |
|
||||
| `cloud_init` | Installe `cloud-init` et `cloud-guest-utils`, puis active les services cloud-init. | Donne au clone son identité initiale : hostname, utilisateur, clé SSH, IP, DNS et agrandissement de disque. | Cloud-init ne sert pas à configurer les applications. |
|
||||
| `sudo_ansible` | Crée ou maintient le compte technique et son sudo NOPASSWD. | Permet l'administration automatisée par Ansible sans stocker de mot de passe dans le dépôt. | Ce compte doit rester technique et contrôlé. |
|
||||
| `chrony` | Installe et active la synchronisation du temps. | Un temps correct est nécessaire pour TLS, journaux, audit, Kerberos/LDAP futur, monitoring et corrélation d'incidents. | La source NTP définitive peut être ajustée plus tard par inventaire. |
|
||||
| `ssh_baseline` | Pose la base SSH : root interdit, clé publique obligatoire, mot de passe désactivé. | Force un accès administrateur par clé dès la construction du template. | Cloud-init doit avoir injecté le `ciuser` et sa clé avant Ansible. |
|
||||
| `systemd_ssh_auto` | Désactive le comportement `systemd.ssh_auto` si demandé. | Évite une exposition SSH automatique via mécanismes transitoires non désirés dans un template serveur. | Ne remplace pas la politique SSH principale. |
|
||||
| `motd` | Déploie un message d'accueil sobre. | Identifie le contexte de l_instance et rappelle que la machine est gérée par Set-OPS. | Ne doit pas contenir d'information sensible. |
|
||||
| `hardening_packages` | Installe les paquets de sécurité communs. | Fournit les briques nécessaires au durcissement sans configurer de service applicatif. | Les politiques strictes par rôle restent appliquées sur les clones. |
|
||||
| `sysctl_durcissement` | Applique des paramètres noyau de sécurité. | Réduit des comportements réseau et noyau risqués avec des réglages standards pour serveur Linux. | Les réglages spécifiques à une charge de travail peuvent être ajustés par rôle. |
|
||||
| `core_dumps` | Désactive les core dumps. | Limite le risque de fuite de secrets ou données sensibles dans des dumps mémoire. | Un serveur de debug peut réactiver un comportement adapté hors template. |
|
||||
| `unattended_upgrades` | Configure les mises à jour automatiques de sécurité. | Réduit l'exposition aux vulnérabilités connues sur les clones qui restent proches du socle. | Les redémarrages automatiques restent désactivés par défaut. |
|
||||
| `apparmor` | Installe et active AppArmor. | Ajoute une couche de confinement standard Debian avec faible coût opérationnel. | Les profils applicatifs spécifiques seront gérés par les rôles applicatifs. |
|
||||
| `auditd` | Installe auditd et des règles de base. | Fournit une trace système utile pour exploitation, investigation et conformité minimale. | Les règles lourdes ou propres à une application ne vont pas dans le template. |
|
||||
| `fail2ban_ssh` | Active une protection SSH simple contre les essais répétés. | Réduit le bruit et les attaques opportunistes sur SSH sans dépendre d'une plateforme centrale. | Ne remplace pas un pare-feu ni une politique d'accès réseau. |
|
||||
| `journald` | Limite l'usage disque et la rétention des journaux. | Évite qu'une VM issue du template remplisse son disque à cause des logs système. | La centralisation des logs viendra plus tard si nécessaire. |
|
||||
| `ssh_durcissement` | Ajoute les paramètres SSH plus stricts : port, délais, tentatives, keepalive, forwarding et tunnels désactivés. | Réduit la surface d'exposition SSH sans dépendre d'un rôle applicatif. | Les exceptions, comme un bastion ou du forwarding contrôlé, doivent être portées par un rôle dédié. |
|
||||
| `nftables_socle` | Installe nftables et prépare une configuration, mais garde le service désactivé par défaut. | Prépare le standard pare-feu sans risquer de couper l'accès au template ou aux clones. | L'activation se fait par rôle serveur avec règles adaptées. |
|
||||
|
||||
## Paquets communs
|
||||
|
||||
Les paquets communs sont choisis pour l'exploitation réelle :
|
||||
|
||||
```text
|
||||
administration : sudo, acl, bash-completion, tmux, vim, nano
|
||||
transport : curl, wget, ca-certificates, gnupg
|
||||
ansible : python3, python3-apt, python3-pip
|
||||
diagnostic : htop, iotop, iftop, sysstat, lsof, ncdu, tree, file, less
|
||||
réseau : dnsutils, iproute2, iputils-ping, net-tools, traceroute, mtr-tiny, tcpdump, netcat-openbsd, socat
|
||||
maintenance : rsync, unzip, zip, tar, jq, logrotate, unattended-upgrades, apt-listchanges, needrestart
|
||||
virtualisation : qemu-guest-agent, cloud-init, cloud-guest-utils
|
||||
temps : chrony
|
||||
```
|
||||
|
||||
Ces paquets sont acceptés dans le template parce qu'ils sont utiles sur presque tous les serveurs et ne transforment pas la VM en serveur applicatif.
|
||||
|
||||
## Choix de sécurité importants
|
||||
|
||||
### SSH
|
||||
|
||||
État attendu dès la construction :
|
||||
|
||||
```text
|
||||
PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
PubkeyAuthentication yes
|
||||
AuthenticationMethods publickey
|
||||
```
|
||||
|
||||
Le playbook `prepare` ne doit être lancé qu'après validation de l'accès SSH par clé au compte technique.
|
||||
|
||||
### Pare-feu
|
||||
|
||||
`nftables` est installé et préparé, mais désactivé par défaut.
|
||||
|
||||
Ce choix est volontaire : un pare-feu générique dans un template peut couper l'accès SSH ou bloquer un futur rôle serveur. L'activation doit être faite sur un clone avec des règles correspondant à son usage.
|
||||
|
||||
### Nettoyage final
|
||||
|
||||
Le nettoyage final est séparé et protégé par confirmation explicite. Il ne doit être lancé qu'au moment où la VM est validée et prête à être convertie en template.
|
||||
|
||||
## Vérification
|
||||
|
||||
```bash
|
||||
make verifier-modele
|
||||
```
|
||||
|
||||
## Validation minimale
|
||||
|
||||
Avant de déclarer le template prêt :
|
||||
|
||||
```bash
|
||||
make verifier
|
||||
make preparer-modele
|
||||
make verifier-modele
|
||||
```
|
||||
|
||||
La relance du playbook de préparation doit idéalement finir avec :
|
||||
|
||||
```text
|
||||
failed=0
|
||||
changed=0
|
||||
```
|
||||
|
||||
## Nettoyage
|
||||
|
||||
```bash
|
||||
make nettoyer-modele CONFIRMER=true
|
||||
```
|
||||
|
||||
Ne pas lancer le nettoyage final sur un serveur de production ou sur une VM qui n'est pas destinée à devenir un template.
|
||||
|
||||
## Hors périmètre du template
|
||||
|
||||
Les éléments suivants ne doivent pas être installés dans le golden template :
|
||||
|
||||
```text
|
||||
NGINX
|
||||
PostgreSQL
|
||||
MariaDB
|
||||
Docker
|
||||
Podman
|
||||
Redis
|
||||
GitLab
|
||||
Nextcloud
|
||||
monitoring complet
|
||||
agents applicatifs spécialisés
|
||||
données propres à un clone
|
||||
secrets
|
||||
clés privées
|
||||
```
|
||||
|
||||
Les intégrations futures sont documentées dans :
|
||||
|
||||
```text
|
||||
docs/integrations-vm.md
|
||||
```
|
||||
|
||||
Le cycle complet VM vanille, golden template, clone et conformité continue est documenté dans :
|
||||
|
||||
```text
|
||||
docs/vm-lifecycle.md
|
||||
```
|
||||
138
docs/nomenclature-vm.md
Normal file
138
docs/nomenclature-vm.md
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# Nomenclature des VM
|
||||
|
||||
La nomenclature doit rendre lisible la fonction opérationnelle d'une VM sans l'enfermer dans un seul service. (« fonction » est le terme du plan ; « domaine » est réservé au DNS.)
|
||||
|
||||
Un hôte peut porter plusieurs groupes Ansible et plusieurs applications. Le nom de VM représente donc une capacité ou une fonction, pas forcément un produit unique.
|
||||
|
||||
## Noms de VM
|
||||
|
||||
Format recommandé :
|
||||
|
||||
```text
|
||||
<fonction>-<NN>
|
||||
```
|
||||
|
||||
Exemples :
|
||||
|
||||
```text
|
||||
infra-pki-01
|
||||
infra-edge-01
|
||||
infra-mail-01
|
||||
infra-dns-01
|
||||
idm-01
|
||||
data-01
|
||||
obs-01
|
||||
mon-01
|
||||
forge-01
|
||||
collab-01
|
||||
web-frontal-01
|
||||
web-dorsal-01
|
||||
```
|
||||
|
||||
La couche applicative web suit le même format. Le tier est porté par la fonction, au singulier puisqu'il nomme une instance :
|
||||
|
||||
```text
|
||||
web-frontal-01 présentation web (UI, rendu, assets), groupe serveur_web_frontal
|
||||
web-frontal-02
|
||||
web-dorsal-01 application web (API, traitement), groupe serveur_web_dorsal
|
||||
```
|
||||
|
||||
Les anciens noms de test `web-01` et `web-02` sont retirés. Ils ne doivent pas être réutilisés comme noms de production : préférer `web-frontal-NN` et `web-dorsal-NN`.
|
||||
|
||||
## Regroupements recommandés
|
||||
|
||||
| Hôte | Groupes prévus |
|
||||
| --- | --- |
|
||||
| `infra-pki-01` | `serveur_step_ca` |
|
||||
| `infra-edge-01` | `serveur_nginx` |
|
||||
| `infra-mail-01` | `serveur_sendmail` |
|
||||
| `infra-dns-01` | `serveur_powerdns` |
|
||||
| `idm-01` | `serveur_openldap`, `serveur_keycloak` |
|
||||
| `data-01` | `serveur_postgresql`, `serveur_redis` |
|
||||
| `obs-01` | `serveur_prometheus`, `serveur_loki`, `serveur_grafana` |
|
||||
| `mon-01` | `serveur_icinga` |
|
||||
| `forge-01` | `serveur_forgejo` |
|
||||
| `collab-01` | `serveur_nextcloud`, `serveur_collabora` |
|
||||
| `web-frontal-01`, `web-frontal-02` | `serveur_web_frontal` |
|
||||
| `web-dorsal-01` | `serveur_web_dorsal` |
|
||||
|
||||
Les groupes restent fins et composables. La cohabitation se fait en associant plusieurs groupes au même hôte.
|
||||
|
||||
## Plages VMID
|
||||
|
||||
| Plage | Usage |
|
||||
| --- | --- |
|
||||
| `91xxx` | fondations transversales : PKI, reverse proxy, SMTP |
|
||||
| `92xxx` | identité : LDAP, SSO |
|
||||
| `93xxx` | données et cache : PostgreSQL, Redis |
|
||||
| `94xxx` | observabilité et supervision |
|
||||
| `95xxx` | applications internes |
|
||||
| `99xxx` | modèles, essais initiaux ou exceptions documentées |
|
||||
|
||||
## Plan d'adressage interne
|
||||
|
||||
Réseau interne unique : `10.0.0.0/16`. Segmentation par fonction, un `/24` et un VLAN par catégorie, **3ᵉ octet = VLAN** (L2 alignée sur L3).
|
||||
|
||||
| Catégorie | VLAN | Sous-réseau | Passerelle |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 — Fondations / infra | 11 | `10.0.11.0/24` | `10.0.11.1` |
|
||||
| 2 — Identité | 12 | `10.0.12.0/24` | `10.0.12.1` |
|
||||
| 3 — Données | 13 | `10.0.13.0/24` | `10.0.13.1` |
|
||||
| 4 — Observabilité | 14 | `10.0.14.0/24` | `10.0.14.1` |
|
||||
| 5 — Applications | 15 | `10.0.15.0/24` | `10.0.15.1` |
|
||||
|
||||
Adresse d'hôte (4ᵉ octet) : **`service × 10 + NN`**. `.1` = passerelle ; `.2`–`.9` réservés. Exemple : `web-dorsal-01` (catégorie 5, service 4, NN 01) → `10.0.15.41`.
|
||||
|
||||
Tout se dérive de la fonction de l'hôte, et la source unique machine-lisible est **`instance/plan/nomenclature.yml`** :
|
||||
|
||||
```text
|
||||
hostname = <fonction>-<NN>
|
||||
VMID = 9 · catégorie · service · NN
|
||||
VLAN = catégorie.vlan
|
||||
IP = 10.0.<vlan>.(service × 10 + NN)
|
||||
```
|
||||
|
||||
`make inventaire-ui` lit ce registre et **propose** automatiquement VMID, VLAN, IP et passerelle quand on nomme un hôte. La sécurité entre zones se fera par règles inter-zones (nftables / edge), pas par l'adressage.
|
||||
|
||||
Contrainte : `NN` de 01 à 09 par fonction (l'octet hôte reste dans le bloc du service). Au-delà, ouvrir une nouvelle fonction/service dans `instance/plan/nomenclature.yml`.
|
||||
|
||||
La segmentation `10.0.0.0/16` remplace l'ancienne plage d'essais `192.168.12.x`.
|
||||
|
||||
## Variables de provisioning d'hôte
|
||||
|
||||
Le **plan** est la source de vérité du provisioning. Le placement et le dimensionnement d'une VM vivent dans `instance/plan/serveurs.yml` (vue **Serveurs** du GUI) ; VMID / IP / VLAN / passerelle sont **dérivés** de la fonction. Ces variables d'hôte sont alors **générées** dans l'inventaire (ne pas les éditer à la main) :
|
||||
|
||||
| Variable | Sens | Type |
|
||||
| --- | --- | --- |
|
||||
| `ansible_host` | adresse IP | str |
|
||||
| `proxmox_cidr` | masque réseau en bits (0-32) | int |
|
||||
| `proxmox_passerelle` | passerelle | str |
|
||||
| `proxmox_vlan` | tag VLAN (1-4094) | int |
|
||||
| `proxmox_pont` | pont réseau Proxmox (ex. `vmbr0`) | str |
|
||||
| `proxmox_dns` | serveurs DNS Cloud-Init (séparés par virgule) | str |
|
||||
| `proxmox_vmid` | identifiant VM Proxmox | int |
|
||||
| `proxmox_noeud` | nœud Proxmox cible | str |
|
||||
| `proxmox_stockage` | stockage du disque | str |
|
||||
| `proxmox_disque_taille` | taille disque (ex. `32G`) | str |
|
||||
| `proxmox_memoire` | mémoire en Mo | int |
|
||||
| `proxmox_coeurs` | nombre de cœurs | int |
|
||||
|
||||
Ces valeurs sont **générées** dans l'inventaire depuis `instance/plan/serveurs.yml` + la nomenclature (`make instancier-appliquer`). Une valeur vide n'est pas écrite, pour garder l'inventaire propre.
|
||||
|
||||
## État d'un hôte (planifié / actif)
|
||||
|
||||
Chaque VM porte un `etat` dans `instance/plan/serveurs.yml` :
|
||||
|
||||
- `planifie` — prévue mais non encore déployée → groupe `hotes_planifies` à la génération ;
|
||||
- `actif` — réellement joignable par Ansible → groupe `hotes_actifs`.
|
||||
|
||||
L'état se change dans la vue **Serveurs** du GUI (ou `instance/plan/serveurs.yml`), puis on
|
||||
régénère l'inventaire :
|
||||
|
||||
```bash
|
||||
make instancier-appliquer
|
||||
```
|
||||
|
||||
Les déploiements groupés limitent automatiquement l'exécution à `<groupe demandé> & hotes_actifs`, ce qui permet de décrire l'écosystème complet (hôtes planifiés inclus) sans tenter de configurer une VM qui n'existe pas encore.
|
||||
|
||||
> Les anciennes commandes `make hote-planifier` / `hote-ajouter` éditaient `hosts.yml` directement ; l'inventaire étant désormais **généré**, elles sont supplantées par le plan (`instance/plan/serveurs.yml`).
|
||||
179
docs/plan-et-generation.md
Normal file
179
docs/plan-et-generation.md
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Le plan et la génération d'inventaire (méta-classe)
|
||||
|
||||
Set-OPS ne s'édite plus comme un inventaire à la main : on **décrit un plan**, et
|
||||
l'inventaire Ansible en est **généré**. Le dépôt est la définition ; chaque VM en
|
||||
est une instance. Ce document décrit le modèle, les registres, les commandes et
|
||||
le flux de travail.
|
||||
|
||||
> Règle d'or : **`instance/inventories/production/hosts.yml` est GÉNÉRÉ. Ne jamais l'éditer
|
||||
> à la main.** On édite le *plan* puis on régénère (`make instancier-appliquer`).
|
||||
|
||||
---
|
||||
|
||||
## 1. Le modèle : deux ancres, cinq liens
|
||||
|
||||
L'écosystème = des **serveurs** (VM) et des **applications**, reliés à leurs
|
||||
**bases**, leurs **domaines** et leurs dépendances :
|
||||
|
||||
```
|
||||
serveur (VM) ──fournit──▶ capacités (= groupes/rôles Ansible)
|
||||
application ──tourne_sur──▶ serveur (une VM peut porter N applications)
|
||||
application ──requiert──▶ application(s) (DNS, PKI, BD…)
|
||||
application ──utilise──▶ base(s) (via le DSN)
|
||||
application ──expose──▶ domaine(s) public(s) (le FQDN, derrière l'edge)
|
||||
base ──hébergée_sur──▶ serveur de BD
|
||||
```
|
||||
|
||||
L'**application** est l'entité pivot : tout ce qui décrit « ce qui tourne et à
|
||||
quoi c'est connecté » pend d'elle. Le **groupe** Ansible n'est plus une cible de
|
||||
liaison — seulement une **capacité** qu'une VM fournit (le rôle appliqué).
|
||||
|
||||
---
|
||||
|
||||
## 2. Les registres (source unique de vérité)
|
||||
|
||||
Tous sous `docs/`, machine-lisibles, validés, consommés par le GUI, le CLI et Ansible.
|
||||
|
||||
| Registre | Décrit | Champs clés |
|
||||
| --- | --- | --- |
|
||||
| `nomenclature.yml` | nommage & adressage | `fonctions` (catégorie/service), `categories` (VLAN/sous-réseau/passerelle), `supernet` |
|
||||
| `serveurs.yml` | les VM du plan | `fonction`, `etat` (actif/planifie), placement Proxmox (`noeud`/`stockage`/`disque`/`memoire`/`coeurs`), `integrations` (les `clients_*`) |
|
||||
| `applications.yml` | les applications | `groupe` (capacité/rôle), `hote` (VM), `port`, `requiert`, `expose`, (+ bases via consommateur) |
|
||||
| `bases-donnees.yml` | serveurs de BD + bases | `serveurs_bd` ; `bases_donnees` : `serveur`/`base`/`proprietaire`/`secret`(Vault), `consommateur` + `portee` (`application`/`groupe`/`hote`), `usage` |
|
||||
| `domaines.yml` | zones DNS publiques | `domaines_publics` : `autorite`, `edge`, `secondaires`, `dnssec`, `mail` |
|
||||
| `dependances-groupes.yml` | prérequis entre groupes | `requiert_groupes_actifs` |
|
||||
|
||||
### Dérivations clés
|
||||
- **Nommage/adressage** : tout part de la `fonction` de l'hôte (`web-frontal-03`).
|
||||
`VMID = 9·catégorie·service·NN`, `VLAN = catégorie.vlan`,
|
||||
`IP = 10.0.<vlan>.(service×10 + NN)`. Voir `docs/nomenclature-vm.md`.
|
||||
- **DSN** (lien application↔base) : `<type>://<proprietaire>:<secret>@<hôte>:<port>/<base>`.
|
||||
Une application reçoit les bases où `(portee=application ET consommateur=elle)`
|
||||
OU `(portee=groupe ET consommateur=son groupe)` OU `(portee=hote ET consommateur=son hôte)`.
|
||||
- **Exposition DNS** : `application.expose: [fqdn]` + l'`edge` du domaine parent →
|
||||
`serveur_nginx` génère le vhost (`application → hôte → IP:port`).
|
||||
|
||||
---
|
||||
|
||||
## 3. La génération (méta-classe)
|
||||
|
||||
`make instancier` produit `hosts.yml` **depuis le plan** :
|
||||
|
||||
- **host vars** : `ansible_host`/`ansible_user` + `proxmox_*` (IP/VMID/VLAN/passerelle
|
||||
**dérivés** de la nomenclature ; placement/taille depuis `serveurs.yml`).
|
||||
- **groupes** d'une VM = socle (`serveur_debian` + `serveur_durci`)
|
||||
+ **services** (les `groupe` des applications de l'hôte)
|
||||
+ **intégrations** (`serveurs.yml: integrations`)
|
||||
+ **état** (`hotes_actifs` / `hotes_planifies`).
|
||||
|
||||
La comparaison est **sémantique** (via `ansible-inventory --list`, formatage
|
||||
ignoré). « **Diff vide** » = le plan reproduit exactement l'inventaire courant ;
|
||||
c'est le feu vert pour appliquer.
|
||||
|
||||
---
|
||||
|
||||
## 4. Le flux de travail
|
||||
|
||||
```
|
||||
éditer le PLAN ──▶ make instancier (revoir le diff) ──▶ make instancier-appliquer ──▶ déployer
|
||||
(GUI ou CLI) (que va-t-il changer ?) (régénère hosts.yml) (make deployer)
|
||||
```
|
||||
|
||||
### Via le GUI — `make inventaire-ui`
|
||||
Cinq vues :
|
||||
|
||||
| Vue | Rôle |
|
||||
| --- | --- |
|
||||
| **Inventaire** | **lecture seule** (inventaire généré) — vue d'ensemble des hôtes |
|
||||
| **Serveurs** | éditer les VM du plan : fonction/état/placement/intégrations (VMID·IP·VLAN dérivés en direct) ; bouton **« Appliquer le plan »** |
|
||||
| **Chaîne** | vue holistique par hôte : groupes → rôles, et par application ses `expose` / `requiert` / bases (DSN) |
|
||||
| **Applications** | éditer les applications : groupe/hôte/port/requiert/expose |
|
||||
| **Bases** | éditer serveurs de BD et bases (portée + consommateur), DSN affiché |
|
||||
|
||||
Édition → **Sauvegarder** (écrit le registre) → **Appliquer le plan** (régénère
|
||||
`hosts.yml`). L'écriture directe de l'inventaire est refusée (409).
|
||||
|
||||
### Via le CLI / `make`
|
||||
Chaque registre a son script miroir et ses cibles `make` :
|
||||
|
||||
| Domaine | Lister | Vérifier | Bootstrap (depuis l'inventaire) |
|
||||
| --- | --- | --- | --- |
|
||||
| Serveurs | `make serveurs` | `make serveurs-verifier` | `make serveurs-bootstrap` |
|
||||
| Applications | `make applications` | `make applications-verifier` | `make applications-bootstrap` |
|
||||
| Bases | `make bases` | `make bases-verifier` | — |
|
||||
| Domaines | `make domaines` | `make domaines-verifier` | — |
|
||||
|
||||
Génération :
|
||||
|
||||
```bash
|
||||
make instancier # génère hosts.genere.yml (gitignoré) + diff sémantique
|
||||
make instancier-appliquer # régénère hosts.yml (refuse si diff non vide ; FORCE=1 pour forcer)
|
||||
```
|
||||
|
||||
Validation globale : `make inventaire-verifier` (ansible-inventory + tous les
|
||||
registres + **`node --check` du JS du GUI**).
|
||||
|
||||
---
|
||||
|
||||
## 5. Garde-fous
|
||||
|
||||
- **Validateurs** : chaque registre est validé (références connues, énumérations,
|
||||
unicité). Un `expose` sans domaine parent, un `requiert` fantôme, une `portee`
|
||||
inconnue, une `fonction` absente → rejet.
|
||||
- **Diff vide** : `instancier-appliquer` refuse d'écraser l'inventaire si le plan
|
||||
ne le reproduit pas (sauf `FORCE=1` pour un changement intentionnel).
|
||||
- **`node --check`** : le JS embarqué du GUI est vérifié (`scripts/verifier_gui.py`,
|
||||
intégré à `make inventaire-verifier`) — une erreur de syntaxe JS casse toute la page.
|
||||
- **git** : `hosts.yml` est versionné ; `git diff` / `git checkout` est le filet.
|
||||
- **Secrets** : jamais en clair ; `secret:` nomme une variable Ansible Vault.
|
||||
|
||||
---
|
||||
|
||||
## 6. Réutilisation de la règle (Ansible)
|
||||
|
||||
La règle de résolution vit **une seule fois**, en Python (`scripts/inventory_rules.py`),
|
||||
et est exposée à Ansible par un *filter plugin* (`filter_plugins/registres.py`) :
|
||||
`bases_de_application`, `applications_de_hote`, `expositions_des_applications`,
|
||||
`chaine_connexion`. Les playbooks par application (`serveur_web_dorsal`/`_frontaux`)
|
||||
itèrent ainsi sur les applications de l'hôte et résolvent leurs DSN.
|
||||
|
||||
---
|
||||
|
||||
## 7. Amorçage / reconstruction
|
||||
|
||||
Pour (re)construire le plan depuis un inventaire existant :
|
||||
|
||||
```bash
|
||||
make serveurs-bootstrap # VM -> instance/plan/serveurs.yml (fonction/état/placement/integrations)
|
||||
make applications-bootstrap # services serveurs_* (hors socle) -> instance/plan/applications.yml
|
||||
make instancier # vérifier le diff vide
|
||||
```
|
||||
|
||||
C'est ainsi que le plan a été initialisé sans perte, avec diff vide vérifié.
|
||||
|
||||
---
|
||||
|
||||
## 8. Moteur et instance : deux dépôts
|
||||
|
||||
Le **moteur** (ce dépôt, `Set-OPS`) est générique et partageable ; il ne contient
|
||||
aucune donnée d'instance. Une **instance** (le plan + l'inventaire d'un loup) vit
|
||||
dans son **propre dépôt** (ex. `OPS-monatelier`).
|
||||
|
||||
Le moteur localise l'instance via **`SETOPS_INSTANCE`** (défaut : `instance`). Deux
|
||||
modèles :
|
||||
|
||||
- **Modèle A — dépôts frères** (en cours) : moteur et instance côte à côte ; un
|
||||
symlink `instance -> ../OPS-monatelier` (gitignoré) fait que le défaut résout
|
||||
l'instance sans configuration. Idéal quand on développe le moteur *et* l'instance.
|
||||
- **Modèle B — moteur en sous-module** (futur, pour la meute) : l'instance épingle
|
||||
une version du moteur ; `SETOPS_INSTANCE` pointe la racine de l'instance.
|
||||
|
||||
Pour brancher une instance (modèle A) :
|
||||
|
||||
```bash
|
||||
cd Set-OPS
|
||||
ln -s ../OPS-monatelier instance # ou : export SETOPS_INSTANCE=/chemin/instance
|
||||
make inventaire-verifier # lit l'instance via le symlink
|
||||
```
|
||||
|
||||
Le moteur écrit `hosts.yml` (généré) **dans le dépôt d'instance**, jamais dans le sien.
|
||||
95
docs/positionnement.md
Normal file
95
docs/positionnement.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Positionnement : ce que Set-OPS fait maison, et quand adopter l'existant
|
||||
|
||||
Ce document **acte une décision** pour ne plus la redébattre à chaque évolution :
|
||||
quelles parties de Set-OPS sont volontairement *maison*, pourquoi, et à partir de
|
||||
quel **seuil** il vaudra mieux adopter un outil du marché plutôt que continuer à
|
||||
le réimplémenter.
|
||||
|
||||
> En une phrase : le cœur de Set-OPS (un plan déclaratif qui génère l'inventaire
|
||||
> Ansible) **existe déjà sous forme mûre** — c'est NetBox. Set-OPS en est une
|
||||
> version **souveraine, légère et sur-mesure**, assumée comme telle. Le risque à
|
||||
> surveiller est de réimplémenter NetBox/AWX brique par brique.
|
||||
|
||||
---
|
||||
|
||||
## 1. La carte : chaque facette a un équivalent du marché
|
||||
|
||||
| Facette de Set-OPS | Équivalent mûr | Remarque |
|
||||
| --- | --- | --- |
|
||||
| Source de vérité déclarative → **génère l'inventaire Ansible** | **NetBox** / **Nautobot** + plugin `netbox.netbox.nb_inventory` | Le plus proche du **cœur** de Set-OPS (le « plan »). |
|
||||
| GUI qui **exécute** Ansible (déployer, RBAC, planification) | **AWX** / Ansible Automation Platform ; **Semaphore** | Set-OPS a un GUI plus modeste (lancer `make`). |
|
||||
| « La **définition instancie** toute la flotte » | **NixOS + Colmena/morph** ; **Terraform** (provider Proxmox) pour créer les VM | L'idée « méta-classe » au sens littéral. |
|
||||
| **Application = entité pivot** avec ses dépendances et ressources | **Backstage** (catalogue de composants + graphe) | Le modèle `requiert`/`utilise`/`expose` y ressemble fortement. |
|
||||
| IPAM / dérivation d'adressage | **NetBox** (IPAM natif) | Set-OPS dérive depuis la nomenclature. |
|
||||
|
||||
**Aucun** produit ne fait l'**assemblage exact** : Proxmox + Ansible + le modèle
|
||||
bespoke (DSN, exposition DNS, dérivation par fonction) en **un seul outil
|
||||
souverain et léger**. Cet assemblage-là est propre à Set-OPS.
|
||||
|
||||
---
|
||||
|
||||
## 2. Ce que Set-OPS fait sciemment maison (et pourquoi)
|
||||
|
||||
- **Le plan déclaratif** (`instance/plan/serveurs.yml`, `applications.yml`, `bases-donnees.yml`,
|
||||
`domaines.yml`, `nomenclature.yml`) et le **générateur d'inventaire** (`make instancier`).
|
||||
- Le **modèle application-hub** : bindings DSN (portée application/groupe/hôte) et
|
||||
exposition DNS, taillés exactement pour nos concepts.
|
||||
- Le **GUI** (Python stdlib, fichier unique) et les **validateurs / garde-fous**
|
||||
(diff-vide, `node --check`, vérificateurs de registres).
|
||||
|
||||
Raisons assumées :
|
||||
|
||||
1. **Souveraineté** — mission explicite du dépôt. NetBox + AWX + Backstage = trois
|
||||
applications lourdes à héberger et maintenir (Django + PostgreSQL, etc.). Set-OPS
|
||||
reste possédé en entier, sans dépendance.
|
||||
2. **Bon dimensionnement** — ~13 VM. NetBox est de la machinerie d'échelle entreprise.
|
||||
3. **Modèle sur-mesure** — NetBox exprimerait nos DSN / expositions à coups de
|
||||
*custom fields* et de plugins, moins naturellement que nos registres.
|
||||
4. **Maîtrise** — chaque ligne est comprise et auditable.
|
||||
|
||||
---
|
||||
|
||||
## 3. Ce que le maison NE fait PAS (et que les outils mûrs ont)
|
||||
|
||||
À garder en tête honnêtement — ce sont des fonctions qu'on n'a pas, pas des bugs :
|
||||
|
||||
- historique/audit des changements (au-delà de `git`) ;
|
||||
- RBAC multi-utilisateurs ;
|
||||
- détection de conflits IPAM, réservations, gestion d'adresses à grande échelle ;
|
||||
- webhooks / intégrations tierces, API riche (REST/GraphQL) ;
|
||||
- écosystème de plugins, communauté, correctifs de sécurité maintenus par d'autres.
|
||||
|
||||
---
|
||||
|
||||
## 4. La règle : plan de contrôle **gelé en fonctionnalités**
|
||||
|
||||
Set-OPS continue d'évoluer pour **décrire et déployer l'écosystème** (rôles,
|
||||
services, registres applicatifs). En revanche, le **plan de contrôle** (le GUI,
|
||||
le générateur, l'IPAM, la modélisation) est considéré **gelé en périmètre** : on
|
||||
ne lui ajoute pas de fonctionnalités de type NetBox/AWX.
|
||||
|
||||
### Seuils d'adoption (les signaux de bascule)
|
||||
|
||||
Adopter l'outil du marché — **sans réécrire**, en branchant Ansible/notre GUI
|
||||
par-dessus — dès qu'un de ces besoins devient réel :
|
||||
|
||||
| Besoin qui apparaît | Adopter |
|
||||
| --- | --- |
|
||||
| RBAC, plusieurs opérateurs, historique d'audit, secrets/credentials centralisés | **AWX** (exécution) |
|
||||
| IPAM sérieux, détection de conflits, source de vérité partagée, API/webhooks | **NetBox** (et `nb_inventory` remplace notre générateur) |
|
||||
| Catalogue de services / portail développeur, ownership, scaffolding | **Backstage** |
|
||||
| Provisionnement de VM déclaratif et reproductible à plus grande échelle | **Terraform** (Proxmox) ou **NixOS + Colmena** |
|
||||
|
||||
**Test simple** : si on se surprend à vouloir réimplémenter une de ces fonctions
|
||||
dans Set-OPS, c'est le signal d'adopter l'outil correspondant plutôt que de
|
||||
prolonger le maison.
|
||||
|
||||
---
|
||||
|
||||
## 5. Décision en vigueur
|
||||
|
||||
- On **garde** le plan de contrôle maison : il fonctionne, il est souverain et
|
||||
bien dimensionné pour aujourd'hui. Pas de réécriture sur NetBox « par principe ».
|
||||
- On **gèle** son périmètre fonctionnel (voir §4).
|
||||
- On **réévalue** à l'échéance d'un seuil ci-dessus, ou si la charge de
|
||||
maintenance du maison dépasse le coût d'héberger l'outil mûr.
|
||||
817
docs/procedure-template-debian13-proxmox.md
Normal file
817
docs/procedure-template-debian13-proxmox.md
Normal file
|
|
@ -0,0 +1,817 @@
|
|||
# Procédure manuelle — VM Debian 13 vanille pour Proxmox
|
||||
|
||||
## Objet du document
|
||||
|
||||
Ce document décrit le travail manuel à effectuer pour créer une VM Debian 13 vanille dans Proxmox, jusqu’au moment où elle peut être prise en charge par Set-OPS.
|
||||
|
||||
Le résultat attendu est une VM minimale, sobre, joignable en SSH, capable d'installer des paquets depuis les dépôts Debian, compatible avec cloud-init et prête à recevoir le playbook de préparation du golden template.
|
||||
|
||||
Ce document s’arrête au point de bascule vers le `Makefile`.
|
||||
|
||||
Les ajouts appliqués ensuite par Ansible, leur validation et leur justification sont documentés dans :
|
||||
|
||||
```text
|
||||
docs/modeles_vm/debian13-proxmox.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Objectif du modèle
|
||||
|
||||
Le modèle Debian 13 doit servir de base commune pour les futurs serveurs de l_instance
|
||||
|
||||
Objectifs :
|
||||
|
||||
- système Debian 13 minimal ;
|
||||
- aucun environnement graphique ;
|
||||
- SSH actif ;
|
||||
- `qemu-guest-agent` installé ;
|
||||
- `cloud-init` installé ;
|
||||
- disque CloudInit Proxmox attaché ;
|
||||
- compte technique `ansible` injecté par cloud-init ;
|
||||
- clé publique SSH injectée par cloud-init ;
|
||||
- `ansible` autorisé à utiliser sudo ;
|
||||
- partitionnement simple et agrandissable ;
|
||||
- aucune partition swap bloquant la croissance du disque ;
|
||||
- aucune donnée propre à une VM finale ;
|
||||
- aucune clé privée ;
|
||||
- aucun secret ;
|
||||
- prêt à être converti en template Proxmox.
|
||||
|
||||
---
|
||||
|
||||
## 2. Création de la VM dans Proxmox
|
||||
|
||||
### Paramètres généraux
|
||||
|
||||
Créer une nouvelle VM dans Proxmox avec des paramètres sobres.
|
||||
|
||||
Exemple :
|
||||
|
||||
```text
|
||||
Nom de la VM : debian13-template
|
||||
VMID : 9000 ou autre ID réservé aux modèles
|
||||
OS : Debian 13
|
||||
BIOS : OVMF / UEFI
|
||||
Machine : q35
|
||||
```
|
||||
|
||||
### Disque EFI Proxmox
|
||||
|
||||
Avec OVMF/UEFI, Proxmox crée un petit disque EFI, par exemple :
|
||||
|
||||
```text
|
||||
efidisk0 : 4 Mo
|
||||
```
|
||||
|
||||
Ce disque ne remplace pas la partition EFI de Debian.
|
||||
|
||||
Il sert à conserver les variables du firmware UEFI virtuel :
|
||||
|
||||
- ordre de démarrage ;
|
||||
- entrées de boot ;
|
||||
- variables UEFI ;
|
||||
- paramètres liés à Secure Boot, si utilisé.
|
||||
|
||||
Il faut le garder.
|
||||
|
||||
---
|
||||
|
||||
## 3. Disque virtuel principal
|
||||
|
||||
### Type de disque
|
||||
|
||||
Pour une VM Linux moderne :
|
||||
|
||||
```text
|
||||
Bus/Device : SCSI
|
||||
SCSI Controller : VirtIO SCSI single
|
||||
IO thread : activé si disponible
|
||||
Cache : Default / No cache
|
||||
Discard : selon stockage, seulement si pertinent
|
||||
SSD emulation : oui si le stockage est réellement SSD/NVMe
|
||||
```
|
||||
|
||||
Même si le stockage réel est sur un stockage réseau iSCSI, le disque présenté à la VM doit rester :
|
||||
|
||||
```text
|
||||
SCSI via VirtIO SCSI single
|
||||
```
|
||||
|
||||
Le choix SCSI ici concerne le bus virtuel vu par la VM, pas le protocole réel entre Proxmox et le stockage.
|
||||
|
||||
### Taille du disque
|
||||
|
||||
Pour le modèle de base :
|
||||
|
||||
```text
|
||||
Disque : 16 Go
|
||||
```
|
||||
|
||||
C’est suffisant pour une base Debian minimale.
|
||||
|
||||
Des clones pourront ensuite être agrandis avant le premier démarrage cloud-init.
|
||||
|
||||
---
|
||||
|
||||
## 4. Processeur
|
||||
|
||||
Pour un modèle portable entre plusieurs hôtes Proxmox :
|
||||
|
||||
```text
|
||||
CPU Type : x86-64-v2-AES
|
||||
Sockets : 1
|
||||
Cores : 2
|
||||
```
|
||||
|
||||
Éviter `host` pour un modèle générique, sauf si tous les nœuds Proxmox sont strictement homogènes et que la portabilité n’est pas une priorité.
|
||||
|
||||
---
|
||||
|
||||
## 5. Mémoire
|
||||
|
||||
Pour le modèle Debian 13 minimal :
|
||||
|
||||
```text
|
||||
Mémoire : 2048 MiB
|
||||
```
|
||||
|
||||
Le ballooning peut être activé, mais si la VM n’a pas de swap, éviter de descendre trop bas.
|
||||
|
||||
Réglage prudent :
|
||||
|
||||
```text
|
||||
RAM max : 2048 MiB
|
||||
RAM minimum : 1536 MiB ou 2048 MiB
|
||||
```
|
||||
|
||||
Pour un modèle simple, il est acceptable de laisser 2048 MiB fixe.
|
||||
|
||||
---
|
||||
|
||||
## 6. Carte graphique virtuelle
|
||||
|
||||
Pour un serveur Debian minimal :
|
||||
|
||||
```text
|
||||
Display : Default / Standard VGA
|
||||
```
|
||||
|
||||
Ne pas installer d’environnement graphique.
|
||||
|
||||
SPICE et VirtIO-GPU ne sont pas nécessaires pour un modèle serveur administré par SSH et Ansible.
|
||||
|
||||
---
|
||||
|
||||
## 7. Installation Debian 13
|
||||
|
||||
Démarrer la VM sur l’ISO Debian 13.
|
||||
|
||||
L’option `Graphical install` est acceptable : elle ne signifie pas qu’un environnement graphique sera installé. Elle ne concerne que l’interface de l’installateur.
|
||||
|
||||
---
|
||||
|
||||
## 8. Partitionnement
|
||||
|
||||
### Objectif
|
||||
|
||||
Le disque doit rester facile à agrandir après clonage.
|
||||
|
||||
Ne pas créer de partition swap à la fin du disque, car cela bloquerait l’agrandissement direct de la partition racine avec `growpart`.
|
||||
|
||||
### Partitionnement recommandé
|
||||
|
||||
Utiliser un partitionnement manuel :
|
||||
|
||||
```text
|
||||
/dev/sda1 EFI System Partition 512 Mo FAT32 /boot/efi
|
||||
/dev/sda2 Linux root reste ext4 /
|
||||
```
|
||||
|
||||
Ne pas créer :
|
||||
|
||||
```text
|
||||
partition swap
|
||||
LVM
|
||||
/home séparé
|
||||
/var séparé
|
||||
```
|
||||
|
||||
### Pourquoi éviter LVM dans le modèle
|
||||
|
||||
Le stockage réel contient déjà plusieurs couches :
|
||||
|
||||
```text
|
||||
stockage ZFS
|
||||
→ zvol iSCSI
|
||||
→ Proxmox
|
||||
→ disque virtuel
|
||||
→ Debian
|
||||
```
|
||||
|
||||
Ajouter LVM dans la VM complique le modèle sans bénéfice clair pour une base minimale.
|
||||
|
||||
### Pourquoi éviter la partition swap
|
||||
|
||||
Un exemple à éviter :
|
||||
|
||||
```text
|
||||
/dev/sda1 EFI
|
||||
/dev/sda2 /
|
||||
/dev/sda3 swap
|
||||
```
|
||||
|
||||
Si le disque est agrandi plus tard, l’espace libre sera après la swap. La partition `/` ne sera donc plus la dernière partition, ce qui complique ou empêche l’usage direct de :
|
||||
|
||||
```bash
|
||||
growpart /dev/sda 2
|
||||
resize2fs /dev/sda2
|
||||
```
|
||||
|
||||
### Swap
|
||||
|
||||
Pour le modèle :
|
||||
|
||||
```text
|
||||
Swap : aucun
|
||||
```
|
||||
|
||||
L’avertissement de Debian au sujet de l’absence de swap peut être ignoré.
|
||||
|
||||
Si un clone a besoin de swap plus tard, utiliser plutôt :
|
||||
|
||||
- un swapfile ;
|
||||
- ou un deuxième disque virtuel dédié au swap.
|
||||
|
||||
Exemple de swapfile futur :
|
||||
|
||||
```bash
|
||||
sudo fallocate -l 1G /swapfile
|
||||
sudo chmod 600 /swapfile
|
||||
sudo mkswap /swapfile
|
||||
sudo swapon /swapfile
|
||||
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Choix du noyau Debian
|
||||
|
||||
Si l’installateur demande quel noyau installer, choisir :
|
||||
|
||||
```text
|
||||
linux-image-amd64
|
||||
```
|
||||
|
||||
Ne pas choisir une version fixe du noyau sauf besoin très particulier.
|
||||
|
||||
Le méta-paquet `linux-image-amd64` suivra les mises à jour normales de Debian.
|
||||
|
||||
---
|
||||
|
||||
## 10. Image initrd
|
||||
|
||||
Si l’installateur demande le type d’image initrd, choisir :
|
||||
|
||||
```text
|
||||
image générique : comporte tous les pilotes disponibles
|
||||
```
|
||||
|
||||
C’est le meilleur choix pour un modèle Proxmox, car la VM doit rester portable même si certains paramètres virtuels changent plus tard.
|
||||
|
||||
---
|
||||
|
||||
## 11. Sélection des logiciels Debian
|
||||
|
||||
Dans l’écran de sélection des logiciels, cocher seulement :
|
||||
|
||||
```text
|
||||
[x] serveur SSH
|
||||
[x] utilitaires usuels du système
|
||||
```
|
||||
|
||||
Laisser décoché :
|
||||
|
||||
```text
|
||||
[ ] environnement de bureau Debian
|
||||
[ ] GNOME
|
||||
[ ] KDE Plasma
|
||||
[ ] XFCE
|
||||
[ ] LXDE
|
||||
[ ] LXQt
|
||||
[ ] MATE
|
||||
[ ] serveur web
|
||||
[ ] serveur d’impression
|
||||
```
|
||||
|
||||
Le serveur web, les rôles applicatifs et les services métier seront installés plus tard par Ansible.
|
||||
|
||||
---
|
||||
|
||||
## 12. Premier démarrage après installation
|
||||
|
||||
Après l’installation, démarrer la VM et se connecter en console ou par SSH.
|
||||
|
||||
Passer root si le compte root est disponible :
|
||||
|
||||
```bash
|
||||
su -
|
||||
```
|
||||
|
||||
ou, si sudo est déjà disponible :
|
||||
|
||||
```bash
|
||||
sudo -i
|
||||
```
|
||||
|
||||
Toutes les commandes de bootstrap suivantes sont exécutées dans la VM.
|
||||
|
||||
---
|
||||
|
||||
## 13. Réparer APT après installation DVD
|
||||
|
||||
Si Debian a été installé depuis l'ISO/DVD complet, APT peut garder une source `cdrom:`. Dans ce cas, `apt update` ou `apt install` échoue parce que le système cherche les paquets sur le média d'installation plutôt que sur les miroirs Debian.
|
||||
|
||||
Vérifier les sources :
|
||||
|
||||
```bash
|
||||
grep -R "^[[:space:]]*deb cdrom:" /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null || true
|
||||
```
|
||||
|
||||
Si une ligne `deb cdrom:` est présente, la commenter ou la retirer.
|
||||
|
||||
Configuration simple attendue pour Debian 13 :
|
||||
|
||||
```bash
|
||||
cat > /etc/apt/sources.list <<'EOF'
|
||||
deb http://deb.debian.org/debian trixie main contrib non-free-firmware
|
||||
deb http://security.debian.org/debian-security trixie-security main contrib non-free-firmware
|
||||
deb http://deb.debian.org/debian trixie-updates main contrib non-free-firmware
|
||||
EOF
|
||||
```
|
||||
|
||||
Si l'installation a créé des fichiers `.sources` sous `/etc/apt/sources.list.d/`, vérifier qu'ils ne contredisent pas cette configuration et qu'ils ne pointent pas vers `cdrom:`.
|
||||
|
||||
Vérifier le réseau avant de continuer :
|
||||
|
||||
```bash
|
||||
ip route
|
||||
cat /etc/resolv.conf
|
||||
ping -c 3 1.1.1.1
|
||||
ping -c 3 deb.debian.org
|
||||
```
|
||||
|
||||
Résultat attendu :
|
||||
|
||||
```text
|
||||
une route par défaut existe
|
||||
un serveur DNS est configuré
|
||||
le ping IP fonctionne
|
||||
la résolution DNS fonctionne
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. Mise à jour du système
|
||||
|
||||
Exécuter :
|
||||
|
||||
```bash
|
||||
apt update
|
||||
apt full-upgrade -y
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 15. Paquets de bootstrap
|
||||
|
||||
Installer seulement les paquets nécessaires pour que Set-OPS puisse prendre le relais :
|
||||
|
||||
```bash
|
||||
apt install -y \
|
||||
sudo \
|
||||
openssh-server \
|
||||
qemu-guest-agent \
|
||||
cloud-init \
|
||||
cloud-guest-utils \
|
||||
ca-certificates \
|
||||
curl \
|
||||
vim \
|
||||
nano
|
||||
```
|
||||
|
||||
Rôle des paquets principaux :
|
||||
|
||||
```text
|
||||
sudo : délégation administrative
|
||||
openssh-server : accès distant initial
|
||||
qemu-guest-agent : communication Proxmox ↔ VM
|
||||
cloud-init : personnalisation au premier boot du clone
|
||||
cloud-guest-utils : fournit notamment growpart
|
||||
```
|
||||
|
||||
Les autres paquets communs, outils de diagnostic, chrony et composants de durcissement sont installés ensuite par `make preparer-modele`.
|
||||
|
||||
---
|
||||
|
||||
## 16. Activation du QEMU Guest Agent
|
||||
|
||||
Activer le service :
|
||||
|
||||
```bash
|
||||
systemctl enable --now qemu-guest-agent
|
||||
```
|
||||
|
||||
Vérifier :
|
||||
|
||||
```bash
|
||||
systemctl status qemu-guest-agent --no-pager
|
||||
```
|
||||
|
||||
Dans Proxmox, activer aussi :
|
||||
|
||||
```text
|
||||
VM → Options → QEMU Guest Agent → Enabled
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 17. Identité initiale par Cloud-Init
|
||||
|
||||
À partir d'ici, ne pas créer manuellement le compte `ansible` ni son fichier `authorized_keys`, sauf dépannage.
|
||||
|
||||
L'identité initiale doit venir de Proxmox + Cloud-Init :
|
||||
|
||||
```text
|
||||
Proxmox : ciuser, clé SSH, réseau, DNS
|
||||
Debian : cloud-init applique ces paramètres au démarrage
|
||||
Ansible : configure ensuite le vrai socle du serveur
|
||||
```
|
||||
|
||||
Cette séparation évite de maintenir deux méthodes concurrentes pour créer le même accès.
|
||||
|
||||
### Ajouter le CloudInit Drive
|
||||
|
||||
Éteindre la VM :
|
||||
|
||||
```bash
|
||||
shutdown -h now
|
||||
```
|
||||
|
||||
Dans Proxmox :
|
||||
|
||||
```text
|
||||
VM → Hardware → Add → CloudInit Drive
|
||||
```
|
||||
|
||||
Ou en ligne de commande Proxmox :
|
||||
|
||||
```bash
|
||||
qm set VMID --ide2 STORAGE:cloudinit
|
||||
```
|
||||
|
||||
Exemple :
|
||||
|
||||
```bash
|
||||
qm set 9000 --ide2 local-lvm:cloudinit
|
||||
```
|
||||
|
||||
Le nom exact du stockage dépend de la configuration Proxmox.
|
||||
|
||||
### Définir les paramètres Cloud-Init du modèle
|
||||
|
||||
Pour la VM qui deviendra le modèle, utiliser une identité technique minimale, pas une identité de serveur final.
|
||||
|
||||
Exemple DHCP :
|
||||
|
||||
```bash
|
||||
qm set 9000 --ciuser ansible
|
||||
qm set 9000 --sshkeys ~/.ssh/id_ed25519.pub
|
||||
qm set 9000 --ipconfig0 ip=dhcp
|
||||
```
|
||||
|
||||
Exemple IP statique temporaire pour joindre la VM de modèle :
|
||||
|
||||
```bash
|
||||
qm set 9000 --ciuser ansible
|
||||
qm set 9000 --sshkeys ~/.ssh/id_ed25519.pub
|
||||
qm set 9000 --ipconfig0 ip=10.0.99.99/24,gw=10.0.99.1
|
||||
qm set 9000 --nameserver 10.0.99.1
|
||||
```
|
||||
|
||||
Pour les clones, ces valeurs seront remplacées par l'identité réelle du serveur.
|
||||
|
||||
### Réinitialiser l'état Cloud-Init avant le test
|
||||
|
||||
Comme `cloud-init` vient d'être installé après le premier démarrage Debian, nettoyer son état avant de tester l'injection Proxmox :
|
||||
|
||||
```bash
|
||||
cloud-init clean --logs
|
||||
reboot
|
||||
```
|
||||
|
||||
Au redémarrage, cloud-init doit appliquer le `ciuser`, la clé SSH et les paramètres réseau.
|
||||
|
||||
---
|
||||
|
||||
## 18. SSH et sudo après Cloud-Init
|
||||
|
||||
### Tester la connexion par clé
|
||||
|
||||
Depuis le poste d'administration :
|
||||
|
||||
```bash
|
||||
ssh -o PreferredAuthentications=publickey ansible@IP_DE_LA_VM
|
||||
```
|
||||
|
||||
Résultat attendu : la connexion fonctionne sans saisir le mot de passe du compte `ansible`.
|
||||
|
||||
### Vérifier sudo
|
||||
|
||||
Tester :
|
||||
|
||||
```bash
|
||||
sudo -v
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo -n true && echo OK
|
||||
```
|
||||
|
||||
Le résultat attendu est `OK`. Le flux `make` ne demande pas de mot de passe interactif.
|
||||
|
||||
### Correction minimale si sudo manque
|
||||
|
||||
Si cloud-init a créé `ansible` sans privilège sudo, corriger seulement ce point depuis la console Proxmox ou un compte administrateur existant :
|
||||
|
||||
```bash
|
||||
usermod -aG sudo ansible
|
||||
```
|
||||
|
||||
Puis retester `sudo -v` avec le compte `ansible`.
|
||||
|
||||
Ne pas créer manuellement `/home/ansible/.ssh/authorized_keys` dans le flux normal. Si la clé ne fonctionne pas, corriger les paramètres Cloud-Init dans Proxmox, puis relancer :
|
||||
|
||||
```bash
|
||||
cloud-init clean --logs
|
||||
reboot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 19. SSH durci attendu
|
||||
|
||||
Le modèle suppose que Cloud-Init injecte le `ciuser` et sa clé publique avant la prise en charge par Ansible.
|
||||
|
||||
L'exigence immédiate est que l'accès par clé fonctionne pour `ansible`.
|
||||
|
||||
L'état final sera appliqué et validé par Set-OPS :
|
||||
|
||||
```text
|
||||
PermitRootLogin no
|
||||
PubkeyAuthentication yes
|
||||
PasswordAuthentication no
|
||||
AuthenticationMethods publickey
|
||||
```
|
||||
|
||||
Ne pas lancer le playbook de préparation tant que l'accès SSH par clé ne fonctionne pas.
|
||||
|
||||
---
|
||||
|
||||
## 20. Vérifications avant passage à Set-OPS
|
||||
|
||||
Redémarrer la VM une dernière fois si nécessaire, puis vérifier :
|
||||
|
||||
```bash
|
||||
lsblk
|
||||
df -h
|
||||
swapon --show
|
||||
ip a
|
||||
hostnamectl
|
||||
timedatectl
|
||||
systemctl status ssh --no-pager
|
||||
systemctl status qemu-guest-agent --no-pager
|
||||
cloud-init --version
|
||||
```
|
||||
|
||||
État attendu :
|
||||
|
||||
```text
|
||||
/boot/efi présent
|
||||
/ sur ext4
|
||||
aucun swap actif
|
||||
qemu-guest-agent actif
|
||||
ssh actif
|
||||
cloud-init installé
|
||||
compte ansible fonctionnel
|
||||
connexion SSH par clé fonctionnelle
|
||||
sudo fonctionnel pour ansible
|
||||
CloudInit Drive présent côté Proxmox
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 21. Point de bascule vers Set-OPS
|
||||
|
||||
À partir de ce point, ne pas continuer manuellement la configuration du socle. Utiliser le `Makefile` depuis le dépôt Set-OPS.
|
||||
|
||||
Depuis le poste Ansible :
|
||||
|
||||
```bash
|
||||
make preparer-modele
|
||||
make verifier-modele
|
||||
```
|
||||
|
||||
Le cleanup final est séparé et protégé :
|
||||
|
||||
```bash
|
||||
make nettoyer-modele CONFIRMER=true
|
||||
```
|
||||
|
||||
Ne pas lancer le cleanup final tant que `make verifier-modele` n'a pas réussi.
|
||||
|
||||
---
|
||||
|
||||
## 22. Dépannage du bootstrap initial
|
||||
|
||||
| Symptôme | Cause probable | Correction |
|
||||
| --- | --- | --- |
|
||||
| `apt install` demande le DVD | Source APT `cdrom:` encore active. | Refaire la section 13 et relancer `apt update`. |
|
||||
| `Temporary failure resolving deb.debian.org` | DNS absent ou incorrect. | Vérifier `/etc/resolv.conf`, Proxmox cloud-init DNS, passerelle et réseau. |
|
||||
| `Network is unreachable` | Pas de route par défaut. | Vérifier l'IP, la passerelle et `ip route`. |
|
||||
| SSH refuse la clé | Clé Cloud-Init absente, mauvais `ciuser`, ou cloud-init déjà initialisé avant l'ajout des paramètres. | Corriger les paramètres Proxmox, puis `cloud-init clean --logs` et redémarrer. |
|
||||
| `sudo: a password is required` | Sudo NOPASSWD pas encore posé. | Corriger sudo NOPASSWD pour `ansible`, puis relancer `make preparer-modele`. |
|
||||
| `ansible is not in the sudoers file` | Le compte a été créé par Cloud-Init sans privilège sudo. | Ajouter seulement `ansible` au groupe `sudo`, puis laisser Set-OPS gérer NOPASSWD. |
|
||||
| Cloud-init sans effet | `cloud-init` absent au premier boot concerné, disque CloudInit absent, ou VM déjà initialisée. | Installer `cloud-init`, ajouter le CloudInit Drive, corriger les paramètres Proxmox, puis `cloud-init clean --logs` et redémarrer. |
|
||||
|
||||
---
|
||||
|
||||
## 23. Nettoyage avant conversion en template
|
||||
|
||||
Le nettoyage est fait par Set-OPS, pas à la main, sauf diagnostic exceptionnel.
|
||||
|
||||
Commande attendue :
|
||||
|
||||
```bash
|
||||
make nettoyer-modele CONFIRMER=true
|
||||
```
|
||||
|
||||
Ce nettoyage peut inclure :
|
||||
|
||||
```text
|
||||
cloud-init clean --logs
|
||||
nettoyage du cache APT
|
||||
rotation ou purge contrôlée des journaux
|
||||
remise à zéro de /etc/machine-id
|
||||
suppression des historiques shell
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 24. Point d’arrêt : VM prête à convertir
|
||||
|
||||
À ce stade, la VM doit être arrêtée.
|
||||
|
||||
Elle est prête à être convertie en template Proxmox.
|
||||
|
||||
État attendu côté Proxmox :
|
||||
|
||||
```text
|
||||
VM arrêtée
|
||||
BIOS OVMF / UEFI
|
||||
Machine q35
|
||||
EFI Disk présent
|
||||
Disque principal SCSI / VirtIO SCSI single
|
||||
CloudInit Drive présent
|
||||
QEMU Guest Agent activé dans les options
|
||||
CPU x86-64-v2-AES
|
||||
RAM 2048 MiB
|
||||
Aucun environnement graphique
|
||||
```
|
||||
|
||||
État attendu côté Debian :
|
||||
|
||||
```text
|
||||
Debian 13 minimal
|
||||
SSH installé
|
||||
qemu-guest-agent installé
|
||||
cloud-init installé
|
||||
cloud-guest-utils installé
|
||||
sudo installé
|
||||
compte ansible injecté par cloud-init
|
||||
clé publique SSH injectée par cloud-init
|
||||
sudo NOPASSWD pour ansible après préparation Set-OPS
|
||||
partition EFI 512 Mo
|
||||
partition / ext4
|
||||
aucune partition swap
|
||||
aucun LVM
|
||||
machine-id nettoyé
|
||||
cloud-init nettoyé
|
||||
apt cache nettoyé
|
||||
VM éteinte
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 25. Conversion en template Proxmox
|
||||
|
||||
Cette commande n’est exécutée qu’après validation finale :
|
||||
|
||||
```bash
|
||||
qm template VMID
|
||||
```
|
||||
|
||||
Exemple :
|
||||
|
||||
```bash
|
||||
qm template 9000
|
||||
```
|
||||
|
||||
À partir de là, le modèle peut être cloné.
|
||||
|
||||
---
|
||||
|
||||
## 26. Flux normal après conversion
|
||||
|
||||
Après conversion du modèle, le flux normal passe par `make` et l'API Proxmox.
|
||||
|
||||
Les paramètres communs Proxmox sont dans :
|
||||
|
||||
```text
|
||||
instance/inventories/lab/group_vars/proxmox.yml
|
||||
```
|
||||
|
||||
Les secrets d'API doivent être dans un fichier Vault non versionné :
|
||||
|
||||
```text
|
||||
instance/inventories/lab/group_vars/proxmox.vault.yml
|
||||
```
|
||||
|
||||
Créer le clone et l'ajouter à l'inventaire :
|
||||
|
||||
```text
|
||||
1. Cloner le template via l'API Proxmox.
|
||||
2. Agrandir le disque si demandé.
|
||||
3. Définir l'identité Cloud-Init.
|
||||
4. Démarrer la VM.
|
||||
5. Ajouter l'hôte à l'inventaire Set-OPS.
|
||||
```
|
||||
|
||||
Exemple :
|
||||
|
||||
```bash
|
||||
make creer-vm HOTE=web-frontal-01
|
||||
```
|
||||
|
||||
Les paramètres par VM (VMID, IP, VLAN, passerelle) ne sont plus saisis à la main : `creer-vm` les lit dans l'inventaire généré depuis le plan. L'hôte doit donc être déclaré dans `instance/plan/serveurs.yml` et l'inventaire régénéré (`make instancier-appliquer`) au préalable.
|
||||
|
||||
Après le premier démarrage, tester l'accès :
|
||||
|
||||
```bash
|
||||
ssh ansible@10.0.15.31
|
||||
```
|
||||
|
||||
Ensuite appliquer la conformité Ansible :
|
||||
|
||||
```bash
|
||||
make deployer HOTE=web-frontal-01
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 27. Résumé court
|
||||
|
||||
La VM vanille idéale est simple :
|
||||
|
||||
```text
|
||||
Debian 13 minimal
|
||||
UEFI / OVMF
|
||||
q35
|
||||
SCSI / VirtIO SCSI single
|
||||
16 Go
|
||||
2 Go RAM
|
||||
2 cores
|
||||
partition EFI 512 Mo
|
||||
partition / ext4
|
||||
pas de LVM
|
||||
pas de swap
|
||||
SSH
|
||||
sudo
|
||||
qemu-guest-agent
|
||||
cloud-init
|
||||
cloud-guest-utils
|
||||
CloudInit Drive Proxmox
|
||||
ciuser ansible défini dans Proxmox
|
||||
clé publique SSH définie dans Proxmox
|
||||
sudo fonctionnel pour ansible
|
||||
APT réseau fonctionnel
|
||||
```
|
||||
|
||||
La philosophie :
|
||||
|
||||
```text
|
||||
Proxmox crée la VM.
|
||||
Cloud-init donne son identité au clone.
|
||||
Ansible configure le vrai serveur.
|
||||
Set-OPS documente et automatise l’ensemble.
|
||||
```
|
||||
201
docs/vm-lifecycle.md
Normal file
201
docs/vm-lifecycle.md
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
# Cycle de vie des VM
|
||||
|
||||
Ce document décrit le cycle normal d'une VM Debian, depuis l'installation minimale jusqu'à la conformité continue par Ansible.
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
```text
|
||||
Debian 13 minimale
|
||||
→ goldenisation du template
|
||||
→ cleanup final
|
||||
→ conversion Proxmox en template
|
||||
→ clonage
|
||||
→ identité initiale par cloud-init
|
||||
→ conformité par groupes Ansible
|
||||
→ intégrations par rôle
|
||||
→ conformité continue
|
||||
```
|
||||
|
||||
## 1. VM vanille
|
||||
|
||||
La VM vanille est une Debian 13 minimale installée manuellement ou par procédure Proxmox.
|
||||
|
||||
Elle contient seulement le nécessaire pour être joignable et prise en charge :
|
||||
|
||||
```text
|
||||
Debian 13
|
||||
SSH
|
||||
réseau fonctionnel
|
||||
cloud-init installé
|
||||
CloudInit Drive Proxmox présent
|
||||
utilisateur initial injecté par Cloud-Init
|
||||
clé publique SSH injectée par Cloud-Init
|
||||
sudo ou accès root possible
|
||||
aucun rôle applicatif
|
||||
aucun secret
|
||||
```
|
||||
|
||||
Cette VM n'est pas encore un golden template.
|
||||
|
||||
## 2. Goldenisation
|
||||
|
||||
La goldenisation est faite par :
|
||||
|
||||
```bash
|
||||
make preparer-modele
|
||||
```
|
||||
|
||||
Ce playbook ajoute le socle commun au template :
|
||||
|
||||
```text
|
||||
paquets communs
|
||||
qemu-guest-agent
|
||||
cloud-init
|
||||
compte technique Ansible
|
||||
chrony
|
||||
SSH socle
|
||||
durcissement template-safe
|
||||
nftables préparé mais désactivé
|
||||
```
|
||||
|
||||
Les détails et justifications sont dans :
|
||||
|
||||
```text
|
||||
docs/modeles_vm/debian13-proxmox.md
|
||||
```
|
||||
|
||||
## 3. Validation et cleanup
|
||||
|
||||
Après la préparation :
|
||||
|
||||
```bash
|
||||
make verifier-modele
|
||||
```
|
||||
|
||||
Le cleanup final est séparé et protégé :
|
||||
|
||||
```bash
|
||||
make nettoyer-modele CONFIRMER=true
|
||||
```
|
||||
|
||||
Le cleanup ne doit jamais être lancé sur une VM de production.
|
||||
|
||||
## 4. Clonage
|
||||
|
||||
Le clone reçoit son identité initiale par Proxmox et cloud-init :
|
||||
|
||||
```text
|
||||
hostname
|
||||
utilisateur initial
|
||||
clé SSH
|
||||
IP ou DHCP
|
||||
passerelle
|
||||
DNS
|
||||
agrandissement disque
|
||||
```
|
||||
|
||||
Cloud-init ne remplace pas Ansible pour la configuration réelle du serveur.
|
||||
|
||||
## 5. Groupes opérationnels
|
||||
|
||||
Une VM déployée doit être placée dans les groupes d'inventaire qui décrivent l'état voulu.
|
||||
|
||||
Les hôtes prévus mais non créés restent dans `hotes_planifies`.
|
||||
|
||||
Les hôtes joignables par Ansible sont dans `hotes_actifs`.
|
||||
|
||||
Chaque groupe opérationnel doit avoir un playbook homonyme :
|
||||
|
||||
```text
|
||||
serveur_debian -> playbooks/groupes/serveur_debian.yml
|
||||
serveur_durci -> playbooks/groupes/serveur_durci.yml
|
||||
```
|
||||
|
||||
L'appartenance aux groupes devient la déclaration d'intention :
|
||||
|
||||
```text
|
||||
web-frontal-01 dans serveur_debian -> applique le socle Debian
|
||||
web-frontal-01 dans serveur_durci -> applique le durcissement commun
|
||||
```
|
||||
|
||||
Un groupe sans playbook ne doit pas être assigné à une VM de production.
|
||||
|
||||
Un playbook de groupe peut être un contrat temporaire sans rôle tant que le service n'est pas encore implémenté. Il doit rester idempotent et explicite.
|
||||
|
||||
## 6. Socle Debian
|
||||
|
||||
Le groupe `serveur_debian` maintient les composants de base :
|
||||
|
||||
```bash
|
||||
make deployer-groupe GROUPE=serveur_debian
|
||||
```
|
||||
|
||||
## 7. Hardening commun
|
||||
|
||||
Le groupe `serveur_durci` maintient les couches de sécurité communes :
|
||||
|
||||
```bash
|
||||
make deployer-groupe GROUPE=serveur_durci
|
||||
```
|
||||
|
||||
L'accès SSH par mot de passe est désactivé dès le socle. L'activation de nftables doit rester dépendante des règles réseau propres au rôle du serveur.
|
||||
|
||||
## 8. Déploiement par Makefile
|
||||
|
||||
L'hôte est d'abord déclaré dans le **plan** (`instance/plan/serveurs.yml`) et l'inventaire régénéré (`make instancier-appliquer`) — `hosts.yml` est généré, il ne s'édite plus à la main. Pour une VM déjà clonée et démarrée :
|
||||
|
||||
```bash
|
||||
make deployer HOTE=web-frontal-01
|
||||
```
|
||||
|
||||
La cible `deployer` lit les groupes de l'hôte, cherche les playbooks correspondants dans `playbooks/groupes/`, puis les applique dans l'ordre de l'inventaire.
|
||||
|
||||
Ensuite, elle lance la vérification post-déploiement :
|
||||
|
||||
```text
|
||||
playbooks/groupes/serveur_debian.yml
|
||||
playbooks/groupes/serveur_durci.yml
|
||||
verifier-hote
|
||||
```
|
||||
|
||||
Pour converger un groupe complet :
|
||||
|
||||
```bash
|
||||
make deployer-groupe GROUPE=serveur_debian
|
||||
```
|
||||
|
||||
Cette commande limite le playbook au croisement entre le groupe demandé et `hotes_actifs`.
|
||||
|
||||
## 9. Variables template et conformité
|
||||
|
||||
Les variables du template servent à construire le golden template dans `instance/inventories/lab/group_vars/modeles_vm.yml`.
|
||||
|
||||
Les variables de conformité servent aux VM déployées dans `instance/inventories/production/group_vars/serveur_debian.yml`.
|
||||
|
||||
Différence attendue :
|
||||
|
||||
```text
|
||||
template : SSH par clé seulement, pare-feu non activé
|
||||
conformité VM : même base SSH, règles réseau adaptées aux serveurs finaux
|
||||
```
|
||||
|
||||
Ne pas durcir une variable de conformité si son application peut couper l'accès sans validation préalable.
|
||||
|
||||
## 10. Intégrations futures
|
||||
|
||||
Les intégrations transversales sont ajoutées après socle et durcissement :
|
||||
|
||||
```text
|
||||
DNS interne
|
||||
PKI interne
|
||||
identité
|
||||
supervision
|
||||
métriques
|
||||
visualisation
|
||||
```
|
||||
|
||||
Elles sont documentées dans :
|
||||
|
||||
```text
|
||||
docs/integrations-vm.md
|
||||
```
|
||||
16
exemples/instance.exemple.yml
Normal file
16
exemples/instance.exemple.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
# Identite d'une INSTANCE Set-OPS (un loup / un client).
|
||||
#
|
||||
# Ces variables distinguent une instance d'une autre. Le MOTEUR (roles, scripts,
|
||||
# generateur) est generique ; c'est ici qu'on dit "qui on est". A placer dans
|
||||
# inventories/<env>/group_vars/all.yml de l'instance.
|
||||
#
|
||||
# Voir docs/plan-et-generation.md et docs/positionnement.md.
|
||||
|
||||
# Domaine DNS interne de l'instance. Les roles en derivent zones, FQDN, base DN
|
||||
# LDAP, expediteurs courriel, etc. (ex. dc=acme,dc=local pour acme.local).
|
||||
domaine_interne: "acme.internal"
|
||||
|
||||
# Le reste de l'identite vit dans le PLAN de l'instance :
|
||||
# - instance/plan/nomenclature.yml : supernet (ex. 10.0.0.0/16) + liste de fonctions
|
||||
# - instance/plan/serveurs.yml / applications.yml / domaines.yml : le plan rempli
|
||||
27
exemples/modeles/README.md
Normal file
27
exemples/modeles/README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Modèles d'écosystèmes numériques
|
||||
|
||||
Des **instances prêtes à déployer** : un hébergeur copie le modèle qui colle à son
|
||||
offre, le renseigne à ses couleurs (ou celles de son client), et instancie.
|
||||
|
||||
## Utilisation
|
||||
```bash
|
||||
cp -r exemples/modeles/<modele> ../mon-instance
|
||||
# éditer mon-instance : domaine_interne, domaines publics, dimensionnement
|
||||
cd <moteur Set-OPS>
|
||||
ln -s ../mon-instance instance # ou export SETOPS_INSTANCE=../mon-instance
|
||||
make instancier-appliquer FORCE=1 # première génération de l'inventaire
|
||||
```
|
||||
|
||||
## Structure : socle + modules
|
||||
Tout modèle part d'un **socle souverain** (DNS interne, AC/PKI, edge TLS, relais
|
||||
courriel) et ajoute des **modules** selon l'offre.
|
||||
|
||||
| Modèle | = socle + | État |
|
||||
| --- | --- | --- |
|
||||
| `socle` | (rien) | ✅ |
|
||||
| **`presence-web`** | web (frontal+dorsal) + données (PostgreSQL/Redis) | ✅ |
|
||||
| `forge` | Forgejo + données | ✅ |
|
||||
| `identite` | LDAP + Keycloak (SSO) | ✅ |
|
||||
| `observabilite` | Prometheus/Loki/Grafana + Icinga | ✅ |
|
||||
| `collaboration` | Nextcloud + Collabora | rôles à construire |
|
||||
| `integral` | tout | ✅ |
|
||||
5
exemples/modeles/forge/README.md
Normal file
5
exemples/modeles/forge/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Modele : forge
|
||||
|
||||
Forge Git souveraine : socle + Forgejo + PostgreSQL.
|
||||
|
||||
6 VM. Renseignez `domaine_interne`, `plan/domaines.yml` et `plan/nomenclature.yml` (supernet), puis generez (voir `exemples/modeles/README.md`).
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
domaine_interne: "exemple.internal" # <- VOTRE domaine DNS interne
|
||||
setops_plan_dir: "{{ playbook_dir }}/../../instance/plan"
|
||||
24
exemples/modeles/forge/plan/applications.yml
Normal file
24
exemples/modeles/forge/plan/applications.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
applications:
|
||||
step_ca:
|
||||
groupe: serveur_step_ca
|
||||
hote: infra-pki-01
|
||||
nginx:
|
||||
groupe: serveur_nginx
|
||||
hote: infra-edge-01
|
||||
sendmail:
|
||||
groupe: serveur_sendmail
|
||||
hote: infra-mail-01
|
||||
powerdns:
|
||||
groupe: serveur_powerdns
|
||||
hote: infra-dns-01
|
||||
postgresql:
|
||||
groupe: serveur_postgresql
|
||||
hote: data-01
|
||||
port: 5432
|
||||
forgejo:
|
||||
groupe: serveur_forgejo
|
||||
hote: forge-01
|
||||
port: 3000
|
||||
expose:
|
||||
- forge.exemple.ca
|
||||
16
exemples/modeles/forge/plan/bases-donnees.yml
Normal file
16
exemples/modeles/forge/plan/bases-donnees.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
serveurs_bd:
|
||||
pg-principal:
|
||||
type: postgres
|
||||
hote: 10.10.13.11
|
||||
port: 5432
|
||||
groupe: serveur_postgresql
|
||||
bases_donnees:
|
||||
forgejo:
|
||||
serveur: pg-principal
|
||||
base: forgejo
|
||||
proprietaire: forgejo
|
||||
secret: vault_bd_forgejo
|
||||
consommateur: serveur_forgejo
|
||||
portee: groupe
|
||||
usage: principale
|
||||
7
exemples/modeles/forge/plan/domaines.yml
Normal file
7
exemples/modeles/forge/plan/domaines.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
domaines_publics:
|
||||
exemple.ca:
|
||||
autorite: primaire-cache
|
||||
edge: serveur_nginx
|
||||
secondaires: []
|
||||
dnssec: false
|
||||
42
exemples/modeles/forge/plan/nomenclature.yml
Normal file
42
exemples/modeles/forge/plan/nomenclature.yml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
supernet: 10.10.0.0/16
|
||||
cidr_hote: 24
|
||||
reservations:
|
||||
passerelle: 1
|
||||
reserve_min: 2
|
||||
reserve_max: 9
|
||||
categories:
|
||||
1:
|
||||
libelle: Fondations
|
||||
vlan: 11
|
||||
sous_reseau: 10.10.11.0/24
|
||||
passerelle: 10.10.11.1
|
||||
3:
|
||||
libelle: Donnees
|
||||
vlan: 13
|
||||
sous_reseau: 10.10.13.0/24
|
||||
passerelle: 10.10.13.1
|
||||
5:
|
||||
libelle: Applications
|
||||
vlan: 15
|
||||
sous_reseau: 10.10.15.0/24
|
||||
passerelle: 10.10.15.1
|
||||
fonctions:
|
||||
data:
|
||||
categorie: 3
|
||||
service: 1
|
||||
forge:
|
||||
categorie: 5
|
||||
service: 1
|
||||
infra-dns:
|
||||
categorie: 1
|
||||
service: 4
|
||||
infra-edge:
|
||||
categorie: 1
|
||||
service: 2
|
||||
infra-mail:
|
||||
categorie: 1
|
||||
service: 3
|
||||
infra-pki:
|
||||
categorie: 1
|
||||
service: 1
|
||||
20
exemples/modeles/forge/plan/serveurs.yml
Normal file
20
exemples/modeles/forge/plan/serveurs.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
serveurs:
|
||||
infra-pki-01:
|
||||
fonction: infra-pki
|
||||
etat: planifie
|
||||
infra-edge-01:
|
||||
fonction: infra-edge
|
||||
etat: planifie
|
||||
infra-mail-01:
|
||||
fonction: infra-mail
|
||||
etat: planifie
|
||||
infra-dns-01:
|
||||
fonction: infra-dns
|
||||
etat: planifie
|
||||
data-01:
|
||||
fonction: data
|
||||
etat: planifie
|
||||
forge-01:
|
||||
fonction: forge
|
||||
etat: planifie
|
||||
5
exemples/modeles/identite/README.md
Normal file
5
exemples/modeles/identite/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Modele : identite
|
||||
|
||||
Identite centralisee : socle + LDAP + Keycloak (SSO) + PostgreSQL.
|
||||
|
||||
6 VM. Renseignez `domaine_interne`, `plan/domaines.yml` et `plan/nomenclature.yml` (supernet), puis generez (voir `exemples/modeles/README.md`).
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
domaine_interne: "exemple.internal" # <- VOTRE domaine DNS interne
|
||||
setops_plan_dir: "{{ playbook_dir }}/../../instance/plan"
|
||||
27
exemples/modeles/identite/plan/applications.yml
Normal file
27
exemples/modeles/identite/plan/applications.yml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
applications:
|
||||
step_ca:
|
||||
groupe: serveur_step_ca
|
||||
hote: infra-pki-01
|
||||
nginx:
|
||||
groupe: serveur_nginx
|
||||
hote: infra-edge-01
|
||||
sendmail:
|
||||
groupe: serveur_sendmail
|
||||
hote: infra-mail-01
|
||||
powerdns:
|
||||
groupe: serveur_powerdns
|
||||
hote: infra-dns-01
|
||||
postgresql:
|
||||
groupe: serveur_postgresql
|
||||
hote: data-01
|
||||
port: 5432
|
||||
openldap:
|
||||
groupe: serveur_openldap
|
||||
hote: idm-01
|
||||
keycloak:
|
||||
groupe: serveur_keycloak
|
||||
hote: idm-01
|
||||
port: 8080
|
||||
expose:
|
||||
- auth.exemple.ca
|
||||
16
exemples/modeles/identite/plan/bases-donnees.yml
Normal file
16
exemples/modeles/identite/plan/bases-donnees.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
serveurs_bd:
|
||||
pg-principal:
|
||||
type: postgres
|
||||
hote: 10.10.13.11
|
||||
port: 5432
|
||||
groupe: serveur_postgresql
|
||||
bases_donnees:
|
||||
keycloak:
|
||||
serveur: pg-principal
|
||||
base: keycloak
|
||||
proprietaire: keycloak
|
||||
secret: vault_bd_keycloak
|
||||
consommateur: serveur_keycloak
|
||||
portee: groupe
|
||||
usage: principale
|
||||
7
exemples/modeles/identite/plan/domaines.yml
Normal file
7
exemples/modeles/identite/plan/domaines.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
domaines_publics:
|
||||
exemple.ca:
|
||||
autorite: primaire-cache
|
||||
edge: serveur_nginx
|
||||
secondaires: []
|
||||
dnssec: false
|
||||
42
exemples/modeles/identite/plan/nomenclature.yml
Normal file
42
exemples/modeles/identite/plan/nomenclature.yml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
supernet: 10.10.0.0/16
|
||||
cidr_hote: 24
|
||||
reservations:
|
||||
passerelle: 1
|
||||
reserve_min: 2
|
||||
reserve_max: 9
|
||||
categories:
|
||||
1:
|
||||
libelle: Fondations
|
||||
vlan: 11
|
||||
sous_reseau: 10.10.11.0/24
|
||||
passerelle: 10.10.11.1
|
||||
2:
|
||||
libelle: Identite
|
||||
vlan: 12
|
||||
sous_reseau: 10.10.12.0/24
|
||||
passerelle: 10.10.12.1
|
||||
3:
|
||||
libelle: Donnees
|
||||
vlan: 13
|
||||
sous_reseau: 10.10.13.0/24
|
||||
passerelle: 10.10.13.1
|
||||
fonctions:
|
||||
data:
|
||||
categorie: 3
|
||||
service: 1
|
||||
idm:
|
||||
categorie: 2
|
||||
service: 1
|
||||
infra-dns:
|
||||
categorie: 1
|
||||
service: 4
|
||||
infra-edge:
|
||||
categorie: 1
|
||||
service: 2
|
||||
infra-mail:
|
||||
categorie: 1
|
||||
service: 3
|
||||
infra-pki:
|
||||
categorie: 1
|
||||
service: 1
|
||||
20
exemples/modeles/identite/plan/serveurs.yml
Normal file
20
exemples/modeles/identite/plan/serveurs.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
serveurs:
|
||||
infra-pki-01:
|
||||
fonction: infra-pki
|
||||
etat: planifie
|
||||
infra-edge-01:
|
||||
fonction: infra-edge
|
||||
etat: planifie
|
||||
infra-mail-01:
|
||||
fonction: infra-mail
|
||||
etat: planifie
|
||||
infra-dns-01:
|
||||
fonction: infra-dns
|
||||
etat: planifie
|
||||
data-01:
|
||||
fonction: data
|
||||
etat: planifie
|
||||
idm-01:
|
||||
fonction: idm
|
||||
etat: planifie
|
||||
5
exemples/modeles/integral/README.md
Normal file
5
exemples/modeles/integral/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Modele : integral
|
||||
|
||||
Ecosysteme integral (services implementes) : socle + donnees + identite + forge + observabilite + web.
|
||||
|
||||
11 VM. Renseignez `domaine_interne`, `plan/domaines.yml` et `plan/nomenclature.yml` (supernet), puis generez (voir `exemples/modeles/README.md`).
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
domaine_interne: "exemple.internal" # <- VOTRE domaine DNS interne
|
||||
setops_plan_dir: "{{ playbook_dir }}/../../instance/plan"
|
||||
57
exemples/modeles/integral/plan/applications.yml
Normal file
57
exemples/modeles/integral/plan/applications.yml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
applications:
|
||||
step_ca:
|
||||
groupe: serveur_step_ca
|
||||
hote: infra-pki-01
|
||||
nginx:
|
||||
groupe: serveur_nginx
|
||||
hote: infra-edge-01
|
||||
sendmail:
|
||||
groupe: serveur_sendmail
|
||||
hote: infra-mail-01
|
||||
powerdns:
|
||||
groupe: serveur_powerdns
|
||||
hote: infra-dns-01
|
||||
postgresql:
|
||||
groupe: serveur_postgresql
|
||||
hote: data-01
|
||||
port: 5432
|
||||
redis:
|
||||
groupe: serveur_redis
|
||||
hote: data-01
|
||||
openldap:
|
||||
groupe: serveur_openldap
|
||||
hote: idm-01
|
||||
keycloak:
|
||||
groupe: serveur_keycloak
|
||||
hote: idm-01
|
||||
port: 8080
|
||||
expose:
|
||||
- auth.exemple.ca
|
||||
forgejo:
|
||||
groupe: serveur_forgejo
|
||||
hote: forge-01
|
||||
port: 3000
|
||||
expose:
|
||||
- forge.exemple.ca
|
||||
prometheus:
|
||||
groupe: serveur_prometheus
|
||||
hote: obs-01
|
||||
loki:
|
||||
groupe: serveur_loki
|
||||
hote: obs-01
|
||||
grafana:
|
||||
groupe: serveur_grafana
|
||||
hote: obs-01
|
||||
port: 3000
|
||||
expose:
|
||||
- grafana.exemple.ca
|
||||
icinga:
|
||||
groupe: serveur_icinga
|
||||
hote: mon-01
|
||||
web_frontal:
|
||||
groupe: serveur_web_frontal
|
||||
hote: web-frontal-01
|
||||
web_dorsal:
|
||||
groupe: serveur_web_dorsal
|
||||
hote: web-dorsal-01
|
||||
32
exemples/modeles/integral/plan/bases-donnees.yml
Normal file
32
exemples/modeles/integral/plan/bases-donnees.yml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
serveurs_bd:
|
||||
pg-principal:
|
||||
type: postgres
|
||||
hote: 10.10.13.11
|
||||
port: 5432
|
||||
groupe: serveur_postgresql
|
||||
bases_donnees:
|
||||
keycloak:
|
||||
serveur: pg-principal
|
||||
base: keycloak
|
||||
proprietaire: keycloak
|
||||
secret: vault_bd_keycloak
|
||||
consommateur: serveur_keycloak
|
||||
portee: groupe
|
||||
usage: principale
|
||||
forgejo:
|
||||
serveur: pg-principal
|
||||
base: forgejo
|
||||
proprietaire: forgejo
|
||||
secret: vault_bd_forgejo
|
||||
consommateur: serveur_forgejo
|
||||
portee: groupe
|
||||
usage: principale
|
||||
icingadb:
|
||||
serveur: pg-principal
|
||||
base: icingadb
|
||||
proprietaire: icingadb
|
||||
secret: vault_bd_icingadb
|
||||
consommateur: serveur_icinga
|
||||
portee: groupe
|
||||
usage: principale
|
||||
7
exemples/modeles/integral/plan/domaines.yml
Normal file
7
exemples/modeles/integral/plan/domaines.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
domaines_publics:
|
||||
exemple.ca:
|
||||
autorite: primaire-cache
|
||||
edge: serveur_nginx
|
||||
secondaires: []
|
||||
dnssec: false
|
||||
67
exemples/modeles/integral/plan/nomenclature.yml
Normal file
67
exemples/modeles/integral/plan/nomenclature.yml
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
supernet: 10.10.0.0/16
|
||||
cidr_hote: 24
|
||||
reservations:
|
||||
passerelle: 1
|
||||
reserve_min: 2
|
||||
reserve_max: 9
|
||||
categories:
|
||||
1:
|
||||
libelle: Fondations
|
||||
vlan: 11
|
||||
sous_reseau: 10.10.11.0/24
|
||||
passerelle: 10.10.11.1
|
||||
2:
|
||||
libelle: Identite
|
||||
vlan: 12
|
||||
sous_reseau: 10.10.12.0/24
|
||||
passerelle: 10.10.12.1
|
||||
3:
|
||||
libelle: Donnees
|
||||
vlan: 13
|
||||
sous_reseau: 10.10.13.0/24
|
||||
passerelle: 10.10.13.1
|
||||
4:
|
||||
libelle: Observabilite
|
||||
vlan: 14
|
||||
sous_reseau: 10.10.14.0/24
|
||||
passerelle: 10.10.14.1
|
||||
5:
|
||||
libelle: Applications
|
||||
vlan: 15
|
||||
sous_reseau: 10.10.15.0/24
|
||||
passerelle: 10.10.15.1
|
||||
fonctions:
|
||||
data:
|
||||
categorie: 3
|
||||
service: 1
|
||||
forge:
|
||||
categorie: 5
|
||||
service: 1
|
||||
idm:
|
||||
categorie: 2
|
||||
service: 1
|
||||
infra-dns:
|
||||
categorie: 1
|
||||
service: 4
|
||||
infra-edge:
|
||||
categorie: 1
|
||||
service: 2
|
||||
infra-mail:
|
||||
categorie: 1
|
||||
service: 3
|
||||
infra-pki:
|
||||
categorie: 1
|
||||
service: 1
|
||||
mon:
|
||||
categorie: 4
|
||||
service: 4
|
||||
obs:
|
||||
categorie: 4
|
||||
service: 1
|
||||
web-dorsal:
|
||||
categorie: 5
|
||||
service: 4
|
||||
web-frontal:
|
||||
categorie: 5
|
||||
service: 3
|
||||
35
exemples/modeles/integral/plan/serveurs.yml
Normal file
35
exemples/modeles/integral/plan/serveurs.yml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
serveurs:
|
||||
infra-pki-01:
|
||||
fonction: infra-pki
|
||||
etat: planifie
|
||||
infra-edge-01:
|
||||
fonction: infra-edge
|
||||
etat: planifie
|
||||
infra-mail-01:
|
||||
fonction: infra-mail
|
||||
etat: planifie
|
||||
infra-dns-01:
|
||||
fonction: infra-dns
|
||||
etat: planifie
|
||||
data-01:
|
||||
fonction: data
|
||||
etat: planifie
|
||||
idm-01:
|
||||
fonction: idm
|
||||
etat: planifie
|
||||
forge-01:
|
||||
fonction: forge
|
||||
etat: planifie
|
||||
obs-01:
|
||||
fonction: obs
|
||||
etat: planifie
|
||||
mon-01:
|
||||
fonction: mon
|
||||
etat: planifie
|
||||
web-frontal-01:
|
||||
fonction: web-frontal
|
||||
etat: planifie
|
||||
web-dorsal-01:
|
||||
fonction: web-dorsal
|
||||
etat: planifie
|
||||
5
exemples/modeles/observabilite/README.md
Normal file
5
exemples/modeles/observabilite/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Modele : observabilite
|
||||
|
||||
Observabilite & supervision : socle + Prometheus/Loki/Grafana + Icinga.
|
||||
|
||||
7 VM. Renseignez `domaine_interne`, `plan/domaines.yml` et `plan/nomenclature.yml` (supernet), puis generez (voir `exemples/modeles/README.md`).
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
domaine_interne: "exemple.internal" # <- VOTRE domaine DNS interne
|
||||
setops_plan_dir: "{{ playbook_dir }}/../../instance/plan"
|
||||
36
exemples/modeles/observabilite/plan/applications.yml
Normal file
36
exemples/modeles/observabilite/plan/applications.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
applications:
|
||||
step_ca:
|
||||
groupe: serveur_step_ca
|
||||
hote: infra-pki-01
|
||||
nginx:
|
||||
groupe: serveur_nginx
|
||||
hote: infra-edge-01
|
||||
sendmail:
|
||||
groupe: serveur_sendmail
|
||||
hote: infra-mail-01
|
||||
powerdns:
|
||||
groupe: serveur_powerdns
|
||||
hote: infra-dns-01
|
||||
postgresql:
|
||||
groupe: serveur_postgresql
|
||||
hote: data-01
|
||||
port: 5432
|
||||
redis:
|
||||
groupe: serveur_redis
|
||||
hote: data-01
|
||||
prometheus:
|
||||
groupe: serveur_prometheus
|
||||
hote: obs-01
|
||||
loki:
|
||||
groupe: serveur_loki
|
||||
hote: obs-01
|
||||
grafana:
|
||||
groupe: serveur_grafana
|
||||
hote: obs-01
|
||||
port: 3000
|
||||
expose:
|
||||
- grafana.exemple.ca
|
||||
icinga:
|
||||
groupe: serveur_icinga
|
||||
hote: mon-01
|
||||
16
exemples/modeles/observabilite/plan/bases-donnees.yml
Normal file
16
exemples/modeles/observabilite/plan/bases-donnees.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
serveurs_bd:
|
||||
pg-principal:
|
||||
type: postgres
|
||||
hote: 10.10.13.11
|
||||
port: 5432
|
||||
groupe: serveur_postgresql
|
||||
bases_donnees:
|
||||
icingadb:
|
||||
serveur: pg-principal
|
||||
base: icingadb
|
||||
proprietaire: icingadb
|
||||
secret: vault_bd_icingadb
|
||||
consommateur: serveur_icinga
|
||||
portee: groupe
|
||||
usage: principale
|
||||
7
exemples/modeles/observabilite/plan/domaines.yml
Normal file
7
exemples/modeles/observabilite/plan/domaines.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
domaines_publics:
|
||||
exemple.ca:
|
||||
autorite: primaire-cache
|
||||
edge: serveur_nginx
|
||||
secondaires: []
|
||||
dnssec: false
|
||||
45
exemples/modeles/observabilite/plan/nomenclature.yml
Normal file
45
exemples/modeles/observabilite/plan/nomenclature.yml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
supernet: 10.10.0.0/16
|
||||
cidr_hote: 24
|
||||
reservations:
|
||||
passerelle: 1
|
||||
reserve_min: 2
|
||||
reserve_max: 9
|
||||
categories:
|
||||
1:
|
||||
libelle: Fondations
|
||||
vlan: 11
|
||||
sous_reseau: 10.10.11.0/24
|
||||
passerelle: 10.10.11.1
|
||||
3:
|
||||
libelle: Donnees
|
||||
vlan: 13
|
||||
sous_reseau: 10.10.13.0/24
|
||||
passerelle: 10.10.13.1
|
||||
4:
|
||||
libelle: Observabilite
|
||||
vlan: 14
|
||||
sous_reseau: 10.10.14.0/24
|
||||
passerelle: 10.10.14.1
|
||||
fonctions:
|
||||
data:
|
||||
categorie: 3
|
||||
service: 1
|
||||
infra-dns:
|
||||
categorie: 1
|
||||
service: 4
|
||||
infra-edge:
|
||||
categorie: 1
|
||||
service: 2
|
||||
infra-mail:
|
||||
categorie: 1
|
||||
service: 3
|
||||
infra-pki:
|
||||
categorie: 1
|
||||
service: 1
|
||||
mon:
|
||||
categorie: 4
|
||||
service: 4
|
||||
obs:
|
||||
categorie: 4
|
||||
service: 1
|
||||
23
exemples/modeles/observabilite/plan/serveurs.yml
Normal file
23
exemples/modeles/observabilite/plan/serveurs.yml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
serveurs:
|
||||
infra-pki-01:
|
||||
fonction: infra-pki
|
||||
etat: planifie
|
||||
infra-edge-01:
|
||||
fonction: infra-edge
|
||||
etat: planifie
|
||||
infra-mail-01:
|
||||
fonction: infra-mail
|
||||
etat: planifie
|
||||
infra-dns-01:
|
||||
fonction: infra-dns
|
||||
etat: planifie
|
||||
data-01:
|
||||
fonction: data
|
||||
etat: planifie
|
||||
obs-01:
|
||||
fonction: obs
|
||||
etat: planifie
|
||||
mon-01:
|
||||
fonction: mon
|
||||
etat: planifie
|
||||
9
exemples/modeles/presence-web/README.md
Normal file
9
exemples/modeles/presence-web/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Modèle : Présence Web
|
||||
|
||||
Écosystème pour héberger **sites et applications web** : socle souverain (DNS,
|
||||
PKI, edge TLS, relais courriel) + couche web (frontal + dorsal) + données
|
||||
(PostgreSQL + Redis). 7 VM.
|
||||
|
||||
Renseignez : `inventories/production/group_vars/all.yml` (`domaine_interne`),
|
||||
`plan/domaines.yml` (votre domaine public), `plan/nomenclature.yml` (supernet),
|
||||
puis générez l'inventaire (voir `exemples/modeles/README.md`).
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
domaine_interne: "exemple.internal" # <- VOTRE domaine DNS interne
|
||||
setops_plan_dir: "{{ playbook_dir }}/../../instance/plan"
|
||||
10
exemples/modeles/presence-web/plan/applications.yml
Normal file
10
exemples/modeles/presence-web/plan/applications.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
applications:
|
||||
pki: { groupe: serveur_step_ca, hote: infra-pki-01 }
|
||||
edge: { groupe: serveur_nginx, hote: infra-edge-01 }
|
||||
mail: { groupe: serveur_sendmail, hote: infra-mail-01 }
|
||||
dns: { groupe: serveur_powerdns, hote: infra-dns-01 }
|
||||
bdd: { groupe: serveur_postgresql, hote: data-01, port: 5432 }
|
||||
cache: { groupe: serveur_redis, hote: data-01 }
|
||||
frontal: { groupe: serveur_web_frontal, hote: web-frontal-01 }
|
||||
dorsal: { groupe: serveur_web_dorsal, hote: web-dorsal-01 }
|
||||
4
exemples/modeles/presence-web/plan/bases-donnees.yml
Normal file
4
exemples/modeles/presence-web/plan/bases-donnees.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
serveurs_bd:
|
||||
pg-principal: { type: postgres, hote: 10.10.13.11, port: 5432, groupe: serveur_postgresql }
|
||||
bases_donnees: {}
|
||||
7
exemples/modeles/presence-web/plan/domaines.yml
Normal file
7
exemples/modeles/presence-web/plan/domaines.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
domaines_publics:
|
||||
exemple.ca: # <- VOTRE domaine public
|
||||
autorite: primaire-cache
|
||||
edge: serveur_nginx
|
||||
secondaires: []
|
||||
dnssec: false
|
||||
17
exemples/modeles/presence-web/plan/nomenclature.yml
Normal file
17
exemples/modeles/presence-web/plan/nomenclature.yml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
# Adaptez le supernet à VOTRE réseau interne.
|
||||
supernet: "10.10.0.0/16"
|
||||
cidr_hote: 24
|
||||
reservations: { passerelle: 1, reserve_min: 2, reserve_max: 9 }
|
||||
categories:
|
||||
1: { libelle: "Fondations", vlan: 11, sous_reseau: "10.10.11.0/24", passerelle: "10.10.11.1" }
|
||||
3: { libelle: "Donnees", vlan: 13, sous_reseau: "10.10.13.0/24", passerelle: "10.10.13.1" }
|
||||
5: { libelle: "Applications", vlan: 15, sous_reseau: "10.10.15.0/24", passerelle: "10.10.15.1" }
|
||||
fonctions:
|
||||
infra-pki: { categorie: 1, service: 1 }
|
||||
infra-edge: { categorie: 1, service: 2 }
|
||||
infra-mail: { categorie: 1, service: 3 }
|
||||
infra-dns: { categorie: 1, service: 4 }
|
||||
data: { categorie: 3, service: 1 }
|
||||
web-frontal: { categorie: 5, service: 3 }
|
||||
web-dorsal: { categorie: 5, service: 4 }
|
||||
9
exemples/modeles/presence-web/plan/serveurs.yml
Normal file
9
exemples/modeles/presence-web/plan/serveurs.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
serveurs:
|
||||
infra-pki-01: { fonction: infra-pki, etat: planifie }
|
||||
infra-edge-01: { fonction: infra-edge, etat: planifie }
|
||||
infra-mail-01: { fonction: infra-mail, etat: planifie }
|
||||
infra-dns-01: { fonction: infra-dns, etat: planifie }
|
||||
data-01: { fonction: data, etat: planifie }
|
||||
web-frontal-01: { fonction: web-frontal, etat: planifie }
|
||||
web-dorsal-01: { fonction: web-dorsal, etat: planifie }
|
||||
5
exemples/modeles/socle/README.md
Normal file
5
exemples/modeles/socle/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Modele : socle
|
||||
|
||||
Socle souverain : DNS interne, AC/PKI, edge TLS, relais courriel.
|
||||
|
||||
4 VM. Renseignez `domaine_interne`, `plan/domaines.yml` et `plan/nomenclature.yml` (supernet), puis generez (voir `exemples/modeles/README.md`).
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
domaine_interne: "exemple.internal" # <- VOTRE domaine DNS interne
|
||||
setops_plan_dir: "{{ playbook_dir }}/../../instance/plan"
|
||||
14
exemples/modeles/socle/plan/applications.yml
Normal file
14
exemples/modeles/socle/plan/applications.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
applications:
|
||||
step_ca:
|
||||
groupe: serveur_step_ca
|
||||
hote: infra-pki-01
|
||||
nginx:
|
||||
groupe: serveur_nginx
|
||||
hote: infra-edge-01
|
||||
sendmail:
|
||||
groupe: serveur_sendmail
|
||||
hote: infra-mail-01
|
||||
powerdns:
|
||||
groupe: serveur_powerdns
|
||||
hote: infra-dns-01
|
||||
3
exemples/modeles/socle/plan/bases-donnees.yml
Normal file
3
exemples/modeles/socle/plan/bases-donnees.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
serveurs_bd: {}
|
||||
bases_donnees: {}
|
||||
7
exemples/modeles/socle/plan/domaines.yml
Normal file
7
exemples/modeles/socle/plan/domaines.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
domaines_publics:
|
||||
exemple.ca:
|
||||
autorite: primaire-cache
|
||||
edge: serveur_nginx
|
||||
secondaires: []
|
||||
dnssec: false
|
||||
26
exemples/modeles/socle/plan/nomenclature.yml
Normal file
26
exemples/modeles/socle/plan/nomenclature.yml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
supernet: 10.10.0.0/16
|
||||
cidr_hote: 24
|
||||
reservations:
|
||||
passerelle: 1
|
||||
reserve_min: 2
|
||||
reserve_max: 9
|
||||
categories:
|
||||
1:
|
||||
libelle: Fondations
|
||||
vlan: 11
|
||||
sous_reseau: 10.10.11.0/24
|
||||
passerelle: 10.10.11.1
|
||||
fonctions:
|
||||
infra-dns:
|
||||
categorie: 1
|
||||
service: 4
|
||||
infra-edge:
|
||||
categorie: 1
|
||||
service: 2
|
||||
infra-mail:
|
||||
categorie: 1
|
||||
service: 3
|
||||
infra-pki:
|
||||
categorie: 1
|
||||
service: 1
|
||||
14
exemples/modeles/socle/plan/serveurs.yml
Normal file
14
exemples/modeles/socle/plan/serveurs.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
serveurs:
|
||||
infra-pki-01:
|
||||
fonction: infra-pki
|
||||
etat: planifie
|
||||
infra-edge-01:
|
||||
fonction: infra-edge
|
||||
etat: planifie
|
||||
infra-mail-01:
|
||||
fonction: infra-mail
|
||||
etat: planifie
|
||||
infra-dns-01:
|
||||
fonction: infra-dns
|
||||
etat: planifie
|
||||
34
filter_plugins/registres.py
Normal file
34
filter_plugins/registres.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
"""Filtres Ansible exposant les regles de resolution des registres Set-OPS.
|
||||
|
||||
Reutilise scripts/inventory_rules.py : la regle de liaison application <-> base
|
||||
(et la derivation du DSN) vit une SEULE fois, en Python. Le CLI, le GUI (qui en
|
||||
est le miroir) et Ansible passent tous par la meme logique.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
|
||||
|
||||
from inventory_rules import ( # noqa: E402
|
||||
applications_de_hote,
|
||||
bases_de_application,
|
||||
bases_du_groupe,
|
||||
chaine_connexion,
|
||||
expositions_des_applications,
|
||||
)
|
||||
|
||||
|
||||
class FilterModule:
|
||||
"""Filtres Set-OPS pour les playbooks par application."""
|
||||
|
||||
def filters(self) -> dict:
|
||||
return {
|
||||
"bases_de_application": bases_de_application,
|
||||
"applications_de_hote": applications_de_hote,
|
||||
"bases_du_groupe": bases_du_groupe,
|
||||
"chaine_connexion": chaine_connexion,
|
||||
"expositions_des_applications": expositions_des_applications,
|
||||
}
|
||||
3
playbooks/applications/README.md
Normal file
3
playbooks/applications/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Playbooks applications
|
||||
|
||||
Espace réservé aux futurs playbooks.
|
||||
3
playbooks/backup/README.md
Normal file
3
playbooks/backup/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Playbooks backup
|
||||
|
||||
Espace réservé aux futurs playbooks.
|
||||
3
playbooks/database/README.md
Normal file
3
playbooks/database/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Playbooks database
|
||||
|
||||
Espace réservé aux futurs playbooks.
|
||||
15
playbooks/groupes/client_dns.yml
Normal file
15
playbooks/groupes/client_dns.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe client_dns
|
||||
hosts: client_dns
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- client_dns
|
||||
15
playbooks/groupes/client_journal.yml
Normal file
15
playbooks/groupes/client_journal.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe client_journal
|
||||
hosts: client_journal
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- client_journal
|
||||
15
playbooks/groupes/client_ldap.yml
Normal file
15
playbooks/groupes/client_ldap.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe client_ldap
|
||||
hosts: client_ldap
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- client_ldap
|
||||
15
playbooks/groupes/client_metrique.yml
Normal file
15
playbooks/groupes/client_metrique.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe client_metrique
|
||||
hosts: client_metrique
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- client_metrique
|
||||
15
playbooks/groupes/client_pki.yml
Normal file
15
playbooks/groupes/client_pki.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe client_pki
|
||||
hosts: client_pki
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- client_pki
|
||||
15
playbooks/groupes/client_smtp.yml
Normal file
15
playbooks/groupes/client_smtp.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe client_smtp
|
||||
hosts: client_smtp
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- client_smtp
|
||||
10
playbooks/groupes/client_supervision.yml
Normal file
10
playbooks/groupes/client_supervision.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
- name: Appliquer le groupe client_supervision
|
||||
hosts: client_supervision
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Indiquer que l'intégration cliente supervision reste à définir
|
||||
ansible.builtin.debug:
|
||||
msg: "Aucun rôle n'est encore associé au groupe client_supervision."
|
||||
10
playbooks/groupes/serveur_collabora.yml
Normal file
10
playbooks/groupes/serveur_collabora.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_collabora
|
||||
hosts: serveur_collabora
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Indiquer que le service Collabora reste à définir
|
||||
ansible.builtin.debug:
|
||||
msg: "Aucun rôle n'est encore associé au groupe serveur_collabora."
|
||||
22
playbooks/groupes/serveur_debian.yml
Normal file
22
playbooks/groupes/serveur_debian.yml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_debian
|
||||
hosts: serveur_debian
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- common_packages
|
||||
- qemu_guest_agent
|
||||
- cloud_init
|
||||
- sudo_ansible
|
||||
- chrony
|
||||
- ssh_baseline
|
||||
- systemd_ssh_auto
|
||||
- motd
|
||||
24
playbooks/groupes/serveur_durci.yml
Normal file
24
playbooks/groupes/serveur_durci.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_durci
|
||||
hosts: serveur_durci
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- hardening_packages
|
||||
- sysctl_hardening
|
||||
- core_dumps
|
||||
- unattended_upgrades
|
||||
- apparmor
|
||||
- auditd
|
||||
- fail2ban_ssh
|
||||
- journald
|
||||
- ssh_hardening
|
||||
- nftables_baseline
|
||||
15
playbooks/groupes/serveur_forgejo.yml
Normal file
15
playbooks/groupes/serveur_forgejo.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_forgejo
|
||||
hosts: serveur_forgejo
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_forgejo
|
||||
15
playbooks/groupes/serveur_grafana.yml
Normal file
15
playbooks/groupes/serveur_grafana.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_grafana
|
||||
hosts: serveur_grafana
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_grafana
|
||||
15
playbooks/groupes/serveur_icinga.yml
Normal file
15
playbooks/groupes/serveur_icinga.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_icinga
|
||||
hosts: serveur_icinga
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_icinga
|
||||
15
playbooks/groupes/serveur_keycloak.yml
Normal file
15
playbooks/groupes/serveur_keycloak.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_keycloak
|
||||
hosts: serveur_keycloak
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_keycloak
|
||||
15
playbooks/groupes/serveur_loki.yml
Normal file
15
playbooks/groupes/serveur_loki.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_loki
|
||||
hosts: serveur_loki
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_loki
|
||||
10
playbooks/groupes/serveur_nextcloud.yml
Normal file
10
playbooks/groupes/serveur_nextcloud.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_nextcloud
|
||||
hosts: serveur_nextcloud
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Indiquer que le service Nextcloud reste à définir
|
||||
ansible.builtin.debug:
|
||||
msg: "Aucun rôle n'est encore associé au groupe serveur_nextcloud."
|
||||
15
playbooks/groupes/serveur_nginx.yml
Normal file
15
playbooks/groupes/serveur_nginx.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_nginx
|
||||
hosts: serveur_nginx
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_nginx
|
||||
15
playbooks/groupes/serveur_openldap.yml
Normal file
15
playbooks/groupes/serveur_openldap.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_openldap
|
||||
hosts: serveur_openldap
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_openldap
|
||||
15
playbooks/groupes/serveur_postgresql.yml
Normal file
15
playbooks/groupes/serveur_postgresql.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_postgresql
|
||||
hosts: serveur_postgresql
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_postgresql
|
||||
15
playbooks/groupes/serveur_powerdns.yml
Normal file
15
playbooks/groupes/serveur_powerdns.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_powerdns
|
||||
hosts: serveur_powerdns
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_powerdns
|
||||
15
playbooks/groupes/serveur_prometheus.yml
Normal file
15
playbooks/groupes/serveur_prometheus.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_prometheus
|
||||
hosts: serveur_prometheus
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_prometheus
|
||||
15
playbooks/groupes/serveur_redis.yml
Normal file
15
playbooks/groupes/serveur_redis.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_redis
|
||||
hosts: serveur_redis
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_redis
|
||||
15
playbooks/groupes/serveur_sendmail.yml
Normal file
15
playbooks/groupes/serveur_sendmail.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_sendmail
|
||||
hosts: serveur_sendmail
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_sendmail
|
||||
15
playbooks/groupes/serveur_step_ca.yml
Normal file
15
playbooks/groupes/serveur_step_ca.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_step_ca
|
||||
hosts: serveur_step_ca
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
roles:
|
||||
- serveur_step_ca
|
||||
43
playbooks/groupes/serveur_web_dorsal.yml
Normal file
43
playbooks/groupes/serveur_web_dorsal.yml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_web_dorsal
|
||||
hosts: serveur_web_dorsal
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
tasks:
|
||||
# Couche application : une VM dorsale peut porter PLUSIEURS applications.
|
||||
# On itere donc sur les applications mappees a cet hote (instance/plan/applications.yml),
|
||||
# chacune resolvant ses bases via son DSN (regle partagee, filter plugin).
|
||||
- name: Charger les registres applications et bases
|
||||
ansible.builtin.include_vars:
|
||||
file: "{{ item }}"
|
||||
loop:
|
||||
- "{{ setops_plan_dir }}/applications.yml"
|
||||
- "{{ setops_plan_dir }}/bases-donnees.yml"
|
||||
|
||||
- name: Determiner les applications instanciees sur cet hote
|
||||
ansible.builtin.set_fact:
|
||||
applications_hote: "{{ {'applications': applications | default({})} | applications_de_hote(inventory_hostname) }}"
|
||||
registre_bd: "{{ {'serveurs_bd': serveurs_bd | default({}), 'bases_donnees': bases_donnees | default({})} }}"
|
||||
|
||||
- name: Afficher la chaine application -> bases (scaffold ; le deploiement reel s'insere ici)
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ item.id }} [{{ item.groupe }}] ->
|
||||
{{ (registre_bd | bases_de_application(item.id, item.groupe, inventory_hostname))
|
||||
| map(attribute='cle') | list }}
|
||||
loop: "{{ applications_hote }}"
|
||||
loop_control:
|
||||
label: "{{ item.id }}"
|
||||
|
||||
- name: Avertir si l'hote ne porte aucune application
|
||||
ansible.builtin.debug:
|
||||
msg: "Aucune application declaree sur cet hote (instance/plan/applications.yml). Couche dorsale : API, traitement."
|
||||
when: applications_hote | length == 0
|
||||
43
playbooks/groupes/serveur_web_frontal.yml
Normal file
43
playbooks/groupes/serveur_web_frontal.yml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_web_frontal
|
||||
hosts: serveur_web_frontal
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Vérifier que la cible est Debian
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
fail_msg: "Ce playbook est prévu pour Debian."
|
||||
|
||||
tasks:
|
||||
# Couche presentation : une VM frontale peut porter PLUSIEURS applications.
|
||||
# On itere sur les applications mappees a cet hote (instance/plan/applications.yml),
|
||||
# chacune resolvant ses bases via son DSN (regle partagee, filter plugin).
|
||||
- name: Charger les registres applications et bases
|
||||
ansible.builtin.include_vars:
|
||||
file: "{{ item }}"
|
||||
loop:
|
||||
- "{{ setops_plan_dir }}/applications.yml"
|
||||
- "{{ setops_plan_dir }}/bases-donnees.yml"
|
||||
|
||||
- name: Determiner les applications instanciees sur cet hote
|
||||
ansible.builtin.set_fact:
|
||||
applications_hote: "{{ {'applications': applications | default({})} | applications_de_hote(inventory_hostname) }}"
|
||||
registre_bd: "{{ {'serveurs_bd': serveurs_bd | default({}), 'bases_donnees': bases_donnees | default({})} }}"
|
||||
|
||||
- name: Afficher la chaine application -> bases (scaffold ; le deploiement reel s'insere ici)
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ item.id }} [{{ item.groupe }}] ->
|
||||
{{ (registre_bd | bases_de_application(item.id, item.groupe, inventory_hostname))
|
||||
| map(attribute='cle') | list }}
|
||||
loop: "{{ applications_hote }}"
|
||||
loop_control:
|
||||
label: "{{ item.id }}"
|
||||
|
||||
- name: Avertir si l'hote ne porte aucune application
|
||||
ansible.builtin.debug:
|
||||
msg: "Aucune application declaree sur cet hote (instance/plan/applications.yml). Couche presentation, derriere serveur_nginx."
|
||||
when: applications_hote | length == 0
|
||||
19
playbooks/maintenance/apt_update.yml
Normal file
19
playbooks/maintenance/apt_update.yml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
- name: Mettre à jour les serveurs Debian
|
||||
hosts: all
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Mettre à jour le cache APT
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Appliquer les mises à jour
|
||||
ansible.builtin.apt:
|
||||
upgrade: full
|
||||
|
||||
- name: Supprimer les paquets inutiles
|
||||
ansible.builtin.apt:
|
||||
autoremove: true
|
||||
38
playbooks/maintenance/verifier_hote_debian.yml
Normal file
38
playbooks/maintenance/verifier_hote_debian.yml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
- name: Vérifier une VM Debian gérée par Set-OPS
|
||||
hosts: serveur_debian
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Vérifier que la cible est Debian 13
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts.distribution == "Debian"
|
||||
- ansible_facts.distribution_major_version == "13"
|
||||
fail_msg: "Cette vérification attend une VM Debian 13."
|
||||
|
||||
- name: Collecter les services
|
||||
ansible.builtin.service_facts:
|
||||
|
||||
- name: Vérifier les services du socle
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- '"ssh.service" in ansible_facts.services'
|
||||
- '"qemu-guest-agent.service" in ansible_facts.services'
|
||||
- '"chrony.service" in ansible_facts.services'
|
||||
- ansible_facts.services["ssh.service"].state == "running"
|
||||
- ansible_facts.services["qemu-guest-agent.service"].state == "running"
|
||||
- ansible_facts.services["chrony.service"].state == "running"
|
||||
fail_msg: "Un service du socle Debian n'est pas actif."
|
||||
|
||||
- name: Vérifier sudo non interactif via become
|
||||
ansible.builtin.command: whoami
|
||||
changed_when: false
|
||||
register: verifier_hote_debian_whoami
|
||||
|
||||
- name: Valider l'élévation root
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- verifier_hote_debian_whoami.stdout == "root"
|
||||
fail_msg: "L'élévation sudo ne retourne pas root."
|
||||
8
playbooks/modeles_vm/debian13_proxmox_nettoyer.yml
Normal file
8
playbooks/modeles_vm/debian13_proxmox_nettoyer.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
- name: Nettoyage final avant conversion en template Proxmox
|
||||
hosts: modeles_vm
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
roles:
|
||||
- template_cleanup
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue