Backup von SonicWall Security Appliances

Die SonicWall Security Appliances bieten zwar über das Web GUI die Möglichkeit die Settings zu exportieren, aber man muss halt daran denken. Bequemer ist es das Backup automatisiert zum Beispiel täglich in der Nacht durchführen zu lassen. Um das zu bewerkstelligen kann das Command Line Interface (CLI) der SonicWall Appliances über einen SSH Zugang verwendet werden.

Backup via SSH

Damit der Login via SSH gelingt, muss am Interface, auf dem der Login erfolgt, SSH aktiviert werden:

SonicWall Interface Einstellungen
Management via SSH auf internem Interface

Wir können uns nun via SSH mit der SonicWall verbinden. Beim ersten Verbindungsaufbau wird der fingerprint des RSA keys der SonicWall angezeigt und wir werden gefragt, ob wir uns wirklich verbinden wollen. Wenn wir mit yes bestätigen, werden wir, anders als bei einer Verbindung zum Beispiel zu einem Linux Host, erst nach einem User und schließlich nach einem Password gefragt:

ssh sonicwall.examp.le
The authenticity of host 'sonicwall.examp.le (1.2.3.4)' can't be established.
RSA key fingerprint is ca:fe:b8:a3:9f:3f:e1:cf:6b:12:06:9a:9a:da:31:4b.
Are you sure you want to continue connecting (yes/no)? yes 
Warning: Permanently added 'sonicwall.examp.le,1.2.3.4' (RSA) to the list of known hosts.

                         ,,,,,,,,,,,,,,,                              
          ,,,mmbbbbbb11111111111111111111111bbbbbmm,,,                
   ,,,b||PPPPPPP||````````````````|PPPPPPPPP111111111111bbm,,         
 ``````                                     `````PPPP111111111bm,     
                                                     ```PP1111111bm,  
                                                          `PP111111b, 
                                                             |111111: 
                                                             .1111P|. 
Copyright (c) 2010 SonicWALL, Inc.                          ,b1PP|`   
                                                         ,,||```      
User:admin
Password:

Sonic_Example> 

Die SonicWall bietet keine Möglichkeit einen public SSH-Key in einem authorized-keys File abzulegen. Es ist nicht einmal möglich beim Verbindungsaufbau den User anzugeben. Damit ist eine passwortlose Authentifizierung mit SSH Keys, und damit ein automatisierter Verbindungsaufbau mit einem shellscript, leider keine Option. Hier kommt Expect ins Spiel. Expect ist eine Erweiterung zu Tcl (gesprochen Tickle und steht für Tool command language). Expect dient zur Automatisierung von interaktiven Anwendungen, also Anwendungen die eine Benutzereingabe erwarten. Das wichtigste Kommando von Expect ist expect nachdem die Scriptsprache auch benannt ist. Das Kommando expect wartet auf bestimmte Zeichen von einem Programm und führt danach eine weitere Aktion aus. Durch die Integration in Tcl, bietet es sich an, das komplette Backup Script in Tcl zu schreiben. Das nachfolgende Script liest die angegebene Konfigurationsdatei ein oder verwendet die Standarddatei /etc/sonicwall_backup.cfg , rotiert die vorhandenen Backups abhängig von der Einstellung in der Konfigurationsdatei, meldet sich via SSH auf dem SonicWall CLI an und veranlasst einen Upload auf einen, ebenfalls konfigurierbaren, FTP Server:

#!/usr/bin/expect

proc rotateFile {filename {rotations {}}} {
    incr rotations -1
    # Delete the oldest backup file if exists
    if {[file exists $filename.$rotations]} {
        # "Deleting $filename.$rotations"
        file delete $filename.$rotations
    }
    incr rotations -1

    # rotate the remaining versions
    for {set count $rotations} {$count > 0} {incr count -1} {
        set previous [expr $count + 1]

        if {[file exists $filename.$count]} {
            #  "Renaming $filename.$count to $filename.$previous"
            file rename $filename.$count $filename.$previous
        }
    }

    if {[file exists $filename]} {
        set previous [expr $count + 1]
        #  "Renaming $filename to $filename.$previous"
        file rename $filename $filename.$previous
    }
}

proc readConfig {filename} {

    if {[file exists $filename]} {
        global cfg
        # Read the file in
        set f [open $filename]
        set contents [read $f]
        close $f

        # Parse the file's contents
        foreach line [split $contents "\n"] {
            set line [string trim $line]
            # Skip comments
            if {[string match "#*" $line] || [string match ";*" $line]} continue
            # Skip blanks
            if {$line eq ""} continue

            if {[regexp {^\w+$} $line]} {
                # Boolean case
                set cfg([string tolower $line]) true
            } elseif {[regexp {^(\w+)\s+([^,]+)$} $line -> var value]} {
                # Simple value case
                set cfg([string tolower $var]) $value
            } elseif {[regexp {^(\w+)\s+(.+)$} $line -> var listValue]} {
                # List value case
                set cfg([string tolower $var]) {}
                foreach value [split $listValue ","] {
                    lappend cfg([string tolower $var]) [string trim $value]
                }
            } else {
                puts "malformatted config file: $filename"
                exit 1
            }
        }

    } else {
        puts "config file does not exit: $filename"
        exit 1
    }
}


set timeout 10
set systemTime     [clock seconds]
set backup_date    [clock format $systemTime -format {%Y%m%d}]

if {[llength $argv] == 1} {
    set config_filename  [lindex $argv 0]
} else {
    set config_filename  "/etc/sonicwall_backup.cfg"
}

readConfig $config_filename
rotateFile "$cfg(local_path)$cfg(sonic_name).exp" $cfg(rotations)

spawn ssh -p $cfg(ssh_port) $cfg(sonic_address)

expect {
    "User:" {
        send "$cfg(sonic_user)\r"
        expect "Password:" {
            send "$cfg(sonic_passwd)\r"
            expect "*>" {
                send "export preferences ftp $cfg(ftp_address) $cfg(ftp_user) $cfg(ftp_passwd) $cfg(sonic_name).exp\r"
                expect "*>" {
                    send "exit\r"
                    puts "Backup succeeded\r"
                }
            }
        }
    }
}

Damit dieses Script ausgeführt werden kann, muss es mit chmod +x ausführbar gemacht werden und Expect muss unter /usr/bin/expect installiert sein. In der nachfolgenden Konfigurationsdatei wird definiert, dass die Einstellungen einer SonicWall Appliance mit dem Namen sonic_example gesichert werden sollen. Von dem Parameter SONIC_NAME hängt auch der Name der Backupfiles ab. In unserem Fall sonicexample.exp und die älteren Versionen sonicexample.exp.1, sonic_example.exp.2, und so weiter. Weiters werden die Adresse und Logindaten, der zu sichernden SonicWall Appliance und des FTP Servers, auf den die Backupfiles hochgeladen werden, konfiguriert. Das Script geht davon aus, dass der FTP Server auf dem selben Host läuft, auf dem das Script ausgeführt wird. Mit dem Parameter LOCAL_PATH wird der Pfad im lokalen Filesystem angegeben, unter dem der FTP Server die Backupfiles ablegt. Nur wenn dies der Fall ist, greift auch der Parameter ROTATIONS, der angibt wie viele Versionen der Backupfiles aufgehoben werden sollen. Wenn die Zahl 7 angegeben wird, wird die Version .6 gelöscht und die anderen Versionen umbenannt. Wird ein entfernter FTP Server verwendet, so wird das Backupfile bei jedem Upload überschrieben. Da in dem Konfigurationsfile Passwörter stehen, sollte der Eigentümer root sein und die Berechtigungen mit chmod 600 gesetzt werden.

# Friendly Name of SonicWall (is used as part of the backup filename)
SONIC_NAME sonic_example

# User with login permission on the SonicWall Appliance
SONIC_USER admin

# Password for the SonicWall User
SONIC_PASSWD StrongPassword

# IP Address or FQDN from the SonicWall
SONIC_ADDRESS 1.2.3.4

# SSH Port
SSH_PORT 22

# IP Address or FQDN from the FTP Server where the Backup will be uploaded
FTP_ADDRESS 5.6.7.8

# FTP User
FTP_USER backup

# FTP Password
FTP_PASSWD AnotherStrongPassword

# local path to backup files
LOCAL_PATH /SonicWall/backups/

# How many versions from the backup to keep
ROTATIONS 7

Cronjob

Nun soll das Backup Script noch regelmäßig ausgeführt werden. Das erledigt ein cronjob zum Beispiel mit folgendem Eintrag in /etc/cron.d/sonicwall_backup:

20 12   * * *   root    /usr/bin/sonic_backup.tcl

llen mehrere SonicWall Appliances gesichert werden, so muss für jede Appliance eine eigene Konfigurationsdatei mit anderem SONIC_NAME und den entsprechenden Daten für die Adresse angelegt, und beim Aufruf des Scripts mit angegeben werden.