Under Construction

Schritt 6: Implementieren von Undo

Für die Implementierung der Undo-Funktionalität gibt es drei Möglichkeiten:

    1. Ein Undo wird nicht unterstützt und daher auch nicht im Skript implementiert. (Einige Standard-Skripte wie validate_check, rmdotfrmpathnroot und weitere unterstützen ebenfalls kein Undo.)
    2. Das Skript zum Setzen und Überprüfen der Sicherheitseinstellung erzeugt ein Skript das den Undo der Sicherheitseinstellung implementiert. (Einige Standard-Skripte wie loginherald, rmrhostsnetrc und weitere machen dies so.)
    3. Das Skript zum Setzen und Überprüfen der Sicherheitseinstellung implementiert selbst den Undo. (Einige Standard-Skripte wie chusrattr, nfsopts und andere implementieren selbst den Undo.)

In vielen Fällen besteht das Setzen einer Sicherheitseinstellung darin einer Variablen oder einem Attribut in einer Konfigurationsdatei einen Wert zuzuweisen. Die entsprechenden Skripte zur Umsetzung erwarten dann in der Regel als Argument beim Skript-Aufruf den zu setzenden Wert (AIXPertArgs). Fragt man den ursprünglichen Wert vor der Änderung ab, ergibt sich ein Undo indem das Skript einfach mit dem ursprünglichen Wert als Argument gestartet wird. Es muss also häufig keine großartige Extra-Funktionalität programmiert werden.

Da unser bisheriges Skript keine Argumente unterstützt, zeigen wir zunächst die Möglichkeit 2.

Unabhängig davon welche der beiden Möglichkeiten implementiert werden soll, muss das Skript beim Setzen der Sicherheitseinstellung einen Eintrag in der Datei /etc/security/aixpert/core/undo.xml für den Undo hinzufügen. Der Eintrag hat fast das gleiche Format wie Einträge in /etc/security/aixpert/core/appliedaixpert.xml. Der Eintrag benötigt einen Namen, dieser wird immer von aixpert über die Variable AIXPERT_NAME übergeben.

Alle Standard-Skripte, die ein Undo unterstützen, erwarten immer als letztes Argument den Namen einer Regel. Da wir bisher keine Argumente haben, erweitern wir unser Skript und fügen zunächst am Anfang einen Kommentar zu Kommandozeilen-Argumente, Ausgabe und Beschreibung des Skripts hinzu:

#   Command Line Arguments  : This script expects exactly one command line argument.
#                           This argument should be the rulename.
#                           Syntac - local_chsshdconf rulename
#
#   OUTPUT                  : None
#
#   Description             : This script sets the value of PermitRootLogin in /etc/ssh/sshd_config
#                           to 'no'.
#                           It dynamically generates the undo rules and scripts.
#                           This script should be run with superuser privileges.
#

Die Überprüfung der Argumente und die Meldung zur Benutzung muss entsprechend auch abgeändert werden:

if [ $# -ne 1 ]
then
    echo "Usage : local_chsshdconf rulename\n"
    exit 1
fi

Da das Skript über einen AIXPertEntry der XML-Datei custom/sshd.xml aufgerufen wird, müssen wir diesen XML-Eintrag auch entsprechend um das Argument erweitern:

/etc/security/aixpert # cat custom/sshd.xml
<?xml version="1.0" encoding="UTF-8"?>
<AIXPertSecurityHardening>
  <AIXPertEntry name="test_permitrootlogin" function="permitrootlogin">
    <AIXPertRuleType type="TEST"/>
    <AIXPertDescription>Ensure that PermitRootLogin is False.</AIXPertDescription>
    <AIXPertPrereqList>openssh.base.server</AIXPertPrereqList>
    <AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCommand>
    <AIXPertArgs>test_permitrootlogin</AIXPertArgs>
    <AIXPertGroup>SSH policy rules</AIXPertGroup>
  </AIXPertEntry>

</AIXPertSecurityHardening>
/etc/security/aixpert #

Der Name des AIXPertEntry wird als Argument für den Skript-Aufruf verwendet. Im Skript steht dieser Name dann über die Variable „$1“ zur Verfügung.

Ob ein Undo-Eintrag generiert werden soll, oder nicht wird bei allen Standard-Skripten über das Setzen der Variablen mit Namen undo implementiert. Am Anfang des Skriptes wird der Wert dieser Variablen auf den Wert „0“ (kein Undo-Eintrag generieren) gesetzt:

# A value of 0 indicates that Undo rule need not be created.
# This variable will be set later in the script if there is anything to be undone
undo=0

Findet eine Überprüfung der Sicherheitseinstellung statt (AIXPERT_CHECK=1), dann wird kein Undo-Eintrag generiert und die Variable undo behält den Wert „0“. Wird die Sicherheitseinstellung gesetzt, wird die Variable undo auf den Wert „1“ gesetzt:

    # Generate a dynamic undo rule
    undo=1

Am Ende des Skripts (nach den Teilen für Überprüfung und Setzen der Sicherheitseinstellung) wird dann die Variable undo geprüft, und falls diese den Wert „1“ hat, wird ein XML-Eintrag für den Undo in /etc/security/aixpert/core/undo.xml hinzugefügt. Für den Fall das das Skript die Möglichkeit 2 von oben realisiert, wird zusätzlich ein Undo-Skript im Verzeichnis /etc/security/aixpert/undo angelegt. Der XML-Eintrag referenziert dann dieses generierte Skript.

if [ $undo -eq 1 ]
then
    time=`date +%s`
    # Create Undo script $SCPTDIR/Undo$1$time

fi

Da das Undo bei AIX Security Expert mehrstufig funktioniert, wird über „date +%s“ ein eindeutiger Zeitstempel generiert. Die Variable SCPTDIR besitzt den Wert /etc/security/aixpert/undo (dies ist in /etc/security/aixpert/bin/initialize_variables festgelegt). Die Variable „$1“ beinhaltet den Regelnamen der beim Aufruf des Skripts als letztes Argument mitgegeben wird.

Das Abändern von PermitRootLogin auf „yes“ machen wir wir nicht ganz elegant mit dem folgenden Zweizeiler:

sed -e 's/\(PermitRootLogin\) \(no\)/\1 yes/' /etc/ssh/sshd_config >/etc/ssh/sshd_config.new
mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config

Hinweis: Wir werden später noch die (bessere) Möglichkeit 3 implementieren und bemühen uns daher hier nicht um eine gute Lösung.

Wie bei dem Skript für die Sicherheitseinstellungen local_chsshdconf soll das ganze mitprotokolliert werden. Wir übernehmen daher wieder ein paar Zeilen aus den Standard-Skripten. Insgesamt sollte dann das folgende Skript automatisch in /etc/security/aixpert/undo erzeugt werden:

#!/usr/bin/ksh
export PATH=/usr/bin:/usr/sbin:$PATH
exec 1>>$LOG
exec 2>&1
set -x
date
echo $0
sed -e 's/\(PermitRootLogin\) \(no\)/\1 yes/' /etc/ssh/sshd_config >/etc/ssh/sshd_config.new
mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config

Dazu bauen wir die folgenden Zeilen in unser Skript local_chsshdconf ein:

    echo "#!/usr/bin/ksh\nexport PATH=/usr/bin:/usr/sbin:\$PATH\n" >$SCPTDIR/Undo$2$time
    echo "exec 1>>\$LOG\nexec 2>&1\nset -x\ndate\necho" '$0' >>$SCPTDIR/Undo$2$time
    echo "sed -e 's/\\(PermitRootLogin\\) \\(no\\)/\\1 yes/' /etc/ssh/sshd_config >/etc/ssh/sshd_config.new\n" >$SCPTDIR/Undo$2$time
    echo "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config\n" >>$SCPTDIR/Undo$2$time
    chmod ug+x $SCPTDIR/Undo$2$time

Als nächstes muss ein Eintrag in /etc/security/aixpert/core/undo.xml erzeugt werden. Der Dateipfad ist in der Variablen UNDOXML hinterlegt. Ist unser Skript das erste Skript das bei der Anwendung aufgerufen wird, dann gibt es die Datei undo.xml noch nicht. Dieser Fall muss überprüft werden, und falls dies der Fall ist, muss eine minimale Version der Datei angelegt werden. Dazu verwenden die Standard-Skripte die folgenden Zeilen:

    # Check if UNDOXML file has <AIXPertUndo> tag or not
    empty=`grep "^<AIXPertUndo>" $UNDOXML`
    if [ "$empty" = "" ]
    then
        echo "\n<AIXPertUndo>\n</AIXPertUndo>" >> $UNDOXML
    fi

Regeln die in /etc/security/aixpert/core/appliedaixpert.xml und /etc/security/aixpert/core/undo.xml eingetragen werden, haben einen leicht abgeänderten Regelnamen gegenüber den in der ursprünglichen XML-Datei verwendeten Namen. Der AIX Security Expert genieriert bei der Anwendung eines Profils oder Sicherheitslevels auf ein System eine eindeutige 8 stellige hexadezimale ID, die mit einem Unterstrich getrennt an den ursprünglichen Regelnamen angefügt wird. Aus test_permitrootlogin wird dann z.B. test_permitrootlogin_C515EA26. Dieser verlängerte Regelname wird in der Variablen AIXPERT_NAME abgespeichert. Die Beschreibung der Regel (AIXPertDescription) wird in AIXPERT_DESC abgespeichert und Informationen für sprachabhängige Meldungen in AIXPERT_DESC_CATMSGINFO. Diese drei Variablen werden über das Environment an das Skript übergeben. Typischerweise werden diese 3 Variablen dann wie folgt neuen Variablen zugewiesen:

    # Get the rulename and put it in undo rule
    name=`echo $AIXPERT_NAME`
    # Get the rule description & pass it to undo rule
    desc=`echo $AIXPERT_DESC`
    desc_catmsginfo=`echo $AIXPERT_DESC_CATMSGINFO`
    undomsg=`/usr/bin/dspmsg -s 49 aixpert.cat 1 "Undo action for: "`

Nun kann der notwendige XML-Eintrag in /etc/security/aixpert/core/undo.xml vorgenommen werden. Der Eintrag sollte in etwa so aussehen:

        <AIXPertEntry name="test_permitrootlogin_C515EA26">
                <AIXPertRuleType type="Undo"/>
                <AIXPertDescription catalog="aixpert.cat" setNum="101" msgNum="15">Undo action for:  " Ensure that PermitRootLogin is False."</AIXPertDescription>
                <AIXPertPrereqList/>
                <AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCommand>
                <AIXPertArgs> </AIXPertArgs>
                <AIXPertGroup>SSH policy rules</AIXPertGroup>
        </AIXPertEntry>

Die Standard-Skripte fügen den Eintrag mit Hilfe des folgenden awk-Kommandos der XML-Datei hinzu:

    # Add an undo XML rule to the file $UNDOXML
    awk -v rulepart1="\t<AIXPertEntry name=\"$name\">\n\
\t\t<AIXPertRuleType type=\"Undo\"/>\n"\
-v rulepart2="\t\t<AIXPertDescription ${desc_catmsginfo}>$undomsg \"$desc\"</AIXPertDescription>\n\
\t\t<AIXPertPrereqList/>\n"\
-v rulepart3="\t\t<AIXPertCommand>$SCPTDIR/Undo$2$time</AIXPertCommand>\n\
\t\t<AIXPertArgs/>\n\t\t<AIXPertGroup>Miscellaneous Rules</AIXPertGroup>\n\
\t</AIXPertEntry>" '{if(match($0,"^[\t ]*</AIXPertUndo>")==0) print $0;
else print rulepart1 rulepart2 rulepart3 "\n" $0}' $UNDOXML >$TMP$PID
    if [ $? -eq 0 ] ; then
        mv $TMP$PID $UNDOXML
    fi

Die beiden Variablen TMP und PID werden typischerweise am Anfang des Skripts gesetzt, direkt nachdem die Datei /etc/security/aixpert/bin/initialize_variables eingelesen wurde:

TMP=/etc/security/aixpert/tmp/permitrootlogin
PID=$$

Insgesamt ergibt sich dann die folgende Version des Skripts:

 

/etc/security/aixpert # cat bin/local_chsshdconf
#! /bin/ksh
#
#       Command Line Arguments  : This script expects exactly one command line argument.
#                                                       This argument should be the rulename.
#                                                       Syntac - local_chsshdconf rulename
#
#       OUTPUT                                  : None
#
#       Description                             : This script sets the value of PermitRootLogin in /etc/ssh/sshd_config
#                                                       to 'no'.
#                                                       It dynamically generates the undo rules and scripts.
#                                                       This script should be run with superuser privileges.
#

export PATH=/usr/bin:/usr/sbin:$PATH

# Initialize variables AIXPERT_FIFO, LOG, REPORT, SCPTDIR and UNDOXML
. /etc/security/aixpert/bin/initialize_variables

TMP=/etc/security/aixpert/tmp/permitrootlogin
PID=$$

# Log output and errors to /etc/security/aixpert/log/aixpert.log
exec 1>>$LOG
exec 2>&1

# echo all the commands and the current time and date to the AIXpert log
set -x
date
echo $0 $@ AIXPERT_CHECK_REPORT=$AIXPERT_CHECK_REPORT BASE_REPT=$BASE_REPT DETAILED_REPT=$DETAILED_REPT

if [ $# -ne 1 ]
then
    echo "Usage : local_chsshdconf rulename\n"
    exit 1
fi

# A value of 0 indicates that Undo rule need not be created.
# This variable will be set later in the script if there is anything to be undone
undo=0

# Check whether AIXPERT_CHECK_REPORT environment variable is set or not.
report=`echo $AIXPERT_CHECK_REPORT`
BrType=`echo $BASE_REPT`
DrType=`echo $DETAILED_REPT`

if [ "$report" = "1" ]
then
        ret=1

        permit=$( awk '$1 ~ /^PermitRootLogin$/ { print $2; }' /etc/ssh/sshd_config 2>/dev/null | tail -n 1 )
        case "${permit}" in
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]) ret=0 ;;
        esac

        if [ $ret = 1 ]
        then
                if [ "$BrType" = "1" ]
                then
                        echo "Base Compliance Report\n";
                        printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" PermitRootLogin no $permit >>$TMPREPT
                elif [ "$DrType" = "1" ]
                then
                        echo "Description Report\n";
                        printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" PermitRootLogin no $permit >>$TMPREPT
                else
                        printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" PermitRootLogin no $permit >>$REPORT
                        printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" PermitRootLogin no $permit >>$AIXPERT_FIFO
                fi
        fi

        exit $ret
fi

# Generate a dynamic undo rule
undo=1

firstOccurrence=true
while read -r line
do
        case "$line" in
        PermitRootLogin*)
                if $firstOccurrence
                then
                        print "PermitRootLogin no"
                        firstOccurrence=false
                fi
                ;;
        *)
                print $line ;;
        esac
done </etc/ssh/sshd_config >/etc/ssh/sshd_config.new
$firstOccurrence && print "PermitRootLogin no" >>/etc/ssh/sshd_config.new
cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config
rm /etc/ssh/sshd_config.new

if [ $undo -eq 1 ]
then
    time=`date +%s`
    # Create Undo script $SCPTDIR/Undo$1$time
        echo "#!/usr/bin/ksh\nexport PATH=/usr/bin:/usr/sbin:\$PATH\n" >$SCPTDIR/Undo$2$time
        echo "exec 1>>$LOG\nexec 2>&1\nset -x\ndate\necho" '$0' >>$SCPTDIR/Undo$2$time
        echo "sed -e 's/\\(PermitRootLogin\\) \\(no\\)/\\1 yes/' /etc/ssh/sshd_config >/etc/ssh/sshd_config.new\n" >>$SCPTDIR/Undo$2$time
        echo "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config\n" >>$SCPTDIR/Undo$2$time
        chmod ug+x $SCPTDIR/Undo$2$time

        # Check if UNDOXML file has <AIXPertUndo> tag or not
        empty=`grep "^<AIXPertUndo>" $UNDOXML`
        if [ "$empty" = "" ]
        then
                echo "\n<AIXPertUndo>\n</AIXPertUndo>" >> $UNDOXML
        fi

        # Get the rulename and put it in undo rule
        name=`echo $AIXPERT_NAME`
        # Get the rule description & pass it to undo rule
        desc=`echo $AIXPERT_DESC`
        desc_catmsginfo=`echo $AIXPERT_DESC_CATMSGINFO`
        undomsg=`/usr/bin/dspmsg -s 49 aixpert.cat 1 "Undo action for: "`

        # Add an undo XML rule to the file $UNDOXML
        awk -v rulepart1="\t<AIXPertEntry name=\"$name\">\n\
\t\t<AIXPertRuleType type=\"Undo\"/>\n"\
-v rulepart2="\t\t<AIXPertDescription ${desc_catmsginfo}>$undomsg \"$desc\"</AIXPertDescription>\n\
\t\t<AIXPertPrereqList/>\n"\
-v rulepart3="\t\t<AIXPertCommand>$SCPTDIR/Undo$2$time</AIXPertCommand>\n\
\t\t<AIXPertArgs/>\n\t\t<AIXPertGroup>Miscellaneous Rules</AIXPertGroup>\n\
\t</AIXPertEntry>" '{if(match($0,"^[\t ]*</AIXPertUndo>")==0) print $0;
else print rulepart1 rulepart2 rulepart3 "\n" $0}' $UNDOXML >$TMP$PID
        if [ $? -eq 0 ] ; then
                mv $TMP$PID $UNDOXML
        fi
fi

exit 0

/etc/security/aixpert #

Bevor wir das Skript ausprobieren, entfernen wir alle aktuell gesetzten Regeln:

/etc/security/aixpert # aixpert -u
/etc/security/aixpert # aixpert -u
There are no security rules to undo in file /etc/security/aixpert/core/appliedaixpert.xml
/etc/security/aixpert # rm check_report.txt core/appliedaixpert.* core/undo.* log/* tmp/* undo/*
rm: cannot remove directory undo/data
/etc/security/aixpert #

Nun wenden wir zunächst unser XML-Profil custom/sshd.xml an:

/etc/security/aixpert # aixpert -f custom/sshd.xml
Processedrules=1        Passedrules=1   PrereqFailedrules=0     Failedrules=0   Level=TEST
        Input file=custom/sshd.xml
/etc/security/aixpert #

Wir überprüfen zunächst die Datei undo.xml:

/etc/security/aixpert # cat /etc/security/aixpert/core/undo.xml

<AIXPertUndo>
        <AIXPertEntry name="test_permitrootlogin_4E952A4B">
                <AIXPertRuleType type="Undo"/>
                <AIXPertDescription catalog="" setNum="" msgNum="">Undo action for:  "Ensure that PermitRootLogin is False."</AIXPertDescription>
                <AIXPertPrereqList/>
                <AIXPertCommand>/etc/security/aixpert/undo/Undo1670354323</AIXPertCommand>
                <AIXPertArgs/>
                <AIXPertGroup>Miscellaneous Rules</AIXPertGroup>
        </AIXPertEntry>
</AIXPertUndo>
/etc/security/aixpert #

Diese hat den erwarteten Inhalt. Das hinterlegte AIXPertCommand ist /etc/security/aixpert/undo/Undo1670354323. Das sollte das von local_chsshdconf generierte Undo-Skript sein. Wir überprüfen den Inhalt des Skripts:

/etc/security/aixpert # cat /etc/security/aixpert/undo/Undo1670354323
#!/usr/bin/ksh
export PATH=/usr/bin:/usr/sbin:$PATH

exec 1>>/etc/security/aixpert/log/aixpert.log
exec 2>&1
set -x
date
echo $0
sed -e 's/\(PermitRootLogin\) \(no\)/\1 yes/' /etc/ssh/sshd_config >/etc/ssh/sshd_config.new

mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config

/etc/security/aixpert #

Dies ist der erwartete generierte Inhalt!

Als letztes überprüfen wir noch den Wert von PermitRootLogin:

# grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin no
#

Dies ist der durch die Sicherheitseinstellung gewünschte Wert!

Als nächstes führen wir ein Undo aus:

# aixpert -u 
#

Die Regel test_permitrootlogin müsste sowohl aus der Datei appliedaixpert.xml, als auch aus der Datei undo.xml, entfernt worden sein. Wir überprüfen das:

# cat /etc/security/aixpert/core/appliedaixpert.xml
<?xml version="1.0"?>
<AIXPertSecurityHardening>
</AIXPertSecurityHardening>
# cat /etc/security/aixpert/core/undo.xml         

<AIXPertUndo>
</AIXPertUndo>
#

In beiden Dateien wurde die Regel entfernt! Als letztes Überprüfen wir noch den Wert von PermitRootLogin. Der Undo sollte den Wert wieder auf yes gesetzt haben:

# grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
#

Der Undo hat also wie gewünscht funktioniert. Vor dem Einsatz in der Praxis, sollte das Skript aber noch um eine bessere Fehlererkennung und Behandlung erweitert werden.