Structurer l'exploitation Ansible Chezlepro
This commit is contained in:
parent
8fac83bcdb
commit
61e2c7ca67
92 changed files with 2829 additions and 853 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,7 +1,9 @@
|
||||||
*.retry
|
*.retry
|
||||||
.vault-pass
|
.vault-pass
|
||||||
facts_cache/
|
facts_cache/
|
||||||
|
.ansible/
|
||||||
*.vault
|
*.vault
|
||||||
|
*.vault.yml
|
||||||
*.secret
|
*.secret
|
||||||
*.pem
|
*.pem
|
||||||
*.key
|
*.key
|
||||||
|
|
|
||||||
241
AGENTS.md
241
AGENTS.md
|
|
@ -114,7 +114,7 @@ Avant de proposer un changement comme terminé, vérifier au minimum la syntaxe
|
||||||
Exemple pour le template Debian 13 Proxmox :
|
Exemple pour le template Debian 13 Proxmox :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_prepare.yml --syntax-check
|
ansible-playbook -i inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_preparer.yml --syntax-check
|
||||||
```
|
```
|
||||||
|
|
||||||
Pour un autre playbook, remplacer le chemin par le playbook concerné.
|
Pour un autre playbook, remplacer le chemin par le playbook concerné.
|
||||||
|
|
@ -210,13 +210,12 @@ Les playbooks peuvent être classés par domaine :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
playbooks/
|
playbooks/
|
||||||
├── baseline/
|
├── groupes/
|
||||||
├── hardening/
|
|
||||||
├── maintenance/
|
├── maintenance/
|
||||||
├── monitoring/
|
├── monitoring/
|
||||||
├── networking/
|
├── networking/
|
||||||
├── proxmox/
|
├── proxmox/
|
||||||
├── vm_templates/
|
├── modeles_vm/
|
||||||
├── web/
|
├── web/
|
||||||
├── database/
|
├── database/
|
||||||
├── identity/
|
├── identity/
|
||||||
|
|
@ -228,6 +227,207 @@ 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.
|
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=serveurs_debian
|
||||||
|
make appliquer GROUPE=serveurs_debian
|
||||||
|
```
|
||||||
|
|
||||||
|
É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 : serveurs_debian
|
||||||
|
playbook : playbooks/groupes/serveurs_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
|
||||||
|
serveurs_debian -> socle commun Debian
|
||||||
|
serveurs_durcis -> durcissement commun
|
||||||
|
clients_dns -> intégration cliente DNS
|
||||||
|
clients_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 ;
|
||||||
|
- 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 Chezlepro :
|
||||||
|
|
||||||
|
```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
|
||||||
|
serveurs_debian
|
||||||
|
```
|
||||||
|
|
||||||
|
Les groupes spécialisés doivent s'ajouter selon les besoins réels, par exemple :
|
||||||
|
|
||||||
|
```text
|
||||||
|
clients_dns
|
||||||
|
clients_pki
|
||||||
|
clients_ldap
|
||||||
|
clients_supervision
|
||||||
|
clients_metriques
|
||||||
|
serveurs_web
|
||||||
|
serveurs_bases_donnees
|
||||||
|
```
|
||||||
|
|
||||||
|
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 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
|
## Template Debian 13 Proxmox
|
||||||
|
|
@ -246,7 +446,7 @@ Il peut contenir :
|
||||||
- `cloud-guest-utils` ;
|
- `cloud-guest-utils` ;
|
||||||
- chrony ;
|
- chrony ;
|
||||||
- outils de diagnostic de base ;
|
- outils de diagnostic de base ;
|
||||||
- hardening raisonnable ;
|
- durcissement raisonnable ;
|
||||||
- AppArmor ;
|
- AppArmor ;
|
||||||
- auditd ;
|
- auditd ;
|
||||||
- fail2ban SSH ;
|
- fail2ban SSH ;
|
||||||
|
|
@ -277,23 +477,20 @@ Les services spécialisés doivent être installés ensuite par des playbooks d
|
||||||
|
|
||||||
## SSH
|
## SSH
|
||||||
|
|
||||||
Pendant la construction du template, l’état transitoire accepté est :
|
Le template Debian 13 Proxmox doit être construit avec un accès SSH par clé dès le départ.
|
||||||
|
|
||||||
```text
|
Cloud-init doit injecter le `ciuser` et sa clé publique avant l'exécution d'Ansible.
|
||||||
PasswordAuthentication yes
|
|
||||||
PermitRootLogin no
|
|
||||||
PubkeyAuthentication yes
|
|
||||||
```
|
|
||||||
|
|
||||||
État cible recommandé après validation des clés SSH :
|
État attendu :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
PasswordAuthentication no
|
PasswordAuthentication no
|
||||||
PermitRootLogin no
|
PermitRootLogin no
|
||||||
PubkeyAuthentication yes
|
PubkeyAuthentication yes
|
||||||
|
AuthenticationMethods publickey
|
||||||
```
|
```
|
||||||
|
|
||||||
Ne jamais désactiver l’authentification par mot de passe avant d’avoir confirmé que l’accès par clé fonctionne.
|
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 :
|
Toute modification SSH doit valider la configuration avant rechargement :
|
||||||
|
|
||||||
|
|
@ -343,7 +540,7 @@ Le nettoyage final avant conversion en template doit être protégé par une con
|
||||||
Exemple :
|
Exemple :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_cleanup.yml -e confirm_template_cleanup=true
|
ansible-playbook -i inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_nettoyer.yml -e template_cleanup_confirm=true
|
||||||
```
|
```
|
||||||
|
|
||||||
Le nettoyage peut inclure :
|
Le nettoyage peut inclure :
|
||||||
|
|
@ -382,6 +579,22 @@ Les corrections de rôles, handlers, playbooks et templates doivent être consig
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 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
|
## Comportement attendu de Codex
|
||||||
|
|
||||||
Avant de modifier :
|
Avant de modifier :
|
||||||
|
|
|
||||||
130
CHANGELOG.md
130
CHANGELOG.md
|
|
@ -1,15 +1,67 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 2026-06-21
|
||||||
|
|
||||||
|
### Ajouté
|
||||||
|
- Ajout de facilités `make` pour exploiter Ansible sur les VM Debian déployées :
|
||||||
|
- diagnostic `ping`, `sudo` et `faits` ;
|
||||||
|
- variables `LIMITE`, `VERIFICATION`, `DIFF`, `ETIQUETTES`, `SAUTER_ETIQUETTES` et `VARIABLES`.
|
||||||
|
- Ajout de facilités `make` pour inspecter et valider les inventaires Ansible :
|
||||||
|
- `hote-ajouter` ;
|
||||||
|
- `hote-groupes` ;
|
||||||
|
- `hote-afficher` ;
|
||||||
|
- `inventaire-verifier` ;
|
||||||
|
- `inventaire-lister` ;
|
||||||
|
- `inventaire-graphe` ;
|
||||||
|
- `inventaire-hote` ;
|
||||||
|
- `inventaire-lab` ;
|
||||||
|
- `inventaire-production`.
|
||||||
|
- Ajout de `deployer` et `deployer-groupe` comme commandes opérateur simplifiées pour appliquer les playbooks de groupes.
|
||||||
|
- Ajout de `scripts/inventory_host.py` pour gérer les entrées d'inventaire et leur appartenance aux groupes sans édition YAML manuelle.
|
||||||
|
- Ajout de la convention `1 groupe opérationnel = 1 playbook homonyme` avec les premiers playbooks :
|
||||||
|
- `playbooks/groupes/serveurs_debian.yml` ;
|
||||||
|
- `playbooks/groupes/serveurs_durcis.yml`.
|
||||||
|
- Ajout du playbook `playbooks/maintenance/verifier_hote_debian.yml` pour valider une VM Debian 13 gérée par Set-OPS après socle et durcissement.
|
||||||
|
- Ajout de directives `AGENTS.md` pour formaliser le `Makefile` comme interface opérateur, la convention groupe/playbook, la francisation de la surface opérateur et les points de stabilisation avant commit.
|
||||||
|
- Ajout du playbook `playbooks/proxmox/cloner_vm_debian.yml` et des cibles `make cloner-vm` / `make creer-vm` pour créer des clones Debian via l'API Proxmox sans stocker de secret dans le dépôt.
|
||||||
|
- Ajout de `inventories/lab/group_vars/proxmox.yml` pour les paramètres Proxmox non sensibles et de `proxmox.vault.yml.example` pour préparer les secrets API avec Ansible Vault.
|
||||||
|
- Ajout de `make config` pour renseigner les paramètres Proxmox et créer ou éditer le Vault API depuis le terminal.
|
||||||
|
|
||||||
|
### Modifié
|
||||||
|
- Francisation de la surface opérateur :
|
||||||
|
- variables `make` ;
|
||||||
|
- cibles `make` ;
|
||||||
|
- groupes d'inventaire ;
|
||||||
|
- chemins des playbooks maison ;
|
||||||
|
- libellés du script de gestion d'inventaire.
|
||||||
|
- Documentation du flux de déploiement d'une VM clonée depuis le modèle doré avec les commandes `make`.
|
||||||
|
- Optimisation de la procédure de bootstrap du modèle Debian 13 pour utiliser Cloud-Init comme source unique de l'identité initiale au lieu de maintenir une création manuelle parallèle du compte et de la clé SSH.
|
||||||
|
- Simplification de `make cloner-vm` et `make creer-vm` pour que les paramètres Proxmox communs viennent des variables Ansible plutôt que de la ligne de commande ou de l'environnement.
|
||||||
|
- Ajustement de `make config` pour ne plus redemander les valeurs Cloud-Init déjà portées par le modèle Proxmox.
|
||||||
|
- Déplacement du VLAN hors de `make config` afin de l'exiger explicitement à chaque création de VM avec `VLAN=...`.
|
||||||
|
- Retrait des options `DEMANDER_MDP` et `DEMANDER_SUDO` du `Makefile`; le flux suppose SSH par clé et sudo NOPASSWD déjà fonctionnels.
|
||||||
|
- Retrait des playbooks de couches redondants `playbooks/socle/debian_commun.yml` et `playbooks/durcissement/debian_serveur_durcissement.yml`; la conformité des VM déployées passe maintenant par `playbooks/groupes/`.
|
||||||
|
- Bonification de `AGENTS.md` pour désigner `playbooks/groupes/` comme source officielle de conformité et éviter les cibles `make` de couches parallèles.
|
||||||
|
- Simplification de l'aide du `Makefile` pour exposer d'abord les gestes opérateur : inventaire, groupes, déploiement.
|
||||||
|
- Clarification de `make aide` pour expliquer les différences entre `creer-vm`, `cloner-vm`, `deployer`, `deployer-groupe` et `appliquer`.
|
||||||
|
- Réorganisation de `make aide` par objets d'exploitation : VM, hôtes, groupes, inventaires, modèle et validation.
|
||||||
|
- Retrait des commandes opérateur explicites de ping et sudo; ces vérifications sont maintenant implicites dans `deployer` et `preparer-modele`.
|
||||||
|
- Ajout d'une demande automatique de mot de passe Ansible Vault pour `make cloner-vm` et `make creer-vm` lorsqu'un `proxmox.vault.yml` chiffré est présent.
|
||||||
|
- Amélioration du message d'erreur lorsque `proxmox.vault.yml` ne peut pas être chargé.
|
||||||
|
- Ajustement du playbook Proxmox pour laisser apparaître les erreurs API utiles sans masquer entièrement les échecs de clonage.
|
||||||
|
- Modification de `make deployer HOTE=...` pour appliquer les playbooks correspondant aux groupes de l'hôte.
|
||||||
|
- Ajout d'une vérification explicite de la bibliothèque Python `proxmoxer` avant les appels API Proxmox.
|
||||||
|
- Retrait de la taille disque clone des paramètres Proxmox persistés afin de ne pas tenter de réduire un disque hérité du modèle.
|
||||||
|
|
||||||
## 2026-06-19
|
## 2026-06-19
|
||||||
|
|
||||||
### Ajouté
|
### Ajouté
|
||||||
- Structure initiale globale du dépôt Set-OPS.
|
- Structure initiale globale du dépôt Set-OPS.
|
||||||
- Playbooks de création du template Debian 13 Proxmox.
|
- Playbooks de création du template Debian 13 Proxmox.
|
||||||
- Rôles de base Debian.
|
- Rôles de base Debian.
|
||||||
- Rôles de hardening template-safe.
|
- Rôles de durcissement template-safe.
|
||||||
- Playbook de vérification.
|
- Playbook de vérification.
|
||||||
- Playbook de nettoyage final avant conversion en template.
|
- Playbook de nettoyage final avant conversion en template.
|
||||||
# CHANGELOG — Set-OPS
|
|
||||||
|
|
||||||
## 2026-06-20
|
## 2026-06-20
|
||||||
|
|
||||||
|
|
@ -26,10 +78,10 @@
|
||||||
- préférence pour les correctifs ciblés au lieu des régénérations massives ;
|
- préférence pour les correctifs ciblés au lieu des régénérations massives ;
|
||||||
- rappel que `Set-OPS` ne doit pas être restructuré autour d’un seul besoin ponctuel.
|
- rappel que `Set-OPS` ne doit pas être restructuré autour d’un seul besoin ponctuel.
|
||||||
- Ajout d’une logique de template Debian 13 Proxmox :
|
- Ajout d’une logique de template Debian 13 Proxmox :
|
||||||
- `playbooks/vm_templates/debian13_proxmox_prepare.yml` ;
|
- `playbooks/modeles_vm/debian13_proxmox_preparer.yml` ;
|
||||||
- `playbooks/vm_templates/debian13_proxmox_verify.yml` ;
|
- `playbooks/modeles_vm/debian13_proxmox_verifier.yml` ;
|
||||||
- `playbooks/vm_templates/debian13_proxmox_cleanup.yml`.
|
- `playbooks/modeles_vm/debian13_proxmox_nettoyer.yml`.
|
||||||
- Ajout d’une couche de hardening template-safe :
|
- Ajout d’une couche de durcissement template-safe :
|
||||||
- AppArmor ;
|
- AppArmor ;
|
||||||
- auditd ;
|
- auditd ;
|
||||||
- fail2ban SSH ;
|
- fail2ban SSH ;
|
||||||
|
|
@ -37,6 +89,40 @@
|
||||||
- journald ;
|
- journald ;
|
||||||
- sysctl de sécurité ;
|
- sysctl de sécurité ;
|
||||||
- nftables installé et préparé, mais désactivé par défaut dans le template.
|
- nftables installé et préparé, mais désactivé par défaut dans le template.
|
||||||
|
- Ajout d’un document d’architecture pour les intégrations futures des VM :
|
||||||
|
- supervision ;
|
||||||
|
- métriques ;
|
||||||
|
- identité ;
|
||||||
|
- PKI interne ;
|
||||||
|
- DNS interne.
|
||||||
|
- Documentation détaillée des ajouts appliqués au modèle doré Debian 13 Proxmox depuis une installation minimale.
|
||||||
|
- Ajout d'un runbook explicite pour le playbook de préparation du modèle doré Debian 13 Proxmox.
|
||||||
|
- Ajout d'un runbook manuel précis pour le bootstrap initial de la VM vanille Debian 13 :
|
||||||
|
- correction des sources APT après installation depuis DVD ;
|
||||||
|
- installation minimale de `sudo`, SSH, `cloud-init`, `cloud-guest-utils` et `qemu-guest-agent` ;
|
||||||
|
- utilisation de Cloud-Init pour injecter le compte `ansible`, sa clé SSH, le réseau et le point de bascule vers le `Makefile`.
|
||||||
|
- Ajout d'un document de cycle de vie des VM Chezlepro :
|
||||||
|
- VM vanille ;
|
||||||
|
- goldenisation ;
|
||||||
|
- clonage ;
|
||||||
|
- socle ;
|
||||||
|
- durcissement ;
|
||||||
|
- conformité continue.
|
||||||
|
- Ajout de directives `AGENTS.md` pour la convergence des VM existantes et futures :
|
||||||
|
- cycle de vie des VM ;
|
||||||
|
- distinction service central et intégration cliente ;
|
||||||
|
- groupes d'inventaire par intégration ;
|
||||||
|
- séparation des variables de template, conformité et services.
|
||||||
|
- Ajout d'un `Makefile` comme interface d'exploitation courante :
|
||||||
|
- validation ;
|
||||||
|
- syntax-checks ;
|
||||||
|
- préparation, vérification et nettoyage protégé du template ;
|
||||||
|
- socle et durcissement des VM Debian.
|
||||||
|
- Durcissement SSH du template dès la construction :
|
||||||
|
- accès par clé publique obligatoire ;
|
||||||
|
- authentification par mot de passe désactivée ;
|
||||||
|
- forwarding et tunnels SSH désactivés par défaut ;
|
||||||
|
- limites de tentatives, sessions et démarrages SSH resserrées.
|
||||||
|
|
||||||
### Modifié
|
### Modifié
|
||||||
- Renforcement attendu de `CLAUDE.md` pour rappeler que `AGENTS.md` est la source d’autorité principale.
|
- Renforcement attendu de `CLAUDE.md` pour rappeler que `AGENTS.md` est la source d’autorité principale.
|
||||||
|
|
@ -47,15 +133,31 @@
|
||||||
- valider les playbooks touchés ;
|
- valider les playbooks touchés ;
|
||||||
- signaler les tests non exécutés ;
|
- signaler les tests non exécutés ;
|
||||||
- mettre à jour `CHANGELOG.md` si pertinent.
|
- mettre à jour `CHANGELOG.md` si pertinent.
|
||||||
|
- Migration des variables de rôles vers des préfixes propres à chaque rôle pour respecter `ansible-lint`.
|
||||||
|
- Mise à jour de la variable de confirmation du nettoyage final :
|
||||||
|
- `template_cleanup_confirm`.
|
||||||
|
- Correction de la structure du `CHANGELOG.md` pour retirer le titre dupliqué.
|
||||||
|
- Simplification ciblée de l'arborescence `roles/` :
|
||||||
|
- retrait des doublons non utilisés sous `roles/base/` ;
|
||||||
|
- retrait des doublons non utilisés sous `roles/security/` ;
|
||||||
|
- retrait des doublons non utilisés sous `roles/vm_template/`.
|
||||||
|
- Ajout d'un renvoi depuis la procédure manuelle vers la justification du golden template.
|
||||||
|
- Séparation documentaire et opérationnelle entre variables de template et variables de conformité.
|
||||||
|
- Extension du playbook de groupe `playbooks/groupes/serveurs_debian.yml` pour maintenir le socle commun des VM Debian déployées.
|
||||||
|
- Mise à jour de la documentation pour exiger un `ciuser` cloud-init avec clé publique avant l'exécution d'Ansible.
|
||||||
|
- Déplacement des listes de paquets communes dans les defaults des rôles `common_packages` et `hardening_packages`.
|
||||||
|
- Déplacement des variables de construction du template dans `inventories/lab/group_vars/modeles_vm.yml`.
|
||||||
|
- Déplacement des variables de conformité Debian dans `inventories/production/group_vars/serveurs_debian.yml`.
|
||||||
|
- Ciblage du playbook de durcissement sur `serveurs_debian` au lieu de `all`.
|
||||||
|
- Renforcement du playbook de vérification du modèle doré.
|
||||||
|
|
||||||
### Corrigé à appliquer
|
### Corrigé
|
||||||
- Vérifier tous les rôles contenant `notify`.
|
- Vérification des rôles contenant `notify`.
|
||||||
- Ajouter les handlers manquants dans les rôles concernés, notamment :
|
- Confirmation des handlers SSH requis dans les rôles concernés :
|
||||||
- `roles/ssh_baseline/handlers/main.yml` ;
|
- `roles/ssh_baseline/handlers/main.yml` ;
|
||||||
- `roles/ssh_hardening/handlers/main.yml`.
|
- `roles/ssh_hardening/handlers/main.yml`.
|
||||||
|
|
||||||
### À valider
|
### Validé
|
||||||
- Vérifier que chaque `notify` pointe vers un handler existant.
|
- Vérification que chaque `notify` du template Debian 13 Proxmox pointe vers un handler existant.
|
||||||
- Relancer le playbook de préparation du template.
|
- Relance du playbook de préparation du template Debian 13 Proxmox.
|
||||||
- Lancer le playbook de vérification.
|
- Nettoyage final non lancé.
|
||||||
- Ne pas lancer le nettoyage final avant validation complète de la VM.
|
|
||||||
|
|
|
||||||
358
Makefile
Normal file
358
Makefile
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
INVENTAIRE_LAB ?= inventories/lab/hosts.yml
|
||||||
|
INVENTAIRE_PRODUCTION ?= inventories/production/hosts.yml
|
||||||
|
FICHIER_INVENTAIRE ?= $(INVENTAIRE_PRODUCTION)
|
||||||
|
GROUPE_MODELE ?= modeles_vm
|
||||||
|
GROUPE_DEBIAN ?= serveurs_debian
|
||||||
|
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: aide
|
||||||
|
aide:
|
||||||
|
@printf '%s\n' 'Set-OPS'
|
||||||
|
@printf '%s\n' ''
|
||||||
|
@printf '%s\n' 'VM'
|
||||||
|
@printf '%s\n' ' Creer une VM complete:'
|
||||||
|
@printf '%s\n' ' make creer-vm \'
|
||||||
|
@printf '%s\n' ' HOTE=web-01 \'
|
||||||
|
@printf '%s\n' ' VMID=101 \'
|
||||||
|
@printf '%s\n' ' VLAN=12 \'
|
||||||
|
@printf '%s\n' ' ADRESSE_IP=192.168.12.101 \'
|
||||||
|
@printf '%s\n' ' PASSERELLE=192.168.12.1 \'
|
||||||
|
@printf '%s\n' ' GROUPES="serveurs_debian serveurs_durcis"'
|
||||||
|
@printf '%s\n' ' Cloner seulement, sans inventaire:'
|
||||||
|
@printf '%s\n' ' make cloner-vm HOTE=web-01 VMID=101 VLAN=12 ADRESSE_IP=192.168.12.101 PASSERELLE=192.168.12.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' ' Remettre un hote en conformite selon ses groupes:'
|
||||||
|
@printf '%s\n' ' make deployer HOTE=web-01'
|
||||||
|
@printf '%s\n' ' Afficher un hote:'
|
||||||
|
@printf '%s\n' ' make hote-afficher HOTE=web-01'
|
||||||
|
@printf '%s\n' ' Ajouter un hote existant:'
|
||||||
|
@printf '%s\n' ' make hote-ajouter HOTE=web-01 ADRESSE_IP=192.168.12.101 GROUPES="serveurs_debian serveurs_durcis"'
|
||||||
|
@printf '%s\n' ' Modifier ses groupes:'
|
||||||
|
@printf '%s\n' ' make hote-groupes HOTE=web-01 GROUPES="serveurs_debian serveurs_durcis"'
|
||||||
|
@printf '%s\n' ' Diagnostiquer:'
|
||||||
|
@printf '%s\n' ' make verifier-hote LIMITE=web-01'
|
||||||
|
@printf '%s\n' ''
|
||||||
|
@printf '%s\n' 'Groupes'
|
||||||
|
@printf '%s\n' ' Appliquer un groupe complet:'
|
||||||
|
@printf '%s\n' ' make deployer-groupe GROUPE=serveurs_debian'
|
||||||
|
@printf '%s\n' ' Rejouer directement le playbook d un groupe:'
|
||||||
|
@printf '%s\n' ' make appliquer GROUPE=serveurs_debian'
|
||||||
|
@printf '%s\n' ' Convention:'
|
||||||
|
@printf '%s\n' ' groupe serveurs_debian -> playbooks/groupes/serveurs_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=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' ''
|
||||||
|
@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-01 GROUPE=serveurs_debian GROUPES="serveurs_debian serveurs_durcis"'
|
||||||
|
@printf '%s\n' ' VMID=101 VLAN=12 ADRESSE_IP=192.168.12.101 PASSERELLE=192.168.12.1'
|
||||||
|
@printf '%s\n' ' FICHIER_INVENTAIRE=inventories/production/hosts.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: verifier
|
||||||
|
verifier: lint syntaxe
|
||||||
|
|
||||||
|
.PHONY: inventaire hote-ajouter hote-groupes hote-afficher appliquer deployer deployer-groupe cloner-vm creer-vm config inventaire-verifier inventaire-lister inventaire-graphe inventaire-hote inventaire-lab inventaire-production
|
||||||
|
inventaire: inventaire-production
|
||||||
|
|
||||||
|
config:
|
||||||
|
python3 scripts/config_proxmox.py
|
||||||
|
|
||||||
|
hote-ajouter: ansible-runtime
|
||||||
|
@if [[ -z "$(HOTE)" || -z "$(ADRESSE_IP)" ]]; then \
|
||||||
|
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote ADRESSE_IP=adresse_ip.'; \
|
||||||
|
exit 2; \
|
||||||
|
fi
|
||||||
|
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) ajouter --hote $(HOTE) --adresse-ip $(ADRESSE_IP) --utilisateur-ansible $(UTILISATEUR_ANSIBLE) --groupes "$(GROUPES)"
|
||||||
|
$(MAKE) inventaire-verifier
|
||||||
|
$(MAKE) hote-afficher HOTE="$(HOTE)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)"
|
||||||
|
|
||||||
|
hote-groupes: ansible-runtime
|
||||||
|
@if [[ -z "$(HOTE)" ]]; then \
|
||||||
|
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote GROUPES="groupe1 groupe2".'; \
|
||||||
|
exit 2; \
|
||||||
|
fi
|
||||||
|
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) definir-groupes --hote $(HOTE) --groupes "$(GROUPES)"
|
||||||
|
$(MAKE) inventaire-verifier
|
||||||
|
$(MAKE) hote-afficher HOTE="$(HOTE)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)"
|
||||||
|
|
||||||
|
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
|
||||||
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml" --limit $(GROUPE)
|
||||||
|
|
||||||
|
deployer:
|
||||||
|
@if [[ -z "$(HOTE)" ]]; then \
|
||||||
|
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
||||||
|
exit 2; \
|
||||||
|
fi
|
||||||
|
$(MAKE) _verifier-acces-hote LIMITE="$(HOTE)"
|
||||||
|
$(MAKE) _verifier-privileges-hote LIMITE="$(HOTE)"
|
||||||
|
@playbooks="$$(python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) playbooks --hote $(HOTE) --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES))" || exit $$?; \
|
||||||
|
if [[ -z "$$playbooks" ]]; then \
|
||||||
|
printf '%s\n' 'Refus: aucun playbook applicable pour HOTE=$(HOTE).'; \
|
||||||
|
exit 2; \
|
||||||
|
fi; \
|
||||||
|
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)"
|
||||||
|
|
||||||
|
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="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:
|
||||||
|
@if [[ -z "$(ADRESSE_IP)" ]]; then \
|
||||||
|
printf '%s\n' 'Refus: creer-vm doit recevoir ADRESSE_IP pour inscrire l hote dans l inventaire.'; \
|
||||||
|
exit 2; \
|
||||||
|
fi
|
||||||
|
$(MAKE) cloner-vm HOTE="$(HOTE)" VMID_MODELE="$(VMID_MODELE)" VMID="$(VMID)" NOEUD_PROXMOX="$(NOEUD_PROXMOX)" STOCKAGE_PROXMOX="$(STOCKAGE_PROXMOX)" FORMAT_DISQUE="$(FORMAT_DISQUE)" TAILLE_DISQUE="$(TAILLE_DISQUE)" DISQUE_PROXMOX="$(DISQUE_PROXMOX)" ADRESSE_IP="$(ADRESSE_IP)" CIDR="$(CIDR)" PASSERELLE="$(PASSERELLE)" DNS="$(DNS)" DHCP="$(DHCP)" CIUSER="$(CIUSER)" CLE_SSH_PUBLIQUE="$(CLE_SSH_PUBLIQUE)" PONT_PROXMOX="$(PONT_PROXMOX)" VLAN="$(VLAN)" DEMARRER="$(DEMARRER)" CLONE_COMPLET="$(CLONE_COMPLET)"
|
||||||
|
$(MAKE) hote-ajouter HOTE="$(HOTE)" ADRESSE_IP="$(ADRESSE_IP)" GROUPES="$(GROUPES)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)"
|
||||||
|
|
||||||
|
inventaire-verifier: ansible-runtime
|
||||||
|
ansible-inventory -i $(INVENTAIRE_LAB) --list > /dev/null
|
||||||
|
ansible-inventory -i $(INVENTAIRE_PRODUCTION) --list > /dev/null
|
||||||
|
|
||||||
|
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)
|
||||||
78
README.md
78
README.md
|
|
@ -5,8 +5,7 @@ Dépôt Ansible central pour construire, configurer, maintenir et documenter les
|
||||||
## Domaines prévus
|
## Domaines prévus
|
||||||
|
|
||||||
- templates de VM Proxmox ;
|
- templates de VM Proxmox ;
|
||||||
- socle Debian ;
|
- groupes de conformité ;
|
||||||
- hardening ;
|
|
||||||
- maintenance ;
|
- maintenance ;
|
||||||
- web ;
|
- web ;
|
||||||
- bases de données ;
|
- bases de données ;
|
||||||
|
|
@ -20,9 +19,9 @@ Dépôt Ansible central pour construire, configurer, maintenir et documenter les
|
||||||
Template Debian 13 Proxmox :
|
Template Debian 13 Proxmox :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
playbooks/vm_templates/debian13_proxmox_prepare.yml
|
playbooks/modeles_vm/debian13_proxmox_preparer.yml
|
||||||
playbooks/vm_templates/debian13_proxmox_verify.yml
|
playbooks/modeles_vm/debian13_proxmox_verifier.yml
|
||||||
playbooks/vm_templates/debian13_proxmox_cleanup.yml
|
playbooks/modeles_vm/debian13_proxmox_nettoyer.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
## Principe
|
## Principe
|
||||||
|
|
@ -37,3 +36,72 @@ Les services spécialisés seront installés ensuite sur les clones :
|
||||||
- Docker/Podman ;
|
- Docker/Podman ;
|
||||||
- monitoring complet ;
|
- monitoring complet ;
|
||||||
- applications métier.
|
- 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-01
|
||||||
|
```
|
||||||
|
|
||||||
|
Ajouter une VM à l'inventaire production et l'associer aux groupes qui détermineront sa configuration :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make hote-ajouter HOTE=web-01 ADRESSE_IP=192.168.12.101 GROUPES="serveurs_debian serveurs_durcis"
|
||||||
|
make hote-groupes HOTE=web-01 GROUPES="serveurs_debian serveurs_durcis"
|
||||||
|
```
|
||||||
|
|
||||||
|
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 `serveurs_debian` et `serveurs_durcis`, pas par des playbooks de couches séparés.
|
||||||
|
|
||||||
|
Créer un clone depuis le modèle Debian 13 via l'API Proxmox :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make config
|
||||||
|
make creer-vm HOTE=web-01 VMID=101 VLAN=12 ADRESSE_IP=192.168.12.101 PASSERELLE=192.168.12.1 GROUPES="serveurs_debian serveurs_durcis"
|
||||||
|
make deployer HOTE=web-01
|
||||||
|
```
|
||||||
|
|
||||||
|
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-01
|
||||||
|
```
|
||||||
|
|
||||||
|
Déployer ou remettre en conformité un groupe :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make deployer-groupe GROUPE=serveurs_debian
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ Il ne doit pas contenir :
|
||||||
Le playbook :
|
Le playbook :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
playbooks/vm_templates/debian13_proxmox_prepare.yml
|
playbooks/modeles_vm/debian13_proxmox_preparer.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
a échoué sur un handler manquant :
|
a échoué sur un handler manquant :
|
||||||
|
|
@ -91,7 +91,7 @@ Rôles à vérifier en priorité :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
roles/ssh_baseline/
|
roles/ssh_baseline/
|
||||||
roles/ssh_hardening/
|
roles/ssh_durcissement/
|
||||||
```
|
```
|
||||||
|
|
||||||
Chaque rôle utilisant `notify` doit avoir son propre fichier :
|
Chaque rôle utilisant `notify` doit avoir son propre fichier :
|
||||||
|
|
@ -110,23 +110,23 @@ Créer ou corriger :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
roles/ssh_baseline/handlers/main.yml
|
roles/ssh_baseline/handlers/main.yml
|
||||||
roles/ssh_hardening/handlers/main.yml
|
roles/ssh_durcissement/handlers/main.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
Contenu attendu :
|
Contenu attendu :
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
---
|
---
|
||||||
- name: Validate and reload ssh
|
- name: Valider la configuration SSH
|
||||||
block:
|
ansible.builtin.command: sshd -t
|
||||||
- name: Valider la configuration SSH
|
changed_when: false
|
||||||
ansible.builtin.command: sshd -t
|
listen: Validate and reload ssh
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Recharger SSH
|
- name: Recharger SSH
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: ssh
|
name: ssh
|
||||||
state: reloaded
|
state: reloaded
|
||||||
|
listen: Validate and reload ssh
|
||||||
```
|
```
|
||||||
|
|
||||||
Puis vérifier tous les `notify` :
|
Puis vérifier tous les `notify` :
|
||||||
|
|
@ -143,19 +143,19 @@ find roles -path '*/handlers/main.yml' -print
|
||||||
Après correction :
|
Après correction :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_prepare.yml --syntax-check
|
make syntax-template
|
||||||
```
|
```
|
||||||
|
|
||||||
Puis relancer :
|
Puis relancer :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_prepare.yml
|
make preparer-modele
|
||||||
```
|
```
|
||||||
|
|
||||||
Puis vérifier :
|
Puis vérifier :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_verify.yml
|
make verifier-modele
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -165,7 +165,7 @@ ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_pr
|
||||||
Ne lancer le nettoyage final que lorsque la VM est validée :
|
Ne lancer le nettoyage final que lorsque la VM est validée :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_cleanup.yml -e confirm_template_cleanup=true
|
make nettoyer-modele CONFIRMER=true
|
||||||
```
|
```
|
||||||
|
|
||||||
Ensuite seulement :
|
Ensuite seulement :
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,59 @@ Set-OPS est un dépôt global d'exploitation.
|
||||||
## Domaines
|
## Domaines
|
||||||
|
|
||||||
```text
|
```text
|
||||||
baseline : socle commun Debian
|
socle : socle commun Debian
|
||||||
hardening : sécurité
|
durcissement : sécurité
|
||||||
maintenance : mises à jour
|
maintenance : mises à jour
|
||||||
monitoring : supervision
|
monitoring : supervision
|
||||||
proxmox : hyperviseurs
|
proxmox : hyperviseurs
|
||||||
vm_templates : modèles de VM
|
modeles_vm : modèles de VM
|
||||||
web : services web
|
web : services web
|
||||||
database : bases de données
|
database : bases de données
|
||||||
backup : sauvegardes
|
backup : sauvegardes
|
||||||
applications : services applicatifs
|
applications : services applicatifs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
|
inventories/production/hosts.yml
|
||||||
|
serveurs_debian
|
||||||
|
|
||||||
|
playbooks/groupes/serveurs_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 Chezlepro 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
|
||||||
|
```
|
||||||
|
|
|
||||||
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 de Chezlepro.
|
||||||
|
|
||||||
|
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 Chezlepro.
|
||||||
|
|
||||||
|
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@192.168.12.99
|
||||||
|
ansible -i inventories/lab/hosts.yml modeles_vm -m ping
|
||||||
|
ansible -i inventories/lab/hosts.yml modeles_vm -m setup
|
||||||
|
```
|
||||||
|
|
||||||
|
Adapter l'utilisateur et l'adresse IP selon `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
|
||||||
|
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 `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 Chezlepro 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
|
||||||
|
```
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
# Procédure manuelle — VM Debian 13 prête à convertir en template Proxmox
|
# Procédure manuelle — VM Debian 13 vanille pour Proxmox
|
||||||
|
|
||||||
## Objet du document
|
## Objet du document
|
||||||
|
|
||||||
Ce document décrit le travail manuel à effectuer pour créer une VM Debian 13 propre dans Proxmox, jusqu’au moment où elle est prête à être convertie en modèle/template.
|
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, clonable, compatible avec cloud-init, prête à être prise en charge par Ansible et par le dépôt `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 juste avant la conversion finale en template Proxmox.
|
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
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -19,10 +25,12 @@ Objectifs :
|
||||||
- système Debian 13 minimal ;
|
- système Debian 13 minimal ;
|
||||||
- aucun environnement graphique ;
|
- aucun environnement graphique ;
|
||||||
- SSH actif ;
|
- SSH actif ;
|
||||||
- compte technique `ansible` disponible ;
|
|
||||||
- `ansible` autorisé à utiliser sudo sans mot de passe ;
|
|
||||||
- `qemu-guest-agent` installé ;
|
- `qemu-guest-agent` installé ;
|
||||||
- `cloud-init` 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 ;
|
- partitionnement simple et agrandissable ;
|
||||||
- aucune partition swap bloquant la croissance du disque ;
|
- aucune partition swap bloquant la croissance du disque ;
|
||||||
- aucune donnée propre à une VM finale ;
|
- aucune donnée propre à une VM finale ;
|
||||||
|
|
@ -304,7 +312,7 @@ Le serveur web, les rôles applicatifs et les services métier seront installés
|
||||||
|
|
||||||
Après l’installation, démarrer la VM et se connecter en console ou par SSH.
|
Après l’installation, démarrer la VM et se connecter en console ou par SSH.
|
||||||
|
|
||||||
Passer root :
|
Passer root si le compte root est disponible :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
su -
|
su -
|
||||||
|
|
@ -316,9 +324,55 @@ ou, si sudo est déjà disponible :
|
||||||
sudo -i
|
sudo -i
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Toutes les commandes de bootstrap suivantes sont exécutées dans la VM.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Mise à jour du système
|
## 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 :
|
Exécuter :
|
||||||
|
|
||||||
|
|
@ -329,46 +383,38 @@ apt full-upgrade -y
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14. Paquets de base
|
## 15. Paquets de bootstrap
|
||||||
|
|
||||||
Installer les paquets nécessaires au modèle :
|
Installer seulement les paquets nécessaires pour que Set-OPS puisse prendre le relais :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
apt install -y \
|
apt install -y \
|
||||||
sudo \
|
sudo \
|
||||||
|
openssh-server \
|
||||||
qemu-guest-agent \
|
qemu-guest-agent \
|
||||||
cloud-init \
|
cloud-init \
|
||||||
cloud-guest-utils \
|
cloud-guest-utils \
|
||||||
curl \
|
|
||||||
wget \
|
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
gnupg \
|
curl \
|
||||||
vim \
|
vim \
|
||||||
nano \
|
nano
|
||||||
bash-completion \
|
|
||||||
htop \
|
|
||||||
lsof \
|
|
||||||
ncdu \
|
|
||||||
tree \
|
|
||||||
net-tools \
|
|
||||||
iproute2 \
|
|
||||||
dnsutils \
|
|
||||||
chrony
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Rôle des paquets principaux :
|
Rôle des paquets principaux :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
sudo : délégation administrative
|
sudo : délégation administrative
|
||||||
|
openssh-server : accès distant initial
|
||||||
qemu-guest-agent : communication Proxmox ↔ VM
|
qemu-guest-agent : communication Proxmox ↔ VM
|
||||||
cloud-init : personnalisation au premier boot du clone
|
cloud-init : personnalisation au premier boot du clone
|
||||||
cloud-guest-utils : fournit notamment growpart
|
cloud-guest-utils : fournit notamment growpart
|
||||||
chrony : synchronisation du temps
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Les autres paquets communs, outils de diagnostic, chrony et composants de durcissement sont installés ensuite par `make preparer-modele`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15. Activation du QEMU Guest Agent
|
## 16. Activation du QEMU Guest Agent
|
||||||
|
|
||||||
Activer le service :
|
Activer le service :
|
||||||
|
|
||||||
|
|
@ -390,126 +436,21 @@ VM → Options → QEMU Guest Agent → Enabled
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 16. Configuration du compte ansible
|
## 17. Identité initiale par Cloud-Init
|
||||||
|
|
||||||
### Ajouter le compte au groupe sudo
|
À partir d'ici, ne pas créer manuellement le compte `ansible` ni son fichier `authorized_keys`, sauf dépannage.
|
||||||
|
|
||||||
```bash
|
L'identité initiale doit venir de Proxmox + Cloud-Init :
|
||||||
usermod -aG sudo ansible
|
|
||||||
```
|
|
||||||
|
|
||||||
### Autoriser sudo sans mot de passe
|
|
||||||
|
|
||||||
Créer le fichier dédié :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat > /etc/sudoers.d/90-ansible <<'EOF'
|
|
||||||
ansible ALL=(ALL) NOPASSWD:ALL
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
Appliquer les permissions :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
chmod 440 /etc/sudoers.d/90-ansible
|
|
||||||
```
|
|
||||||
|
|
||||||
Valider la syntaxe :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
visudo -cf /etc/sudoers.d/90-ansible
|
|
||||||
```
|
|
||||||
|
|
||||||
Le résultat attendu est :
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/etc/sudoers.d/90-ansible: parsed OK
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
Tester depuis le compte `ansible` :
|
Cette séparation évite de maintenir deux méthodes concurrentes pour créer le même accès.
|
||||||
|
|
||||||
```bash
|
### Ajouter le CloudInit Drive
|
||||||
sudo -n true && echo OK
|
|
||||||
```
|
|
||||||
|
|
||||||
Résultat attendu :
|
|
||||||
|
|
||||||
```text
|
|
||||||
OK
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 17. SSH
|
|
||||||
|
|
||||||
### État transitoire
|
|
||||||
|
|
||||||
Pendant la construction du modèle, l’authentification par mot de passe peut rester active :
|
|
||||||
|
|
||||||
```text
|
|
||||||
PasswordAuthentication yes
|
|
||||||
```
|
|
||||||
|
|
||||||
C’est pratique tant que la clé SSH n’est pas encore injectée.
|
|
||||||
|
|
||||||
### État cible
|
|
||||||
|
|
||||||
Quand l’accès par clé SSH est confirmé, l’état cible sera :
|
|
||||||
|
|
||||||
```text
|
|
||||||
PermitRootLogin no
|
|
||||||
PubkeyAuthentication yes
|
|
||||||
PasswordAuthentication no
|
|
||||||
```
|
|
||||||
|
|
||||||
Ne pas désactiver le login par mot de passe avant d’avoir confirmé que l’accès par clé fonctionne.
|
|
||||||
|
|
||||||
### Tester une connexion SSH par mot de passe
|
|
||||||
|
|
||||||
Depuis un poste d’administration :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no ansible@IP_DE_LA_VM
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 18. Cloud-init dans Debian
|
|
||||||
|
|
||||||
Vérifier que cloud-init est installé :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cloud-init --version
|
|
||||||
```
|
|
||||||
|
|
||||||
Vérifier le service :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
systemctl status cloud-init --no-pager
|
|
||||||
```
|
|
||||||
|
|
||||||
Cloud-init servira à appliquer, au premier démarrage d’un clone :
|
|
||||||
|
|
||||||
- hostname ;
|
|
||||||
- utilisateur initial ;
|
|
||||||
- clé SSH publique ;
|
|
||||||
- IP ;
|
|
||||||
- passerelle ;
|
|
||||||
- DNS ;
|
|
||||||
- agrandissement de la partition racine si le disque a été étendu.
|
|
||||||
|
|
||||||
Cloud-init ne doit pas remplacer Ansible pour les rôles serveur complexes.
|
|
||||||
|
|
||||||
Séparation recommandée :
|
|
||||||
|
|
||||||
```text
|
|
||||||
cloud-init : identité initiale de la VM
|
|
||||||
Ansible : configuration réelle du serveur
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 19. Ajout du CloudInit Drive dans Proxmox
|
|
||||||
|
|
||||||
Éteindre la VM :
|
Éteindre la VM :
|
||||||
|
|
||||||
|
|
@ -535,19 +476,11 @@ Exemple :
|
||||||
qm set 9000 --ide2 local-lvm:cloudinit
|
qm set 9000 --ide2 local-lvm:cloudinit
|
||||||
```
|
```
|
||||||
|
|
||||||
ou :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
qm set 9000 --ide2 truenas-lvm:cloudinit
|
|
||||||
```
|
|
||||||
|
|
||||||
Le nom exact du stockage dépend de la configuration Proxmox.
|
Le nom exact du stockage dépend de la configuration Proxmox.
|
||||||
|
|
||||||
---
|
### Définir les paramètres Cloud-Init du modèle
|
||||||
|
|
||||||
## 20. Paramètres cloud-init dans Proxmox
|
Pour la VM qui deviendra le modèle, utiliser une identité technique minimale, pas une identité de serveur final.
|
||||||
|
|
||||||
Après ajout du CloudInit Drive, Proxmox permet de définir les paramètres cloud-init.
|
|
||||||
|
|
||||||
Exemple DHCP :
|
Exemple DHCP :
|
||||||
|
|
||||||
|
|
@ -557,7 +490,7 @@ qm set 9000 --sshkeys ~/.ssh/id_ed25519.pub
|
||||||
qm set 9000 --ipconfig0 ip=dhcp
|
qm set 9000 --ipconfig0 ip=dhcp
|
||||||
```
|
```
|
||||||
|
|
||||||
Exemple IP statique :
|
Exemple IP statique temporaire pour joindre la VM de modèle :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
qm set 9000 --ciuser ansible
|
qm set 9000 --ciuser ansible
|
||||||
|
|
@ -566,13 +499,86 @@ qm set 9000 --ipconfig0 ip=192.168.11.150/24,gw=192.168.11.1
|
||||||
qm set 9000 --nameserver 192.168.11.1
|
qm set 9000 --nameserver 192.168.11.1
|
||||||
```
|
```
|
||||||
|
|
||||||
Pour le modèle, éviter de lui donner une identité finale trop spécifique.
|
Pour les clones, ces valeurs seront remplacées par l'identité réelle du serveur.
|
||||||
|
|
||||||
L’identité définitive doit plutôt être appliquée aux clones.
|
### 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 21. Vérifications avant nettoyage
|
## 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 Chezlepro 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 :
|
Redémarrer la VM une dernière fois si nécessaire, puis vérifier :
|
||||||
|
|
||||||
|
|
@ -598,52 +604,71 @@ qemu-guest-agent actif
|
||||||
ssh actif
|
ssh actif
|
||||||
cloud-init installé
|
cloud-init installé
|
||||||
compte ansible fonctionnel
|
compte ansible fonctionnel
|
||||||
sudo NOPASSWD fonctionnel pour ansible
|
connexion SSH par clé fonctionnelle
|
||||||
|
sudo fonctionnel pour ansible
|
||||||
|
CloudInit Drive présent côté Proxmox
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 22. Nettoyage avant conversion en template
|
## 21. Point de bascule vers Set-OPS
|
||||||
|
|
||||||
Avant de convertir la VM en modèle, nettoyer l’état propre à cette installation.
|
À partir de ce point, ne pas continuer manuellement la configuration du socle. Utiliser le `Makefile` depuis le dépôt Set-OPS.
|
||||||
|
|
||||||
Exécuter dans la VM :
|
Depuis le poste Ansible :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo cloud-init clean --logs
|
make preparer-modele
|
||||||
sudo apt clean
|
make verifier-modele
|
||||||
```
|
```
|
||||||
|
|
||||||
Nettoyer l’identifiant machine :
|
Le cleanup final est séparé et protégé :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo truncate -s 0 /etc/machine-id
|
make nettoyer-modele CONFIRMER=true
|
||||||
sudo rm -f /var/lib/dbus/machine-id
|
|
||||||
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Optionnel : vider les journaux persistants si présents :
|
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
|
```bash
|
||||||
sudo journalctl --rotate
|
make nettoyer-modele CONFIRMER=true
|
||||||
sudo journalctl --vacuum-time=1s
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Optionnel : supprimer l’historique shell du compte courant :
|
Ce nettoyage peut inclure :
|
||||||
|
|
||||||
```bash
|
```text
|
||||||
history -c
|
cloud-init clean --logs
|
||||||
```
|
nettoyage du cache APT
|
||||||
|
rotation ou purge contrôlée des journaux
|
||||||
Puis éteindre :
|
remise à zéro de /etc/machine-id
|
||||||
|
suppression des historiques shell
|
||||||
```bash
|
|
||||||
sudo shutdown -h now
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 23. Point d’arrêt : VM prête à convertir
|
## 24. Point d’arrêt : VM prête à convertir
|
||||||
|
|
||||||
À ce stade, la VM doit être arrêtée.
|
À ce stade, la VM doit être arrêtée.
|
||||||
|
|
||||||
|
|
@ -673,8 +698,9 @@ qemu-guest-agent installé
|
||||||
cloud-init installé
|
cloud-init installé
|
||||||
cloud-guest-utils installé
|
cloud-guest-utils installé
|
||||||
sudo installé
|
sudo installé
|
||||||
compte ansible présent
|
compte ansible injecté par cloud-init
|
||||||
sudo NOPASSWD pour ansible
|
clé publique SSH injectée par cloud-init
|
||||||
|
sudo NOPASSWD pour ansible après préparation Set-OPS
|
||||||
partition EFI 512 Mo
|
partition EFI 512 Mo
|
||||||
partition / ext4
|
partition / ext4
|
||||||
aucune partition swap
|
aucune partition swap
|
||||||
|
|
@ -687,7 +713,7 @@ VM éteinte
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 24. Conversion en template Proxmox
|
## 25. Conversion en template Proxmox
|
||||||
|
|
||||||
Cette commande n’est exécutée qu’après validation finale :
|
Cette commande n’est exécutée qu’après validation finale :
|
||||||
|
|
||||||
|
|
@ -705,49 +731,63 @@ qm template 9000
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 25. Flux normal après conversion
|
## 26. Flux normal après conversion
|
||||||
|
|
||||||
Après conversion du modèle :
|
Après conversion du modèle, le flux normal passe par `make` et l'API Proxmox.
|
||||||
|
|
||||||
|
Les paramètres communs Proxmox sont dans :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
1. Cloner le template.
|
inventories/lab/group_vars/proxmox.yml
|
||||||
2. Agrandir le disque si nécessaire.
|
```
|
||||||
3. Définir hostname, IP, DNS et clé SSH via cloud-init.
|
|
||||||
|
Les secrets d'API doivent être dans un fichier Vault non versionné :
|
||||||
|
|
||||||
|
```text
|
||||||
|
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.
|
4. Démarrer la VM.
|
||||||
5. Laisser cloud-init appliquer l’identité initiale.
|
5. Ajouter l'hôte à l'inventaire Set-OPS.
|
||||||
6. Se connecter en SSH.
|
|
||||||
7. Appliquer les rôles Ansible depuis Set-OPS.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Exemple :
|
Exemple :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
qm clone 9000 101 --name web-01 --full true
|
make creer-vm \
|
||||||
qm resize 101 scsi0 32G
|
HOTE=web-01 \
|
||||||
qm set 101 --ciuser ansible
|
VMID=101 \
|
||||||
qm set 101 --sshkeys ~/.ssh/id_ed25519.pub
|
VLAN=11 \
|
||||||
qm set 101 --ipconfig0 ip=192.168.11.101/24,gw=192.168.11.1
|
ADRESSE_IP=192.168.11.101 \
|
||||||
qm set 101 --nameserver 192.168.11.1
|
PASSERELLE=192.168.11.1 \
|
||||||
qm start 101
|
GROUPES="serveurs_debian serveurs_durcis"
|
||||||
```
|
```
|
||||||
|
|
||||||
Puis :
|
Le VLAN est volontairement saisi au moment de créer chaque VM. Il ne fait pas partie des valeurs persistantes de `make config`.
|
||||||
|
|
||||||
|
Après le premier démarrage, tester l'accès :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh ansible@192.168.11.101
|
ssh ansible@192.168.11.101
|
||||||
```
|
```
|
||||||
|
|
||||||
Ensuite seulement :
|
Ensuite appliquer la conformité Ansible :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ansible-playbook -i inventories/production/hosts.yml playbooks/baseline.yml
|
make deployer HOTE=web-01
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 26. Résumé court
|
## 27. Résumé court
|
||||||
|
|
||||||
Le modèle idéal est simple :
|
La VM vanille idéale est simple :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Debian 13 minimal
|
Debian 13 minimal
|
||||||
|
|
@ -766,11 +806,11 @@ sudo
|
||||||
qemu-guest-agent
|
qemu-guest-agent
|
||||||
cloud-init
|
cloud-init
|
||||||
cloud-guest-utils
|
cloud-guest-utils
|
||||||
compte ansible
|
CloudInit Drive Proxmox
|
||||||
sudo NOPASSWD pour ansible
|
ciuser ansible défini dans Proxmox
|
||||||
cloud-init clean
|
clé publique SSH définie dans Proxmox
|
||||||
machine-id vidé
|
sudo fonctionnel pour ansible
|
||||||
VM éteinte
|
APT réseau fonctionnel
|
||||||
```
|
```
|
||||||
|
|
||||||
La philosophie :
|
La philosophie :
|
||||||
|
|
|
||||||
194
docs/vm-lifecycle.md
Normal file
194
docs/vm-lifecycle.md
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
# Cycle de vie des VM Chezlepro
|
||||||
|
|
||||||
|
Ce document décrit le cycle normal d'une VM Debian Chezlepro, 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 Chezlepro.
|
||||||
|
|
||||||
|
## 2. Goldenisation
|
||||||
|
|
||||||
|
La goldenisation est faite par :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make preparer-modele
|
||||||
|
```
|
||||||
|
|
||||||
|
Ce playbook ajoute le socle Chezlepro 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.
|
||||||
|
|
||||||
|
Chaque groupe opérationnel doit avoir un playbook homonyme :
|
||||||
|
|
||||||
|
```text
|
||||||
|
serveurs_debian -> playbooks/groupes/serveurs_debian.yml
|
||||||
|
serveurs_durcis -> playbooks/groupes/serveurs_durcis.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
L'appartenance aux groupes devient la déclaration d'intention :
|
||||||
|
|
||||||
|
```text
|
||||||
|
web-01 dans serveurs_debian -> applique le socle Debian
|
||||||
|
web-01 dans serveurs_durcis -> applique le durcissement commun
|
||||||
|
```
|
||||||
|
|
||||||
|
Un groupe sans playbook ne doit pas être assigné à une VM de production tant que son rôle n'est pas implémenté.
|
||||||
|
|
||||||
|
## 6. Socle Debian
|
||||||
|
|
||||||
|
Le groupe `serveurs_debian` maintient les composants de base :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make appliquer GROUPE=serveurs_debian
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Hardening commun
|
||||||
|
|
||||||
|
Le groupe `serveurs_durcis` maintient les couches de sécurité communes :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make appliquer GROUPE=serveurs_durcis
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Pour une VM déjà clonée et démarrée :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make hote-ajouter HOTE=web-01 ADRESSE_IP=192.168.12.101 GROUPES="serveurs_debian serveurs_durcis"
|
||||||
|
make deployer HOTE=web-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/serveurs_debian.yml
|
||||||
|
playbooks/groupes/serveurs_durcis.yml
|
||||||
|
verifier-hote
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour converger un groupe complet :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make deployer-groupe GROUPE=serveurs_debian
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Variables template et conformité
|
||||||
|
|
||||||
|
Les variables du template servent à construire le golden template dans `inventories/lab/group_vars/modeles_vm.yml`.
|
||||||
|
|
||||||
|
Les variables de conformité servent aux VM déployées dans `inventories/production/group_vars/serveurs_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
|
||||||
|
```
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
# Template Debian 13 Proxmox
|
|
||||||
|
|
||||||
## Préparation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_prepare.yml --ask-pass --ask-become-pass
|
|
||||||
```
|
|
||||||
|
|
||||||
## Vérification
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_verify.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Nettoyage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_cleanup.yml -e confirm_template_cleanup=true
|
|
||||||
```
|
|
||||||
|
|
@ -1,119 +1,2 @@
|
||||||
---
|
---
|
||||||
chezlepro_timezone: "America/Toronto"
|
chezlepro_timezone: "America/Toronto"
|
||||||
chezlepro_admin_user: "ansible"
|
|
||||||
|
|
||||||
# SSH pendant la construction du template.
|
|
||||||
# Passer à "no" seulement après validation des clés SSH.
|
|
||||||
chezlepro_ssh_port: 22
|
|
||||||
chezlepro_ssh_password_authentication: "yes"
|
|
||||||
chezlepro_ssh_permit_root_login: "no"
|
|
||||||
chezlepro_ssh_pubkey_authentication: "yes"
|
|
||||||
chezlepro_ssh_client_alive_interval: 300
|
|
||||||
chezlepro_ssh_client_alive_count_max: 2
|
|
||||||
chezlepro_ssh_max_auth_tries: 4
|
|
||||||
chezlepro_ssh_login_grace_time: "30s"
|
|
||||||
|
|
||||||
# systemd-ssh-generator / VSOCK
|
|
||||||
chezlepro_disable_systemd_ssh_auto: true
|
|
||||||
|
|
||||||
# Cloud-init
|
|
||||||
cloud_init_ssh_pwauth: true
|
|
||||||
cloud_init_manage_etc_hosts: true
|
|
||||||
cloud_init_disable_root: true
|
|
||||||
cloud_init_ssh_deletekeys: true
|
|
||||||
|
|
||||||
# Pare-feu : préparé mais non activé dans le template.
|
|
||||||
chezlepro_nftables_enabled: false
|
|
||||||
chezlepro_firewall_allow_ssh: true
|
|
||||||
chezlepro_firewall_allow_icmp: true
|
|
||||||
chezlepro_firewall_input_policy: "drop"
|
|
||||||
chezlepro_firewall_forward_policy: "drop"
|
|
||||||
chezlepro_firewall_output_policy: "accept"
|
|
||||||
chezlepro_firewall_extra_tcp_ports: []
|
|
||||||
chezlepro_firewall_extra_udp_ports: []
|
|
||||||
|
|
||||||
# Fail2ban
|
|
||||||
chezlepro_fail2ban_enabled: true
|
|
||||||
chezlepro_fail2ban_bantime: "1h"
|
|
||||||
chezlepro_fail2ban_findtime: "10m"
|
|
||||||
chezlepro_fail2ban_maxretry: 5
|
|
||||||
|
|
||||||
# Sécurité
|
|
||||||
chezlepro_auditd_enabled: true
|
|
||||||
chezlepro_apparmor_enabled: true
|
|
||||||
chezlepro_sysctl_apply: true
|
|
||||||
chezlepro_disable_core_dumps: true
|
|
||||||
|
|
||||||
# Unattended upgrades
|
|
||||||
chezlepro_unattended_upgrades_enabled: true
|
|
||||||
chezlepro_unattended_remove_unused_dependencies: true
|
|
||||||
chezlepro_unattended_automatic_reboot: false
|
|
||||||
|
|
||||||
# Journald
|
|
||||||
chezlepro_journald_system_max_use: "200M"
|
|
||||||
chezlepro_journald_runtime_max_use: "100M"
|
|
||||||
chezlepro_journald_max_retention_sec: "1month"
|
|
||||||
|
|
||||||
# Nettoyage final
|
|
||||||
confirm_template_cleanup: false
|
|
||||||
|
|
||||||
chezlepro_common_packages:
|
|
||||||
- sudo
|
|
||||||
- openssh-server
|
|
||||||
- qemu-guest-agent
|
|
||||||
- cloud-init
|
|
||||||
- cloud-guest-utils
|
|
||||||
- python3
|
|
||||||
- python3-apt
|
|
||||||
- python3-pip
|
|
||||||
- acl
|
|
||||||
- curl
|
|
||||||
- wget
|
|
||||||
- ca-certificates
|
|
||||||
- gnupg
|
|
||||||
- git
|
|
||||||
- vim
|
|
||||||
- nano
|
|
||||||
- bash-completion
|
|
||||||
- tmux
|
|
||||||
- rsync
|
|
||||||
- unzip
|
|
||||||
- zip
|
|
||||||
- tar
|
|
||||||
- jq
|
|
||||||
- htop
|
|
||||||
- iotop
|
|
||||||
- iftop
|
|
||||||
- sysstat
|
|
||||||
- lsof
|
|
||||||
- ncdu
|
|
||||||
- tree
|
|
||||||
- file
|
|
||||||
- less
|
|
||||||
- dnsutils
|
|
||||||
- iproute2
|
|
||||||
- iputils-ping
|
|
||||||
- net-tools
|
|
||||||
- traceroute
|
|
||||||
- mtr-tiny
|
|
||||||
- tcpdump
|
|
||||||
- netcat-openbsd
|
|
||||||
- socat
|
|
||||||
- chrony
|
|
||||||
- logrotate
|
|
||||||
- unattended-upgrades
|
|
||||||
- apt-listchanges
|
|
||||||
- needrestart
|
|
||||||
|
|
||||||
chezlepro_hardening_packages:
|
|
||||||
- apparmor
|
|
||||||
- apparmor-utils
|
|
||||||
- auditd
|
|
||||||
- audispd-plugins
|
|
||||||
- fail2ban
|
|
||||||
- nftables
|
|
||||||
- unattended-upgrades
|
|
||||||
- apt-listchanges
|
|
||||||
- debsums
|
|
||||||
- needrestart
|
|
||||||
- libpam-pwquality
|
|
||||||
|
|
|
||||||
58
inventories/lab/group_vars/modeles_vm.yml
Normal file
58
inventories/lab/group_vars/modeles_vm.yml
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
---
|
||||||
|
# Variables de construction du golden template Debian 13 Proxmox.
|
||||||
|
|
||||||
|
sudo_ansible_admin_user: "ansible"
|
||||||
|
|
||||||
|
# SSH : cloud-init doit avoir injecté ciuser et clé publique avant Ansible.
|
||||||
|
ssh_baseline_password_authentication: "no"
|
||||||
|
ssh_baseline_permit_root_login: "no"
|
||||||
|
ssh_baseline_pubkey_authentication: "yes"
|
||||||
|
|
||||||
|
ssh_hardening_port: 22
|
||||||
|
ssh_hardening_password_authentication: "no"
|
||||||
|
ssh_hardening_permit_root_login: "no"
|
||||||
|
ssh_hardening_pubkey_authentication: "yes"
|
||||||
|
ssh_hardening_client_alive_interval: 300
|
||||||
|
ssh_hardening_client_alive_count_max: 2
|
||||||
|
ssh_hardening_max_auth_tries: 3
|
||||||
|
ssh_hardening_login_grace_time: "20s"
|
||||||
|
|
||||||
|
systemd_ssh_auto_disable: true
|
||||||
|
|
||||||
|
cloud_init_ssh_pwauth: false
|
||||||
|
cloud_init_manage_etc_hosts: true
|
||||||
|
cloud_init_disable_root: true
|
||||||
|
cloud_init_ssh_deletekeys: true
|
||||||
|
|
||||||
|
# Pare-feu : préparé mais non activé dans le template.
|
||||||
|
nftables_baseline_enabled: false
|
||||||
|
nftables_baseline_allow_ssh: true
|
||||||
|
nftables_baseline_allow_icmp: true
|
||||||
|
nftables_baseline_ssh_port: 22
|
||||||
|
nftables_baseline_input_policy: "drop"
|
||||||
|
nftables_baseline_forward_policy: "drop"
|
||||||
|
nftables_baseline_output_policy: "accept"
|
||||||
|
nftables_baseline_extra_tcp_ports: []
|
||||||
|
nftables_baseline_extra_udp_ports: []
|
||||||
|
|
||||||
|
fail2ban_ssh_enabled: true
|
||||||
|
fail2ban_ssh_port: 22
|
||||||
|
fail2ban_ssh_bantime: "1h"
|
||||||
|
fail2ban_ssh_findtime: "10m"
|
||||||
|
fail2ban_ssh_maxretry: 5
|
||||||
|
|
||||||
|
auditd_enabled: true
|
||||||
|
apparmor_enabled: true
|
||||||
|
sysctl_hardening_apply: true
|
||||||
|
core_dumps_disable: true
|
||||||
|
|
||||||
|
unattended_upgrades_enabled: true
|
||||||
|
unattended_upgrades_remove_unused_dependencies: true
|
||||||
|
unattended_upgrades_automatic_reboot: false
|
||||||
|
|
||||||
|
journald_system_max_use: "200M"
|
||||||
|
journald_runtime_max_use: "100M"
|
||||||
|
journald_max_retention_sec: "1month"
|
||||||
|
|
||||||
|
template_cleanup_confirm: false
|
||||||
|
template_cleanup_admin_user: "ansible"
|
||||||
8
inventories/lab/group_vars/proxmox.vault.yml.example
Normal file
8
inventories/lab/group_vars/proxmox.vault.yml.example
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Copier ce fichier vers proxmox.vault.yml, puis le chiffrer avec :
|
||||||
|
# ansible-vault encrypt inventories/lab/group_vars/proxmox.vault.yml
|
||||||
|
#
|
||||||
|
# Ne jamais versionner proxmox.vault.yml.
|
||||||
|
|
||||||
|
proxmox_api_token_id: ""
|
||||||
|
proxmox_api_token_secret: ""
|
||||||
20
inventories/lab/group_vars/proxmox.yml
Normal file
20
inventories/lab/group_vars/proxmox.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
# Parametres non sensibles pour les operations Proxmox.
|
||||||
|
# Les secrets API doivent aller dans proxmox.vault.yml.
|
||||||
|
|
||||||
|
proxmox_api_host: asgard
|
||||||
|
proxmox_api_user: ansible@pve
|
||||||
|
proxmox_api_port: '8006'
|
||||||
|
proxmox_validate_certs: false
|
||||||
|
proxmox_clone_noeud: asgard
|
||||||
|
proxmox_clone_vmid_modele: 99999
|
||||||
|
proxmox_clone_source_nom: modeleChezlepro
|
||||||
|
proxmox_clone_stockage: TrueNAS
|
||||||
|
proxmox_clone_format: ''
|
||||||
|
proxmox_clone_complet: true
|
||||||
|
proxmox_clone_timeout: 600
|
||||||
|
proxmox_clone_disque: scsi0
|
||||||
|
proxmox_clone_interface: net0
|
||||||
|
proxmox_clone_pont: vmbr1
|
||||||
|
proxmox_clone_parefeu_interface: false
|
||||||
|
proxmox_clone_demarrer: true
|
||||||
|
|
@ -1,20 +1,26 @@
|
||||||
all:
|
all:
|
||||||
children:
|
children:
|
||||||
vm_templates:
|
modeles_vm:
|
||||||
hosts:
|
hosts:
|
||||||
basiqueChezlepro:
|
basiqueChezlepro:
|
||||||
ansible_host: 192.168.12.99
|
ansible_host: 192.168.12.99
|
||||||
ansible_user: ansible
|
ansible_user: ansible
|
||||||
ansible_become: true
|
ansible_become: true
|
||||||
|
|
||||||
web_servers:
|
serveurs_debian:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
|
|
||||||
database_servers:
|
serveurs_durcis:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
|
|
||||||
monitoring_servers:
|
serveurs_web:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
|
|
||||||
proxmox_hosts:
|
serveurs_bases_donnees:
|
||||||
|
hosts: {}
|
||||||
|
|
||||||
|
serveurs_supervision:
|
||||||
|
hosts: {}
|
||||||
|
|
||||||
|
hotes_proxmox:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
---
|
---
|
||||||
# Variables globales de production à remplir progressivement.
|
# Variables globales de production.
|
||||||
|
# Les politiques Debian communes sont dans group_vars/serveurs_debian.yml.
|
||||||
|
|
|
||||||
54
inventories/production/group_vars/serveurs_debian.yml
Normal file
54
inventories/production/group_vars/serveurs_debian.yml
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
# Variables de conformité communes aux VM Debian déployées.
|
||||||
|
|
||||||
|
sudo_ansible_admin_user: "ansible"
|
||||||
|
|
||||||
|
ssh_baseline_password_authentication: "no"
|
||||||
|
ssh_baseline_permit_root_login: "no"
|
||||||
|
ssh_baseline_pubkey_authentication: "yes"
|
||||||
|
|
||||||
|
ssh_hardening_port: 22
|
||||||
|
ssh_hardening_password_authentication: "no"
|
||||||
|
ssh_hardening_permit_root_login: "no"
|
||||||
|
ssh_hardening_pubkey_authentication: "yes"
|
||||||
|
ssh_hardening_client_alive_interval: 300
|
||||||
|
ssh_hardening_client_alive_count_max: 2
|
||||||
|
ssh_hardening_max_auth_tries: 3
|
||||||
|
ssh_hardening_login_grace_time: "20s"
|
||||||
|
|
||||||
|
systemd_ssh_auto_disable: true
|
||||||
|
|
||||||
|
cloud_init_ssh_pwauth: false
|
||||||
|
cloud_init_manage_etc_hosts: true
|
||||||
|
cloud_init_disable_root: true
|
||||||
|
cloud_init_ssh_deletekeys: true
|
||||||
|
|
||||||
|
# Pare-feu : ne pas activer globalement sans validation des règles par rôle.
|
||||||
|
nftables_baseline_enabled: false
|
||||||
|
nftables_baseline_allow_ssh: true
|
||||||
|
nftables_baseline_allow_icmp: true
|
||||||
|
nftables_baseline_ssh_port: 22
|
||||||
|
nftables_baseline_input_policy: "drop"
|
||||||
|
nftables_baseline_forward_policy: "drop"
|
||||||
|
nftables_baseline_output_policy: "accept"
|
||||||
|
nftables_baseline_extra_tcp_ports: []
|
||||||
|
nftables_baseline_extra_udp_ports: []
|
||||||
|
|
||||||
|
fail2ban_ssh_enabled: true
|
||||||
|
fail2ban_ssh_port: 22
|
||||||
|
fail2ban_ssh_bantime: "1h"
|
||||||
|
fail2ban_ssh_findtime: "10m"
|
||||||
|
fail2ban_ssh_maxretry: 5
|
||||||
|
|
||||||
|
auditd_enabled: true
|
||||||
|
apparmor_enabled: true
|
||||||
|
sysctl_hardening_apply: true
|
||||||
|
core_dumps_disable: true
|
||||||
|
|
||||||
|
unattended_upgrades_enabled: true
|
||||||
|
unattended_upgrades_remove_unused_dependencies: true
|
||||||
|
unattended_upgrades_automatic_reboot: false
|
||||||
|
|
||||||
|
journald_system_max_use: "200M"
|
||||||
|
journald_runtime_max_use: "100M"
|
||||||
|
journald_max_retention_sec: "1month"
|
||||||
|
|
@ -1,12 +1,28 @@
|
||||||
all:
|
all:
|
||||||
children:
|
children:
|
||||||
vm_templates:
|
modeles_vm:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
web_servers:
|
serveurs_debian:
|
||||||
|
hosts:
|
||||||
|
web-01:
|
||||||
|
ansible_host: 192.168.12.101
|
||||||
|
ansible_user: ansible
|
||||||
|
web-02:
|
||||||
|
ansible_host: 192.168.12.102
|
||||||
|
ansible_user: ansible
|
||||||
|
serveurs_durcis:
|
||||||
|
hosts:
|
||||||
|
web-01:
|
||||||
|
ansible_host: 192.168.12.101
|
||||||
|
ansible_user: ansible
|
||||||
|
web-02:
|
||||||
|
ansible_host: 192.168.12.102
|
||||||
|
ansible_user: ansible
|
||||||
|
serveurs_web:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
database_servers:
|
serveurs_bases_donnees:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
monitoring_servers:
|
serveurs_supervision:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
proxmox_hosts:
|
hotes_proxmox:
|
||||||
hosts: {}
|
hosts: {}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
---
|
|
||||||
- name: Appliquer le socle Debian commun
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: true
|
|
||||||
|
|
||||||
roles:
|
|
||||||
- common_packages
|
|
||||||
- chrony
|
|
||||||
- ssh_baseline
|
|
||||||
22
playbooks/groupes/serveurs_debian.yml
Normal file
22
playbooks/groupes/serveurs_debian.yml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
- name: Appliquer le groupe serveurs_debian
|
||||||
|
hosts: serveurs_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
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
- name: Appliquer le hardening Debian serveur Chezlepro
|
- name: Appliquer le groupe serveurs_durcis
|
||||||
hosts: all
|
hosts: serveurs_durcis
|
||||||
become: true
|
become: true
|
||||||
gather_facts: true
|
gather_facts: 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: serveurs_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."
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
- name: Nettoyage final avant conversion en template Proxmox
|
- name: Nettoyage final avant conversion en template Proxmox
|
||||||
hosts: vm_templates
|
hosts: modeles_vm
|
||||||
become: true
|
become: true
|
||||||
gather_facts: true
|
gather_facts: true
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
- name: Préparer le template Debian 13 Proxmox Chezlepro
|
- name: Préparer le template Debian 13 Proxmox Chezlepro
|
||||||
hosts: vm_templates
|
hosts: modeles_vm
|
||||||
become: true
|
become: true
|
||||||
gather_facts: true
|
gather_facts: true
|
||||||
|
|
||||||
130
playbooks/modeles_vm/debian13_proxmox_verifier.yml
Normal file
130
playbooks/modeles_vm/debian13_proxmox_verifier.yml
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
---
|
||||||
|
- name: Vérifier le template Debian 13 Proxmox Chezlepro
|
||||||
|
hosts: modeles_vm
|
||||||
|
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: "Ce template doit être une Debian 13."
|
||||||
|
|
||||||
|
- name: Afficher les partitions
|
||||||
|
ansible.builtin.command: lsblk -f
|
||||||
|
register: lsblk_output
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Résultat lsblk
|
||||||
|
ansible.builtin.debug:
|
||||||
|
var: lsblk_output.stdout_lines
|
||||||
|
|
||||||
|
- name: Vérifier l'absence de swap actif
|
||||||
|
ansible.builtin.command: swapon --show
|
||||||
|
register: swapon_output
|
||||||
|
changed_when: false
|
||||||
|
failed_when: swapon_output.stdout | length > 0
|
||||||
|
|
||||||
|
- name: Collecter les paquets installés
|
||||||
|
ansible.builtin.package_facts:
|
||||||
|
manager: auto
|
||||||
|
|
||||||
|
- name: Valider les paquets requis du template
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- "'sudo' in ansible_facts.packages"
|
||||||
|
- "'openssh-server' in ansible_facts.packages"
|
||||||
|
- "'qemu-guest-agent' in ansible_facts.packages"
|
||||||
|
- "'cloud-init' in ansible_facts.packages"
|
||||||
|
- "'cloud-guest-utils' in ansible_facts.packages"
|
||||||
|
- "'chrony' in ansible_facts.packages"
|
||||||
|
- "'apparmor' in ansible_facts.packages"
|
||||||
|
- "'auditd' in ansible_facts.packages"
|
||||||
|
- "'fail2ban' in ansible_facts.packages"
|
||||||
|
- "'nftables' in ansible_facts.packages"
|
||||||
|
- "'unattended-upgrades' in ansible_facts.packages"
|
||||||
|
fail_msg: "Un paquet requis du golden template est absent."
|
||||||
|
|
||||||
|
- name: Vérifier l'absence d'environnement graphique
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- "'task-desktop' not in ansible_facts.packages"
|
||||||
|
- "'xserver-xorg' not in ansible_facts.packages"
|
||||||
|
- "'gdm3' not in ansible_facts.packages"
|
||||||
|
- "'sddm' not in ansible_facts.packages"
|
||||||
|
- "'lightdm' not in ansible_facts.packages"
|
||||||
|
fail_msg: "Un environnement graphique semble installé."
|
||||||
|
|
||||||
|
- name: Collecter les services
|
||||||
|
ansible.builtin.service_facts:
|
||||||
|
|
||||||
|
- name: Valider les services de base
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ansible_facts.services['ssh.service'].state == 'running'
|
||||||
|
- ansible_facts.services['qemu-guest-agent.service'].state == 'running'
|
||||||
|
- ansible_facts.services['chrony.service'].state == 'running'
|
||||||
|
- ansible_facts.services['auditd.service'].state == 'running'
|
||||||
|
- ansible_facts.services['fail2ban.service'].state == 'running'
|
||||||
|
fail_msg: "Un service de base n'est pas actif."
|
||||||
|
|
||||||
|
- name: Vérifier que AppArmor est actif
|
||||||
|
ansible.builtin.command: aa-enabled
|
||||||
|
register: apparmor_state
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Valider l'état nftables du template
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ansible_facts.services['nftables.service'].state != 'running'
|
||||||
|
fail_msg: "nftables ne doit pas être actif par défaut dans le template."
|
||||||
|
|
||||||
|
- name: Vérifier cloud-init
|
||||||
|
ansible.builtin.command: cloud-init --version
|
||||||
|
register: cloud_init_version
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Afficher cloud-init
|
||||||
|
ansible.builtin.debug:
|
||||||
|
var: cloud_init_version.stdout
|
||||||
|
|
||||||
|
- name: Vérifier sudo NOPASSWD du compte Ansible
|
||||||
|
ansible.builtin.command: sudo -n true
|
||||||
|
become: false
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Collecter la configuration SSH effective
|
||||||
|
ansible.builtin.command: sshd -T
|
||||||
|
register: sshd_effective_config
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Valider le hardening SSH effectif
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- "'passwordauthentication no' in sshd_effective_config.stdout"
|
||||||
|
- "'kbdinteractiveauthentication no' in sshd_effective_config.stdout"
|
||||||
|
- "'permitrootlogin no' in sshd_effective_config.stdout"
|
||||||
|
- "'pubkeyauthentication yes' in sshd_effective_config.stdout"
|
||||||
|
- "'authenticationmethods publickey' in sshd_effective_config.stdout"
|
||||||
|
- "'x11forwarding no' in sshd_effective_config.stdout"
|
||||||
|
- "'allowtcpforwarding no' in sshd_effective_config.stdout"
|
||||||
|
- "'allowagentforwarding no' in sshd_effective_config.stdout"
|
||||||
|
- "'allowstreamlocalforwarding no' in sshd_effective_config.stdout"
|
||||||
|
- "'permittunnel no' in sshd_effective_config.stdout"
|
||||||
|
- "'permituserenvironment no' in sshd_effective_config.stdout"
|
||||||
|
- "'maxauthtries 3' in sshd_effective_config.stdout"
|
||||||
|
- "'logingracetime 20' in sshd_effective_config.stdout"
|
||||||
|
- "'maxsessions 2' in sshd_effective_config.stdout"
|
||||||
|
fail_msg: "La configuration SSH effective ne respecte pas le hardening attendu."
|
||||||
|
|
||||||
|
- name: Vérifier les erreurs critiques du boot courant
|
||||||
|
ansible.builtin.command: journalctl -b -p err..alert --no-pager
|
||||||
|
register: boot_errors
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Afficher les erreurs du boot courant
|
||||||
|
ansible.builtin.debug:
|
||||||
|
var: boot_errors.stdout_lines
|
||||||
|
|
@ -1,3 +1,79 @@
|
||||||
# Playbooks Proxmox
|
# Playbooks Proxmox
|
||||||
|
|
||||||
Espace réservé aux futurs playbooks.
|
Ces playbooks pilotent Proxmox par API depuis le poste Ansible.
|
||||||
|
|
||||||
|
Les valeurs Cloud-Init communes déjà définies sur le modèle Proxmox sont héritées par les clones. Set-OPS ne les redemande pas.
|
||||||
|
|
||||||
|
## Prérequis du poste Ansible
|
||||||
|
|
||||||
|
Le clonage Proxmox utilise les modules `community.general.proxmox_*`.
|
||||||
|
|
||||||
|
Le poste Ansible doit donc avoir :
|
||||||
|
|
||||||
|
- la collection Ansible `community.general` ;
|
||||||
|
- la bibliothèque Python `proxmoxer` disponible dans le Python utilisé par Ansible.
|
||||||
|
|
||||||
|
Sur Debian, installer généralement :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install python3-proxmoxer
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérification locale :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -c 'import proxmoxer'
|
||||||
|
```
|
||||||
|
|
||||||
|
Les paramètres non sensibles sont dans :
|
||||||
|
|
||||||
|
```text
|
||||||
|
inventories/lab/group_vars/proxmox.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Assistant terminal :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make config
|
||||||
|
```
|
||||||
|
|
||||||
|
Les secrets d'API doivent être dans un fichier Vault non versionné :
|
||||||
|
|
||||||
|
```text
|
||||||
|
inventories/lab/group_vars/proxmox.vault.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Créer le fichier depuis l'exemple, puis le chiffrer :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp inventories/lab/group_vars/proxmox.vault.yml.example inventories/lab/group_vars/proxmox.vault.yml
|
||||||
|
ansible-vault encrypt inventories/lab/group_vars/proxmox.vault.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Créer un clone Debian depuis le modèle :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make creer-vm \
|
||||||
|
HOTE=web-01 \
|
||||||
|
VMID=101 \
|
||||||
|
VLAN=12 \
|
||||||
|
ADRESSE_IP=192.168.12.101 \
|
||||||
|
PASSERELLE=192.168.12.1 \
|
||||||
|
GROUPES="serveurs_debian serveurs_durcis"
|
||||||
|
```
|
||||||
|
|
||||||
|
`VLAN` doit être saisi à chaque création de VM pour éviter de réutiliser par erreur un réseau d'un autre clone.
|
||||||
|
|
||||||
|
Le disque du clone hérite de la taille du modèle. Pour l'agrandir à la création, fournir explicitement une taille supérieure à celle du modèle :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make creer-vm HOTE=web-01 VMID=101 VLAN=12 ADRESSE_IP=192.168.12.101 PASSERELLE=192.168.12.1 TAILLE_DISQUE=64G GROUPES="serveurs_debian serveurs_durcis"
|
||||||
|
```
|
||||||
|
|
||||||
|
Proxmox ne permet pas de réduire un disque existant.
|
||||||
|
|
||||||
|
`creer-vm` clone la VM, applique les paramètres Cloud-Init et ajoute l'hôte à l'inventaire. La conformité Ansible reste séparée :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make deployer HOTE=web-01
|
||||||
|
```
|
||||||
|
|
|
||||||
202
playbooks/proxmox/cloner_vm_debian.yml
Normal file
202
playbooks/proxmox/cloner_vm_debian.yml
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
---
|
||||||
|
- name: Cloner une VM Debian depuis le modele Proxmox
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: false
|
||||||
|
become: false
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Verifier les fichiers de variables Proxmox optionnels
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- "{{ playbook_dir }}/../../inventories/lab/group_vars/proxmox.yml"
|
||||||
|
- "{{ playbook_dir }}/../../inventories/lab/group_vars/proxmox.vault.yml"
|
||||||
|
- "{{ playbook_dir }}/../../inventories/lab/group_vars/proxmox.local.yml"
|
||||||
|
register: proxmox_fichiers_variables
|
||||||
|
|
||||||
|
- name: Charger les variables Proxmox non sensibles disponibles
|
||||||
|
ansible.builtin.include_vars:
|
||||||
|
file: "{{ item.stat.path }}"
|
||||||
|
loop: "{{ proxmox_fichiers_variables.results }}"
|
||||||
|
when:
|
||||||
|
- item.stat.exists
|
||||||
|
- item.stat.path is not search('vault')
|
||||||
|
|
||||||
|
- name: Charger les secrets Proxmox Vault
|
||||||
|
block:
|
||||||
|
- name: Charger proxmox.vault.yml
|
||||||
|
ansible.builtin.include_vars:
|
||||||
|
file: "{{ item.stat.path }}"
|
||||||
|
loop: "{{ proxmox_fichiers_variables.results }}"
|
||||||
|
when:
|
||||||
|
- item.stat.exists
|
||||||
|
- item.stat.path is search('vault')
|
||||||
|
no_log: true
|
||||||
|
rescue:
|
||||||
|
- name: Expliquer l echec de chargement du Vault
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: >-
|
||||||
|
Impossible de charger inventories/lab/group_vars/proxmox.vault.yml.
|
||||||
|
Si le fichier est chiffre avec Ansible Vault, fournir son mot de passe
|
||||||
|
ou definir ANSIBLE_VAULT_PASSWORD_FILE avant de relancer make creer-vm.
|
||||||
|
|
||||||
|
- name: Appliquer les valeurs Proxmox avec repli environnement
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
proxmox_api_host_effectif: "{{ proxmox_api_host | default(lookup('env', 'PROXMOX_API_HOST'), true) }}"
|
||||||
|
proxmox_api_user_effectif: "{{ proxmox_api_user | default(lookup('env', 'PROXMOX_API_USER'), true) }}"
|
||||||
|
proxmox_api_token_id_effectif: "{{ proxmox_api_token_id | default(lookup('env', 'PROXMOX_API_TOKEN_ID'), true) }}"
|
||||||
|
proxmox_api_token_secret_effectif: "{{ proxmox_api_token_secret | default(lookup('env', 'PROXMOX_API_TOKEN_SECRET'), true) }}"
|
||||||
|
proxmox_api_port_effectif: "{{ proxmox_api_port | default(lookup('env', 'PROXMOX_API_PORT'), true) }}"
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Valider les parametres obligatoires Proxmox
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- proxmox_api_host_effectif | length > 0
|
||||||
|
- proxmox_api_user_effectif | length > 0
|
||||||
|
- proxmox_api_token_id_effectif | length > 0
|
||||||
|
- proxmox_api_token_secret_effectif | length > 0
|
||||||
|
- proxmox_clone_nom is defined
|
||||||
|
- proxmox_clone_nom | length > 0
|
||||||
|
- proxmox_clone_vmid_modele is defined
|
||||||
|
- proxmox_clone_vmid is defined
|
||||||
|
- proxmox_clone_noeud is defined
|
||||||
|
- proxmox_clone_noeud | length > 0
|
||||||
|
- proxmox_clone_ipconfig0 is defined
|
||||||
|
- proxmox_clone_ipconfig0 | length > 0
|
||||||
|
fail_msg: "Parametres Proxmox incomplets. Verifier proxmox.yml, proxmox.vault.yml et les variables make propres a la VM."
|
||||||
|
|
||||||
|
- name: Lire la cle publique SSH depuis le fichier fourni
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
proxmox_clone_sshkeys: "{{ lookup('ansible.builtin.file', proxmox_clone_cle_publique_fichier) }}"
|
||||||
|
when:
|
||||||
|
- proxmox_clone_cle_publique is not defined
|
||||||
|
- proxmox_clone_cle_publique_fichier is defined
|
||||||
|
- proxmox_clone_cle_publique_fichier | length > 0
|
||||||
|
|
||||||
|
- name: Utiliser la cle publique SSH fournie directement
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
proxmox_clone_sshkeys: "{{ proxmox_clone_cle_publique }}"
|
||||||
|
when:
|
||||||
|
- proxmox_clone_cle_publique is defined
|
||||||
|
- proxmox_clone_cle_publique | length > 0
|
||||||
|
|
||||||
|
- name: Construire les serveurs DNS Cloud-Init
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
proxmox_clone_nameservers: >-
|
||||||
|
{{
|
||||||
|
(proxmox_clone_dns | default('') | split(','))
|
||||||
|
| map('trim')
|
||||||
|
| reject('equalto', '')
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: Verifier la bibliotheque Python proxmoxer locale
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "{{ ansible_playbook_python }} -c 'import proxmoxer'"
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
register: proxmoxer_verification
|
||||||
|
|
||||||
|
- name: Refuser si proxmoxer est absent
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: >-
|
||||||
|
La bibliotheque Python proxmoxer est absente pour {{ ansible_playbook_python }}.
|
||||||
|
Installer le paquet systeme approprie, par exemple
|
||||||
|
sudo apt install python3-proxmoxer, ou installer proxmoxer dans
|
||||||
|
l'environnement Python utilise par Ansible, puis relancer make creer-vm.
|
||||||
|
when: proxmoxer_verification.rc != 0
|
||||||
|
|
||||||
|
- name: Cloner la VM depuis le modele
|
||||||
|
community.general.proxmox_kvm:
|
||||||
|
api_host: "{{ proxmox_api_host_effectif }}"
|
||||||
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
||||||
|
api_user: "{{ proxmox_api_user_effectif }}"
|
||||||
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
||||||
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
||||||
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
||||||
|
node: "{{ proxmox_clone_noeud }}"
|
||||||
|
clone: "{{ proxmox_clone_source_nom | default('modele-debian13') }}"
|
||||||
|
vmid: "{{ proxmox_clone_vmid_modele | int }}"
|
||||||
|
newid: "{{ proxmox_clone_vmid | int }}"
|
||||||
|
name: "{{ proxmox_clone_nom }}"
|
||||||
|
storage: "{{ proxmox_clone_stockage | default(omit, true) }}"
|
||||||
|
format: "{{ proxmox_clone_format | default(omit, true) }}"
|
||||||
|
full: "{{ proxmox_clone_complet | default(true) | bool }}"
|
||||||
|
timeout: "{{ proxmox_clone_timeout | default(600) | int }}"
|
||||||
|
|
||||||
|
- name: Ajuster le reseau de la VM clonee
|
||||||
|
community.general.proxmox_nic:
|
||||||
|
api_host: "{{ proxmox_api_host_effectif }}"
|
||||||
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
||||||
|
api_user: "{{ proxmox_api_user_effectif }}"
|
||||||
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
||||||
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
||||||
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
||||||
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
||||||
|
interface: "{{ proxmox_clone_interface | default('net0') }}"
|
||||||
|
model: virtio
|
||||||
|
bridge: "{{ proxmox_clone_pont }}"
|
||||||
|
tag: "{{ proxmox_clone_vlan | int if proxmox_clone_vlan is defined and proxmox_clone_vlan | string | length > 0 else omit }}"
|
||||||
|
firewall: "{{ proxmox_clone_parefeu_interface | default(false) | bool }}"
|
||||||
|
state: present
|
||||||
|
when:
|
||||||
|
- proxmox_clone_pont is defined
|
||||||
|
- proxmox_clone_pont | length > 0
|
||||||
|
|
||||||
|
- name: Agrandir le disque principal du clone
|
||||||
|
community.general.proxmox_disk:
|
||||||
|
api_host: "{{ proxmox_api_host_effectif }}"
|
||||||
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
||||||
|
api_user: "{{ proxmox_api_user_effectif }}"
|
||||||
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
||||||
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
||||||
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
||||||
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
||||||
|
disk: "{{ proxmox_clone_disque | default('scsi0') }}"
|
||||||
|
size: "{{ proxmox_clone_taille_disque }}"
|
||||||
|
state: resized
|
||||||
|
when:
|
||||||
|
- proxmox_clone_taille_disque is defined
|
||||||
|
- proxmox_clone_taille_disque | length > 0
|
||||||
|
|
||||||
|
- name: Configurer Cloud-Init sur le clone
|
||||||
|
community.general.proxmox_kvm:
|
||||||
|
api_host: "{{ proxmox_api_host_effectif }}"
|
||||||
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
||||||
|
api_user: "{{ proxmox_api_user_effectif }}"
|
||||||
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
||||||
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
||||||
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
||||||
|
node: "{{ proxmox_clone_noeud }}"
|
||||||
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
||||||
|
name: "{{ proxmox_clone_nom }}"
|
||||||
|
update: true
|
||||||
|
ciuser: "{{ proxmox_clone_ciuser | default(omit, true) }}"
|
||||||
|
sshkeys: "{{ proxmox_clone_sshkeys | default(omit) }}"
|
||||||
|
ipconfig:
|
||||||
|
ipconfig0: "{{ proxmox_clone_ipconfig0 }}"
|
||||||
|
nameservers: "{{ proxmox_clone_nameservers if proxmox_clone_nameservers | length > 0 else omit }}"
|
||||||
|
searchdomains: "{{ proxmox_clone_domaines_recherche | default(omit, true) }}"
|
||||||
|
agent: "enabled=1"
|
||||||
|
|
||||||
|
- name: Demarrer le clone
|
||||||
|
community.general.proxmox_kvm:
|
||||||
|
api_host: "{{ proxmox_api_host_effectif }}"
|
||||||
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
||||||
|
api_user: "{{ proxmox_api_user_effectif }}"
|
||||||
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
||||||
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
||||||
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
||||||
|
node: "{{ proxmox_clone_noeud }}"
|
||||||
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
||||||
|
name: "{{ proxmox_clone_nom }}"
|
||||||
|
state: started
|
||||||
|
when: proxmox_clone_demarrer | default(true) | bool
|
||||||
|
|
||||||
|
- name: Afficher le resume du clone
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg:
|
||||||
|
- "VM creee: {{ proxmox_clone_nom }} (VMID {{ proxmox_clone_vmid }})"
|
||||||
|
- "Cloud-Init ipconfig0: {{ proxmox_clone_ipconfig0 }}"
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
---
|
|
||||||
- name: Vérifier le template Debian 13 Proxmox Chezlepro
|
|
||||||
hosts: vm_templates
|
|
||||||
become: true
|
|
||||||
gather_facts: true
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Afficher les partitions
|
|
||||||
ansible.builtin.command: lsblk -f
|
|
||||||
register: lsblk_output
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Résultat lsblk
|
|
||||||
ansible.builtin.debug:
|
|
||||||
var: lsblk_output.stdout_lines
|
|
||||||
|
|
||||||
- name: Vérifier l'absence de swap actif
|
|
||||||
ansible.builtin.command: swapon --show
|
|
||||||
register: swapon_output
|
|
||||||
changed_when: false
|
|
||||||
failed_when: swapon_output.stdout | length > 0
|
|
||||||
|
|
||||||
- name: Collecter les services
|
|
||||||
ansible.builtin.service_facts:
|
|
||||||
|
|
||||||
- name: Valider les services de base
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- 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 de base n'est pas actif."
|
|
||||||
|
|
||||||
- name: Vérifier cloud-init
|
|
||||||
ansible.builtin.command: cloud-init --version
|
|
||||||
register: cloud_init_version
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Afficher cloud-init
|
|
||||||
ansible.builtin.debug:
|
|
||||||
var: cloud_init_version.stdout
|
|
||||||
|
|
||||||
- name: Vérifier les erreurs critiques du boot courant
|
|
||||||
ansible.builtin.command: journalctl -b -p err..alert --no-pager
|
|
||||||
register: boot_errors
|
|
||||||
changed_when: false
|
|
||||||
failed_when: false
|
|
||||||
|
|
||||||
- name: Afficher les erreurs du boot courant
|
|
||||||
ansible.builtin.debug:
|
|
||||||
var: boot_errors.stdout_lines
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
---
|
---
|
||||||
chezlepro_apparmor_enabled: true
|
apparmor_enabled: true
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,5 @@
|
||||||
name: apparmor
|
name: apparmor
|
||||||
enabled: true
|
enabled: true
|
||||||
state: started
|
state: started
|
||||||
when: chezlepro_apparmor_enabled | bool
|
when: apparmor_enabled | bool
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
---
|
---
|
||||||
chezlepro_auditd_enabled: true
|
auditd_enabled: true
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,12 @@
|
||||||
group: root
|
group: root
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify: Restart auditd
|
notify: Restart auditd
|
||||||
when: chezlepro_auditd_enabled | bool
|
when: auditd_enabled | bool
|
||||||
|
|
||||||
- name: Activer auditd
|
- name: Activer auditd
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: auditd
|
name: auditd
|
||||||
enabled: true
|
enabled: true
|
||||||
state: started
|
state: started
|
||||||
when: chezlepro_auditd_enabled | bool
|
when: auditd_enabled | bool
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
---
|
|
||||||
- name: Installer chrony
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name: chrony
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Activer et démarrer chrony
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: chrony
|
|
||||||
enabled: true
|
|
||||||
state: started
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
cloud_init_ssh_pwauth: true
|
|
||||||
cloud_init_manage_etc_hosts: true
|
|
||||||
cloud_init_disable_root: true
|
|
||||||
cloud_init_ssh_deletekeys: true
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
- name: Installer cloud-init et cloud-guest-utils
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- cloud-init
|
|
||||||
- cloud-guest-utils
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Déployer la configuration cloud-init Chezlepro
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: 99_chezlepro.cfg.j2
|
|
||||||
dest: /etc/cloud/cloud.cfg.d/99_chezlepro.cfg
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Activer les services cloud-init Debian 13
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: "{{ item }}"
|
|
||||||
enabled: true
|
|
||||||
loop:
|
|
||||||
- cloud-init-local.service
|
|
||||||
- cloud-init-main.service
|
|
||||||
- cloud-init-network.service
|
|
||||||
- cloud-config.service
|
|
||||||
- cloud-final.service
|
|
||||||
failed_when: false
|
|
||||||
|
|
||||||
- name: Vérifier cloud-init
|
|
||||||
ansible.builtin.command: cloud-init --version
|
|
||||||
register: cloud_init_version
|
|
||||||
changed_when: false
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
# Managed by Ansible — Set-OPS
|
|
||||||
# Configuration cloud-init pour template Debian 13 Chezlepro.
|
|
||||||
|
|
||||||
datasource_list: [ NoCloud, ConfigDrive, None ]
|
|
||||||
|
|
||||||
preserve_hostname: false
|
|
||||||
manage_etc_hosts: {{ cloud_init_manage_etc_hosts | bool | lower }}
|
|
||||||
disable_root: {{ cloud_init_disable_root | bool | lower }}
|
|
||||||
ssh_pwauth: {{ cloud_init_ssh_pwauth | bool | lower }}
|
|
||||||
|
|
||||||
ssh_deletekeys: {{ cloud_init_ssh_deletekeys | bool | lower }}
|
|
||||||
ssh_genkeytypes:
|
|
||||||
- rsa
|
|
||||||
- ecdsa
|
|
||||||
- ed25519
|
|
||||||
|
|
||||||
growpart:
|
|
||||||
mode: auto
|
|
||||||
devices:
|
|
||||||
- /
|
|
||||||
ignore_growroot_disabled: false
|
|
||||||
|
|
||||||
resize_rootfs: true
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
chezlepro_common_packages: []
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
---
|
|
||||||
- name: Mettre à jour le cache APT
|
|
||||||
ansible.builtin.apt:
|
|
||||||
update_cache: true
|
|
||||||
cache_valid_time: 3600
|
|
||||||
|
|
||||||
- name: Appliquer les mises à jour disponibles
|
|
||||||
ansible.builtin.apt:
|
|
||||||
upgrade: full
|
|
||||||
|
|
||||||
- name: Installer les paquets communs
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name: "{{ chezlepro_common_packages }}"
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Supprimer les dépendances devenues inutiles
|
|
||||||
ansible.builtin.apt:
|
|
||||||
autoremove: true
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
- name: Déployer le MOTD Chezlepro
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: motd.j2
|
|
||||||
dest: /etc/motd
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0644"
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
Système Chezlepro
|
|
||||||
Gestion : Set-OPS / Ansible
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
---
|
|
||||||
- name: Installer qemu-guest-agent
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name: qemu-guest-agent
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Activer et démarrer qemu-guest-agent
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: qemu-guest-agent
|
|
||||||
enabled: true
|
|
||||||
state: started
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
cloud_init_ssh_pwauth: true
|
cloud_init_ssh_pwauth: false
|
||||||
cloud_init_manage_etc_hosts: true
|
cloud_init_manage_etc_hosts: true
|
||||||
cloud_init_disable_root: true
|
cloud_init_disable_root: true
|
||||||
cloud_init_ssh_deletekeys: true
|
cloud_init_ssh_deletekeys: true
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,48 @@
|
||||||
---
|
---
|
||||||
chezlepro_common_packages: []
|
common_packages_list:
|
||||||
|
- sudo
|
||||||
|
- openssh-server
|
||||||
|
- qemu-guest-agent
|
||||||
|
- cloud-init
|
||||||
|
- cloud-guest-utils
|
||||||
|
- python3
|
||||||
|
- python3-apt
|
||||||
|
- python3-pip
|
||||||
|
- acl
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- ca-certificates
|
||||||
|
- gnupg
|
||||||
|
- git
|
||||||
|
- vim
|
||||||
|
- nano
|
||||||
|
- bash-completion
|
||||||
|
- tmux
|
||||||
|
- rsync
|
||||||
|
- unzip
|
||||||
|
- zip
|
||||||
|
- tar
|
||||||
|
- jq
|
||||||
|
- htop
|
||||||
|
- iotop
|
||||||
|
- iftop
|
||||||
|
- sysstat
|
||||||
|
- lsof
|
||||||
|
- ncdu
|
||||||
|
- tree
|
||||||
|
- file
|
||||||
|
- less
|
||||||
|
- dnsutils
|
||||||
|
- iproute2
|
||||||
|
- iputils-ping
|
||||||
|
- net-tools
|
||||||
|
- traceroute
|
||||||
|
- mtr-tiny
|
||||||
|
- tcpdump
|
||||||
|
- netcat-openbsd
|
||||||
|
- socat
|
||||||
|
- chrony
|
||||||
|
- logrotate
|
||||||
|
- unattended-upgrades
|
||||||
|
- apt-listchanges
|
||||||
|
- needrestart
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
- name: Installer les paquets communs
|
- name: Installer les paquets communs
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
name: "{{ chezlepro_common_packages }}"
|
name: "{{ common_packages_list }}"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Supprimer les dépendances devenues inutiles
|
- name: Supprimer les dépendances devenues inutiles
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
---
|
---
|
||||||
chezlepro_disable_core_dumps: true
|
core_dumps_disable: true
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
when: chezlepro_disable_core_dumps | bool
|
when: core_dumps_disable | bool
|
||||||
|
|
||||||
- name: Configurer systemd-coredump si présent
|
- name: Configurer systemd-coredump si présent
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
|
|
@ -15,5 +15,5 @@
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
when: chezlepro_disable_core_dumps | bool
|
when: core_dumps_disable | bool
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
chezlepro_fail2ban_enabled: true
|
fail2ban_ssh_enabled: true
|
||||||
chezlepro_fail2ban_bantime: "1h"
|
fail2ban_ssh_bantime: "1h"
|
||||||
chezlepro_fail2ban_findtime: "10m"
|
fail2ban_ssh_findtime: "10m"
|
||||||
chezlepro_fail2ban_maxretry: 5
|
fail2ban_ssh_maxretry: 5
|
||||||
chezlepro_ssh_port: 22
|
fail2ban_ssh_port: 22
|
||||||
|
|
|
||||||
|
|
@ -26,4 +26,4 @@
|
||||||
name: fail2ban
|
name: fail2ban
|
||||||
enabled: true
|
enabled: true
|
||||||
state: started
|
state: started
|
||||||
when: chezlepro_fail2ban_enabled | bool
|
when: fail2ban_ssh_enabled | bool
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
# Managed by Ansible — Set-OPS
|
# Managed by Ansible — Set-OPS
|
||||||
|
|
||||||
[sshd]
|
[sshd]
|
||||||
enabled = {{ 'true' if chezlepro_fail2ban_enabled | bool else 'false' }}
|
enabled = {{ 'true' if fail2ban_ssh_enabled | bool else 'false' }}
|
||||||
port = {{ chezlepro_ssh_port }}
|
port = {{ fail2ban_ssh_port }}
|
||||||
backend = systemd
|
backend = systemd
|
||||||
maxretry = {{ chezlepro_fail2ban_maxretry }}
|
maxretry = {{ fail2ban_ssh_maxretry }}
|
||||||
findtime = {{ chezlepro_fail2ban_findtime }}
|
findtime = {{ fail2ban_ssh_findtime }}
|
||||||
bantime = {{ chezlepro_fail2ban_bantime }}
|
bantime = {{ fail2ban_ssh_bantime }}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,13 @@
|
||||||
---
|
---
|
||||||
chezlepro_hardening_packages: []
|
hardening_packages_list:
|
||||||
|
- apparmor
|
||||||
|
- apparmor-utils
|
||||||
|
- auditd
|
||||||
|
- audispd-plugins
|
||||||
|
- fail2ban
|
||||||
|
- nftables
|
||||||
|
- unattended-upgrades
|
||||||
|
- apt-listchanges
|
||||||
|
- debsums
|
||||||
|
- needrestart
|
||||||
|
- libpam-pwquality
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
- name: Installer les paquets de hardening
|
- name: Installer les paquets de hardening
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
name: "{{ chezlepro_hardening_packages }}"
|
name: "{{ hardening_packages_list }}"
|
||||||
state: present
|
state: present
|
||||||
update_cache: true
|
update_cache: true
|
||||||
cache_valid_time: 3600
|
cache_valid_time: 3600
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
chezlepro_journald_system_max_use: "200M"
|
journald_system_max_use: "200M"
|
||||||
chezlepro_journald_runtime_max_use: "100M"
|
journald_runtime_max_use: "100M"
|
||||||
chezlepro_journald_max_retention_sec: "1month"
|
journald_max_retention_sec: "1month"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Managed by Ansible — Set-OPS
|
# Managed by Ansible — Set-OPS
|
||||||
[Journal]
|
[Journal]
|
||||||
SystemMaxUse={{ chezlepro_journald_system_max_use }}
|
SystemMaxUse={{ journald_system_max_use }}
|
||||||
RuntimeMaxUse={{ chezlepro_journald_runtime_max_use }}
|
RuntimeMaxUse={{ journald_runtime_max_use }}
|
||||||
MaxRetentionSec={{ chezlepro_journald_max_retention_sec }}
|
MaxRetentionSec={{ journald_max_retention_sec }}
|
||||||
Compress=yes
|
Compress=yes
|
||||||
Seal=yes
|
Seal=yes
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
chezlepro_nftables_enabled: false
|
nftables_baseline_enabled: false
|
||||||
chezlepro_firewall_allow_ssh: true
|
nftables_baseline_allow_ssh: true
|
||||||
chezlepro_firewall_allow_icmp: true
|
nftables_baseline_allow_icmp: true
|
||||||
chezlepro_firewall_input_policy: "drop"
|
nftables_baseline_input_policy: "drop"
|
||||||
chezlepro_firewall_forward_policy: "drop"
|
nftables_baseline_forward_policy: "drop"
|
||||||
chezlepro_firewall_output_policy: "accept"
|
nftables_baseline_output_policy: "accept"
|
||||||
chezlepro_ssh_port: 22
|
nftables_baseline_ssh_port: 22
|
||||||
chezlepro_firewall_extra_tcp_ports: []
|
nftables_baseline_extra_tcp_ports: []
|
||||||
chezlepro_firewall_extra_udp_ports: []
|
nftables_baseline_extra_udp_ports: []
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,19 @@
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
notify: Reload nftables
|
notify: Reload nftables
|
||||||
when: chezlepro_nftables_enabled | bool
|
when: nftables_baseline_enabled | bool
|
||||||
|
|
||||||
- name: Activer nftables si demandé
|
- name: Activer nftables si demandé
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: nftables
|
name: nftables
|
||||||
enabled: true
|
enabled: true
|
||||||
state: started
|
state: started
|
||||||
when: chezlepro_nftables_enabled | bool
|
when: nftables_baseline_enabled | bool
|
||||||
|
|
||||||
- name: Désactiver nftables si demandé
|
- name: Désactiver nftables si demandé
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: nftables
|
name: nftables
|
||||||
enabled: false
|
enabled: false
|
||||||
state: stopped
|
state: stopped
|
||||||
when: not (chezlepro_nftables_enabled | bool)
|
when: not (nftables_baseline_enabled | bool)
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
|
||||||
|
|
@ -5,35 +5,35 @@ flush ruleset
|
||||||
|
|
||||||
table inet chezlepro_filter {
|
table inet chezlepro_filter {
|
||||||
chain input {
|
chain input {
|
||||||
type filter hook input priority 0; policy {{ chezlepro_firewall_input_policy }};
|
type filter hook input priority 0; policy {{ nftables_baseline_input_policy }};
|
||||||
|
|
||||||
iif "lo" accept
|
iif "lo" accept
|
||||||
ct state established,related accept
|
ct state established,related accept
|
||||||
ct state invalid drop
|
ct state invalid drop
|
||||||
|
|
||||||
{% if chezlepro_firewall_allow_icmp | bool %}
|
{% if nftables_baseline_allow_icmp | bool %}
|
||||||
ip protocol icmp accept
|
ip protocol icmp accept
|
||||||
ip6 nexthdr icmpv6 accept
|
ip6 nexthdr icmpv6 accept
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if chezlepro_firewall_allow_ssh | bool %}
|
{% if nftables_baseline_allow_ssh | bool %}
|
||||||
tcp dport {{ chezlepro_ssh_port }} accept
|
tcp dport {{ nftables_baseline_ssh_port }} accept
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for port in chezlepro_firewall_extra_tcp_ports %}
|
{% for port in nftables_baseline_extra_tcp_ports %}
|
||||||
tcp dport {{ port }} accept
|
tcp dport {{ port }} accept
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% for port in chezlepro_firewall_extra_udp_ports %}
|
{% for port in nftables_baseline_extra_udp_ports %}
|
||||||
udp dport {{ port }} accept
|
udp dport {{ port }} accept
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
}
|
}
|
||||||
|
|
||||||
chain forward {
|
chain forward {
|
||||||
type filter hook forward priority 0; policy {{ chezlepro_firewall_forward_policy }};
|
type filter hook forward priority 0; policy {{ nftables_baseline_forward_policy }};
|
||||||
}
|
}
|
||||||
|
|
||||||
chain output {
|
chain output {
|
||||||
type filter hook output priority 0; policy {{ chezlepro_firewall_output_policy }};
|
type filter hook output priority 0; policy {{ nftables_baseline_output_policy }};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
---
|
|
||||||
chezlepro_ssh_password_authentication: "yes"
|
|
||||||
chezlepro_ssh_permit_root_login: "no"
|
|
||||||
chezlepro_ssh_pubkey_authentication: "yes"
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
---
|
|
||||||
- name: Validate and reload ssh
|
|
||||||
block:
|
|
||||||
- name: Valider la configuration SSH
|
|
||||||
ansible.builtin.command: sshd -t
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Recharger SSH
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: ssh
|
|
||||||
state: reloaded
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
---
|
|
||||||
- name: Installer openssh-server
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name: openssh-server
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Créer le répertoire sshd_config.d
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /etc/ssh/sshd_config.d
|
|
||||||
state: directory
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0755"
|
|
||||||
|
|
||||||
- name: Déployer la configuration SSH Chezlepro
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: 10-chezlepro.conf.j2
|
|
||||||
dest: /etc/ssh/sshd_config.d/10-chezlepro.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0644"
|
|
||||||
notify: Validate and reload ssh
|
|
||||||
|
|
||||||
- name: Activer et démarrer SSH
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: ssh
|
|
||||||
enabled: true
|
|
||||||
state: started
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
# Managed by Ansible — Set-OPS
|
|
||||||
|
|
||||||
PermitRootLogin {{ chezlepro_ssh_permit_root_login }}
|
|
||||||
PubkeyAuthentication {{ chezlepro_ssh_pubkey_authentication }}
|
|
||||||
PasswordAuthentication {{ chezlepro_ssh_password_authentication }}
|
|
||||||
KbdInteractiveAuthentication no
|
|
||||||
X11Forwarding no
|
|
||||||
UsePAM yes
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
chezlepro_admin_user: ansible
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
---
|
|
||||||
- name: S'assurer que le groupe sudo existe
|
|
||||||
ansible.builtin.group:
|
|
||||||
name: sudo
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: S'assurer que le compte technique existe
|
|
||||||
ansible.builtin.user:
|
|
||||||
name: "{{ chezlepro_admin_user }}"
|
|
||||||
shell: /bin/bash
|
|
||||||
groups: sudo
|
|
||||||
append: true
|
|
||||||
create_home: true
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Déployer sudo NOPASSWD pour le compte technique
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: 90-ansible.j2
|
|
||||||
dest: "/etc/sudoers.d/90-{{ chezlepro_admin_user }}"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0440"
|
|
||||||
validate: "visudo -cf %s"
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
# Managed by Ansible — Set-OPS
|
|
||||||
{{ chezlepro_admin_user }} ALL=(ALL) NOPASSWD:ALL
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
chezlepro_ssh_password_authentication: "yes"
|
ssh_baseline_password_authentication: "no"
|
||||||
chezlepro_ssh_permit_root_login: "no"
|
ssh_baseline_permit_root_login: "no"
|
||||||
chezlepro_ssh_pubkey_authentication: "yes"
|
ssh_baseline_pubkey_authentication: "yes"
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
- name: Validate and reload ssh
|
- name: Valider la configuration SSH
|
||||||
block:
|
ansible.builtin.command: sshd -t
|
||||||
- name: Valider la configuration SSH
|
changed_when: false
|
||||||
ansible.builtin.command: sshd -t
|
listen: Validate and reload ssh
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Recharger SSH
|
- name: Recharger SSH
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: ssh
|
name: ssh
|
||||||
state: reloaded
|
state: reloaded
|
||||||
|
listen: Validate and reload ssh
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
# Managed by Ansible — Set-OPS
|
# Managed by Ansible — Set-OPS
|
||||||
|
|
||||||
PermitRootLogin {{ chezlepro_ssh_permit_root_login }}
|
PermitRootLogin {{ ssh_baseline_permit_root_login }}
|
||||||
PubkeyAuthentication {{ chezlepro_ssh_pubkey_authentication }}
|
PubkeyAuthentication {{ ssh_baseline_pubkey_authentication }}
|
||||||
PasswordAuthentication {{ chezlepro_ssh_password_authentication }}
|
PasswordAuthentication {{ ssh_baseline_password_authentication }}
|
||||||
|
AuthenticationMethods publickey
|
||||||
KbdInteractiveAuthentication no
|
KbdInteractiveAuthentication no
|
||||||
|
ChallengeResponseAuthentication no
|
||||||
|
PermitEmptyPasswords no
|
||||||
|
HostbasedAuthentication no
|
||||||
|
IgnoreRhosts yes
|
||||||
X11Forwarding no
|
X11Forwarding no
|
||||||
|
PermitUserEnvironment no
|
||||||
UsePAM yes
|
UsePAM yes
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
---
|
---
|
||||||
chezlepro_ssh_port: 22
|
ssh_hardening_port: 22
|
||||||
chezlepro_ssh_password_authentication: "yes"
|
ssh_hardening_password_authentication: "no"
|
||||||
chezlepro_ssh_permit_root_login: "no"
|
ssh_hardening_permit_root_login: "no"
|
||||||
chezlepro_ssh_pubkey_authentication: "yes"
|
ssh_hardening_pubkey_authentication: "yes"
|
||||||
chezlepro_ssh_client_alive_interval: 300
|
ssh_hardening_client_alive_interval: 300
|
||||||
chezlepro_ssh_client_alive_count_max: 2
|
ssh_hardening_client_alive_count_max: 2
|
||||||
chezlepro_ssh_max_auth_tries: 4
|
ssh_hardening_max_auth_tries: 3
|
||||||
chezlepro_ssh_login_grace_time: "30s"
|
ssh_hardening_login_grace_time: "20s"
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
- name: Validate and reload ssh
|
- name: Valider la configuration SSH
|
||||||
block:
|
ansible.builtin.command: sshd -t
|
||||||
- name: Valider la configuration SSH
|
changed_when: false
|
||||||
ansible.builtin.command: sshd -t
|
listen: Validate and reload ssh
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Recharger SSH
|
- name: Recharger SSH
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: ssh
|
name: ssh
|
||||||
state: reloaded
|
state: reloaded
|
||||||
|
listen: Validate and reload ssh
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,27 @@
|
||||||
# Managed by Ansible — Set-OPS
|
# Managed by Ansible — Set-OPS
|
||||||
|
|
||||||
Port {{ chezlepro_ssh_port }}
|
Port {{ ssh_hardening_port }}
|
||||||
PermitRootLogin {{ chezlepro_ssh_permit_root_login }}
|
PermitRootLogin {{ ssh_hardening_permit_root_login }}
|
||||||
PubkeyAuthentication {{ chezlepro_ssh_pubkey_authentication }}
|
PubkeyAuthentication {{ ssh_hardening_pubkey_authentication }}
|
||||||
PasswordAuthentication {{ chezlepro_ssh_password_authentication }}
|
PasswordAuthentication {{ ssh_hardening_password_authentication }}
|
||||||
|
AuthenticationMethods publickey
|
||||||
KbdInteractiveAuthentication no
|
KbdInteractiveAuthentication no
|
||||||
|
ChallengeResponseAuthentication no
|
||||||
PermitEmptyPasswords no
|
PermitEmptyPasswords no
|
||||||
|
HostbasedAuthentication no
|
||||||
|
IgnoreRhosts yes
|
||||||
X11Forwarding no
|
X11Forwarding no
|
||||||
AllowTcpForwarding no
|
AllowTcpForwarding no
|
||||||
AllowAgentForwarding no
|
AllowAgentForwarding no
|
||||||
ClientAliveInterval {{ chezlepro_ssh_client_alive_interval }}
|
AllowStreamLocalForwarding no
|
||||||
ClientAliveCountMax {{ chezlepro_ssh_client_alive_count_max }}
|
PermitTunnel no
|
||||||
MaxAuthTries {{ chezlepro_ssh_max_auth_tries }}
|
GatewayPorts no
|
||||||
LoginGraceTime {{ chezlepro_ssh_login_grace_time }}
|
PermitUserEnvironment no
|
||||||
|
PermitTTY yes
|
||||||
|
TCPKeepAlive no
|
||||||
|
ClientAliveInterval {{ ssh_hardening_client_alive_interval }}
|
||||||
|
ClientAliveCountMax {{ ssh_hardening_client_alive_count_max }}
|
||||||
|
MaxAuthTries {{ ssh_hardening_max_auth_tries }}
|
||||||
|
LoginGraceTime {{ ssh_hardening_login_grace_time }}
|
||||||
|
MaxSessions 2
|
||||||
|
MaxStartups 5:30:20
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
---
|
---
|
||||||
chezlepro_admin_user: ansible
|
sudo_ansible_admin_user: ansible
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
- name: S'assurer que le compte technique existe
|
- name: S'assurer que le compte technique existe
|
||||||
ansible.builtin.user:
|
ansible.builtin.user:
|
||||||
name: "{{ chezlepro_admin_user }}"
|
name: "{{ sudo_ansible_admin_user }}"
|
||||||
shell: /bin/bash
|
shell: /bin/bash
|
||||||
groups: sudo
|
groups: sudo
|
||||||
append: true
|
append: true
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
- name: Déployer sudo NOPASSWD pour le compte technique
|
- name: Déployer sudo NOPASSWD pour le compte technique
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: 90-ansible.j2
|
src: 90-ansible.j2
|
||||||
dest: "/etc/sudoers.d/90-{{ chezlepro_admin_user }}"
|
dest: "/etc/sudoers.d/90-{{ sudo_ansible_admin_user }}"
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0440"
|
mode: "0440"
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
# Managed by Ansible — Set-OPS
|
# Managed by Ansible — Set-OPS
|
||||||
{{ chezlepro_admin_user }} ALL=(ALL) NOPASSWD:ALL
|
{{ sudo_ansible_admin_user }} ALL=(ALL) NOPASSWD:ALL
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
chezlepro_sysctl_apply: true
|
sysctl_hardening_apply: true
|
||||||
chezlepro_sysctl_hardening_values:
|
sysctl_hardening_values:
|
||||||
fs.protected_hardlinks: 1
|
fs.protected_hardlinks: 1
|
||||||
fs.protected_symlinks: 1
|
fs.protected_symlinks: 1
|
||||||
fs.protected_fifos: 2
|
fs.protected_fifos: 2
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
notify: Reload sysctl
|
notify: Reload sysctl
|
||||||
when: chezlepro_sysctl_apply | bool
|
when: sysctl_hardening_apply | bool
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Managed by Ansible — Set-OPS
|
# Managed by Ansible — Set-OPS
|
||||||
|
|
||||||
{% for key, value in chezlepro_sysctl_hardening_values | dictsort %}
|
{% for key, value in sysctl_hardening_values | dictsort %}
|
||||||
{{ key }} = {{ value }}
|
{{ key }} = {{ value }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
---
|
---
|
||||||
chezlepro_disable_systemd_ssh_auto: true
|
systemd_ssh_auto_disable: true
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
when: chezlepro_disable_systemd_ssh_auto | bool
|
when: systemd_ssh_auto_disable | bool
|
||||||
notify: Update grub
|
notify: Update grub
|
||||||
|
|
||||||
- name: Supprimer le paramètre si désactivé
|
- name: Supprimer le paramètre si désactivé
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: /etc/default/grub.d/99-chezlepro-systemd-ssh-auto.cfg
|
path: /etc/default/grub.d/99-chezlepro-systemd-ssh-auto.cfg
|
||||||
state: absent
|
state: absent
|
||||||
when: not (chezlepro_disable_systemd_ssh_auto | bool)
|
when: not (systemd_ssh_auto_disable | bool)
|
||||||
notify: Update grub
|
notify: Update grub
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
---
|
---
|
||||||
confirm_template_cleanup: false
|
template_cleanup_confirm: false
|
||||||
chezlepro_admin_user: ansible
|
template_cleanup_admin_user: ansible
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
- name: Refuser le nettoyage sans confirmation explicite
|
- name: Refuser le nettoyage sans confirmation explicite
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- confirm_template_cleanup | bool
|
- template_cleanup_confirm | bool
|
||||||
fail_msg: "Nettoyage refusé. Relancer avec -e confirm_template_cleanup=true"
|
fail_msg: "Nettoyage refusé. Relancer avec -e template_cleanup_confirm=true"
|
||||||
|
|
||||||
- name: Nettoyer cloud-init
|
- name: Nettoyer cloud-init
|
||||||
ansible.builtin.command: cloud-init clean --logs
|
ansible.builtin.command: cloud-init clean --logs
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
state: absent
|
state: absent
|
||||||
loop:
|
loop:
|
||||||
- /root/.bash_history
|
- /root/.bash_history
|
||||||
- "/home/{{ chezlepro_admin_user }}/.bash_history"
|
- "/home/{{ template_cleanup_admin_user }}/.bash_history"
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
- name: Message final
|
- name: Message final
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
chezlepro_unattended_upgrades_enabled: true
|
unattended_upgrades_enabled: true
|
||||||
chezlepro_unattended_remove_unused_dependencies: true
|
unattended_upgrades_remove_unused_dependencies: true
|
||||||
chezlepro_unattended_automatic_reboot: false
|
unattended_upgrades_automatic_reboot: false
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Managed by Ansible — Set-OPS
|
// Managed by Ansible — Set-OPS
|
||||||
APT::Periodic::Update-Package-Lists "{{ 1 if chezlepro_unattended_upgrades_enabled | bool else 0 }}";
|
APT::Periodic::Update-Package-Lists "{{ 1 if unattended_upgrades_enabled | bool else 0 }}";
|
||||||
APT::Periodic::Unattended-Upgrade "{{ 1 if chezlepro_unattended_upgrades_enabled | bool else 0 }}";
|
APT::Periodic::Unattended-Upgrade "{{ 1 if unattended_upgrades_enabled | bool else 0 }}";
|
||||||
APT::Periodic::AutocleanInterval "7";
|
APT::Periodic::AutocleanInterval "7";
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ Unattended-Upgrade::Origins-Pattern {
|
||||||
};
|
};
|
||||||
|
|
||||||
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
||||||
Unattended-Upgrade::Remove-New-Unused-Dependencies "{{ 'true' if chezlepro_unattended_remove_unused_dependencies | bool else 'false' }}";
|
Unattended-Upgrade::Remove-New-Unused-Dependencies "{{ 'true' if unattended_upgrades_remove_unused_dependencies | bool else 'false' }}";
|
||||||
Unattended-Upgrade::Remove-Unused-Dependencies "{{ 'true' if chezlepro_unattended_remove_unused_dependencies | bool else 'false' }}";
|
Unattended-Upgrade::Remove-Unused-Dependencies "{{ 'true' if unattended_upgrades_remove_unused_dependencies | bool else 'false' }}";
|
||||||
Unattended-Upgrade::Automatic-Reboot "{{ 'true' if chezlepro_unattended_automatic_reboot | bool else 'false' }}";
|
Unattended-Upgrade::Automatic-Reboot "{{ 'true' if unattended_upgrades_automatic_reboot | bool else 'false' }}";
|
||||||
Unattended-Upgrade::SyslogEnable "true";
|
Unattended-Upgrade::SyslogEnable "true";
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
chezlepro_disable_systemd_ssh_auto: true
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
---
|
|
||||||
- name: Update grub
|
|
||||||
ansible.builtin.command: update-grub
|
|
||||||
changed_when: true
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
---
|
|
||||||
- name: Déployer le paramètre GRUB pour désactiver systemd.ssh_auto
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: 99-chezlepro-systemd-ssh-auto.cfg.j2
|
|
||||||
dest: /etc/default/grub.d/99-chezlepro-systemd-ssh-auto.cfg
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0644"
|
|
||||||
when: chezlepro_disable_systemd_ssh_auto | bool
|
|
||||||
notify: Update grub
|
|
||||||
|
|
||||||
- name: Supprimer le paramètre si désactivé dans les variables
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /etc/default/grub.d/99-chezlepro-systemd-ssh-auto.cfg
|
|
||||||
state: absent
|
|
||||||
when: not (chezlepro_disable_systemd_ssh_auto | bool)
|
|
||||||
notify: Update grub
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
# Managed by Ansible — Set-OPS
|
|
||||||
GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} systemd.ssh_auto=no"
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
confirm_template_cleanup: false
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
---
|
|
||||||
- name: Refuser le nettoyage sans confirmation explicite
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- confirm_template_cleanup | bool
|
|
||||||
fail_msg: "Nettoyage refusé. Relancer avec -e confirm_template_cleanup=true"
|
|
||||||
|
|
||||||
- name: Nettoyer cloud-init
|
|
||||||
ansible.builtin.command: cloud-init clean --logs
|
|
||||||
changed_when: true
|
|
||||||
|
|
||||||
- name: Nettoyer le cache APT
|
|
||||||
ansible.builtin.apt:
|
|
||||||
clean: true
|
|
||||||
|
|
||||||
- name: Supprimer les paquets devenus inutiles
|
|
||||||
ansible.builtin.apt:
|
|
||||||
autoremove: true
|
|
||||||
|
|
||||||
- name: Rotation des journaux systemd
|
|
||||||
ansible.builtin.command: journalctl --rotate
|
|
||||||
changed_when: true
|
|
||||||
failed_when: false
|
|
||||||
|
|
||||||
- name: Vider les anciens journaux systemd
|
|
||||||
ansible.builtin.command: journalctl --vacuum-time=1s
|
|
||||||
changed_when: true
|
|
||||||
failed_when: false
|
|
||||||
|
|
||||||
- name: Vider /etc/machine-id
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: /etc/machine-id
|
|
||||||
content: ""
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0444"
|
|
||||||
|
|
||||||
- name: Supprimer l'ancien machine-id D-Bus
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /var/lib/dbus/machine-id
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Recréer le lien D-Bus vers /etc/machine-id
|
|
||||||
ansible.builtin.file:
|
|
||||||
src: /etc/machine-id
|
|
||||||
dest: /var/lib/dbus/machine-id
|
|
||||||
state: link
|
|
||||||
force: true
|
|
||||||
|
|
||||||
- name: Message final
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg:
|
|
||||||
- "Nettoyage final terminé."
|
|
||||||
- "Éteindre la VM puis convertir en template Proxmox."
|
|
||||||
170
scripts/config_proxmox.py
Normal file
170
scripts/config_proxmox.py
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Assistant de configuration Proxmox pour Set-OPS."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from getpass import getpass
|
||||||
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
RACINE = Path(__file__).resolve().parents[1]
|
||||||
|
FICHIER_PROXMOX = RACINE / "inventories/lab/group_vars/proxmox.yml"
|
||||||
|
FICHIER_VAULT = RACINE / "inventories/lab/group_vars/proxmox.vault.yml"
|
||||||
|
|
||||||
|
|
||||||
|
VALEURS_DEFAUT = {
|
||||||
|
"proxmox_api_host": "",
|
||||||
|
"proxmox_api_user": "",
|
||||||
|
"proxmox_api_port": "",
|
||||||
|
"proxmox_validate_certs": False,
|
||||||
|
"proxmox_clone_noeud": "",
|
||||||
|
"proxmox_clone_vmid_modele": 9000,
|
||||||
|
"proxmox_clone_source_nom": "modele-debian13",
|
||||||
|
"proxmox_clone_stockage": "",
|
||||||
|
"proxmox_clone_format": "",
|
||||||
|
"proxmox_clone_complet": True,
|
||||||
|
"proxmox_clone_timeout": 600,
|
||||||
|
"proxmox_clone_disque": "scsi0",
|
||||||
|
"proxmox_clone_interface": "net0",
|
||||||
|
"proxmox_clone_pont": "vmbr0",
|
||||||
|
"proxmox_clone_parefeu_interface": False,
|
||||||
|
"proxmox_clone_demarrer": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LIBELLES = {
|
||||||
|
"proxmox_api_host": "Hote API Proxmox",
|
||||||
|
"proxmox_api_user": "Utilisateur API Proxmox",
|
||||||
|
"proxmox_api_port": "Port API Proxmox",
|
||||||
|
"proxmox_validate_certs": "Valider les certificats TLS",
|
||||||
|
"proxmox_clone_noeud": "Noeud Proxmox par defaut",
|
||||||
|
"proxmox_clone_vmid_modele": "VMID du modele Debian 13",
|
||||||
|
"proxmox_clone_source_nom": "Nom logique du modele",
|
||||||
|
"proxmox_clone_stockage": "Stockage Proxmox par defaut",
|
||||||
|
"proxmox_clone_format": "Format disque par defaut",
|
||||||
|
"proxmox_clone_complet": "Clone complet",
|
||||||
|
"proxmox_clone_timeout": "Timeout operations Proxmox",
|
||||||
|
"proxmox_clone_disque": "Disque principal",
|
||||||
|
"proxmox_clone_interface": "Interface reseau",
|
||||||
|
"proxmox_clone_pont": "Pont Proxmox",
|
||||||
|
"proxmox_clone_parefeu_interface": "Pare-feu interface Proxmox",
|
||||||
|
"proxmox_clone_demarrer": "Demarrer le clone apres creation",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def charger_yaml(path: Path) -> dict:
|
||||||
|
if not path.exists():
|
||||||
|
return {}
|
||||||
|
with path.open("r", encoding="utf-8") as fichier:
|
||||||
|
data = yaml.safe_load(fichier) or {}
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
raise ValueError(f"{path} ne contient pas une table YAML.")
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def ecrire_yaml(path: Path, data: dict) -> None:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with path.open("w", encoding="utf-8") as fichier:
|
||||||
|
fichier.write("---\n")
|
||||||
|
fichier.write("# Parametres non sensibles pour les operations Proxmox.\n")
|
||||||
|
fichier.write("# Les secrets API doivent aller dans proxmox.vault.yml.\n\n")
|
||||||
|
yaml.safe_dump(data, fichier, default_flow_style=False, sort_keys=False, allow_unicode=True)
|
||||||
|
|
||||||
|
|
||||||
|
def demander(identifiant: str, courant: object) -> object:
|
||||||
|
libelle = LIBELLES[identifiant]
|
||||||
|
if isinstance(courant, bool):
|
||||||
|
defaut = "oui" if courant else "non"
|
||||||
|
reponse = input(f"{libelle} [{defaut}] : ").strip().lower()
|
||||||
|
if not reponse:
|
||||||
|
return courant
|
||||||
|
return reponse in {"o", "oui", "y", "yes", "true", "1"}
|
||||||
|
|
||||||
|
reponse = input(f"{libelle} [{courant}] : ").strip()
|
||||||
|
if not reponse:
|
||||||
|
return courant
|
||||||
|
|
||||||
|
if isinstance(courant, int):
|
||||||
|
return int(reponse)
|
||||||
|
return reponse
|
||||||
|
|
||||||
|
|
||||||
|
def configurer_proxmox() -> None:
|
||||||
|
courant = VALEURS_DEFAUT | charger_yaml(FICHIER_PROXMOX)
|
||||||
|
nouveau = {}
|
||||||
|
|
||||||
|
print("Configuration Proxmox non sensible")
|
||||||
|
print("Entrer pour conserver la valeur entre crochets.\n")
|
||||||
|
print("Les valeurs Cloud-Init deja portees par le modele ne sont pas redemandees.\n")
|
||||||
|
|
||||||
|
for identifiant in VALEURS_DEFAUT:
|
||||||
|
nouveau[identifiant] = demander(identifiant, courant.get(identifiant, VALEURS_DEFAUT[identifiant]))
|
||||||
|
|
||||||
|
ecrire_yaml(FICHIER_PROXMOX, nouveau)
|
||||||
|
print(f"\nEcrit: {FICHIER_PROXMOX.relative_to(RACINE)}")
|
||||||
|
|
||||||
|
|
||||||
|
def demander_oui_non(question: str, defaut: bool = False) -> bool:
|
||||||
|
suffixe = "O/n" if defaut else "o/N"
|
||||||
|
reponse = input(f"{question} [{suffixe}] : ").strip().lower()
|
||||||
|
if not reponse:
|
||||||
|
return defaut
|
||||||
|
return reponse in {"o", "oui", "y", "yes", "true", "1"}
|
||||||
|
|
||||||
|
|
||||||
|
def configurer_vault() -> None:
|
||||||
|
if not demander_oui_non("Configurer les secrets API Proxmox maintenant"):
|
||||||
|
return
|
||||||
|
|
||||||
|
if FICHIER_VAULT.exists():
|
||||||
|
print(f"Ouverture du Vault existant: {FICHIER_VAULT.relative_to(RACINE)}")
|
||||||
|
subprocess.run(["ansible-vault", "edit", str(FICHIER_VAULT)], check=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
token_id = input("Token ID Proxmox [set-ops] : ").strip() or "set-ops"
|
||||||
|
token_secret = getpass("Token secret Proxmox : ").strip()
|
||||||
|
if not token_secret:
|
||||||
|
print("Secret vide: Vault non cree.")
|
||||||
|
return
|
||||||
|
|
||||||
|
FICHIER_VAULT.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
try:
|
||||||
|
fd = os.open(FICHIER_VAULT, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
|
||||||
|
with os.fdopen(fd, "w", encoding="utf-8") as fichier:
|
||||||
|
yaml.safe_dump(
|
||||||
|
{
|
||||||
|
"proxmox_api_token_id": token_id,
|
||||||
|
"proxmox_api_token_secret": token_secret,
|
||||||
|
},
|
||||||
|
fichier,
|
||||||
|
default_flow_style=False,
|
||||||
|
sort_keys=False,
|
||||||
|
)
|
||||||
|
subprocess.run(["ansible-vault", "encrypt", str(FICHIER_VAULT)], check=True)
|
||||||
|
print(f"Vault cree: {FICHIER_VAULT.relative_to(RACINE)}")
|
||||||
|
except Exception:
|
||||||
|
if FICHIER_VAULT.exists():
|
||||||
|
FICHIER_VAULT.unlink()
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
try:
|
||||||
|
configurer_proxmox()
|
||||||
|
configurer_vault()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nConfiguration interrompue.", file=sys.stderr)
|
||||||
|
return 130
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"erreur: {exc}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
191
scripts/inventory_host.py
Normal file
191
scripts/inventory_host.py
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Gere les hotes d'un inventaire Ansible statique Set-OPS."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
def charger_inventaire(path: Path) -> dict:
|
||||||
|
if not path.exists():
|
||||||
|
return {"all": {"children": {}}}
|
||||||
|
|
||||||
|
with path.open("r", encoding="utf-8") as inventory_file:
|
||||||
|
data = yaml.safe_load(inventory_file) or {}
|
||||||
|
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
raise ValueError(f"{path} ne contient pas une table YAML.")
|
||||||
|
|
||||||
|
data.setdefault("all", {})
|
||||||
|
data["all"].setdefault("children", {})
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def ecrire_inventaire(path: Path, data: dict) -> None:
|
||||||
|
with path.open("w", encoding="utf-8") as inventory_file:
|
||||||
|
yaml.safe_dump(
|
||||||
|
data,
|
||||||
|
inventory_file,
|
||||||
|
default_flow_style=False,
|
||||||
|
sort_keys=False,
|
||||||
|
allow_unicode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def enfants(data: dict) -> dict:
|
||||||
|
return data.setdefault("all", {}).setdefault("children", {})
|
||||||
|
|
||||||
|
|
||||||
|
def assurer_groupe(data: dict, group: str) -> dict:
|
||||||
|
group_data = enfants(data).setdefault(group, {})
|
||||||
|
group_data.setdefault("hosts", {})
|
||||||
|
return group_data
|
||||||
|
|
||||||
|
|
||||||
|
def variables_hote(data: dict, host: str) -> dict:
|
||||||
|
merged: dict = {}
|
||||||
|
for group_data in enfants(data).values():
|
||||||
|
hosts = group_data.get("hosts", {})
|
||||||
|
if host in hosts and isinstance(hosts[host], dict):
|
||||||
|
merged.update(hosts[host])
|
||||||
|
return merged
|
||||||
|
|
||||||
|
|
||||||
|
def groupes_hote(data: dict, host: str) -> list[str]:
|
||||||
|
groups: list[str] = []
|
||||||
|
for group, group_data in enfants(data).items():
|
||||||
|
if host in group_data.get("hosts", {}):
|
||||||
|
groups.append(group)
|
||||||
|
return groups
|
||||||
|
|
||||||
|
|
||||||
|
def retirer_hote_de_tous_les_groupes(data: dict, host: str) -> None:
|
||||||
|
for group_data in enfants(data).values():
|
||||||
|
group_data.get("hosts", {}).pop(host, None)
|
||||||
|
|
||||||
|
|
||||||
|
def ajouter_hote(data: dict, host: str, groups: list[str], ip: str | None, ansible_user: str | None) -> None:
|
||||||
|
vars_for_host = variables_hote(data, host)
|
||||||
|
if ip:
|
||||||
|
vars_for_host["ansible_host"] = ip
|
||||||
|
if ansible_user:
|
||||||
|
vars_for_host["ansible_user"] = ansible_user
|
||||||
|
|
||||||
|
for group in groups:
|
||||||
|
assurer_groupe(data, group)["hosts"][host] = dict(vars_for_host)
|
||||||
|
|
||||||
|
|
||||||
|
def definir_groupes_hote(data: dict, host: str, groups: list[str]) -> None:
|
||||||
|
vars_for_host = variables_hote(data, host)
|
||||||
|
if not groupes_hote(data, host):
|
||||||
|
raise ValueError(f"Hote absent de l'inventaire: {host}")
|
||||||
|
retirer_hote_de_tous_les_groupes(data, host)
|
||||||
|
for group in groups:
|
||||||
|
assurer_groupe(data, group)["hosts"][host] = dict(vars_for_host)
|
||||||
|
|
||||||
|
|
||||||
|
def analyser_groupes(raw_groups: str) -> list[str]:
|
||||||
|
groups = [group.strip() for group in raw_groups.replace(",", " ").split() if group.strip()]
|
||||||
|
if not groups:
|
||||||
|
raise ValueError("Au moins un groupe est requis.")
|
||||||
|
return groups
|
||||||
|
|
||||||
|
|
||||||
|
def afficher_hote(data: dict, host: str) -> None:
|
||||||
|
groups = groupes_hote(data, host)
|
||||||
|
if not groups:
|
||||||
|
raise ValueError(f"Hote absent de l'inventaire: {host}")
|
||||||
|
|
||||||
|
yaml.safe_dump(
|
||||||
|
{
|
||||||
|
"hote": host,
|
||||||
|
"groupes": groups,
|
||||||
|
"variables": variables_hote(data, host),
|
||||||
|
},
|
||||||
|
sys.stdout,
|
||||||
|
default_flow_style=False,
|
||||||
|
sort_keys=False,
|
||||||
|
allow_unicode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def afficher_playbooks_hote(data: dict, host: str, playbook_dir: Path) -> None:
|
||||||
|
groups = groupes_hote(data, host)
|
||||||
|
if not groups:
|
||||||
|
raise ValueError(f"Hote absent de l'inventaire: {host}")
|
||||||
|
|
||||||
|
missing_playbooks: list[str] = []
|
||||||
|
playbooks: list[Path] = []
|
||||||
|
|
||||||
|
for group in groups:
|
||||||
|
playbook = playbook_dir / f"{group}.yml"
|
||||||
|
if playbook.exists():
|
||||||
|
playbooks.append(playbook)
|
||||||
|
else:
|
||||||
|
missing_playbooks.append(group)
|
||||||
|
|
||||||
|
if missing_playbooks:
|
||||||
|
missing = ", ".join(missing_playbooks)
|
||||||
|
raise ValueError(f"Playbook de groupe manquant pour: {missing}")
|
||||||
|
|
||||||
|
for playbook in playbooks:
|
||||||
|
print(playbook)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Gere les hotes d'un inventaire Ansible statique Set-OPS.")
|
||||||
|
parser.add_argument("--inventaire", required=True, type=Path)
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||||
|
|
||||||
|
add_parser = subparsers.add_parser("ajouter", help="Ajoute ou met a jour un hote dans un ou plusieurs groupes.")
|
||||||
|
add_parser.add_argument("--hote", required=True)
|
||||||
|
add_parser.add_argument("--groupes", required=True)
|
||||||
|
add_parser.add_argument("--adresse-ip")
|
||||||
|
add_parser.add_argument("--utilisateur-ansible")
|
||||||
|
|
||||||
|
groups_parser = subparsers.add_parser("definir-groupes", help="Remplace l'appartenance aux groupes pour un hote.")
|
||||||
|
groups_parser.add_argument("--hote", required=True)
|
||||||
|
groups_parser.add_argument("--groupes", required=True)
|
||||||
|
|
||||||
|
show_parser = subparsers.add_parser("afficher", help="Affiche les groupes et variables d'un hote.")
|
||||||
|
show_parser.add_argument("--hote", required=True)
|
||||||
|
|
||||||
|
playbooks_parser = subparsers.add_parser("playbooks", help="Affiche les playbooks de groupes pour un hote.")
|
||||||
|
playbooks_parser.add_argument("--hote", required=True)
|
||||||
|
playbooks_parser.add_argument("--dossier-playbooks", required=True, type=Path)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = charger_inventaire(args.inventaire)
|
||||||
|
|
||||||
|
if args.command == "ajouter":
|
||||||
|
ajouter_hote(
|
||||||
|
data,
|
||||||
|
args.hote,
|
||||||
|
analyser_groupes(args.groupes),
|
||||||
|
args.adresse_ip,
|
||||||
|
args.utilisateur_ansible,
|
||||||
|
)
|
||||||
|
ecrire_inventaire(args.inventaire, data)
|
||||||
|
elif args.command == "definir-groupes":
|
||||||
|
definir_groupes_hote(data, args.hote, analyser_groupes(args.groupes))
|
||||||
|
ecrire_inventaire(args.inventaire, data)
|
||||||
|
elif args.command == "afficher":
|
||||||
|
afficher_hote(data, args.hote)
|
||||||
|
elif args.command == "playbooks":
|
||||||
|
afficher_playbooks_hote(data, args.hote, args.dossier_playbooks)
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"erreur: {exc}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in a new issue