Documentation · version 0.4.0
Asgard Forge
Déployez une machine virtuelle Proxmox depuis une page web. Forge exécute la configuration Packer → OpenTofu → Ansible de votre dépôt GitLab telle quelle : GitLab reste la seule source de vérité.
1 Présentation
Forge est un conteneur Docker que vous installez sur une VM Linux de votre réseau. Il n'a aucune copie de votre infrastructure as code : à chaque exécution, il télécharge votre dépôt GitLab au commit exact et lance les outils sur ces fichiers.
- OpenTofu crée la VM en clonant le template Proxmox (dossier Terraform du dépôt).
- Ansible la configure ensuite (dossier Ansible du dépôt) : réseau, comptes, swap, langue, agents…
- Packer reconstruit le template quand vous le demandez (dossier Packer du dépôt).
- Le formulaire est généré à partir des fichiers : une variable ajoutée dans GitLab apparaît toute seule dans Forge.
Navigateur ──▶ Forge :8080 (VM Linux, docker, réseau de l'hôte)
│
├─▶ GitLab archive du dépôt au commit · variables CI/CD · un état Terraform par VM
├─▶ Proxmox listes (nœuds, stockages, templates, étiquettes) · contrôles · clonage
├─▶ nouvelle VM OpenTofu → attente SSH → Ansible → agents
└─▶ Argos · Wazuh · ntfy · Discord (facultatif)
Chaque VM a son propre état Terraform dans GitLab (forge-<vmid>-<nom>) : déployer une machine n'en détruit jamais une autre.
2 Prérequis
- VM Linux avec Docker et docker compose (amd64 ou arm64), 2 Go de RAM et une vingtaine de Go de disque (caches des providers et plugins). Elle doit joindre GitLab, Proxmox et le réseau des futures VM (SSH).
- Un dépôt GitLab organisé en trois dossiers (ex.
01_packer/,02_terraform/,03_ansible/) avec un.gitlab-ci.yml: Forge y lit les dossiers, les valeurs par défaut et la commande Ansible. - Un jeton d'accès de projet GitLab : rôle Maintainer, portée
api(lecture du dépôt et des variables CI/CD, écriture des états Terraform). - Dans les variables CI/CD du projet :
PROXMOX_HOST(URL de l'API, avec/api2/json),PROXMOX_TOKEN_IDetPROXMOX_TOKEN_SECRET— les mêmes que pour le pipeline. - Un template Proxmox avec cloud-init et l'agent QEMU (ou l'ISO pour le construire avec Packer).
3 Installation
L'image est publiée sur le Docker Hub (anpms/asgard-forge:latest, amd64 et arm64, chaque version aussi sous son numéro) : elle contient Forge, OpenTofu, Packer et Ansible — rien à installer sur la VM à part Docker.
-
1 Préparer le dossier
mkdir -p ~/asgard-forge/data && cd ~/asgard-forge # compose.yml : dépôt asgard-forge, dossier deploy/ — aucun .env -
2 Le
compose.ymlservices: forge: image: anpms/asgard-forge:latest container_name: asgard-forge restart: unless-stopped network_mode: host # Proxmox doit joindre le serveur HTTP de Packer (8802) volumes: - ./data:/data stop_grace_period: 40s # OpenTofu relâche son verrou d'état -
3 Démarrer et créer le compte
docker compose up -d docker compose logs -f # « à l'écoute sur 0.0.0.0:8080 »Ouvrez
http://<ip-vm>:8080: au premier accès, Forge propose de créer le compte administrateur. Réglez ensuite les accès dans Paramètres, cliquez sur Tester pour chacun et activez la double authentification.
Le dossier data/ (base SQLite avec les paramètres chiffrés, clé maître secret.key, journaux, caches) doit appartenir à l'uid 1000, utilisateur du conteneur.
4 Les paramètres
Tout se règle dans Paramètres, par onglet, appliqué sans redémarrage. Seul le jeton GitLab est indispensable : les accès Proxmox et les options viennent de GitLab, comme pour le pipeline. Les secrets sont chiffrés et jamais réaffichés.
| Onglet | Contenu |
|---|---|
| Compte | Identifiant, mot de passe, double authentification. |
| Accès et réseau | Adresse publique (liens des notifications), reverse proxy, cookies « Secure ». |
| GitLab | Instance, projet (groupe/projet), branche, jeton de projet (Maintainer, api) ; liste des variables CI/CD lues. |
| Proxmox et Packer | Surcharges facultatives des accès Proxmox (sinon variables CI/CD), IP de Forge joignable par Proxmox (serveur HTTP de Packer). |
| Intégrations | Argos (adresse et jeton créé dans Argos → Applications → forge), ntfy, Wazuh, Discord. |
| Avancé | Délais SSH, cache du dépôt, surcharges de variables CI/CD (NOM=valeur). |
Mot de passe perdu : ADMIN_RESET_PASSWORD: "…" dans le compose, docker compose up -d, connectez-vous, retirez la ligne.
5 Ce que Forge lit dans GitLab
Rien n'est figé dans Forge : changez le dépôt, Forge suit (relecture toutes les 5 minutes, ou bouton Relire GitLab). La page GitLab de Forge affiche les fichiers du commit utilisé.
| Dans le dépôt | Devient dans Forge |
|---|---|
Blocs variable du dossier Terraform | Les champs du formulaire (type, valeur par défaut, description). Une variable sensitive devient un mot de passe jamais enregistré. |
validation { condition = contains([…], var.x) } | Une liste de choix (ex. type de processeur). |
Bloc variables: du .gitlab-ci.yml et -var="x=${Y}" du job d'application | Les valeurs par défaut du pipeline, prioritaires sur celles du .tf. |
| Variables CI/CD du projet / du groupe | Accès Proxmox, webhook Discord, identifiants Wazuh… Jamais affichés, seulement leur origine. |
lookup('env', 'X') dans le playbook | Une option de la section « Après le déploiement » (case à cocher si la valeur est true/false) ; son libellé est le commentaire de la ligne dans .gitlab-ci.yml. |
cd … et export … des jobs, commande ansible-playbook | Les dossiers et l'environnement de chaque outil, comme dans le job CI. |
# .gitlab-ci.yml — une option apparaît dans Forge, libellé compris
variables:
INSTALL_DOCKER: "false" # Installer Docker et ajouter l'utilisateur au groupe docker
6 Déployer une machine
-
1 Remplir le formulaire
Identité (nom, VMID libre proposé, nœud, template, étiquettes), ressources, réseau, accès, options. Les listes viennent de Proxmox : nœuds avec leur mémoire libre, stockages avec leur place, templates du nœud, étiquettes déjà utilisées.
-
2 Profils
Enregistrez un jeu de valeurs (ex. « serveur Docker VLAN 20 »). Le nom, le VMID, l'IP et le mot de passe restent propres à chaque VM.
-
3 Vérifier
Contrôles avant envoi : formats, VMID libre, nom unique, IP qui ne répond pas, template présent, place sur le stockage, mémoire du nœud, clés SSH, état Terraform inexistant. Une erreur bloque, un avertissement non ; ils sont refaits au lancement.
-
4 Suivre en direct
Le journal défile en temps réel, secrets masqués ; une exécution à la fois, les suivantes attendent dans la file et peuvent être annulées.
| Étape | Ce qui se passe |
|---|---|
| Configuration GitLab | Archive du dépôt au commit affiché. |
| Contrôles | Les mêmes que « Vérifier ». |
| Création de la VM (OpenTofu) | init, validate, apply ; état stocké dans GitLab. |
| Démarrage de la VM | Attente de la connexion SSH (cloud-init). |
| Wazuh : agent du même nom | Supprime un ancien agent déconnecté du même nom (sinon Wazuh refuserait l'inscription). |
| Configuration (Ansible) | Le playbook du dépôt, avec les options choisies. |
| Retrait du lecteur cloud-init | cloud-init est purgé par le playbook : son lecteur est retiré de la VM. |
| Agent Argos · Fiche Remote · ntfy · Discord | Facultatifs : un échec devient un avertissement, la VM reste prête. |
7 Options du déploiement
Celles du dépôt machine-conf de référence ; elles sont toutes déclarées dans GitLab et utilisables aussi par le pipeline.
| Option | Effet |
|---|---|
| Type de processeur | x86-64-v2-AES (défaut, compatible avec tous les nœuds) ou host. |
| Options disque | IO thread et discard (TRIM) actifs ; émulation SSD réglée selon le stockage : inutile sur un stockage SSD en LVM-thin, cochée sur un stockage fichier (datastore). Modifiable à la main. |
| Étiquettes Proxmox | Choisies parmi celles déjà utilisées sur Proxmox, ou nouvelles. |
| DNS · domaine de recherche | Un ou plusieurs serveurs DNS (liste dans le formulaire, 4 au plus, dans l'ordre de préférence ; par défaut 192.168.40.153 puis 192.168.40.154, variable NAMESERVER) et DNS_SEARCH, écrits dans netplan. Réseau par défaut : VLAN 40, 192.168.40.101/24, passerelle 192.168.40.254. |
INSTALL_DOCKER | Docker Engine + Compose (dépôt officiel), utilisateur dans le groupe docker. |
INSTALL_WAZUH | Agent Wazuh à la version du serveur (exigé par Wazuh), bloquée contre les mises à jour automatiques. Serveur et version en options avancées. |
SSH_AUTHORIZED_KEYS | Clés publiques ajoutées à ~/.ssh/authorized_keys (une par ligne). Une clé privée collée par erreur est refusée. |
Toujours appliqués : swap /swap.img (mémoire, 4 Go au plus), langue fr_FR.UTF-8, fuseau Europe/Paris, ballooning mémoire actif, cloud-init purgé.
8 Intégrations
- Agent Argos — Automatique (Docker si l'option Docker est cochée, sinon natif), Natif (service systemd) ou Docker (vérifie la présence de Docker avant d'inscrire la machine). À la destruction, la machine est retirée d'Argos (Argos 0.3.2 et plus).
- Fiche Asgard Remote — la VM est proposée à Remote (dossier « homelab », sans identifiant) par l'intermédiaire d'Argos ; Remote l'ajoute à son coffre chiffré.
- Discord — fiche de la VM à la fin du déploiement (nom, ID, IP, utilisateur, ressources, commande SSH, nœud, VLAN, démarrée), l'erreur en cas d'échec, et un message à la destruction. Le webhook se règle dans Paramètres → Intégrations → Discord : Forge l'écrit dans la variable CI/CD
DISCORD_WEBHOOK_URL, partagée avec le pipeline. - Wazuh — Paramètres → Intégrations → Wazuh : un utilisateur de l'API Wazuh (lecture et suppression des agents), vérifié auprès du serveur puis enregistré dans les variables CI/CD (
WAZUH_API_USER, et le mot de passe en base64 dansWAZUH_API_PASSWORD_B64, toujours masquable par GitLab). L'agent est alors supprimé du serveur à la destruction de la VM, et un ancien agent déconnecté du même nom est retiré avant un déploiement. - ntfy — succès ou échec, avec lien vers le journal.
Chaque intégration se coche ou se décoche à chaque déploiement, dans le panneau Intégrations.
Créer l'utilisateur d'API Wazuh
L'API Wazuh (port 55000) a ses propres utilisateurs, distincts de ceux du tableau de bord. Pour Forge, un utilisateur dédié limité à deux droits suffit : dans le tableau de bord, Server management → Security :
- Policies → Create policy :
forge-agents, actionsagent:readetagent:delete, ressourceagent:id:*, effet Allow. - Roles → Create role :
forge, avec la policyforge-agents. - Users → Create user :
forge-api(mot de passe de 8 à 64 caractères avec majuscule, minuscule, chiffre et symbole), rôleforge.
Ou en ligne de commande sur le serveur Wazuh, avec l'administrateur de l'API (wazuh, mot de passe dans wazuh-passwords.txt) :
API=https://localhost:55000
TOKEN=$(curl -sk -u wazuh:'<mot de passe admin>' -X POST "$API/security/user/authenticate?raw=true")
H=(-sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json")
curl "${H[@]}" -X POST "$API/security/policies" -d '{"name":"forge-agents","policy":{"actions":["agent:read","agent:delete"],"resources":["agent:id:*"],"effect":"allow"}}'
curl "${H[@]}" -X POST "$API/security/roles" -d '{"name":"forge"}'
curl "${H[@]}" -X POST "$API/security/users" -d '{"username":"forge-api","password":"<mot de passe>"}'
# puis, avec les identifiants renvoyés :
curl "${H[@]}" -X POST "$API/security/roles/<id_role>/policies?policy_ids=<id_policy>"
curl "${H[@]}" -X POST "$API/security/users/<id_user>/roles?role_ids=<id_role>"
9 Machines & destruction
La page Machines liste les VM créées par Forge avec leur état réel sur Proxmox (allumée, éteinte, absente), leurs ressources, agent Argos, commit et état Terraform. Les options n'y figurent que si elles distinguent la VM : cases cochées sous un nom court (Docker, Wazuh), nombre de clés SSH, réglages différents du défaut (libellé complet au survol).
- Détruire exige de retaper le nom de la VM. Forge rejoue OpenTofu avec la configuration du commit du déploiement (même si le dépôt a changé depuis), supprime l'état Terraform de GitLab, puis retire la machine d'Argos et son agent de Wazuh.
- Une VM en échec peut être détruite (nettoyage) ou simplement retirée de la liste.
- Le mot de passe de la VM n'est jamais enregistré : notez-le, ou déposez une clé SSH.
10 Template Packer
Chaque sous-dossier de 01_packer/ qui contient des fichiers .pkr.hcl est un template : la page Template les propose tous (onglets), celui du job CI en premier. Le dépôt de référence en contient deux :
| Template | Contenu |
|---|---|
template-ubuntu-resolute VMID 301 | Ubuntu Server 26.04 LTS « Resolute Raccoon » (dossier ubuntu-server-resolute), pour les applications et Docker. Ex-template-ubuntu-noble. |
template-debian-trixie VMID 302 | Debian 13 « Trixie » (dossier debian-server-trixie, installation par preseed), plus léger, sudo classique : pour les services d'infrastructure. |
Les deux ont le même réseau (netplan + systemd-networkd), cloud-init et l'agent QEMU : le playbook Ansible est commun et s'adapte à la distribution (dépôt Docker, langue, sudo). Le template à cloner se choisit dans le formulaire de déploiement ; dans la CI GitLab, TEMPLATE_NAME (déploiement) et PACKER_TEMPLATE (construction).
Avant de lancer, Forge vérifie : ISO présent sur le stockage, VMID cible, nœud, IP de Forge pour le serveur HTTP de Packer.
- Packer construit le nouveau template sur un VMID temporaire : l'ancien reste utilisable pendant ce temps.
- En cas de succès, l'ancien est supprimé et le nouveau reprend le VMID et le nom du dépôt.
- En cas d'échec, rien ne change.
11 Sécurité
- Secrets chiffrés dans la base de Forge ou dans les variables CI/CD GitLab ; l'interface n'en réaffiche aucun.
- Les outils reçoivent les secrets par variables d'environnement, jamais en argument ; ils sont masqués dans les journaux. Les outils ne voient pas l'environnement de Forge.
- Session par cookie, protection CSRF, limitation des tentatives, double authentification TOTP.
- Chaque exécution d'Ansible part d'un dossier vierge (empreintes SSH, connexions) : une VM qui reprend une IP déjà vue n'est pas bloquée.
- Réseau local ou VPN uniquement : Forge crée et détruit des VM.
12 Mise à jour & sauvegarde
cd ~/asgard-forge
docker compose pull && docker compose up -d
Le compose.yml suit le tag latest : ces deux commandes suffisent à passer à la dernière version (affichée en bas du menu de Forge). Pour figer une version, remplacez latest par un numéro (ex. anpms/asgard-forge:0.4.0) dans le compose.
À sauvegarder : le dossier data/ (forge.db avec VM, profils, historique et paramètres, et secret.key). Les états Terraform sont dans GitLab.
Si votre .gitlab-ci.yml lance un job de déploiement à chaque push sur main, poussez vos modifications de configuration avec git push -o ci.skip.
13 Dépannage
| Symptôme | Cause et solution |
|---|---|
| « Configuration GitLab illisible » | Jeton GitLab absent, expiré ou sans rôle Maintainer (Paramètres → GitLab). |
| Ansible : « Timeout waiting for privilege escalation prompt » | Ubuntu 25.10+ utilise sudo-rs : le playbook doit passer par sudo.ws (choix automatique selon la version dans le dépôt de référence). |
| « Timed out waiting for last boot time check » | cloud-init revient au redémarrage et régénère les clés SSH : purger aussi cloud-init-base (Ubuntu 25.10+). |
| « REMOTE HOST IDENTIFICATION HAS CHANGED » | Corrigé en 0.2.0 (empreintes SSH propres à chaque exécution) : mettez Forge à jour. |
| Reconstruction du template refusée | L'ISO indiquée dans le dépôt est absente du stockage Proxmox : déposez-la ou corrigez le dépôt. |
| « GitLab (variable CI/CD) : HTTP 400 — is invalid » en enregistrant un réglage | GitLab refuse de masquer une valeur contenant *, !… Corrigé en 0.2.1 (mot de passe Wazuh stocké en base64, repli sans masque sinon) : mettez Forge à jour. |
| Étape Argos ou Remote en avertissement | Jeton absent ou révoqué (Argos → Paramètres → Applications), ou Argos antérieur à 0.3.2. |
| Agent Wazuh non inscrit | Version de l'agent différente de celle du serveur, ou ancien agent actif du même nom. |
| Session perdue après une mise à jour | Normal : les sessions sont en mémoire, reconnectez-vous. |