DevSecOps – Automatisierung von Sicherheitsüberprüfungen: Beispiel mit Jenkins und SSLyze

Die neue Pipeline bekommt noch eine sprechende kurze Beschreibung und dann springen wir direkt zum Pipeline-Code.

SSLyze – Pipeline

Fangen wir mit SSLyze an. SSLyze hat wenige Parameter, läuft schnell durch und eignet sich daher auch zum Experimentieren mit Scripten und Rückgabewerten ausgezeichnet.

In Verbindung mit sshCommand verwenden wir drei Stages:

  • startSSLyze (Startet SSLyze und wartet auf das Ende des Durchlaufs)
  • checkRunningSSLyze (Prüf hier nur einmalig, ob SSLyze wirklich fertig ist.)
  • getResultsSSLyze (Wertet die Ergebnisse von SSLyze aus und gibt sie an Jenkins zurück)

Alle drei Stages rufen per SSH ein Python-Script auf dem KALI-Linux System auf. Beispiel startSSLyze:

 stages {
 stage('startSSLyze') {
  steps {
   script { 
    def remote = [:]
    remote.name = 'ScanHost'
    remote.host = '127.0.0.1'
    remote.user = 'jenkinsuser'
    remote.identityFile = '/var/lib/jenkins/jenkinsscriptlets/jenkinsuser_key'
    remote.allowAnyHosts = true 
    def ret = sshCommand remote: remote, command: "/usr/bin/python scriptlets/runSSLyze.py --serverURL https://lab.bi-sec.de"
    print ret
   }
  }
}

Den vollständigen Code der Pipeline findet ihr hier in unserem git-Repo.

Auf der Gegenseite nimmt das Python-Script runSSLyze.py den Befehl entgegen und startet SSLyze:

import os
import argparse

args = argparse.ArgumentParser()
args.add_argument("--serverURL", "-s", default=False, help="serverURL", required=True)
currArgs = args.parse_args()

serverURL = currArgs.serverURL
serverURL = serverURL.replace("http://", "")
serverURL = serverURL.replace("https://", "")
serverURL = serverURL.replace("/", "")

executablePath = "/usr/local/bin/sslyze"
executionCommand = "--regular"
outputCommand = "--xml_out="
outFilePath = "./"
os.system(executablePath + " " + executionCommand + " " + serverURL + " " + outputCommand + "" + outFilePath + "/" + serverURL +".xml &")

Analog funktionieren die beiden anderen Stages aus Sicht von Jenkins. Ein kurzer Aufruf des Scripts per sshCommand auf dem Remote-Host und die Anzeige der Ergebnisse im Jenkins.

Unsere Beispiel-Implementierung gibt alle Ergebnisse von SSLyze in der Jenkins-Console aus. Diese wollen wir uns natürlich nicht nach jedem Build anschauen. Also brauchen wir einen Automatismus, der bei bestimmten Ergebnissen die Stage – oder die Pipeline – failen lässt. Wie genau die Kriterien aussehen muss leider jeweils im Kontext der Anwendung und der Organisation entschieden werden: Ein öffentlicher Webshop wird vermutlich TLS1.1 unterstützen, um möglichst vielen Kunden zur Verfügung zu stehen. Ein Austauschportal für vertrauliche Daten soll vermutlich nur über TLS1.2 und auswärts abrufbar sein.

Die Infos dazu liefert das Python-Script. Wir haben beispielsweise alle Cipher Suites mit dem Betriebsmodus CBC als „Warning“ markiert – und festgelegt, dass ab einer Gesamtanzahl von 3 Warnings die Stage failed – nicht aber der gesamte Build-Prozess:

Natürlich gibt es noch viel mehr Beispiele für schlechte Cipher Suites – etwa wenn SHA-1 oder MD5 verwendet werden. Auch EXPort-Ciphers oder anonyme Cipher suites wären Kandidaten für die Showstopper-Kategorie. Für ein vollständiges Bild helfen etwa die aktuellen Empfehlungen vom BSI oder aus dem Mozilla-TLS-Konfigurator.