linux:rewinged
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| linux:rewinged [2026/09/12 07:05] – root | linux:rewinged [2026/09/18 17:40] (Version actuelle) – [13.2 Règles personnalisées] root | ||
|---|---|---|---|
| Ligne 8: | Ligne 8: | ||
| < | < | ||
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | +------------------------------+ | + | +------------------------------+ |
| - | | VM Caddy (frontal existant) | + | | VM Caddy (frontal existant) |
| - | | repo.makeitsimple.be | + | | repo.makeitsimple.be |
| - | | TLS Let's Encrypt | + | | TLS Let's Encrypt |
| - | +---------------+--------------+ | + | +---------------+--------------+ |
| - | | | + | | |
| - | | HTTP 8080 (réseau | + | | HTTP 8080 (interne) |
| - | v | + | v |
| - | Forgejo | + | Forgejo |
| - | (winget-manifests) | + | mis/winget-manifests |
| - | | | + | |
| - | | git pull --ff-only | + | + MSI en Git LFS |
| - | | timer 1 min | + | |
| - | +--------------------> | + | |
| - | +------------------------------+ | + | | + lfs pull |
| + | | timer 1 min | | | ||
| + | +-------------> | ||
| + | | ||
| </ | </ | ||
| ^ Composant ^ Machine ^ Rôle ^ | ^ Composant ^ Machine ^ Rôle ^ | ||
| - | | Forgejo | existante | Source de vérité | + | | Forgejo | existante | Source de vérité |
| - | | Caddy | frontal existant | Terminaison TLS uniquement. Aucun fichier local. | | + | | Caddy frontal |
| - | | rewinged | VM dédiée | Sert l'API REST '' | + | | rewinged | VM dédiée | API REST '' |
| - | | Wazuh | existant | FIM sur manifests et binaire de la VM rewinged. | | + | | Wazuh | existant | FIM sur manifests, installeurs |
| - | **Deux machines distinctes.** rewinged n'écoute donc pas sur la boucle locale | + | **Le dépôt Forgejo peut rester privé.** Les postes ne dialoguent qu'avec |
| - | mais sur l'interface interne, filtrée au pare-feu vers la seule IP du frontal. | + | '' |
| + | la synchronisation se fait par clé de déploiement SSH. | ||
| - | **Principe | + | **Chaîne |
| - | mais sur le SHA256 déclaré dans chaque manifest. Un installeur substitué | + | sur le SHA256 déclaré dans chaque manifest. Un installeur substitué échoue à |
| - | échoue à la vérification et winget refuse l' | + | la vérification et winget refuse l' |
| ===== 2. Prérequis ===== | ===== 2. Prérequis ===== | ||
| - | * VM Debian 12 minimale, 1 vCPU / 1 Go RAM / 20 Go suffisent | + | * VM Debian 12 minimale, 1 vCPU / 1 Go RAM / disque dimensionné au volume d' |
| - | * Enregistrement DNS public '' | + | * Enregistrement DNS public '' |
| - | * Ports 80 et 443 joignables (ACME + service) | + | * Dépôt Forgejo '' |
| - | * Dépôt Forgejo '' | + | |
| * Clé de déploiement Forgejo **en lecture seule** | * Clé de déploiement Forgejo **en lecture seule** | ||
| + | * Paquets '' | ||
| ===== 3. Installation de rewinged ===== | ===== 3. Installation de rewinged ===== | ||
| Ligne 56: | Ligne 60: | ||
| <code bash> | <code bash> | ||
| useradd --system --home /srv/winget --shell / | useradd --system --home /srv/winget --shell / | ||
| - | mkdir -p /srv/winget/ | + | mkdir -p /srv/winget |
| chown -R rewinged: | chown -R rewinged: | ||
| </ | </ | ||
| + | |||
| + | Les répertoires '' | ||
| + | (section 6). | ||
| + | |||
| + | Le compte '' | ||
| + | l' | ||
| ==== 3.2 Binaire ==== | ==== 3.2 Binaire ==== | ||
| Ligne 76: | Ligne 86: | ||
| </ | </ | ||
| - | <WRAP center round important> | + | ==== 3.3 Options utiles ==== |
| - | Relever dans '' | + | |
| - | manifests, et vérifier si rewinged recharge à chaud ou s'il faut un signal | + | |
| - | après un '' | + | |
| - | </ | + | |
| - | ==== 3.3 Service systemd ==== | + | ^ Flag ^ Rôle ^ |
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | |||
| + | **Deux usages de '' | ||
| + | qu'il rapatrie automatiquement, | ||
| + | trouve sous ''/ | ||
| + | servis sans serveur de fichiers supplémentaire. | ||
| + | |||
| + | Vérifié : | ||
| + | <code bash> | ||
| + | curl -I http:// | ||
| + | # HTTP/1.1 200 OK | ||
| + | # Content-Type: | ||
| + | # Accept-Ranges: | ||
| + | </ | ||
| + | |||
| + | ==== 3.4 Service systemd ==== | ||
| <file ini / | <file ini / | ||
| Ligne 92: | Ligne 121: | ||
| User=rewinged | User=rewinged | ||
| Group=rewinged | Group=rewinged | ||
| - | ExecStart=/ | + | ExecStart=/ |
| + | | ||
| + | -manifestPath / | ||
| + | -autoInternalize \ | ||
| + | -autoInternalizePath / | ||
| + | -trustedProxies 10.0.0.10 \ | ||
| + | -logLevel info | ||
| Restart=on-failure | Restart=on-failure | ||
| RestartSec=5 | RestartSec=5 | ||
| + | |||
| + | # Journalisation vers fichier, pour collecte Wazuh en JSON natif | ||
| + | StandardOutput=append:/ | ||
| + | StandardError=append:/ | ||
| # Durcissement | # Durcissement | ||
| Ligne 106: | Ligne 145: | ||
| MemoryDenyWriteExecute=true | MemoryDenyWriteExecute=true | ||
| ReadOnlyPaths=/ | ReadOnlyPaths=/ | ||
| - | ReadWritePaths=/ | + | ReadWritePaths=/ |
| [Install] | [Install] | ||
| Ligne 113: | Ligne 152: | ||
| <code bash> | <code bash> | ||
| + | mkdir -p / | ||
| + | chown rewinged: | ||
| + | |||
| systemctl daemon-reload | systemctl daemon-reload | ||
| systemctl enable --now rewinged | systemctl enable --now rewinged | ||
| Ligne 118: | Ligne 160: | ||
| </ | </ | ||
| - | rewinged écoute en clair sur le réseau interne. Le TLS est assuré par le | + | Rotation du journal : |
| - | frontal Caddy, sur une autre machine. | + | |
| + | <file - / | ||
| + | / | ||
| + | daily | ||
| + | rotate 30 | ||
| + | compress | ||
| + | missingok | ||
| + | notifempty | ||
| + | copytruncate | ||
| + | su rewinged rewinged | ||
| + | } | ||
| + | </ | ||
| - | ==== 3.4 Pare-feu de la VM rewinged | + | ===== 4. Pare-feu de la VM ===== |
| - | Le port 8080 ne doit être joignable que par le frontal. | + | Seul le frontal |
| <code bash> | <code bash> | ||
| Ligne 133: | Ligne 186: | ||
| </ | </ | ||
| - | ===== 4. Configuration du frontal Caddy ===== | + | ===== 5. Configuration du frontal Caddy ===== |
| - | À ajouter au Caddyfile **de la machine frontale**, pas de la VM rewinged. | + | À ajouter au Caddyfile **de la machine frontale**. |
| <file - / | <file - / | ||
| Ligne 155: | Ligne 208: | ||
| } | } | ||
| </ | </ | ||
| - | |||
| - | Un seul '' | ||
| - | aucun fichier de la solution. Les installeurs sont servis soit par Forgejo, | ||
| - | soit par rewinged lui-même (section 6). | ||
| Winget exige HTTPS avec une chaîne validée par le magasin de confiance | Winget exige HTTPS avec une chaîne validée par le magasin de confiance | ||
| Ligne 164: | Ligne 213: | ||
| interne sur chaque poste. | interne sur chaque poste. | ||
| - | ===== 5. Dépôt Git des manifests ===== | + | Un seul '' |
| + | installeurs sous ''/ | ||
| - | Le dépôt ne contient **que du YAML**. Les binaires sont hébergés séparément | + | ===== 6. Dépôt Forgejo ===== |
| - | (voir section | + | |
| - | ==== 5.1 Structure ==== | + | Un seul dépôt contient manifests et installeurs. Les MSI passent par Git LFS |
| + | pour ne pas alourdir l' | ||
| + | |||
| + | ==== 6.1 Structure ==== | ||
| < | < | ||
| winget-manifests/ | winget-manifests/ | ||
| + | ├── .gitattributes | ||
| ├── manifests/ | ├── manifests/ | ||
| - | │ | + | │ |
| - | │ | + | │ |
| - | │ | + | │ |
| - | │ | + | └── |
| - | │ | + | ├── mis-agent-1.2.0.msi |
| - | │ | + | └── |
| - | │ | + | |
| - | │ └── | + | |
| - | └── | + | |
| </ | </ | ||
| - | ==== 5.2 Clone initial | + | ==== 6.2 Activation de Git LFS ==== |
| + | |||
| + | Côté poste de travail, une seule fois : | ||
| <code bash> | <code bash> | ||
| + | git lfs install | ||
| + | git lfs track " | ||
| + | git lfs track " | ||
| + | git add .gitattributes | ||
| + | git commit -m "Suivi LFS des installeurs" | ||
| + | git push | ||
| + | </ | ||
| + | |||
| + | Vérifier que LFS est activé sur l' | ||
| + | stockage est suffisant. LFS ne fait pas de delta : chaque version d'un MSI | ||
| + | est stockée intégralement. | ||
| + | |||
| + | ==== 6.3 Clone initial sur la VM ==== | ||
| + | |||
| + | <code bash> | ||
| + | apt install git-lfs | ||
| + | sudo -u rewinged git lfs install --skip-repo | ||
| + | |||
| sudo -u rewinged git clone \ | sudo -u rewinged git clone \ | ||
| git@forgejo.makeitsimple.be: | git@forgejo.makeitsimple.be: | ||
| - | / | + | /srv/winget |
| + | |||
| + | sudo -u rewinged git -C /srv/winget lfs pull | ||
| </ | </ | ||
| Ligne 196: | Ligne 268: | ||
| ne doit jamais pouvoir écrire dans le dépôt. | ne doit jamais pouvoir écrire dans le dépôt. | ||
| - | ===== 6. Stockage des installeurs | + | ===== 7. Synchronisation automatique |
| - | Trois options. Choix retenu | + | Pas de webhook |
| - | SFTP tout en gardant | + | qui décide de ce que le parc installe. Le flux part toujours du serveur vers |
| + | Forgejo. | ||
| - | ^ Option ^ Avantage ^ Inconvénient ^ | + | ==== 7.1 Rechargement natif ==== |
| - | | Package registry Forgejo | Dépôt Git léger, publication en une commande | Un système de plus à connaître | | + | |
| - | | Git LFS | Manifest et binaire dans un même commit | Pas de delta, volume croissant | | + | |
| - | | URL éditeur | Rien à héberger | Ne convient qu'aux logiciels tiers | | + | |
| - | ==== 6.1 Publication d'un installeur ==== | + | rewinged surveille le répertoire de manifests et recharge sans intervention. |
| + | Confirmé au démarrage du service : | ||
| - | < | + | < |
| - | curl --user vincent:$FORGEJO_TOKEN \ | + | {" |
| - | --upload-file mis-agent-1.2.0.msi \ | + | |
| - | https:// | + | |
| </ | </ | ||
| - | L'URL obtenue | + | **Conséquence** : aucun redémarrage n' |
| + | L' | ||
| + | '' | ||
| - | <WRAP center round important> | + | ==== 7.2 Script de synchronisation ==== |
| - | **Point bloquant à vérifier.** Winget ne sait pas s' | + | |
| - | source auto-hébergée | + | <file bash / |
| - | Forgejo | + | # |
| + | # | ||
| + | # Synchronise le depot de paquets depuis Forgejo. | ||
| + | # Execute par winget-sync.timer sous le compte rewinged. | ||
| + | # | ||
| + | set -euo pipefail | ||
| + | |||
| + | REPO_DIR="/ | ||
| + | BRANCH=" | ||
| + | |||
| + | cd " | ||
| + | |||
| + | BEFORE=$(git rev-parse HEAD) | ||
| + | |||
| + | git fetch origin " | ||
| + | git merge --ff-only " | ||
| + | git lfs pull origin | ||
| + | |||
| + | AFTER=$(git rev-parse HEAD) | ||
| + | |||
| + | if [ " | ||
| + | # Verification de signature | ||
| + | if ! git verify-commit HEAD >/ | ||
| + | logger -t winget-sync -p auth.crit \ | ||
| + | " | ||
| + | git reset --hard " | ||
| + | exit 1 | ||
| + | fi | ||
| + | logger -t winget-sync " | ||
| + | fi | ||
| + | |||
| + | exit 0 | ||
| + | </ | ||
| + | |||
| + | Le bloc '' | ||
| + | clé publique du signataire est présente dans le trousseau du compte | ||
| + | '' | ||
| + | est ce qui rend la détection Wazuh exploitable (13.3). | ||
| - | Tester avant de bâtir dessus : | ||
| <code bash> | <code bash> | ||
| - | curl -I https://forgejo.makeitsimple.be/api/packages/mis/generic/agent/1.2.0/mis-agent-1.2.0.msi | + | chown root:root /usr/local/bin/winget-sync.sh |
| + | chmod 0755 /usr/local/bin/winget-sync.sh | ||
| </ | </ | ||
| - | Un 401 ou 404 impose de rendre l' | ||
| - | basculer sur l' | ||
| - | </ | ||
| - | ==== 6.2 Logiciels tiers ==== | + | Le script appartient à root en lecture seule pour '' |
| + | service exécute le script sans pouvoir le modifier. | ||
| - | Pour Chrome, Acrobat et assimilés, deux voies : | + | Le '' |
| + | échoue au lieu de fusionner silencieusement. Une divergence signifie une | ||
| + | écriture locale sur le serveur, ce qui ne doit jamais arriver. | ||
| - | * pointer directement l'URL éditeur | + | Le '' |
| - | * utiliser l'internalisation | + | corréler les alertes FIM Wazuh avec une publication légitime (section 12.2). |
| - | | + | |
| - | pour les postes sans accès internet direct | + | |
| - | ===== 7. Synchronisation automatique | + | ==== 7.3 Unités systemd |
| - | + | ||
| - | Pas de webhook : un timer évite d' | + | |
| - | qui décide de ce que le parc installe. Le flux part toujours du serveur vers | + | |
| - | Forgejo. | + | |
| <file ini / | <file ini / | ||
| [Unit] | [Unit] | ||
| - | Description=Sync winget manifests from Forgejo | + | Description=Sync winget manifests |
| + | After=network-online.target | ||
| + | Wants=network-online.target | ||
| [Service] | [Service] | ||
| Type=oneshot | Type=oneshot | ||
| User=rewinged | User=rewinged | ||
| - | WorkingDirectory=/ | + | Group=rewinged |
| - | ExecStart=/ | + | WorkingDirectory=/ |
| + | ExecStart=/ | ||
| + | |||
| + | # Durcissement | ||
| + | ProtectSystem=strict | ||
| + | ProtectHome=true | ||
| + | PrivateTmp=true | ||
| + | NoNewPrivileges=true | ||
| + | ReadWritePaths=/ | ||
| </ | </ | ||
| <file ini / | <file ini / | ||
| [Unit] | [Unit] | ||
| - | Description=Sync winget | + | Description=Sync winget |
| [Timer] | [Timer] | ||
| OnBootSec=1min | OnBootSec=1min | ||
| OnUnitActiveSec=1min | OnUnitActiveSec=1min | ||
| + | AccuracySec=10s | ||
| [Install] | [Install] | ||
| Ligne 271: | Ligne 384: | ||
| systemctl enable --now winget-sync.timer | systemctl enable --now winget-sync.timer | ||
| systemctl list-timers winget-sync.timer | systemctl list-timers winget-sync.timer | ||
| + | journalctl -u winget-sync.service -f | ||
| </ | </ | ||
| - | Le '' | + | ==== 7.4 Propriété des fichiers ==== |
| - | au lieu de fusionner silencieusement. Une divergence signifie | + | |
| - | locale, ce qui ne doit jamais arriver. | + | Le clone doit appartenir à '' |
| + | root bloque la synchronisation. | ||
| + | |||
| + | <code bash> | ||
| + | # Preparation, | ||
| + | mkdir -p / | ||
| + | chown rewinged: | ||
| + | |||
| + | # Clone, sous le compte de service | ||
| + | sudo -u rewinged git clone git@forgejo.makeitsimple.be: | ||
| + | </ | ||
| + | |||
| + | Rattrapage si le clone a déjà été fait en root : | ||
| + | |||
| + | <code bash> | ||
| + | chown -R rewinged: | ||
| + | sudo -u rewinged git -C /srv/winget status | ||
| + | </ | ||
| + | |||
| + | Git refuse d'opérer sur un dépôt dont le propriétaire diffère de l' | ||
| + | courant ('' | ||
| + | oublié. | ||
| + | |||
| + | Vérification décisive : | ||
| + | |||
| + | <code bash> | ||
| + | sudo -u rewinged /usr/local/ | ||
| + | </ | ||
| + | |||
| + | Si elle passe, le timer passera aussi. | ||
| + | |||
| + | ==== 7.5 Variante avec redémarrage ==== | ||
| + | |||
| + | À n' | ||
| + | après | ||
| + | |||
| + | Autorisation ciblée dans sudoers : | ||
| + | |||
| + | <file - / | ||
| + | rewinged ALL=(root) NOPASSWD: / | ||
| + | </ | ||
| + | |||
| + | <code bash> | ||
| + | visudo -c -f / | ||
| + | chmod 0440 / | ||
| + | </ | ||
| + | |||
| + | Ligne à ajouter dans le bloc conditionnel du script : | ||
| + | |||
| + | <code bash> | ||
| + | sudo / | ||
| + | </ | ||
| + | |||
| + | **Redémarrer uniquement sur changement de HEAD.** À raison de 1440 exécutions | ||
| + | par jour, un redémarrage systématique pollue les journaux et provoque des | ||
| + | micro-coupures pendant les téléchargements. | ||
| ===== 8. Format d'un manifest ===== | ===== 8. Format d'un manifest ===== | ||
| Ligne 290: | Ligne 459: | ||
| - Architecture: | - Architecture: | ||
| InstallerType: | InstallerType: | ||
| - | InstallerUrl: | + | InstallerUrl: |
| InstallerSha256: | InstallerSha256: | ||
| Scope: machine | Scope: machine | ||
| Ligne 313: | Ligne 482: | ||
| sur le PATH. | sur le PATH. | ||
| - | Le bloc '' | + | ===== 9. Convention pour les paquets par client ===== |
| - | installés depuis d' | + | |
| - | pour que winget établisse le lien. | + | |
| - | ===== 9. Workflow | + | RustDesk est publié en un paquet par client : le mot de passe d' |
| + | non-surveillé est préconfiguré dans le MSI et diffère d'un client à l' | ||
| - | | + | ==== 9.1 Nommage ==== |
| - | - Pousser | + | |
| + | < | ||
| + | PackageIdentifier: | ||
| + | </ | ||
| + | |||
| + | * manifest : '' | ||
| + | * installeur : '' | ||
| + | |||
| + | ==== 9.2 Conséquence opérationnelle ==== | ||
| + | |||
| + | À chaque version de RustDesk, autant de MSI à régénérer et de manifests à | ||
| + | republier qu'il y a de clients. À l'échelle de la centaine, la publication | ||
| + | doit être scriptée : un outil qui parcourt la liste des clients, appelle | ||
| + | '' | ||
| + | |||
| + | La saisie manuelle n'est pas tenable et expose au risque de coller le GUID | ||
| + | d'une version précédente. | ||
| + | |||
| + | ==== 9.3 Visibilité ==== | ||
| + | |||
| + | La source n'a pas de notion de périmètre : tout poste ayant enregistré | ||
| + | '' | ||
| + | clients. Sans conséquence sur l' | ||
| + | |||
| + | ==== 9.4 Alternative : paquet unique ==== | ||
| + | |||
| + | Le paquet par client existe parce que le mot de passe non-surveillé est | ||
| + | préconfiguré dans le MSI. Ce mot de passe peut aussi être posé **après** | ||
| + | installation, | ||
| + | |||
| + | === Ce qui n'est pas possible === | ||
| + | |||
| + | Le mot de passe permanent **ne se propage pas par API ni par stratégie**. | ||
| + | C'est un secret local à la machine. La demande d'en faire un paramètre de | ||
| + | stratégie Pro est ouverte depuis 2023 et n'a pas abouti. | ||
| + | |||
| + | Ne pas confondre trois objets distincts : | ||
| + | |||
| + | ^ Élément ^ Où il vit ^ Comment il se pose ^ | ||
| + | | Mot de passe permanent | Sur la machine, haché localement | '' | ||
| + | | Mot de passe du carnet | Côté serveur Pro | '' | ||
| + | | Stratégie Pro | Côté serveur Pro | Réglages client, **hors** mot de passe | | ||
| + | |||
| + | Le premier authentifie les connexions entrantes. Le second est celui que le | ||
| + | client technicien utilise pour remplir automatiquement le champ. | ||
| + | |||
| + | === Le flux en deux temps === | ||
| + | |||
| + | Le secret naît sur la machine, puis remonte vers le serveur. | ||
| + | |||
| + | <file powershell onboard-rustdesk.ps1> | ||
| + | $rd = " | ||
| + | |||
| + | # 1. Generer un mot de passe propre a CETTE machine | ||
| + | $pw = -join ((48..57)+(65..90)+(97..122) | Get-Random -Count 20 | % {[char]$_}) | ||
| + | |||
| + | # 2. Le poser localement | ||
| + | & $rd --password $pw | ||
| + | |||
| + | # 3. Recuperer l'ID attribue | ||
| + | $id = (& $rd --get-id).Trim() | ||
| + | |||
| + | # 4. Rattacher au carnet du client et y stocker le mot de passe | ||
| + | & $rd --assign ` | ||
| + | --token $env: | ||
| + | --address_book_name " | ||
| + | --address_book_alias $env: | ||
| + | --address_book_password $pw | ||
| + | |||
| + | # 5. Archiver dans Vaultwarden (ID + mot de passe) | ||
| + | </ | ||
| + | |||
| + | === Ce que cela change === | ||
| + | |||
| + | * **Un seul manifest** RustDesk pour l' | ||
| + | * **Un mot de passe par machine** au lieu d'un par client : la fuite d'un | ||
| + | secret n' | ||
| + | * Plus de régénération de MSI à chaque release | ||
| + | * Prérequis : Server Pro 1.5.8 et client 1.4.1 pour '' | ||
| + | |||
| + | === À valider avant de basculer === | ||
| + | |||
| + | <WRAP center round important> | ||
| + | Un dysfonctionnement de '' | ||
| + | signalé en mai 2025 : la commande retourne sans effet. Tester sur un poste | ||
| + | témoin, service arrêté puis démarré, avant de bâtir l' | ||
| + | </ | ||
| + | |||
| + | Vérifier également que le token API utilisé porte les seules permissions | ||
| + | '' | ||
| + | script — le passer par variable d' | ||
| + | Vaultwarden au moment de l'exécution. | ||
| + | |||
| + | ===== 10. Extraction des codes MSI ===== | ||
| + | |||
| + | Le '' | ||
| + | l''' | ||
| + | Le bloc '' | ||
| + | logiciels déjà installés depuis d' | ||
| + | |||
| + | ==== 10.1 Depuis un fichier MSI ==== | ||
| + | |||
| + | À exécuter sur la machine de build (Windows). Lecture seule, sans installation | ||
| + | ni Orca. | ||
| + | |||
| + | <file powershell | ||
| + | function Get-MsiCodes { | ||
| + | param([string]$Path) | ||
| + | $installer = New-Object -ComObject WindowsInstaller.Installer | ||
| + | $db = $installer.GetType().InvokeMember('OpenDatabase',' | ||
| + | | ||
| + | foreach ($p in ' | ||
| + | $view = $db.GetType().InvokeMember(' | ||
| + | @(" | ||
| + | $view.GetType().InvokeMember(' | ||
| + | $rec = $view.GetType().InvokeMember(' | ||
| + | if ($rec) { | ||
| + | $props[$p] = $rec.GetType().InvokeMember(' | ||
| + | } | ||
| + | } | ||
| + | [PSCustomObject]$props | ||
| + | } | ||
| + | |||
| + | Get-MsiCodes ' | ||
| + | </ | ||
| + | |||
| + | Sortie type : | ||
| + | |||
| + | < | ||
| + | ProductName | ||
| + | ProductVersion : 1.2.0 | ||
| + | ProductCode | ||
| + | UpgradeCode | ||
| + | </ | ||
| + | |||
| + | Le COM '' | ||
| + | tourne pas sur la VM Debian. | ||
| + | |||
| + | ==== 10.2 Depuis un poste où le logiciel est installé ==== | ||
| + | |||
| + | Pour recenser les GUID en circulation | ||
| + | |||
| + | <code powershell> | ||
| + | Get-ItemProperty ` | ||
| + | HKLM: | ||
| + | HKLM: | ||
| + | Where-Object DisplayName -like ' | ||
| + | Select-Object DisplayName, | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | cas des MSI. L' | ||
| + | |||
| + | <WRAP center round important> | ||
| + | Éviter '' | ||
| + | une réévaluation de tous les MSI installés, ce qui est lent et peut générer | ||
| + | des événements de réparation. Acceptable ponctuellement sur un poste témoin. | ||
| + | </ | ||
| + | |||
| + | ==== 10.3 Automatisation ==== | ||
| + | |||
| + | L' | ||
| + | installé. Cela donne côté serveur la liste exacte des GUID du parc, donc les | ||
| + | '' | ||
| + | |||
| + | ===== 11. Workflow de publication ===== | ||
| + | |||
| + | - Construire l' | ||
| + | - Relever les codes avec '' | ||
| - Calculer le SHA256 | - Calculer le SHA256 | ||
| - | - Créer | + | - Placer le MSI dans '' |
| - | - Revue, merge sur '' | + | - Commit sur une branche, ouvrir une PR, revue, merge sur '' |
| - Le timer applique dans la minute | - Le timer applique dans la minute | ||
| - Valider depuis un poste témoin avant diffusion | - Valider depuis un poste témoin avant diffusion | ||
| Ligne 332: | Ligne 668: | ||
| </ | </ | ||
| - | ===== 10. Configuration des postes ===== | + | ===== 12. Configuration des postes ===== |
| - | ==== 10.1 Enregistrement de la source ==== | + | ==== 12.1 Enregistrement de la source ==== |
| <code powershell> | <code powershell> | ||
| Ligne 345: | Ligne 681: | ||
| l' | l' | ||
| - | ==== 10.2 Winget en contexte SYSTEM ==== | + | ==== 12.2 Winget en contexte SYSTEM ==== |
| '' | '' | ||
| Ligne 359: | Ligne 695: | ||
| un prompt bloque le processus indéfiniment. | un prompt bloque le processus indéfiniment. | ||
| - | ==== 10.3 Adoption du parc existant ==== | + | ==== 12.3 Adoption du parc existant ==== |
| Un paquet installé autrement que depuis la source privée n'est pas reconnu | Un paquet installé autrement que depuis la source privée n'est pas reconnu | ||
| Ligne 370: | Ligne 706: | ||
| À valider sur un poste témoin **avant** de dimensionner la campagne. | À valider sur un poste témoin **avant** de dimensionner la campagne. | ||
| - | ==== 10.4 Compatibilité ==== | + | ==== 12.4 Compatibilité ==== |
| ^ Système ^ App Installer ^ | ^ Système ^ App Installer ^ | ||
| Ligne 381: | Ligne 717: | ||
| le canal unique ou s'il faut un second canal. | le canal unique ou s'il faut un second canal. | ||
| - | ===== 11. Surveillance Wazuh ===== | + | ===== 13. Surveillance Wazuh ===== |
| - | ==== 11.1 FIM ==== | + | Trois sources distinctes : l' |
| + | rewinged, et l' | ||
| - | <file xml ossec.conf> | + | ==== 13.1 Configuration de l' |
| - | <syscheck> | + | |
| - | < | + | <file xml / |
| - | / | + | <ossec_config> |
| - | | + | |
| - | < | + | |
| - | / | + | < |
| - | | + | < |
| - | < | + | < |
| - | / | + | |
| - | </ | + | <!-- Manifests : decident de ce que le parc installe --> |
| - | </ | + | |
| + | tags=" | ||
| + | |||
| + | <!-- Installeurs : les binaires servis aux postes --> | ||
| + | | ||
| + | tags=" | ||
| + | |||
| + | <!-- Binaire rewinged et script de synchronisation --> | ||
| + | | ||
| + | tags=" | ||
| + | |||
| + | <!-- Unites systemd du service --> | ||
| + | < | ||
| + | | ||
| + | |||
| + | <!-- Bruit git interne --> | ||
| + | <ignore type=" | ||
| + | | ||
| + | |||
| + | <!-- Journal applicatif rewinged, deja en JSON --> | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <!-- Etat des services, toutes les 5 minutes --> | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | </ | ||
| </ | </ | ||
| - | ==== 11.2 Réduction du bruit ==== | + | Le journal de '' |
| + | collecté par la configuration Wazuh par défaut. | ||
| - | La FIM se déclenche à chaque '' | + | ==== 13.2 Règles personnalisées ==== |
| - | légitime de l' | + | |
| - | * signer les commits en GPG et vérifier la signature dans le service de | + | <file xml / |
| - | sync avant application — un manifest modifié sans commit signé devient | + | <group name=" |
| - | alors une alerte non ambiguë | + | |
| - | * à défaut, corréler avec les logs de '' | + | |
| - | ==== 11.3 Alertes complémentaires ==== | + | <rule id=" |
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| - | | + | |
| - | * échecs répétés de '' | + | < |
| - | | + | |
| - | * volumétrie anormale de téléchargements sur '' | + | < |
| + | </rule> | ||
| - | ===== 12. Points ouverts ===== | + | <rule id=" |
| + | < | ||
| + | <field name=" | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <rule id=" | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <rule id=" | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <rule id=" | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <rule id=" | ||
| + | < | ||
| + | <field name=" | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <rule id=" | ||
| + | < | ||
| + | <field name=" | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <rule id=" | ||
| + | < | ||
| + | <field name=" | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <rule id=" | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <rule id=" | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | </ | ||
| + | |||
| + | <WRAP center round important> | ||
| + | Les identifiants 100600–100631 sont donnés à titre indicatif. Les adapter à | ||
| + | la numérotation des règles personnalisées déjà en place. | ||
| + | </ | ||
| + | |||
| + | ==== 13.3 Traiter le bruit FIM ==== | ||
| + | |||
| + | La FIM se déclenche à chaque publication légitime. Wazuh ne sait pas exprimer | ||
| + | nativement « alerter sauf si précédé de tel événement », il faut donc déplacer | ||
| + | le contrôle plutôt que tenter de corréler. | ||
| + | |||
| + | **Approche retenue** : la signature GPG des commits est le contrôle réel. | ||
| + | |||
| + | - Les commits de publication sont signés ; la clé publique du signataire est | ||
| + | dans le trousseau du compte '' | ||
| + | - '' | ||
| + | d' | ||
| + | - La FIM sur '' | ||
| + | elle n' | ||
| + | - L' | ||
| + | |||
| + | Une modification de manifest effectuée directement sur le serveur ne passe pas | ||
| + | par un commit, donc ne déclenche pas 100611 — mais elle sera écrasée au | ||
| + | prochain '' | ||
| + | |||
| + | Les installeurs et les binaires, eux, ne changent pas hors publication : leurs | ||
| + | règles restent à niveau élevé. | ||
| + | |||
| + | ==== 13.4 Mise en place de la signature ==== | ||
| + | |||
| + | Côté poste de publication : | ||
| + | |||
| + | <code bash> | ||
| + | git config --global user.signingkey < | ||
| + | git config --global commit.gpgsign true | ||
| + | gpg --export --armor < | ||
| + | </ | ||
| + | |||
| + | Côté serveur rewinged : | ||
| + | |||
| + | <code bash> | ||
| + | sudo -u rewinged gpg --import mis-publication.pub | ||
| + | sudo -u rewinged gpg --edit-key < | ||
| + | sudo -u rewinged git -C /srv/winget verify-commit HEAD | ||
| + | </ | ||
| + | |||
| + | Idéalement la clé de signature réside sur une YubiKey, cohérent avec | ||
| + | l' | ||
| + | |||
| + | ==== 13.5 Ce qui reste non couvert ==== | ||
| + | |||
| + | * **Publication légitime mais erronée** — un mauvais '' | ||
| + | ou un SHA256 incorrect signé de bonne foi passe toutes les vérifications. | ||
| + | Le garde-fou est la revue de la PR, pas la détection. | ||
| + | * **Compromission du poste de publication** — si la clé de signature est | ||
| + | utilisable par un attaquant, la chaîne entière est valide de son point de | ||
| + | vue. D'où la YubiKey. | ||
| + | * **Saturation disque** — à surveiller côté Zabbix plutôt que Wazuh, la | ||
| + | croissance LFS étant progressive et prévisible. | ||
| + | |||
| + | ===== 14. Points ouverts ===== | ||
| ^ Sujet ^ Action ^ | ^ Sujet ^ Action ^ | ||
| - | | Flags rewinged | + | | Auto-internalisation |
| | Bug de matching | Tester sur un poste témoin avec un logiciel préinstallé | | | Bug de matching | Tester sur un poste témoin avec un logiciel préinstallé | | ||
| | Server 2019/2022 | Inventorier la proportion dans le parc | | | Server 2019/2022 | Inventorier la proportion dans le parc | | ||
| | Upgrade RustDesk | Vérifier que la mise à jour préserve '' | | Upgrade RustDesk | Vérifier que la mise à jour préserve '' | ||
| - | | Rétention | Définir une politique de purge des anciennes versions d' | + | | '' |
| - | | Forgejo | + | | Rétention |
| - | | Internalisation | Relever | + | | Quota Forgejo | Dimensionner |
| - | ===== 13. VersionID ===== | + | ===== 15. Références ===== |
| - | + | ||
| - | <code powershell> | + | |
| - | function Get-MsiCodes { | + | |
| - | param([string]$Path) | + | |
| - | $installer = New-Object -ComObject WindowsInstaller.Installer | + | |
| - | $db = $installer.GetType().InvokeMember(' | + | |
| - | $props = @{} | + | |
| - | foreach ($p in ' | + | |
| - | $view = $db.GetType().InvokeMember(' | + | |
| - | @(" | + | |
| - | $view.GetType().InvokeMember(' | + | |
| - | $rec = $view.GetType().InvokeMember(' | + | |
| - | if ($rec) { | + | |
| - | $props[$p] = $rec.GetType().InvokeMember(' | + | |
| - | } | + | |
| - | } | + | |
| - | [PSCustomObject]$props | + | |
| - | } | + | |
| - | + | ||
| - | Get-MsiCodes ' | + | |
| - | </ | + | |
| - | ===== 14. Références ===== | + | |
| * [[https:// | * [[https:// | ||
| * [[https:// | * [[https:// | ||
| * [[https:// | * [[https:// | ||
linux/rewinged.1789196740.txt.gz · Dernière modification : de root
