Quelques billes pour automatiser la préparation d’un serveur en Powershell

Je déploie régulièrement des VM à partir d’un template, seulement il reste pas mal d’opérations à faire à la main, comme le changement de nom, la configuration du réseau, l’installation de certaines applications et paramètres qui redescendent pas forcément par GPO.

Je vais donc présenter plusieurs instructions et snippets Powershell qui pourront fournir une bonne base pour la création d’un script complet pouvant être intégré dans un template et exécuté directement après le déploiement.

Tout d’abord, le changement du nom du serveur. On peut faire quelque chose de sympa comme ceci :

$hostname = $env:computername
Write-Host « Current Server name: $hostname »
$newhostname = Read-Host « New hostname »
Rename-Computer -NewName $newhostname
Write-Host « A reboot is required and will be performed in approx. 10 seconds. The script will automatically start after reboot to continue post-deployment operations. »
shutdown -r -t 10

On affiche le nom actuel du serveur, puis un prompt permettant de saisir le nouveau nom de machine. Un reboot permettra de prendre en compte le changement.

Après le redémarrage, on peut passer à la configuration de la carte réseau. En fonction de la configuration de la machine, cela peut être délicat puisqu’il faut être sûr d’affecter l’IP à la bonne carte réseau ; pour cela, on va donc récupérer toutes les cartes réseaux branchées sur le système, puis faire un filtre par nom et qui fonctionnent en IPv4. Par exemple, si la carte réseau s’appelle Ethernet0 :

$ipv4 = Read-Host « IPV4 address »
$gateway = Read-Host « Gateway »
$dnsprim = Read-Host « Primary DNS »
$dnssec = Read-Host « Secondary DNS »

$networkcards = Get-NetIPInterface | Where-Object {$_.InterfaceAlias -eq « Ethernet0 » -and $_.AddressFamily -eq « IPv4 »}
$interfaceindex = $networkcards[0].ifIndex
New-NetIPAddress -InterfaceIndex $interfaceindex -IPAddress $ipv4 -PrefixLength 24 -DefaultGateway $gateway
Set-DnsClientServerAddress -InterfaceIndex $interfaceindex -ServerAddresses ($dnsprim,$dnssec)

Get-NetIPInterface avec son pipe nous permet de rechercher les interfaces ayant pour nom Ethernet0 et configurées en IPv4. On récupère donc la carte qui est retournée par l’instruction et son index (qui n’est naturellement pas 1, ce serait trop facile !), qui nous permet ensuite de pouvoir le passer en paramètre de l’instruction New-NetIPAddress qui va se charger de coller la configuration IP à la carte. Le masque de sous réseau ne s’exprime pas en 255.255.255.0 mais notation CIDR, soit 24. Des tables de conversion sont facilement accessibles grâce à n’importe quel moteur de recherche, vous pouvez utiliser celle-ci. Si l’instruction est bien passée, elle retournera alors plusieurs informations quant à l’interface.

Ensuite, maintenant que le réseau est configuré, on peut joindre la machine au domaine.



Add-Computer -DomainName « super-domaine.local »
if ($?){ Write-Host « A reboot is required and will be performed in approx. 10 seconds. The script will automatically start after reboot to continue post-deployment operations. »
shutdown -r -t 10 }

Un prompt devrait apparaître pour demander un identifiant et un mot de passe d’un compte autorisé à ajouter des machines au domaine. Si la jonction se fait bien, alors le code dans la boucle if est exécuté et la machine redémarre après environ 10 secondes.

La machine mise sur le domaine, les divers paramètres poussés par GPO devraient redescendre (il faut bien évidemment pas oublier de déplacer l’objet Ordinateur qui s’est créé dans l’AD dans la bonne OU, sinon ça risque de ne pas bien marcher 😱). Cependant, d’autres opérations ou paramètres peuvent être modifiés par Powershell ; en voici quelques-uns.

Autorisation de l’exécution de scripts Powershell sans restriction :

Write-Host « Setting Powershell execution policy to Unrestricted… »
Set-ExecutionPolicy Unrestricted

Désactivation du pare-feu pour le domaine :

Set-NetFirewallProfile -Profile Domain -Enabled False 

Si on souhaite tout automatiser et placer dans un même script, il faut prévoir la phase de reboot suite au changement de nom de la machine et la jonction au domaine (bien que la commande Add-Computer tolère un renommage de la station dans l’instruction). Pour n’utiliser qu’un seul script, et faire en sorte qu’il reprenne exactement là où il s’était arrêté, on peut placer chaque étape dans une fonction, et placer en paramètre facultatif le numéro de l’étape sur laquelle le script démarre ; ensuite une tâche planifiée démarre le script à l’ouverture de session de l’administrateur local.

Déclaration du paramètre :

Param
([string]$step)

Ensuite, une fonction pour créer la tâche, qui elle-même va prendre un paramètre :

function createtask{
param($rebootstep)
$TaskDetails = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType ServiceAccount -RunLevel Highest
$TaskAction = New-ScheduledTaskAction -Execute « powershell.exe » -Argument « C:\post-deployment.ps1 -s $rebootstep »
$TaskSched = New-ScheduledTaskTrigger -AtLogOn
$TaskName = « PostDeployReboot »
Register-ScheduledTask -Action $TaskAction -Principal $TaskDetails -Trigger $TaskSched -TaskName $TaskName
}

Et on appelle cette fonction après le renommage de la machine par exemple :

Rename-Computer -NewName $newhostname
createtask(2)

Ainsi, au début du script, on peut placer cette instruction qui appellera la fonction setnetwork dans laquelle le code pour paramétrer la carte réseau sera placé :

if ($step -eq « 2 ») { setnetwork }

La tâche planifiée exécutant le script avec le paramètre -s 2, le script démarrera directement sur cette étape.

Powershell : modification du registre pour contourner CredSSP

Au mois de mars, des correctifs Microsoft ont corrigé certaines failles par rapport à CredSSP qui est notamment utilisé pour sécuriser des connexions RDP (voir ce lien). Un message d’erreur peut survenir si un client patché tente de se connecter à un serveur non patché ou vice-versa. Pour faire simple, il est nécessaire que client comme serveur soient patchés pour qu’ils puissent communiquer.

J’ai réalisé un script Powershell permettant de contourner la sécurité via le registre afin que le système ne tienne pas compte du delta de version entre le CredSSP client et serveur. Dans un monde parfait, cela ne devrait pas exister car postes de travail et serveurs devraient être patchés en temps et en heure, mais la réalité est bien évidemment tout autre pour tout un tas de raisons. 👍

#Requires -RunAsAdministrator
$CredSspPath = « HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System »
$ParametersPath = « HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP »
$AllowEncryptionOraclePath = « HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters »
New-Item -Path $CredSspPath -Name « CredSSP » -Force
New-Item -Path $ParametersPath -Name « Parameters » -Force
New-ItemProperty -Path $AllowEncryptionOraclePath -Name « AllowEncryptionOracle » -PropertyType DWORD -Value « 2 » -Force
Write-Host « If everything went fine, please reboot the system for the changes to take effect. »
Sleep 5

Le script doit être lancé en administrateur ; une fois les clefs déployées, il est nécessaire de redémarrer la station qui devrait pouvoir se connecter sans le message d’erreur plus haut, ce qui ne dispense évidemment pas d’une campagne de patch ! 😉

Vous pouvez trouver une version commentée du script sur le serveur de fichiers en cliquant sur ce lien. 💾

Quelques techniques de sioux pour sécuriser un hôte Proxmox VE

Maintenant que ma nouvelle installation de Proxmox VE tourne à merveille suite aux déboires que j’ai pu avoir chez mon ancien prestataire, je vais vous dévoiler quelques-unes de mes techniques de sioux pour sécuriser un peu plus un hôte Proxmox, car en configuration par défaut ce n’est pas très excitant. Ces quelques billes ne transformeront pas votre hôte en forteresse inviolable, mais il sera déjà un peu plus blindé ! 😁

Sécuriser SSH

Un petit tour dans /etc/ssh/sshd_config rapidement, et on va procéder au changement de quelques paramètres, tout d’abord le port par défaut sur lequel SSH écoute. Le 22 étant le port par défaut, on va le changer. Naturellement, on évitera de mettre un port qui est déjà utilisé pour une autre application ou qui pourrait être bloqué par un éventuel pare-feu. Ensuite, l’option PermitRootLogin ne doit surtout pas être à yes mais à without-password, prohibit-password ou à no. Les deux premières options peuvent être utilisées avec des clefs SSH, tandis que la dernière bloquera complètement le login en root, forçant un su une fois la connexion avec un utilisateur standard établie.

Rejeter les tentatives de connexion avec une autre IP

Dans /etc/hosts.allow, on va pouvoir définir les adresses IP qui sont autorisées à communiquer avec certains services installés sur la machine. Il peut être judicieux de rejeter les connexions SSH sur toutes les IP sauf une. Par exemple, celle d’un VPN et éventuellement d’une de vos machines virtuelles si vous avez une VM dédiée à l’administration.

Dans cet exemple, je n’autorise qu’une IP à se connecter et je bloque toutes les autres.

sshd : 192.168.1.2 : allow
sshd : all : deny

Autoriser l’accès à l’interface web de Proxmox uniquement sur une adresse ou un range d’IP

Par défaut, l’interface web de Proxmox est accessible sur le port 8006 pour tout le réseau internet. Le moteur web étant basé sur Apache, il est possible d’appliquer des règles allow et deny toutes simples pour n’autoriser l’accès à l’interface web que sur les IP que l’on souhaite. Ici aussi, utiliser un VPN peut s’avérer utile car on déplace derrière une authentification supplémentaire le portail web.

On édite avec nano le fichier /etc/default/pveproxy, puis on saisit les IP qu’on souhaite autoriser ou refuser comme ceci :

ALLOW_FROM= »192.168.1.2,192.168.2.12″
DENY_FROM= »all »

POLICY= »allow »

Un redémarrage de l’interface web est nécessaire :

pveproxy restart

Installer fail2ban

fail2ban est une application tournant en tâche de fond qui écoute les divers logs système et applicatifs et repère les tentatives de brute-force et place en cas d’échecs répétés de connexion les IP dans les règles de rejet du pare-feu ; en conséquence, toutes les IP (ou plage) voient leurs connexions rejetées pendant un certain laps de temps durant la configuration. Celle par défaut suffit normalement pour le peu de services qui sont en théorie installés sur l’hôte.

apt install fail2ban

Le fichier de configuration le plus intéressant est /etc/fail2ban/jail.conf car c’est ici que l’on peut éventuellement ajouter des services à monitorer.

En dehors de ces astuces, je ne saurai que conseiller de créer des utilisateurs avec le minimum de privilège par VM, créer un compte pour l’administration du datastore, et de passer par un VPN pour vous connecter en SSH ou en web. Vous pouvez trouver plus de documentation sur ces liens concernant fail2ban, pveproxy et sshd_config.

Migration des VM d’un hôte Proxmox VE vers un autre hôte sans cluster

Suite à des déboires par rapport à l’hébergeur de mon serveur, j’ai fini par revenir chez OVH chez qui j’ai toujours été satisfait. Sur ce nouveau serveur, j’ai donc rempilé pour la même distribution que l’ancien, un Proxmox VE 5 sur base de Debian 9, pour des raisons de compatibilité principalement, et aussi car j’étais satisfait de cet hyperviseur après quelques années sous ESXi.

Le principal intérêt étant la possibilité de conserver les machines virtuelles et ne rien avoir à réinstaller à part l’hyperviseur lui-même et refaire la configuration (ou plutôt, la redéployer étant donné que j’avais tout sauvegardé), je vais expliquer dans cet article comment procéder à l’export et à l’importation des VM de l’ancien hôte vers le nouveau.

Sur l’interface de Proxmox, sélectionner la machine virtuelle que l’on souhaite sauvegarder, puis aller dans Backup, et enfin, cliquer sur Backup Now. Si le datastore est invisible, il faut activer le stockage de fichiers de sauvegarde dessus (Datacenter > Storage > Edit > Content, cocher VZDump backup file).

La fenêtre de sauvegarde d’une VM. Il faut choisir le datastore sur lequel écrire la sauvegarde, le mode (snapshot, mise en veille de la VM ou arrêt complet) et enfin, spécifier si l’on souhaite une compression de celle-ci et/ou un mail.

Un snapshot n’étant pas suffisant pour restaurer une VM sur un autre hôte sans cluster, il faut donc soit mettre en sommeil la VM le temps de la sauvegarde (option Suspend) ou l’arrêter complètement (option Stop). Dans mon cas, le mode Suspend suffit ; j’ai choisi une compression LZO pour réduire le temps de transfert vers l’autre hyperviseur.

Il se peut que la sauvegarde échoue : le message d’erreur est généralement assez clair, mais s’assurer qu’il ne reste pas un ISO de monté et inaccessible ou que la VM n’est pas en cours d’extinction déjà est un début.

Un écran apparaît alors permettant de suivre le déroulement de la sauvegarde, en fonction de la taille de la machine, de vos performances CPU et disque, il n’y a pas de vrai moyen de déterminer le temps que cela peut prendre. A titre d’exemple, une sauvegarde d’une VM avec un seul disque virtuel contenant environ 65 Go de données s’est terminée en environ 15 minutes (CPU Core i7-4770, 32 Go de RAM, disques SATA 10K).

Une fois la sauvegarde terminée, il va s’agir de la transférer. Le moyen présentant le meilleur ratio simplicité/sécurité est d’utiliser SCP. Dans un shell, nous allons donc nous placer dans le répertoire des dumps, identifier le fichier de sauvegarde, puis lancer le transfert SCP.

cd /var/lib/vz/dump/
ls

La sauvegarde est donc au format .vma.lzo puisque l’on a décidé de compresser en LZO. En cas de doute un ls -l affiche la taille, permettant de différencier le log de la sauvegarde elle-même.

Reste plus qu’à lancer le SCP :

scp vzdump-qemu-machineidtime_stamp.vma.lzo user@destination:/var/lib/vz/dump/vzdump-qemu-machineidtime_stamp.vma.lzo

A noter que machineid et time_stamp sont des variables qui changent naturellement en fonction de l’ID de la VM et de l’heure à laquelle la sauvegarde a commencé ; on utilisera bien sûr le nom récupéré plus haut. scp utilisant SSH, il peut être nécessaire de préciser le port sur lequel écoute SSH sur le serveur de destination (scp -P 2222 par exemple, si le port SSH est 2222). Il faut également que l’utilisateur spécifié soit en mesure d’écrire dans le répertoire de destination. Vous pouvez faire le transfert vers un homedirectory avec un utilisateur tout simple puis ensuite déplacer la sauvegarde vers le répertoire des dumps.

Le temps de transfert dépendant quasi-uniquement de la bande passante entre les deux hôtes, impossible de prédire celui-ci. Une fois le transfert terminé, sur le nouveau Proxmox, il suffit de se rendre sur les propriétés du datastore pour permettre de gérer les sauvegardes si cela n’est pas déjà fait  (éventuellement déjà opéré sur l’hôte d’origine pour faire les sauvegardes) :

En cochant VZDump backup file, on permet au datastore de gérer les fichiers dumps.

Puis, en se rendant dans le datastore lui-même, on aperçoit bien notre backup :

Il ne reste plus qu’à le sélectionner, cliquer sur Restore, indiquer un ID de machine virtuelle libre sur le nouvel hôte et le datastore de stockage. Puis au redémarrage, tout sera comme à l’extinction sur l’ancien hôte 😎

Si l’envie vous prend de réaliser tout en ligne de commande ou que vous ne pouvez pas utiliser l’interface web, je vous renvoie vers la documentation de vzdump et qmrestore.