News

Das Neuste aus der Welt von Adfinis SyGroup

Performance Analyse mit strace

4. March 2017

Ich hatte neulich einen Kunden am Telefon, der sich über ein langsam ablaufendes Script beschwerte. Es handelte sich dabei um einen Import, welcher in der Regel mehrere Stunden läuft.

Der Quellcode stammt nicht von mir und das Script greift auf mehrere Datenbanken auf verschiedenen Servern zu.

Die üblichen Tools für eine Performance-Analyse konnten hier nicht zum Einsatz kommen: Für mindestens eine Datenbank haben wir nicht genügend Rechte, um z.B. das MySQL Slow Query Log einzuschalten und zu überwachen.

Nach einem ersten Einblick in den Quellcode sehen wir, dass das Script sehr viele Queries verschickt sowie auch viele Dateien kopiert und verarbeitet. Wir müssen also zuerst herausfinden, was wirklich langsam ist. Ist es wirklich die Datenbank? Oder am Ende der Datentransfer?

Irrwege

Der erste Instinkt ist in solchen Fällen häufig, die SQL-Queries auf ineffiziente Patterns zu checken und die Datenbanken auf fehlende Indizes zu prüfen.

Einige der Queries hatten in der Tat solche Patterns – zum Beispiel fällt die folgende Bedingung schon früh als verdächtig auf:

    WHERE `p`.`product_ean` LIKE '%123456789'

Wie man relativ früh in der Schule lernt, können solche Abfragen nicht mittels Index abgedeckt werden und sind daher immer mit einem Table Scan verbunden – was bei wenigen Daten vielleicht noch geht, aber mit zunehmender Datenmenge garantiert zu Problemen führt.

Aber: Welches dieser Queries im Code ist wirklich problematisch? Und: Wie dürfte man die Queries korrigieren? Der obere Fall deutet auf eine EAN hin und wir können die Vermutung anstellen, dass hier wohl führende Nullen abgedeckt werden sollen. Aber Vermutungen können zu Fehleinschätzungen führen, daher fahren wir weiter mit dem Fakten-Check…

Ziele setzen

Wichtig ist, dass wir das Ziel nicht aus den Augen verlieren. Welche dieser ineffizienten Queries sind wirklich problematisch? Und welche davon können wir ignorieren? Und wie häufig werden all diese Queries ausgeführt?

Ich bin seit langer Zeit Fan des Tools strace. strace zeichnet alle System Calls eines Programms auf. Man sieht also damit, welche Auswirkungen ein Programm wirklich auf seine Umgebung hat. Da unser Script vermutlich primär aufgrund der Interaktionen mit seinen Umsystemen langsam wird, denke ich, dass wir hiermit das richtige Tool haben.

Debugging

Ich werfe also Strace an und hänge es mit dem Parameter -p $PID an den bereits laufenden Prozess.

# strace -p 933950
Process 933950 attached
write(1, "Produkt wurde erfolgreich aktual"..., 133) = 133
sendto(5, "\334\4\0\0\3\n\t\t\tSELECT\n\t\t\t\tentryID AS I"..., 1248, MSG_DONTWAIT, NULL, 0) = 1248
poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}], 1, 1471228928) = 1 ([{fd=5, revents=POLLIN}])
recvfrom(5, "\1\0\0\1\30+\0\0\2\3def\6mmdb15\1t\5Entry\2ID\7"..., 1139, MSG_DONTWAIT, NULL, NULL) = 1139
poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}], 1, 1471228928) = 1 ([{fd=5, revents=POLLIN}])
recvfrom(5, "\31\3def\6mmdb15\1t\5Entry\10statusID\10st"..., 1519, MSG_DONTWAIT, NULL, NULL) = 69
sendto(5, "\304\0\0\0\3\n\t\t\t\tSELECT\n\t\t\t\t\tEAN,\n\t\t\t\t\t"..., 200, MSG_DONTWAIT, NULL, 0) = 200
poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}], 1, 1471228928) = 1 ([{fd=5, revents=POLLIN}])
recvfrom(5, "\1\0\0\1\10,\0\0\2\3def\6mmdb15\5Track\5Track"..., 1450, MSG_DONTWAIT, NULL, NULL) = 443

Okay, ich sehe hier viele Interaktionen, aber gefühlt bleibt der Output immer mal wieder für den Bruchteil einer Sekunde stehen. Was genau passiert da? Ich vermute ja schon, dass das Script auf die Antwort einer Datenbank wartet. Können wir prüfen, wo das Script genau hängt?

Stellt sich heraus – ja, man kann: strace kennt eine Option -c, welche nicht “live” einen Output generiert, sondern am Ende (nachdem man strace abbricht, oder der Zielprozess fertig ist) eine Statistik ausgibt. Klingt gut, testen wir das mal:

# strace -p 933950 -c
Process 933950 attached
^CProcess 933950 detached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 46.43    0.000970          10        99           poll
 45.14    0.000943         236         4           stat
  3.49    0.000073           5        16           lstat
  3.45    0.000072           1        71           sendto
  0.91    0.000019           0       100           recvfrom
  0.19    0.000004           0        48           write
  0.19    0.000004           0        16           open
  0.05    0.000001           0        22           lseek
  0.05    0.000001           0         6           mmap

Und hier sehen wir auch schon den ersten Verdächtigen: poll wird sehr oft aufgerufen und verbraucht damit den Grossteil der Zeit! stat hingegen können wir wohl vorerst vernachlässigen, da er nur 4 mal aufgerufen wird. poll wird verwendet um auf Antworten vom Netzwerk zu warten. Ein Programm braucht diesen System Call, um zu schlafen, bis von einer Gegenstelle wieder Daten geliefert werden. Aber welche Daten? Und wie kommen wir anhand dieser Informationen wieder zu möglichen Lösungen für unser eigentliches Problem?

Wenn wir den Output von oben nochmals anschauen, sehen wir ein Pattern von System Calls: Es wird immer ein sendto gemacht, gefolgt von poll und schlussendlich recvfrom. Wie die Namen andeuten, sind diese System Calls für das Senden und Empfangen von Daten via Netzwerk zuständig.

Wir könnten jetzt also schauen, wie lange es zwischen einem sendto– und recvfrom-Paar genau dauert. Vielleicht gibt uns das ja Aufschluss! Aber wie geht das am einfachsten?

Manpage to the rescue!

Nach etwas lesen in der Manpage von strace finde ich eine Option, die mir sehr nützlich erscheint:

-r Print a relative timestamp upon entry to each system call.
This records the time difference between the beginning of
successive system calls.

Mit dieser Option sehe ich also, wieviel Zeit seit dem letzten System Call verging. Etwas Nachdenken, dann der Geistesblitz: Was passiert wohl, wenn ich mit strace nur die beiden System Calls sendto und recvfrom anzeige und den Rest ausfiltere? Mal schauen:

strace -p 933950 -r -e recvfrom,sendto
Process 933950 attached

     0.000169 sendto(4, "\v\1\0\0\3\n\t\t\tSELECT\n\t\t\t\t`image_name`"..., 271, MSG_DONTWAIT, NULL, 0) = 271
     1.036864 recvfrom(4, "\1\0\0\1\1^\0\0\2\3def\21sometable\1"..., 131, MSG_DONTWAIT, NULL, NULL) = 131
     0.000088 recvfrom(4, "0.jpg\5\0\0\5\376\0\0\"\0", 173, MSG_DONTWAIT, NULL, NULL) = 14

Perfekt! Und bereits einen Verdächtigen erwischt! Da haben wir ein Query (man sieht ein SELECT) und irgendwelche Tabellennamen im Output (recvfrom-Zeile). Interessant. Aber vielleicht war es ja nur ein statistischer Ausreisser. Denn die anderen Calls brauchen viel weniger und ich sehe auch nicht das ganze Query.

Du bist umzingelt!

Wir wissen also wonach wir suchen müssen. Jetzt muss die Falle nur noch richtig gestellt werden und dann schauen was passiert. Mein Plan ist folgender:

Wir lassen strace in eine Datei schreiben (Option -o), sortieren dann die Aufrufe nach Zeit und sollten so, statistisch gesehen, die langsamsten Queries finden.

Und wenn wir schon dabei sind, möchten wir dann auch sehen, welche Queries daran schuld sind. Der obige Output zeigt uns, dass strace lange String-Argumente stark zusammenkürzt. In der Manpage finden wir den Parameter -s, mit welchem man angeben kann, wie stark die Kürzung ist. Wir wollen möglicht die ganzen Daten; ich gebe also einen extrem langen Parameter von 10000 Zeichen an. Also:

# strace -p 933950 -r -e sendto,recvfrom -s 10000 -o import_db_stats.txt
Process 933950 attached

Wir lassen den Trace etwas laufen und brechen dann mit Ctrl-C ab. Anschliessend sortieren wir die Aufzeichnung numerisch und schauen uns die letzten paar Zeilen an:

# sort -n import_db_stats.txt | tail -n5
     0.749176 recvfrom(4, "\1\0\0\1\1^\0\0\2\3def\21sometable\1i\"product_images\nimage_name\nimage_name\f!\0\375\2\0\0\375\1P\0\0\0\5\0\0\3\376\0\0\"\0\24\0\0\4\0231234567890_1.jpg\5\0\0\5\376\0\0\"\0", 159, MSG_DONTWAIT, NULL, NULL) = 145
     0.769669 recvfrom(4, "\1\0\0\1\1^\0\0\2\3def\21sometable\1i\"product_images\nimage_name\nimage_name\f!\0\375\2\0\0\375\1P\0\0\0\5\0\0\3\376\0\0\"\0\24\0\0\4\0231234567890_0.jpg\5\0\0\5\376\0\0\"\0", 172, MSG_DONTWAIT, NULL, NULL) = 145
     0.803661 recvfrom(4, "\1\0\0\1\1^\0\0\2\3def\21sometable\1i\"product_images\n", 69, MSG_DONTWAIT, NULL, NULL) = 69
     0.814297 recvfrom(4, "\1\0\0\1\1^\0\0\2\3def\21me", 16, MSG_DONTWAIT, NULL, NULL) = 16
     0.947148 recvfrom(4, "\1\0\0\1\1^\0\0\2\3def\21sometable\1i\"product_images\nimage_name\nimage_name\f!\0\375\2\0\0\375\1P\0\0", 102, MSG_DONTWAIT, NULL, NULL) = 102

Oh, wunderbar! Wir haben also die fünf langsamsten Calls (respektive diejenigen mit der längsten Wartezeit vorher), alle sind recvfrom und zudem von der gleichen Datenbank (der erste Parameter entspricht dem File Handle respektive dem Socket). Bonus: Vier dieser Calls enthalten Daten der gleichen Tabelle! Jackpot!

Moment – wie sehe ich jetzt aber die Queries, welche langsam sind? Die recvfrom betreffen ja nur das Auslesen der Resultate. Wir erinnern uns – das Query wird in der Regel direkt vorher mittels sendto abgeschickt. Wir müssen also nur im (unsortierten!) Output nach den entsprechenden Zeilen suchen und den Vorgänger finden.

Ich denke, dass die relativen Timestamps über die kurze Zeit wohl eindeutig genug sind um als Suchparameter zu dienen. Also holen wir von den obigen Resultaten mal nur diese raus:

# sort -n import_db_stats.txt | tail -n5 | awk '{print $1}'
0.749176
0.769669
0.803661
0.814297
0.947148

Perfekt! Und mit grep können wir jetzt die Vorgänger-Zeilen dazu finden. Dabei hilft uns der Parameter -B. Weil wir die Resultate nicht wollen, filtern wir diese gleich wieder raus:

# sort -n import_db_stats.txt | tail -n5 | awk '{print $1}' > slowest_times.txt
> for time in $(cat slowest_times.txt); do
>     grep -B1 $time import_db_stats.txt | grep -v $time
> done
     0.000091 sendto(4, "\v\1\0\0\3\n\t\t\tSELECT\n\t\t\t\t`image_name`\n\t\t\tFROM\n\t\t\t\t`product_images` AS `i`\n\t\t\tJOIN\n\t\t\t\t`products` AS `p`\n\t\t\t\t\tUSING (`product_id`)\n\t\t\tWHERE\n\t\t\t\t`image_name` LIKE '12345678896_1.jpg'\n\t\t\t\tAND\n\t\t\t\t`p`.`product_ean` LIKE '%12345678896'\n\t\t", 271, MSG_DONTWAIT, NULL, 0) = 271
     0.000222 sendto(4, "\v\1\0\0\3\n\t\t\tSELECT\n\t\t\t\t`image_name`\n\t\t\tFROM\n\t\t\t\t`product_images` AS `i`\n\t\t\tJOIN\n\t\t\t\t`products` AS `p`\n\t\t\t\t\tUSING (`product_id`)\n\t\t\tWHERE\n\t\t\t\t`image_name` LIKE '1234567890134_0.jpg'\n\t\t\t\tAND\n\t\t\t\t`p`.`product_ean` LIKE '%1234567890134'\n\t\t", 271, MSG_DONTWAIT, NULL, 0) = 271
     0.000196 sendto(4, "\v\1\0\0\3\n\t\t\tSELECT\n\t\t\t\t`image_name`\n\t\t\tFROM\n\t\t\t\t`product_images` AS `i`\n\t\t\tJOIN\n\t\t\t\t`products` AS `p`\n\t\t\t\t\tUSING (`product_id`)\n\t\t\tWHERE\n\t\t\t\t`image_name` LIKE '1234567890189_0.jpg'\n\t\t\t\tAND\n\t\t\t\t`p`.`product_ean` LIKE '%1234567890189'\n\t\t", 271, MSG_DONTWAIT, NULL, 0) = 271
     0.000089 sendto(4, "\v\1\0\0\3\n\t\t\tSELECT\n\t\t\t\t`image_name`\n\t\t\tFROM\n\t\t\t\t`product_images` AS `i`\n\t\t\tJOIN\n\t\t\t\t`products` AS `p`\n\t\t\t\t\tUSING (`product_id`)\n\t\t\tWHERE\n\t\t\t\t`image_name` LIKE '1234567890134_1.jpg'\n\t\t\t\tAND\n\t\t\t\t`p`.`product_ean` LIKE '%1234567890134'\n\t\t", 271, MSG_DONTWAIT, NULL, 0) = 271
     0.000167 sendto(4, "\v\1\0\0\3\n\t\t\tSELECT\n\t\t\t\t`image_name`\n\t\t\tFROM\n\t\t\t\t`product_images` AS `i`\n\t\t\tJOIN\n\t\t\t\t`products` AS `p`\n\t\t\t\t\tUSING (`product_id`)\n\t\t\tWHERE\n\t\t\t\t`image_name` LIKE '1234567890103_0.jpg'\n\t\t\t\tAND\n\t\t\t\t`p`.`product_ean` LIKE '%1234567890103'\n\t\t", 271, MSG_DONTWAIT, NULL, 0) = 271

Wunderbar. Wie bereits ganz am Anfang vermutet, ist es eines der Queries, welches eine LIKE-Suche mit einem Wildcard-Anfang macht.

Jetzt müssen wir also nur noch nach dem entsprechenden Query im Code suchen und uns überlegen, wie wir dies optimieren können. Aber das muss ich jetzt nicht mehr erklären; heute ging es darum, ein Problem einmal auf eine andere Art zu suchen.

Fazit

Wir lernen also, dass Linux mit strace ein wunderbares Werkzeug zur Verfügung stellt, um nicht nur allgemeine Probleme zu finden, sondern auch für Performance-Analysen. Das Schöne daran ist, dass man hier bereits viel über ein Programm erfahren kann, insbesondere auch wenn man auf den Quellcode keinen Zugriff hat.

Ich hatte strace bisher primär für die Fehlersuche bei hängenden Programmen verwendet oder zur Analyse was ein Programm genau tut.

Die wichtigsten Parameter von strace nochmals zusammengefasst:

  • -o schreibt den Output in eine Datei
  • -r zeigt die relative Zeit seit dem letzten aufgezeichneten (!) System
    Call
  • -s kann verwendet werden, um die String-Parameter-Kürzung einzustellen
  • -c erstellt ein Call Profiling für die aufgerufenen Calls

strace kann noch viel mehr, es lohnt sich also, die Manpage einfach mal zu
überfliegen.

Adfinis SyGroup wird mit dem SUSE Innovationspreis ausgezeichnet

14. February 2017

Mit Stolz verkünden wir, dass wir am diesjährigen SUSE D-A-CH Partner Summit in München mit dem Innovationspreis in der Hauptkategorie “Technologie” geehrt wurden. Der Preis baut auf einer langjährigen und professionellen Zusammenarbeit auf und zeichnet Adfinis SyGroup unter den SUSE Technologiepartnern aus Deutschland, Österreich und der Schweiz als Innovation Leader aus. Dies betrifft vor allem den Bereich DevOps und den Umgang mit Bleeding-Edge-Technologien wie beispielsweise Container und Platform as a Service (PaaS).

Mehr dazu in der Pressemitteilung

Secret Management mit HashiCorp’s Vault

10. February 2017

Security ist nach wie vor ein heisses Thema in der IT. Das zeigt auch das Aufkommen diverser Security bezogenen Tools wie z.B. Square’s Keywhiz oder HashiCorp’s Vault. Wir haben uns Vault etwas genauer angeschaut und uns überlegt wie wir Vault in der Adfinis SyGroupeinsetzen können.

Was ist Vault?

In seiner simpelsten Form ist Vault ein hierarchischer Key/Value Store zum Speichern von Secrets. Die Idee ist, dass man Vault an eine persistente Datenbank (z.B. MySQL, PostgreSQL, Consul, …) seiner Wahl anschliesst oder alternativ auf das built-in File-Backend zurückgreift. Die Interaktion mit Vault geschieht über eine HTTP REST API, zu welcher es Client Libraries in den verschiedensten Programmiersprachen gibt.

Bevor wir aber genauer darauf eingehen wie Vault funktioniert, sollte geklärt sein, welche Probleme Vault lösen zu versucht. Betrachtet man den Lifecycle eines generischen Secrets, z.B. eines Passwortes für einen Datenbank-Benutzer, sieht dieser meist wie folgt aus:

1. Der Admin legt ein Secret mit Berücksichtigung der firmenweiten Passwort-Richtlinien fest.
2. Das Passwort wird in einem Passwortmanager seiner Wahl festgehalten.
3. Beim Rückbau des Benutzers wird die Passwortliste entsprechend angepasst.

Leider geht oftmals ein wichtiger Punkt vergessen, nämlich die regelmässige Rotation der Secrets. Mit der Annahme, dass man mit genug Zeit und Ressourcen jede Verschlüsselung brechen kann, wäre es verheerend wenn ein Angreifer an eine Kopie der verschlüsselten Passwort-Datenbank gelangt.

Die Vision von HashiCorp sind sogenannte “dynamische Secrets”. Anstatt, dass der System Administrator beim Einrichten einer Webapplikation das Passwort setzt, holt sich die Webapplikation das Secret selber in regelmässigen Zeitabständen bei Vault ab. Dabei wird jedem Secret eine TTL mitgegeben, welche die Lebensdauer des Secrets auf wenige Stunden oder Tage limitiert. Sollte in einem solchen Szenario der Angreifer an die verschlüsselten Passwörter gelangen, wäre dies “harmlos” da in einem Tag bereits alle rotiert sind.

Durch die Zentralisierung entsteht ausserdem ein weiterer Nebeneffekt, denn sie ermöglicht sogenannte Break Glass Procedures. Stellt man in der eigenen Infrastruktur eine Schwachstelle fest, kann der Zugriff auf das betroffene Subset an Secrets gesperrt werden. Hat man die Schwachstelle gefunden und behoben, werden die Secrets rotiert und wieder freigegeben.

Zu diesem Zeitpunkt unterstützen die wenigsten Applikationen Vault nativ. Verwendet man allerdings das HashiCorp eigene Consul als Datenbackend, können Konfigurationsdateien durch das Tool consul-template bei Key/Value Änderung automatisch neu generiert werden.

Um Änderungen am Datenbestand protokollieren zu können, stellt Vault verschiedene Audit Backends zur Verfügung (Structured Logs und Syslog). So können Mutation auch später eingesehen werden. Der Zugriff auf Secrets lässt sich ausserdem durch ein ausgeklügeltes ACL System einschränken. ACLs lassen sich wiederum mit verschiedenen Authentication Backends verknüpfen. So kann man den Zugriff auf einen Pfad für eine bestimmte LDAP Gruppe bspw. auf “Read-Only” einschränken.

Die Konfiguration von Vault geschieht wahlweise über eine HCL oder JSON Datei. In folgendem Beispeil sieht man eine Konfiguration mit einem Consul Backend:

backend "consul" {
address = "127.0.0.1:8500"
path = "vault"
}

listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 0
tls_cert_file = "/etc/ssl/host.crt"
tls_key_file = "/etc/ssl/host.key"
tls_min_version = "tls12"
}

> Was die Erstellung des TLS Zertikates betrifft, verweise ich an dieser Stelle gerne auf unseren Post OpenSSL x509 Zertifikate erstellen.

Demo

Um ein Gefühl dafür zu bekommen wie sich Vault bedienen lässt, folgt nun eine kleine Demo.

Sobald der Vault Server läuft, muss er initialisiert werden.

$ vault init
Unseal Key 1: aRqypTLVENeZ9Tt1Kw2sy7XlnqHLT8XOUn3yqGTFMvsB
Unseal Key 2: o4Rd/1ZyzBwZaVEksIHsMpCJimv/pOt1+pSfQFiOEUkC
Unseal Key 3: S1x0hTZ5SrqiQlH1Boh8c/teKtfypu/PS6c5aHGj31cD
Unseal Key 4: TNdq4mdDDUMXAlxbtH8GCRRn3KU4HR3VSiefbWDUjtAE
Unseal Key 5: pA9DmAdIi+WsKVyKAnaWSH+wfBk1Hxlv+xQ5RUn5QM4F
Initial Root Token: 53368d66-8d50-ba5a-f953-7ef6b2dc03de
...

$ for KEY in ${UNSEAL_KEYS}; do vault unseal ${KEY}; done
...
Key (will be hidden):
Sealed: false
Key Shares: 5
Key Threshold: 3
Unseal Progress: 0
...

$ vault auth $ROOT_TOKEN
Successfully authenticated! You are now logged in.
token: 1bb7c7c6-6d4e-be92-cb5c-2838ccde3b5c
token_duration: 0
token_policies: [root]
...

Dabei wird ein Master Key generiert und in mehrere Subkeys aufgeteilt (siehe Shamir’s Secret Sharing). Von den generierten Subkeys werden in der Standardkonfiguration ein Quorum von 3 Keys benötigt um die Vault Instanz zu “entsiegeln”, ein Prozedere das bei jedem Start der Vault Instanz vorgenommen werden muss. Das initiale Root Token wird anschliessend benötigt um sich gegenüber Vault zu authentisieren.

Ab jetzt können Secrets in das standardmässig vorhandene secret/ Backend geschrieben werden.

$ vault mounts
Path Type Default TTL Max TTL Description
cubbyhole/ cubbyhole n/a n/a per-token private secret storage
secret/ generic system system generic secret storage
sys/ system n/a n/a system endpoints used for control, policy and debugging

$ vault write secret/test secret_key=secret_value
Success! Data written to: secret/test

$ vault list secret/
Keys
----
test

$ vault read secret/test
Key Value
--- -----
refresh_interval 720h0m0s
secret_key secret_value

Das war nur ein kleiner Auszug aus den verfügbaren Features welche Vault anbietet. Hier ein paar weiterführende Use Cases welche aber den Rahmen dieses Blogpostes sprengen würden:

  • Generieren von Amazon Web Services IAM Policies
  • Verwaltung von dynamischen Datenbank Benutzer/Rollen für MySQL, PostgreSQL, MongoDB…
  • Vollständige PKI zum Erstellen und Signieren von TLS Zertifikaten
  • SSH Zugriff auf Systeme durch OTP absichern

Ich kann jedem empfehlen einen Blick in die hervorragende Dokumentation von Vault zu werfen. In kürze folgt ausserdem ein zweiter Teil der aufzeigt, wie wir Vault adaptiert haben.

OpenSSH Security

10. February 2017

SSL Protokolle und Ciphers auf Webservern zu konfigurieren gehört seit längerem zum guten Ton. Bei anderen Services geht dies schnell vergessen, obwohl eine Vielzahl der Services über die Möglichkeit verfügt. Ein gutes Beispiel dafür ist der SSH Server OpenSSH.

SSH ist ein sehr weit verbreitetes Protokoll und die meisten Server bieten bspw. nach wie vor auch DSA Host-Keys an, welche aber schon seit längerem als nicht mehr sicher gelten. Dieser Artikel soll aufzeigen wie der OpenSSH Server und Client besser konfiguriert werden können. Dabei wird auch die Cipher-Suite und andere Parameter angepasst. Danach kann es sein, dass bei der Verbindung auf einen älteren Server, welcher keine der Ciphers in der Cipher-Suite unterstützt, die Cipher-Suite spezifisch angepasst werden muss. Bei der Cipher-Suite werden bewusst alle NIST Kurven deaktiviert und Elliptische Kurven von Daniel J. Bernstein aktiviert. Eine aktuelle Liste aller möglichen Ciphers und Algorithmen ist jeweils in der Manpage ssh_config oder mit dem Command ssh -Q <cipher|key|kex|mac> abrufbar.

OpenSSH Server

Aktuelle Distributionen (getestet mit CentOS 7 und Debian Jessie) unterstützen nebst RSA auch Ed25519 Keys. Werden Ed25519 Keys noch nicht unterstützt, sollte die entsprechende Zeile einfach gelöscht werden. Die DSA Host-Keys sollten immer deaktiviert werden, da diese als unsicher gelten.

HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com

Falls schon unterstützt, können auch noch folgende Parameter gesetzt werden:

HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa
FingerprintHash sha256
PubkeyAcceptedKeyTypes ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa

Nicht alle oben genannten Parameter und Argumente sind in OpenSSH 6.6 schon verfügbar. Dementsprechend müssen die entsprechenden Optionen, je nach Version, dann einfach entfernt werden.

OpenSSH Client

Aktuelle Clients (CentOS 7 und Debian Jessie) sollten die folgende Konfiguration verstehen. Da mit Clients oft auch mal auf ältere Server (oder spezielle Geräte wie Netzwerk Hardware) zugegriffen wird, müssen teilweise gewisse Optionen wie Ciphers, KexAlgorithms oder MACs angepasst werden.

Host *
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-rsa
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
FingerprintHash sha256
HostbasedKeyTypes ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa
PubkeyAcceptedKeyTypes ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa

Je nach Version, welche installiert ist, funktionieren nicht alle eben genannten Parameter und Argumente. Die oben gelistete Konfiguration wurde mit OpenSSH 7.4p1 erstellt.

Wird auf einen älteren SSH Server verbunden, welcher die Optionen nicht unterstützt, sieht die Ausgabe etwa wie folgt aus:

Unable to negotiate with SERVER port 22: no matching MAC found. Their offer: hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96

Dies kann z.B. gelöst werden, indem ssh mit der Option -o MACs=hmac-sha1 aufgerufen oder die entsprechenden Parameter für diesen Server in der Konfiguration angegeben wird.

Tests

Um SSH Server zu testen, gibt es ein Tool namens ssh-audit. Alle oben genannten Parameter des SSH Servers wurden mit diesem Tool verifiziert und teilweise erweitert. Eine Ausgabe kann in etwa wie folgt aussehen:

# general
(gen) banner: SSH-2.0-OpenSSH_7.4
(gen) software: OpenSSH 7.4
(gen) compatibility: OpenSSH 7.3+, Dropbear SSH 2016.73+
(gen) compression: enabled (zlib@openssh.com)

# key exchange algorithms
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62
(kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3
(kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group14-sha256 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73

# host-key algorithms
(key) ssh-rsa -- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
(key) rsa-sha2-512 -- [info] available since OpenSSH 7.2
(key) rsa-sha2-256 -- [info] available since OpenSSH 7.2
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5

# encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5
`- [info] default cipher since OpenSSH 6.9.
(enc) aes256-gcm@openssh.com -- [info] available since OpenSSH 6.2
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52

# message authentication code algorithms
(mac) hmac-sha2-512-etm@openssh.com -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-256-etm@openssh.com -- [info] available since OpenSSH 6.2

# algorithm recommendations (for OpenSSH 7.4)
(rec) +aes128-ctr -- enc algorithm to append
(rec) +aes192-ctr -- enc algorithm to append
(rec) +aes128-gcm@openssh.com -- enc algorithm to append
(rec) +umac-128-etm@openssh.com -- mac algorithm to append

Dabei ist vor allem der letzte Abschnitt relevant, welcher zusätzliche “recommendations” empfiehlt.

SUSECon 2016

17. January 2017

Wir waren mit dem Chamäleon in Washington D.C. und haben an der jährlichen SUSECon viel Spannendes gesehen und vor allem den Open Source Spirit erlebt.

Die ansteckende Stimmung, die Nähe zum SUSE-Management, die vielen Techies aber auch die Art und Weise, wie SUSE sich präsentiert sind nur einige der Gründe, warum die SUSECon zu den besten IT-Konferenzen überhaupt gehört – doch schauen Sie selbst.

Rock’n’Roll Baby!

Sich selber nicht all zu ernst zu nehmen und eine Konferenz mit der nötigen Priese Humor zu würzen ist das eine, aber bei der Schluss Keynote ein Cover von R.A.T.M zu spielen, ist nochmlas eine ganz andere Nummer: Coding in the Name of – Rage Against the Machine Parody – yay, so muss das! 😀

SUSE Band - Coding in the Name of

SUSE hat auch dieses Jahr eine entspannte Atmosphäre geschaffen, bei der man sich als Konferenz-TeilnehmerIn nicht in einer Sales-Show wähnt, in der es nur darum geht, Grösse zu demonstrieren. Auch die Konferenz-Goodies (Raspberry Pi 3 mit vorinstalliertem SLE), der Besuch des Nations Air and Space Museums und vielen Techie-Talks zeigen, dass bei den Jungs und Mädels aus Nürnberg die Technik nach wie vor im Zentrum steht.

SUSECon 2016 Konferenz-Goodie

Ankündigungen

Natürlich kamen auch die Ankündigungen nicht zu kurz. Für uns spannend waren insb. folgende Neuigkeiten:

Übernahme von OpenAttic

SUSE hat mit dem OpenAttic-Merger die erste Übernahme einer Technologie-Firma in der mehr als 20 jährigen Firmengeschichte bekannt gegeben und betont, dass weitere strategische Übenahmen in Betracht gezogen werden.

SUSE Enterprise Storage 4

SUSE hat SES 4 angekündigt und dabei folgendes in Aussicht gestellt:

  • Production ready CephFS
  • Integration des ersten Teils der OpenAttic Management Lösung
  • Ankündigung von DeepSea welches OSDs, MONs, iSCSI Gateways, etc. zukünftig über Salt provisionieren wird
  • ARM Support

CaaSP und Kubernetes (k8s)

Omnipräsent war in Washington u.a. auch Kubernetes, welches mit etwas Verzögerung nun offenbar auch seinen Weg ins SUSE Portfolio gefunden hat. Die hauseigene OpenStack Distribution SUSE OpenStack Cloud 7 kann einen Kubernetes Cluster über Heat-Templates direkt deployen.

Mit CaaSP (Container as a Service Platform) hat SUSE zudem eine Lösung angekündigt, welche Kubernetes, Docker und ein eigenes – von SLE abstammendes – MicroOS kombinieren wird.

Saltify all the things

Ebenfalls sehr präsent waren die Lösungen von Salt. SUSE setzt Salt in immer mehr Bereichen ein und es gibt keine Zweifel daran, dass Salt gekommen ist um zu bleiben. Der Speech von Thomas Hatch (Gründer und CTO von SaltStack) in dem die Architektur und die Vorteile von Salt sehr gekonnt aufgezeigt wurden, gehört zu einem der besten Speeches, die wir in den vergangenen Jahren gesehen habe.

SLE SP2

SUSE hat zudem SP2 für SLE 12 angekündigt – unsere Highlights hier sind die Unterstützung für 64Bit ARM sowie NVDIMM. HP hat schon Server mit NVDIMM angekündigt – das wird spannend! 🙂

MSSQL auf SLE

Auch Microsoft war an der SUSECon und was die Redmonder zeigten, war äusserst eindrücklich. Tommy Mullaney hat zum ersten mal öffentlich MSSQL auf SLE gezeigt!

Die wichtigsten Eckdaten:

  • Installation über herkömmliche Pakete, MS bietet Repositories direkt an
  • Management via systemd
  • Command Line Tools für das Management sind alle unter Linux verfügbar
  • Microsoft wird MSSQL auch als Docker Container anbieten
  • Gleicher Support von MS für Linux wie für Windows

Technisch verwendet Microsoft den selben Kniff wie beim WSL, einfach in die andere Richtung. Das heisst, die Binaries sind unter Linux die selben wie unter Windows und ein Layer übersetzt die Syscalls. Offenbar ist der Performance-Impact dabei so gering, dass kein Unterschied spürbar ist.

Fragt sich nur, wie lange es noch dauert, bis Microsoft auch Exchange, AD und IIS für Linux anbietet. 😉

Fazit

SUSECon ist nicht irgend eine Konferenz – SUSECon ist ein grossartiges Get-together einer ausgewogenen Mischung aus Techies, Entscheidungsträgern, Trainern, Doku-Heroes, Partnern, Presse-Leuten und noch vielem mehr.

Tolles technisches Niveau, viel Humor, grossartige Gespräche, gutes Essen, Execs zum Anfassen, gratis Zertifizierungen und v.a. Down to Earth oder kurz: eine Konferenz, von der andere lernen könnten.