Deploiement de logiciel sur des ordinateurs non administrateurs Windows depuis un site

Intro


Aujourd'hui il est assez compliqué de déployer des logiciels sur des postes non admin sans mettre la main à la poche, ou que les solutions existantes ne conviennent pas

Je vais donc vous montrer toutes les étapes pour mettre en place un système de déploiements de logiciels via un site

Un dockerfile est présent en bas de page, lisez quand même toutes la documentation, ca vous servira

Pour cela il vous faudra :

  • Un serveur debian ou toutes autre distribution Linux
  • Installé dessus les outils nécessaires

Sur les postes Windows, il faudra :

  • Installer openssh-server
  • Configurer le fichier sshd_config
  • Générer un certificat ssh
  • Déployer le certificat sur le compte admin local de toutes les machines du parc

Tout cela se fera via un script, sauf la création du certificat

A qui cela est-il dédié

Toutes les sociétés qui ont un besoin de restreindre les droits des utilisateurs, tout en leur laissant la possibilité d'installer les logiciels autorisé par le SI ou RSSI

Comment cela fonctionne

  • L'utilisateur se connecte sur le site, choisit son logiciel à installer/MAJ ou supprimées
  • Le serveur flask lance un playbook ansible avec les paramètres (IP du demandeur, logiciel à installer/Mettre à jour ou supprimé)
  • Pour l'installation
    Il lance le playbook qui va télécharger le logiciel via son URL, l'installer, puis supprimer le package du poste
  • Pour la désinstallation
    Il lance le playbook de suppressions qui va se baser sur les arguments pour rechercher le logiciel dans le registre et le supprimer

Pré-requis de maintenance

J'ai fait en sorte que la maintenance soit minimale

  • Pour ajouter un logiciel, il suffit de dupliquer un des fichiers d'arguments, nommer le fichier comme le logiciel (que des chiffre et lettre, pas d'accent) et modifier les arguments à l'intérieur
  • Cela implémentera le site du nouveau logiciel, car tout est basé sur les fichiers d'arguments ansible

Création des clés SSH


Allez sur un Linux, sinon mobaxterm devrait faire l'affaire, entrer la commande suivante :

Dans notre documentation, les fichiers se nomment id_rsa et id_rsa.pub, mais ils peuvent avoir un nom différent suivant le chiffrement utilisé
Exemple : id_ed25519, ce type de clé est apparemment plus performante que le RSA

ssh-keygen

Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:ktByASokdWIAgCc6OZJ9V8fEAjMxlxE9iNL5HCMBzUg root@MiniPC
The key's randomart image is:
+---[RSA 3072]----+
|O++.EBO*+X.      |
|=..+o.B*B *      |
|o*. o.o= = .     |
|B.. .+..o        |
|.o . .o S        |
|       .         |
|                 |
|                 |
|                 |
+----[SHA256]-----+

Vous allez avoir deux clés sous ~/.ssh

  • id_rsa
    La clé privée sert à se connecter aux machines, attention à la garder privée
  • id_rsa.pub
    La .pub devra être mise sur les postes Windows (vue après dans le script)

~ signifie le chemin du répertoire home de l'utilisateur, exemple pour root
/root/

Mise en place


Partie Windows

Activation et connexion aux comptes administrateurs des poste Windows

  • Activer le compte administrateur du poste, modifier le nom du compte pour plus de sécurité
  • Connectez-vous une première fois dessus

Lancement du script sur les postes Windows

L'intérêt du script est double,

  • Il permet d'installer les logiciels depuis le site que l'on va mettre en place
  • De pouvoir se connecter de façon sécurisée au poste via SSH plutôt que Winrm mais toujours avec powershell (v7 uniquement, utiliser -hostname plutôt que -computername)

https://github.com/Yoyox78/Deploy_OpenSSH_Powershell/blob/main/Install_powershell-openssh.ps1
Voici les modifications à effectuer dans le script avant son execution sur les postes
Ligne 7 et 22 : mettre à jour l'URL par la nouvelle version au besoin
Ligne 81 : Décommenter et modifiez si vous souhaitez autoriser les accès à la machine via un groupe du domaine (par mot de passe)
Ligne 145 : permet d'ajouter une règle firewall pour le SSH, si vous êtes sur un AD, faites plutôt une GPO qui regroupe les règles firewall de vos ordinateurs, adaptez le profil suivant si le poste est sur un domaine, public ou privé
Ligne 152 : modifier le chemin 'C:\Users\Adminrenommer' par le compte admin que vous avez renommer (si t-elle est le cas), si vous n'avez pas renommé le compte, supprimer cette partie ,'C:\Users\Adminrenommer'
Ligne 169 : Remplacer cela (ssh-rsa ACLEPUB) par le contenu de votre fichier id_rsa.pub (clé publique générée plus haut)

Vous pouvez modifier d'autres options au besoin dans la partie variable $sshd
Puis tester la connexion avec votre Linux ou Mobaxterm

Exécuter le script via un système déploiement t-elle que OCS inventory. Si vous le lancez à la main, lancez powershell ISE en administrateur

Partie Linux

  • Il vous faudra une VM avec un debian déjà en place
  • Toutes les commandes sont à exécuter avec le compte root (pas biennn)

Commençons par installer les package necessaire

Mettre à jour le système
apt update && apt upgrade -y

Installez les modules requis
apt install python3 python3-pip ansible python3-ansible-runner python3-flask unzip gunicorn3

Copier la clé privée sur le serveur linux id_rsa
scp ~/.ssh/id_rsa root@IPSRV:/.ssh/

Sur le serveur modifier les droits de la clé (pour la protéger, mais aussi pour éviter les erreurs par la suite)
chmod 600 ~/.ssh/id_rsa

Téléchargez le zip du site
https://github.com/Yoyox78/Site_Deploiement_Logiciels

Cliquez à droite sur code puis download zip

Transférer le dossier contenant tous les fichiers Full_independant
scp ./Site_Deploiement_Logiciels-main.zip root@IPSRVDEBIAN:/

Connectez-vous sur le serveur
ssh root@IPSRVDEBIAN

Extraire le package
mkdir /etc/Deploiement_Logiciel ;unzip -f Site_Deploiement_Logiciels-main.zip && cp -fr Site_Deploiement_Logiciels-main/Full_independant/* /etc/Deploiement_Logiciel/

Modifier le fichier app.py
nano /etc/Deploiement_Logiciel/app.py

Modifier la ligne suivante en remplaçant USRADM par le nom de l'administrateur de vos postes (par défaut administrateur) :
useradm = "USRADM"

Test avant mise en prod

  • Testons le site avant de le mettre en prod
    cd /etc/Deploiement_Logiciel/
    export FLASK_APP=app.py
    flask run -h 0.0.0.0
  • Vous devriez avoir ce retour
 * Serving Flask app 'app.py'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://IPSRV:5000
  • Sur le poste sous Windows, allez sur le site via l'ip http://IPSRV:5000 avec edge par exemple
  • Cliquez sur installer, d'un des trois logiciels présents, Firefox par exemple
  • Vous devriez voir le mode verbeux sur le serveur qui s'affiche, si tout se passe bien vous devriez avoir cela
192.168.122.238 - - [24/May/2024 12:25:34] "GET / HTTP/1.1" 200 -
192.168.122.238 - - [24/May/2024 12:25:34] "GET /static/css/main.css HTTP/1.1" 304 -
192.168.122.238 - - [24/May/2024 12:25:34] "GET /static/css/blog.css HTTP/1.1" 304 -
192.168.122.238 - - [24/May/2024 12:25:34] "GET /static/js/jquery.min.js HTTP/1.1" 304 -
192.168.122.238 - - [24/May/2024 12:25:34] "GET /static/js/chart.js HTTP/1.1" 304 -

PLAY [Installation du logiciel] ************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.122.238]

TASK [include_tasks] ***********************************************************
included: /etc/Deploiement_Logiciel/ansible/logiciel.yaml for 192.168.122.238

TASK [Download firefox] ********************************************************
changed: [192.168.122.238]

TASK [Install firefox] *********************************************************
changed: [192.168.122.238]

TASK [Supression de l'executable firefox.exe] **********************************
changed: [192.168.122.238]

PLAY RECAP *********************************************************************
192.168.122.238            : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.122.238 - - [24/May/2024 12:26:43] "GET /deploy?logiciel=firefox HTTP/1.1" 200 -
  • Voici le resultat après l'installation reussi

InstallationDeFirefox

  • Verifier que le logiciel est bien installer sur le poste en verifiant les programme dans ajout supression de programme

Mise en production

Flask n'est pas fait pour la production, nous allons donc utiliser gunicorn

Nous allons procéder en deux étapes

  • Créer un service systemd avec gunicorn pour le site
  • Créer un reverse proxy pour permettre l'accès en http, vous pouvez aussi le faire en https
Mise en place du service avec SystemD

Création du service
nano /etc/systemd/system/SiteLogiciel.service

[Unit]
Description=Sert pour le déploiement des logiciels
After=network.target

[Install]
WantedBy=multi-user.target

[Service]
WorkingDirectory=/etc/Deploiement_Logiciel/
Environment=FLASK_CONFIG=production
ExecStart=/usr/bin/gunicorn -w 1 -b 127.0.0.1:5000 --timeout 600 app:app
Restart=on-failure
TimeoutSec=60

-Execstart j'indique d'utiliser gunicorn, le timeout permet de ne pas retourner une erreur dans le cas ou l'installation du logiciel serait trop longue, J'explique cela dans les erreurs

  • -w permet de choisir le nombre de worker qui travaille en simultanée

    Si vous ne souhaitez pas monter un reverse proxy, il vous suffit de mettre cette ligne, vous pourrez sauter la partie d'installation et de configuration apache
    il est aussi possible de mettre gunicorn en ssl si vous préférez : https://docs.gunicorn.org/en/stable/settings.html

#Remplacer 0.0.0.0 par l'ip souhaitez si vous avez plusieurs carte reseau avec plusieurs IP
ExecStart=/usr/bin/gunicorn -w 1 -b 0.0.0.0:80 --timeout 600 app:app

Entrez les commandes suivantes pour l'activer

 # Active le service créé
 systemctl enable SiteLogiciel.service
 # démarre le service
 systemctl start SiteLogiciel.service

Vérifier que le service à bien démarré
systemctl status SiteLogiciel.service

Création du reverse proxy avec apache2

Nous allons mettre en place le reverse proxy en HTTP, il serait préférable de le mettre en SSL (443)

A savoir : l'extension .local utilisée par pal mal d'entreprise pour leur domaine local, appartient à apple. Logiquement on devrait éviter de l'utiliser surtout si vous utilisez du materiel apple

Installation de apache2
apt install apache2

Activation du module pour faire le reverse proxy
a2enmod proxy_http

<VirtualHost *:80>
        ServerName deploiement.TONDOMAINE.LOCAL

        ProxyPass / http://127.0.0.1:5000/
        ProxyPassReverse / http://127.0.0.1:5000/
        ErrorLog ${APACHE_LOG_DIR}/deploiement-error.log
        CustomLog ${APACHE_LOG_DIR}/deploiement-access.log combined

</VirtualHost>
Fonctionnement du site
  • App.py
    • Je liste les fichiers présents dans /etc/Deploiement_Logiciel/ansible/logiciels/
    • J'enlève l'extension
    • je mets le tout en variable
    • 7zip.yaml deviens 7zip
    • J'envoie la variable dans l'index.html
  • Index.html
    • Une boucle affiche tous les logiciels présent dans la variable avec deux boutons
    • 1 pour l'installation et la mise à jour
    • l'autre pour la suppression
    • Chaque bouton a un identifiant unique (le nom du logiciel)
  • Quand une personne clique sur installation
    • Le playbook d'installation se lance via le app.py qui est apellé avec le /deploy
    • il télécharge le logiciel présent dans l'URL importé via des variables ansible
    • Il installe le logiciel
    • il supprime l'executable
  • Quand il clique sur la suppression
    • Le playbook d'installation se lance via le app.py qui est apellé avec le /remove
    • Cela récupère la variable ansible contenant le nom du logiciel via les variables ansible, puis recherche le nom du logiciel dans la partie uninstall 32 et 64bits du registre Windows
    • Si il la trouve, il lance la suppression
  • Dans tous les cas un retour est fait à l'utilisateur, si vous n'avez pas le logiciel et que vous le supprimer vous aurez quand même un retour positif
Ajout de logiciels

Allez dans /etc/Deploiement_Logiciel/ansible/logiciels/
Copier un des fichiers présents
cp 7zip.yaml notepadpp.yaml
Ouvrez le fichier et modifiez les lignes
nano notepadpp.yaml

Attention à n'utiliser que des chiffres et lettres pour le nom des fichiers

Exemple du fichier notepadpp.yaml:

url: 'https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.5.2/npp.8.5.2.Installer.x64.exe'
arg: '/S /noUpdater'
argunin: '/S'
product: Notepad\+\+
  • url mettre l'URL de téléchargement du logiciel, peut être une latest (donc toujours à jour pas besoin de mettre à jour l'URL)

    • url n'accepte que des URL HTTP ou FTP
  • arg indiquer les arguments d'installation

  • argunin Indiquer les arguments de désinstallation

  • product il faut indiquer le nom de la clé présente dans le registre, il faudra donc installer le logiciel une premier fois sur le poste pour avoir l'information

    • 32 bits : HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
    • 64 bits : HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall
  • product : le nom à donner est au format regex (c'est quoi ça ? :p, pas d'inquiétude je vais expliquer)

    • Les regex c'est des règles mathématiques pour retrouver du texte, par exemple dans le registre, sans savoir exactement ce que l'on recherche :)
    • Pourquoi tu as fait ça ?
    • Parce que les petits malins de certains logiciels tels que Firefox mettent la version à la suite de Mozilla Firefox dans le registre, ce qui donne: Mozilla Firefox 123.2.35
      Du coup vous remarquez le foutoir avec le temps, donc on fait de la regex basique pour vous promis

Deux cas possibles :

  1. Votre logiciel contient que le nom comme 7zip ou notepad++
    vous mettez le nom du logiciel, attention si vous avez des caractères spéciaux +*?.(){}[] faut les annuler avec des antislash \
    Donc notepad++ donne notepad\+\+
  2. Votre logiciel contient un numéro de version
    Prenont Firefox comme exemple Mozilla Firefox 123.0.2.5
    Il va donc falloir rendre générique la version pour que ansible puisse récupérer la clé
    Nous allons faire une chose super simple mais imprudente, on va utiliser un wildcard
    .* le point indique n'importe quel caractère même les espaces ou tabulations, l'étoile signifie que ce caractère se répète 0 fois ou un nombre de fois illlimitée
    Donc le . signifie n'importe quel caractère mais une seule fois, l'étoile va répéter n'importe quel caractère autant de fois qu'il sera nécessaire
    Le .* va donc substituer 123.0.2.5 ou 123.0.2.6 etc..
  3. Récapitulatif: indique le nom du logiciel et le reste qui peut changer, vous mettez .*, je ne vais pas faire un cours sur les regex et cela suffira dans 90% des cas

Deux possibilités d'executable, l'exemple sera sur 7zip

  1. MSI
    Voici le yaml de 7zip pour du msi
    url: 'https://www.7-zip.org/a/7z2405-x64.msi'
    arg: '/qn'
    argunin: '/qn'
    product: \{23170F69-40C1-2702-2405-000001000000\}

    ne pas oublier les regex d'ou l'antislash avant l'accolade ouvrante et fermante

  2. EXE
    le fichier yaml du même 7zip mais en exe
    url: 'https://www.7-zip.org/a/7z2401-x64.exe'
    arg: '/S'
    argunin: '/S'
    product: 7-Zip

Résumé

  • Comme vous avez remarqué les msi n'ont pas les nom des logiciel mais des UID, il faudra donc l'indiqué
  • Pareil pour les argument d'installation et de desinstallation, il peuvent différer

Logs

Pour gunicorn
journalctl -u SiteLogiciel.service

pour apache2
journalctl -u apache2.service

Pour voir les logs d'accès
tail -f /var/log/apache2/deploiement-access.log

Pour voir les logs d'erreurs
tail -f /var/log/apache2/deploiement-error.log

Un peu de sécurité

  • Pour que l'installation soit plus sécurisée, il faudrait :
    • Mettre en place un pare-feu sous Linux (UFW)
    • Changement d'utilisateur pour le lancement de gunicorn qui est par defaut root
    • Passer le site apache2 en HTTPS avec un certificat autosigné avec une autorité de certification que vous aurez créé et déployer sur tous les postes de votre entreprise

Dockerfile (méthode simplifié)


Intro

Désolé si ce n'est pas très propre, je viens tout juste de me mettre à docker
Vous aurez besoin de docker pour le lancer
apt install docker.io

Téléchargement

Il faudra téléchargez tout le dossier
https://github.com/Yoyox78/Site_Deploiement_Logiciels/tree/main/dockerfile
Si vous avez git :
git clone https://github.com/Yoyox78/Site_Deploiement_Logiciels

  • Entrez dans le dossier extrait
    • Ajoutez y la clé privée (à coté du fichier dockerfile) que vous avez générée au début, elle doit commencer par id_ pour qu'elle soit copiée dans le répertoire .ssh du container docker
  • Le dossier logiciel sera monté dans le container, c'est dans ce dossier que vous allez devoir ajouter vos fichiers pour l'installation des logiciels

Utilisation

Toujours dans le dossier téléchargé
La commande suivante va permettre de build le dockerfile, cela peut prendre un peu de temps suivant les performances de la machine
docker build -t deploiement .
-t sert à tagger l'image crée

Une fois le build terminé, cette commande va permettre de lancer le container
docker run --name site -d -p 80:80 -v /root/docker/logiciels:/etc/Deploiement_Logiciel/ansible/logiciels:ro -e USER=administrateur deploiement

--name site nom que vous souhaitez donner au container
-p 80:80 sera utilisé sur le port 80, vous pouvez modifier
-v /root/docker/logiciels:/etc/Deploiement_Logiciel/ansible/logiciels:ro Remplacer /root/docker/logiciels, par le chemin complet d'accès au répertoire logiciels présent à coté du fichier dockerfile
-e USER=administrateur n'indiquer ce paramètre que si l'utilisateur administrateur des machines a été modifié, la valeur indiqué dans la ligne de commande RUN surpasse la variable présente dans le dockerfile

Ne pas oublier de faire la partie mise en place (partie Windows) au début de la page

Remerciement :

ChatGPT m'a pas mal aidé sur le squelette des parties flask et js.
Si des dev y voit des abérrations, ne pas hésiter à apporter des modifications sur le git ou à me faire un retour

ERREURS

Dockerfile

  • COPY failed: no source files were specified
    Vous avez oublié de mettre la clé privée dans le dossier a coté du fichier dockerfile
  • Vous n'avez pas de logiciel présent sur le site alors que le dossier en contient
    Verifier le chemin indiqué lors du lancement de la commande RUN
  • Les nouveau logiciel crée ne s'affiche pas
    Relancez votre container

général

  • Vous avez une ereur 502 sous firefox ou ERR_EMPTY_RESPONSE sous Chrome / Edge
    ErreurTimeout
    Augmenter le timeout dans le entrypoint
    ENTRYPOINT /usr/bin/gunicorn -w 1 -b 0.0.0.0:80 --timeout 30 app:app
    Si c'est une installation standalone, modifier le timeout dans le service systemd

SOURCE

https://learn.microsoft.com/en-us/powershell/module/netsecurity/new-netfirewallrule?view=windowsserver2022-ps
https://learn.microsoft.com/fr-fr/windows-server/administration/openssh/openssh_install_firstuse
https://learn.microsoft.com/fr-fr/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-7.3
https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-7.3
https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration
https://learn.microsoft.com/fr-fr/powershell/module/microsoft.powershell.core/disable-psremoting?view=powershell-7.3
https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement