Sous backuppc, les utilisateurs peuvent être avertis d’une erreur de sauvegarde des fichiers Outlook lorsque leur poste est sauvegardé par smb. Mais je voulais profiter de la rapidité et de la sécurité de SSH couplé à Rsync. Le problème de cette solution est que les fichiers ouverts, tout comme en sauvegardant en smb, no peuvent pas être sauvegardés.
Mon but est donc de procéder comme suit :
- création d’une volume shadow copy puis montage de volume avant la sauvegarde
- sauvegarde du postes par SSH/Rsync
- démontage et suppression de la volume shadow copy
Cette solution a les avantages :
- d’une sauvegarde rapide
- d’avoir une communication cryptée
- de sauvegarder tous les fichiers, même ceux qui sont verouillés
Les points négatifs sont :
- une installation assez lourde (Cygwin, scripts, exe) que je vais essayer d’optimiser/automatiser
- une difficulté pour restaurer les fichiers à leur emplacement d’origine en effet les fichiers sont sauvegardés depuis un dossier monté spécialement (exemple : c:\shadow\C).
I – Copie du fichier vshadow.exe
Le fichier vshadow.exe est l’exécutable utilisé pour gérer les clichés instantanés.
Afin d’éviter d’installer le SDK, voilà une archive regroupant les fichiers vshadow pour Windows XP, Vista, 7, 2003, 2008 et 2008 R2 : vshadow versions
Je copie ce fichier dans le dossier c:\shadow\
2 – Installation de Cygwin et paramétrage de l’authentification par clef publique
a – Installer Cygwin avec les paquets suivants :
- nano
- rsync
- openssh
- cygrunsrv
Accepter l’installation des paquets dépendants.
Créer l’utilisateur qui sera utilisé pour effectuer les sauvegardes, je vais créer l’utilisateur backuppc et lui donner un mot de passe.
Se reconnecter au PC sous ce nouveau compte et exécuter cygwin en tant qu’admin (clic droi, exécuter…).
Lancez les commandes suivantes :
cygrunsrv -S sshd
b – Ajout de la clef publique
Depuis le serveur connectez-vous en ssh à la machine en train d’installer :
su backuppc
ssh nomdelamachine
# entrer le mot de passe de l'utilisateur backuppc
nano /home/backuppc/.ssh/authorized_keys
# coller la ligne de la clef publique, bien vérifier que tout soit sur une seule ligne et enregistrer le fichier
Essayez de vous connecter à nouveau, cette fois aucun mot de passe ne devrait être demandé, en effet la clef publique sera utilisée pour la connexion
c – Eviter l’expiration du mot de passe des comptes Windows créés
Sur une ligne de commande classique exécutée en tant qu’admin, lancez les commandes suivantes afin de désactiver l’expiration des mots de passes des comptes cyg_server et backuppc :
wmic path Win32_UserAccount where Name='cyg_server' set PasswordExpires=false
3 – Scripts pour l’utilisation de VSS
a – Fichier VssSnapshot.vbs
Un script doit être mis en place sur la machine, je me suis inspiré du script disponible sur cette page.
Mais je l’ai simplifié pour les test, seul le volume shadow de C est monté. De plus j’avais un bloquage au moment de démonter l’image j’ai dont ajouté quelques lignes pour éviter ce blocage.
Mon script vssShadow.vbs à placer sur chaque poste sauvegardé dans le dossier C:\shadow\
''# http://serverfault.com/questions/119120/how-to-use-a-volume-shadow-copy-to-make-backups/119592#119592
Option Explicit
Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")
''# -- MAIN SCRIPT -------------------------------------------
Dim args, snapshotId, targetPath, success, vshadowPath
Set args = WScript.Arguments.Named
vshadowPath = "C:\shadow\"
CheckEnvironment
Log "preparing VSS mount point..."
targetPath = PrepareVssMountPoint(args("target"))
If args.Exists("unmount") Then
Log "nothing else to do"
ElseIf targetPath <> vbEmpty Then
Log "mount point prepared at: " & targetPath
Log "creating VSS snapshot for volume: " & args("volume")
snapshotId = CreateVssSnapshot(args("volume"))
If snapshotId <> vbEmpty Then
Log "snapshot created with ID: " & snapshotId
success = MountVssSnapshot(snapshotId, targetPath)
If success Then
Log "VSS snapshot mounted sucessfully"
Else
Die "failed to mount snapshot"
End If
Else
Die "failed to create snapshot"
End If
Else
Die "failed to prepare mount point"
End If
Log "finished"
''# -- FUNCTIONS ---------------------------------------------
Function PrepareVssMountPoint(target) ''# As String
Dim cmd, result, outArray
Dim path, snapshot, snapshotId
Dim re, matches, match
PrepareVssMountPoint = VbEmpty
target = fso.GetAbsolutePathName(target)
If Not fso.FolderExists(fso.GetParentFolderName(target)) Then
Die "Invalid mount point: " & target
End If
''# create or unmount (=delete existing snapshot) mountpoint
If Not fso.FolderExists(target) Then
If Not args.Exists("unmount") Then fso.CreateFolder target
Else
Set re = New RegExp
re.MultiLine = False
re.Pattern = "- Exposed locally as: ([^\r\n]*)"
cmd = vshadowPath & "vshadow -q"
result = RunCommand(cmd, false)
outarray = Split(result, "*")
For Each snapshot In outArray
snapshotId = ParseSnapshotId(snapshot)
If snapshotId <> vbEmpty Then
Set matches = re.Execute(snapshot)
If matches.Count = 1 Then
path = Trim(matches(0).SubMatches(0))
If fso.GetAbsolutePathName(path) = target Then
cmd = vshadowPath & "vshadow -ds=" & snapshotId
RunCommand cmd, true
Exit For
End If
End If
End If
Next
If args.Exists("unmount") Then fso.DeleteFolder target
End If
PrepareVssMountPoint = target
End Function
Function CreateVssSnapshot(volume) ''# As String
Dim cmd, result
If Not fso.DriveExists(volume) Then
Die "Drive " & volume & " does not exist."
End If
cmd = vshadowPath & "vshadow -p " & Replace(UCase(volume), ":", "") & ":"
result = RunCommand(cmd, false)
CreateVssSnapshot = ParseSnapshotId(result)
End Function
Function MountVssSnapshot(snapshotId, target) ''# As Boolean
Dim cmd, result
If fso.FolderExists(targetPath) Then
cmd = vshadowPath & "vshadow -el=" & snapshotId & "," & targetPath
result = RunCommand(cmd, true)
Else
Die "Mountpoint does not exist: " & target
End If
MountVssSnapshot = (result = "0")
End Function
Function ParseSnapshotId(output) ''# As String
Dim re, matches, match
Set re = New RegExp
re.Pattern = "SNAPSHOT ID = (\{[^}]{36}\})"
Set matches = re.Execute(output)
If matches.Count = 1 Then
ParseSnapshotId = matches(0).SubMatches(0)
Else
ParseSnapshotId = vbEmpty
End If
End Function
Function RunCommand(cmd, exitCodeOnly) ''# As String
Dim shell, process, output
Dbg "Running: " & cmd
Set shell = CreateObject("WScript.Shell")
On Error Resume Next
Set process = Shell.Exec(cmd)
If Err.Number <> 0 Then
Die Hex(Err.Number) & " - " & Err.Description
End If
On Error GoTo 0
If Not cmd = vshadowPath & "vshadow -q" Then
Do While process.Status = 0
WScript.Sleep 100
Loop
End If
output = Process.StdOut.ReadAll
If process.ExitCode = 0 Then
Dbg "OK"
Dbg output
Else
Dbg "Failed with ERRORLEVEL " & process.ExitCode
Dbg output
If Not process.StdErr.AtEndOfStream Then
Dbg process.StdErr.ReadAll
End If
End If
If exitCodeOnly Then
Runcommand = process.ExitCode
Else
RunCommand = output
End If
End Function
Sub CheckEnvironment
Dim argsOk
If LCase(fso.GetFileName(WScript.FullName)) <> "cscript.exe" Then
Say "Please execute me on the command line via cscript.exe!"
Die ""
End If
argsOk = args.Exists("target")
argsOk = argsOk And (args.Exists("volume") Or args.Exists("unmount"))
If Not argsOk Then
Say "VSS Snapshot Create/Mount Tool" & vbNewLine & _
vbNewLine & _
"Usage: " & vbNewLine & _
"cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
" /target:path { /volume:X | /unmount } [/debug]" & _
vbNewLine & vbNewLine & _
"/volume - drive letter of the volume to snapshot" & _
vbNewLine & _
"/target - the path (absolute or relative) to mount the snapshot to" & _
vbNewLine & _
"/debug - swich on debug output" & _
vbNewLine & vbNewLine & _
"Examples: " & vbNewLine & _
"cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
" /target:C:\Backup\DriveD /volume:D" & vbNewLine & _
"cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
" /target:C:\Backup\DriveD /unmount" & _
vbNewLine & vbNewLine & _
"Hint: No need to unmount before taking a new snapshot." & vbNewLine
Die ""
End If
End Sub
Sub Say(message)
If message <> "" Then WScript.Echo message
End Sub
Sub Log(message)
Say FormatDateTime(Now()) & " " & message
End Sub
Sub Dbg(message)
If args.Exists("debug") Then
Say String(75, "-")
Say "DEBUG: " & message
End If
End Sub
Sub Die(message)
If message <> "" Then Say "FATAL ERROR: " & message
WScript.Quit 1
End Sub
Il faut créer deux script utilisés par backuppc avant et après la sauvegarde afin de gérer le volume shadow copy.
Mon plus gros problème aura été de trouver pourquoi vshadow faisait des erreurs à chaque exécution depuis backuppc, cela est causé par le fait que lorsqu’un se connecte à Cygwin par ssh en authentification par clef, l’utilisateur n’est pas authentifié comme l’utilisateur normal mais comme le compte système. De ce fait, ce compte ne dispose pas des droits de gestion de VSS.
Une authentification est donc obligatoire. N’ayant rien trouvé dans le man ssh je me suis tourné vers expect qui permet d’automatiser des enchaînements de commandes.
b – Fichier pre-backuppc.sh
Script sur le serveur utilisé avant la sauvegarde (/home/backuppc/pre-backuppc.sh chez moi) :
set force_conservative 1;
set USER [lindex $argv 0]
set HOST [lindex $argv 1]
set timeout 30
spawn ssh -o PubkeyAuthentication=no $USER@$HOST "cscript.exe /nologo c:\\\\shadow\\\\vssSnapshot.vbs /target:C:\\\\shadow\\\\C /volume:C /debug\r"
expect "password:\r"
send -- "motdepasse\r"
set timeout 500
expect OEF
c – Fichier post-backuppc.sh
Script sur le serveur utilisé après la sauvegarde (/home/backuppc/post-backuppc.sh chez moi) :
set force_conservative 1;
set USER [lindex $argv 0]
set HOST [lindex $argv 1]
set timeout 30
spawn ssh -o PubkeyAuthentication=no $USER@$HOST "cscript.exe /nologo c:\\\\shadow\\\\vssSnapshot.vbs /target:C:\\\\shadow\\\\C /unmount \r"
expect "*password:*"
send -- "motdepasse\r"
set timeout 500
expect OEF
4 – Optimisations et corrections de problèmes
- Autoriser les réponses ICMP dans le firewall afin de pouvoir faire un ping
- Ajouter au moins les droits de lecture à l’utilisateur backuppc sur les dossiers/fichiers à sauvegarder
- Sous Windows XP vérifier que les services suivants sont bien en démarrage automatiques et sont démarrés :
- MS Software Shadow Copy Provider
- Volume Shadow Copy
Si il y a un pbl avec la création d’un utilisateur lancer la commande
mkpasswd.exe > /etc/passwd
Si impossible de se connecter avec l’utilisateur backuppc essayer la commande ssh-user-config
Masquer les comptes utilisés par Cygwin et backuppc
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList]
"backuppc"=dword:00000000
"cyg_server"=dword:00000000
Quelques tutos qui m’ont aidé :
- http://msdn.microsoft.com/en-us/library/bb530725(v=vs.85).aspx#creating_a_shadow_copy_set
- http://geraldbrandt.com/2010/06/08/backuppc-with-sshrsyncvss-on-windows-server/
- http://sourceforge.net/apps/mediawiki/backuppc/index.php?title=User_Scripts_-_Client_-_Windows_VSS
- http://www.backupcentral.com/phpBB2/two-way-mirrors-of-external-mailing-lists-3/backuppc-21/complete-cygwin-vss-rsync-solution-for-windows-backup-106181/