ufw auf Strato-vServern mit Debian 8 – fehlende iptables Log-Meldungen im systemd-Journal – rsyslogd

Gestern hatte ich das Vergnügen, ein Debian-Server-System auf einer aktuellen vServer-Plattform bei Strato einzurichten. Ich bereite entsprechende Arbeiten in der Regel vor, indem ich elementare Konfigurationsschritte - im Besonderen solche, die sicherheitsrelevant sind - vorab auf einem ähnlichen KVM-Gast-System in unserem Hausnetz simuliere und teste.

Diese Art von vorbereitenden Tests hat jedoch ihre Grenzen; nicht alles ist vergleichbar. Gestern bin ich mal wieder auf einen Unterschied im Zusammenhang mit iptables, ufw und den zugehörigen LOG-Meldungen unter systemd gestoßen. Letztere fehlten nämlich im systemd-Journal des Strato-vServers völlig.

Da fragt man sich schon, wie man denn unter solchen Voraussetzungen das gehostete System bzgl. von Angriffsmustern monitoren soll. Ich finde, diese Frage ist so relevant, dass sie sich auch andere Strato-Kunden besser vor dem Mieten eines vServers beantworten sollten. Deshalb dieser Post. Die gute Nachricht ist: Es gibt unabhängig von den Ursachen für das Fehlen der LOG-Meldungen einen Workaround.

Die schlechte Nachricht ist: Die Ursache der fehlenden Kernel-Meldungen im systemd-Journal ist unklar; zumindest mir. Auf einem KVM-Host funktioniert alles wie erwartet. Unterschiede zu gehosteten Servern sind meist auf einen anderen Ansatz in der Virtualisierung zurückzuführen (Stichwort: Container-Technologie vs. Hypervisor für Full/Para-Virtualisierung).

In diesem Falle erscheint mir das aber als Erklärungsansatz nicht plausibel und hinreichend. Ich gehe nachfolgend auf die Gründe etwas genauer ein. Zudem ist bei Debian 8 (leider) eben auch systemd in den Logging-Prozess involviert. Defizite von "systemd" in der Interaktion mit bestimmten Virtualisierungsumgebungen halte ich für durchaus möglich. Der Irrwitz, dass ein Programm beim Systemstart die Umgebung analysieren und für jeden Fall die richtige Antwort ziehen muss, hat halt seinen Preis ...

ufw, netfilter/iptables und das Logging-Problem

Ich bin eigentlich ein Freund von Firewall-Builder (FWB). Für Debian-Systeme verwende ich aber auch "ufw", um initial die wichtigsten Paketfilter-Regeln, also iptables-Anweisungen, bequem und zeitsparend aufzusetzen. Die drehen sich zunächst um den SSH-Zugang von außen und die Erlaubnis, dass der gehostete Server DNS-Server, NTP-Server und bestimmte Update-Server kontaktieren darf. Auch "pings" und "traceroute" vom Server nach außen erlaube ich. Alles andere wird von mir anfänglich rigoros geblockt. Später wird dann für die angestrebten Services des Servers gezielt nachgearbeitet. (Off topic: Viele Dienste, die mein Kunde benötigt, tunnele ich auf dem Server über eine SSH-Verbindung; ein direkter SSH-Zugang des Users root wird sowieso unterbunden und der SSH-Port verschoben.)

Anfänglich ist hinsichtlich eines minimalen Regelsatzes gar nicht viel zu tun. Im Anschluss an das Etablieren der ersten Paketfilter-Regeln möchte ich gerne die Arbeit von "netfilter" testen und das zugehörige Logging mitverfolgen. Typischerweise lasse ich dann "nmap" von außen auf das gehostete System los. Für einen Test des Serverzugriffs auf externe DNS-Dienste und Zugriffe auf Update-Server tut es dagegen "apt-get". In beiden Fällen verfolge ich per SSH auf einem (Remote-) Terminal den Strom der Meldungen der (ufw-)"Firewall".

Das erhoffte Verfolgen der iptables-Log-Meldungen schlug auf dem Strato-vServer mit installiertem Debian 8 aber fehl.

Debian 8.x nutzt wie gesagt systemd. Ufw schreibt die iptables-Log-Daten mit eigenen Zusätzen in das Log-System des Servers - bei einem systemd-basierten Systemen also in das dortige binäre Journal. Das systemd-Journal fängt im Normalfall neben System-Meldungen und Meldungen aus dem Userspace auch Kernel-Messages auf. Da systemd den gesamten Mix aus Messages in ein binäres Datenformat in einer Datei überführt, muss man das Kommando "journalctl" mit geeigneten Filtern bzw. der Option "-f -nxxx" benutzen, um Log-Einträge auswerten bzw. direkt am Schirm mitverfolgen zu können.

Gesagt, getan. Leider tauchen auf einem Strato-vServer im Journal von "systemd" generell nur sehr wenig Informationen auf; hinsichtlich der Paketfilter-LOG-Meldungen findet man dort jedoch leider gar nichts.

Das iptables-Target "LOG" mündet auf einem mit "rsyslogd" ausgestatteten Log- und Warnsystem dagegen in Meldungen in der Datei "/var/log/kern.log" - schließlich handelt es sich ja um Kernel-Meldungen.

Die aus meiner Sicht schon immer kritikwürdige Idee, alle systemrelevanten Meldungen an einer Stelle in einem Binärformat zu sammeln, wird uns auf einem Strato vServer nun offenbar zum Verhängnis: Nur mit systemd können wir kleine und große externe Zugriffsversuche auf einen vServer offenbar nicht überwachen!

Ich bin übrigens nicht der Einzige, der dieses Problem hatte; siehe:
http://linux.debian.user.german.narkive.com/8AbyxJTP/keine-eintrage-von-dmesg-im-journal-systemd
Erstaunlich ist dennoch, dass man ansonsten im Internet fast nichts zu dieser Thematik findet.

Ob das Problem nun etwas mit systemd-Defiziten oder einer speziellen Konfiguration der systemd-Interaktion mit der Virtualisierungsumgebung bei Strato zu tun hat, muss man natürlich ein wenig austesten.

Firewall-Logging, Virtualisierung und Container

Tatsächlich erweist sich das Verhalten von Debian 8 mit "ufw" auf einem KVM-Gastsystem als gänzlich anders. Hier ein Auszug der ufw-Meldungen von einem KVM-Gast mit Debian 8, die mittels des Befehls

"journalctl -f -n20"

zur Anzeige gebracht wurden:

Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=54 ID=25556 PROTO=TCP SPT=64358 DPT=110 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=59 ID=47868 PROTO=TCP SPT=64358 DPT=135 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=45 ID=41401 PROTO=TCP SPT=64358 DPT=53 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW ALLOW] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=42 ID=10106 PROTO=TCP SPT=64358 DPT=22 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=54 ID=65381 PROTO=TCP SPT=64358 DPT=113 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=47 ID=1758 PROTO=TCP SPT=64358 DPT=587 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=47 ID=22236 PROTO=TCP SPT=64358 DPT=443 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=55 ID=60478 PROTO=TCP SPT=64358 DPT=23 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= 

 
Offensichtlich führt im obigen Fall das System 192.168.10.1 einen Portscan auf dem betroffenen KVM-Host mit der IP 192.168.10.11 durch.

Ähnliche Meldungen erhält man bei einem Portscan auf einem vServer aber - wie gesagt - nicht.

Wie könnte man das erklären?
Ein naheliegender Erklärungsansatz wäre etwa folgender:
Das Logging von Kernel-Messages klappt auf einem KVM-Gast, also unter dem QEMU-Hypervisor (sog. Typ 2 Hypervisor), der über "virtio" auf dem Host nur partiell Paravirtualisierung und keine Container-Technologie einsetzt, natürlich problemfrei. Das Betriebssystem des KVM-Gastes und dessen Kernel arbeiten ja weitgehend autonom und greifen nur über Vermittlungsschichten auf den Kernel des Hosts und dessen HW-Unterstützung zu. Es besteht von Haus aus kein Problem bzgl. des Loggings von Kernel-Meldungen - sie beziehen sich immer auf den Kernel des Gastsystems.

Dagegen setzt Strato Container-Technologie ein - genauer VZ-Container unter Virtuozzo; selbiges basiert auf OpenVZ. Zu Grundeigenschaften siehe :
https://openvz.org/Main_Page und https://openvz.org/Features

Es handelt sich bei Strato wohl um Version 4.7 oder eine frühe 6er Version von "Virtuozzo Containers". Dafür gibt es Indizien (u.a, dass sich Docker nicht installieren lässt); um einen genauen Nachweis habe ich mich aber (noch) nicht gekümmert. Ist auch egal.

In einer Container-Lösung wird jedenfalls die Kapazität und Funktionalität des Host-Kernels zwischen den Containern, die keinen eigenen Kernel besitzen, geteilt (schlanker "Single-Kernel-Approach"). Der Zugriff auf Netze erfolgt über eine entsprechende Netzwerk- und Schnittstellen-Virtualisierung. Typischerweise werden virtuelle venet- oder veth-NICs eingesetzt; je nachdem, auf welcher Ebene OSI-Stacks man arbeiten will. (veth-NICs setze ich selbst vielfach auch in komplexeren KVM/Qemu-Umgebungen bei der Netzwerkvirtualisierung ein.)

Die notwendige Separation der Container und ihrer Netzwerk-Kommunikation gegeneinander und gegenüber dem Host muss vom Host-Kernel bzw. dessen Modulen auf der Basis von Konfigurationsvorgaben für unpriviligierte Container (in ihren separaten Namespaces und bei modernen Ansätzen ggf. in cGroups) gewährleistet werden. Man wird den Container-Systemen jedenfalls nicht erlauben, alles einzusehen, was auf dem für alle zuständigen Host-Kernel abläuft. Dies bedeutet u.a., dass Containersysteme nicht beliebige Kernel-Module (z.B. für Packettracking unter Wireshark) laden dürfen.

Wer "iptables" im Zusammenhang mit Virtualisierungshosts aber ein wenig genauer kennt, kann sich vorstellen, dass man eine Host-Firewall natürlich immer so konfigurieren kann, dass die einzelnen virtuellen Netzwerkschnittstellen der (Container-) Gäste gegeneinander geblockt werden, aber dass generelle Forward-Regeln für physikalische Interfaces des Hosts nicht in Konflikt mit speziellen Filter-Regeln für ein spezifisches (virtuelles) Gast-Interface geraten müssen.

OpenVZ kann man deshalb sehr wohl so einrichten, dass der Admin eines Container-Systems seine eigenen iptables-Regeln für seine gastspezifischen NICs definieren kann. Siehe hierzu z.B.:
https://openvz.org/Setting_up_an_iptables_firewall.

Wesentliche Teile der verschiedenen netfilter-Module - im Besonderen für die Schicht 3 - stehen also auch Gästen zur Verfügung. Voraussetzung ist in einer Container-Architektur natürlich, dass grundlegende "netfilter"-Module auf dem OpenVZ-Host selbst geladen wurden.

Aber: Es wäre fahrlässig, wenn ein Container-Host alle netzwerkspezifischen Kernel-Meldungen (darunter iptables-Meldungen) auch für die Einsichtnahme durch die root-User der Container preisgeben würde. Das würde u.a ein Ausspionieren der virtuellen Netzwerkumgebung und darauf aufbauend bestimmte Angriffsszenarien ermöglichen. Wenn wir überhaupt etwas im Container sehen, dann höchstens Meldungen zu selbst gesetzten Paketfilterregeln für die Container-spezifische NIC.

Zwischenfazit:

  • Wir dürfen uns in einer Container-Umgebung u.a. nicht darüber wundern, dass man bestimmte Kernel-Module vom Container aus erst gar nicht laden darf und z.B. lsmod eine vernünftige Antwort schuldig bleibt.
  • Wir dürfen uns nicht wundern, dass bestimmte sysctl-Befehle, die im Container abgesetzt werden, ggf. ignoriert werden.
  • Wir dürfen uns in einer Container-Umgebung nicht wundern, wenn man bestimmte Teile des systemd-Logs auf einem Container - und damit auf einem Strato-V-Server - nicht ggf. zu Gesicht bekommt. (Im Gegensatz zu einem KVM-Gast).

Der erste Punkt ist u.a. für den Betrieb der ufw relevant; s.u..

Bzgl. des zweiten Punktes ist zu beachten, dass OpenVZ, genauer der OpenVZ-Kernel, (network-) "Namespaces" nutzt. ("Namespaces" werden natürlich aber auch von aktuellen Linux-Kerneln unterstützt. Zu "Namespaces" siehe etwa
https://jvns.ca/blog/2016/10/10/what-even-is-a-container/
https://de.slideshare.net/jpetazzo/anatomy-of-a-container-namespaces-cgroups-some-filesystem-magic-linuxcon
https://openvz.org/WP/What_are_containers.

Deshalb lassen sich bestimmte Einstellung unterhalb von "/proc/sys" durchaus auch vom Container aus anpassen. Was in der jeweiligen OpenVZ-Umgebung erlaubt ist und was nicht, muss man ggf. durch Probieren herausfinden.

Den dritten Punkt werden wir in den nächsten Abschnitten für vServer kritisch hinterfragen.

Erste Konsequenzen für den Einsatz von "ufw"

Auch durch Probieren wird man herausfinden, dass "ufw" auch auf einem mit Debian 8 betriebenen vServer von Strato läuft - und man eigene iptables-Regeln problemfrei an den OpenVZ-Kernel weiterreichen kann.

Achtung:

Nach der Installation von ufw auf dem vServer NICHT unmittelbar "ufw enable" absetzen!! Zuerst den Port, auf dem man SSH betreibt, freischalten. Also etwa durch "ufw allow 22", wenn man den SSH-Standardport benutzt. Ihr wollt euch ja nicht durch Anschalten der Firewall selbst aussperren!

Wie man schnell (hier durch einen Blick in das systemd-Journal feststellt), ist der Start von ufw auf einem vServer - auch im Rahmen eines Systemstarts - mit ein paar Fehlermeldungen verbunden.

Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: Starting firewall: ufw...modprobe: ERROR: ../libkmod/libkmod.c:557 kmod_search_moddep() could not ope
Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: modprobe: ERROR: ../libkmod/libkmod.c:557 kmod_search_moddep() could not open moddep file '/lib/modul
Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: modprobe: ERROR: ../libkmod/libkmod.c:557 kmod_search_moddep() could not open moddep file '/lib/modul
Apr 05 14:21:03 xxx.stratoserver.net systemd-journal[114]: Permanent journal is using 24.0M (max allowed 4.0G, trying to leave 4.0G free of 499.5G a
Apr 05 14:21:03 xxx.stratoserver.net systemd-journal[114]: Time spent on flushing to /var is 1.770ms for 8 entries.
Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: sysctl: permission denied on key 'net.ipv4.tcp_sack'
Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: Setting kernel variables (/etc/ufw/sysctl.conf)...done.

 
Diese Meldungen rühren u.a. daher, dass ufw mit Hilfe von modprobe versucht, bestimmte "conntrack"-Sub-Module zu laden. Zudem versucht ufw per sysctl Kernel-Parameter abzuändern. Vorgegeben sind diese Schritte in den Dateien "/etc/default/ufw" und "/etc/ufw/sysctl.conf".

Die genannten Fehler blockieren den Start aktueller ufw-Versionen aber nicht; wer sich dennoch an den Meldungen stört, kann die über Modifikationen der genannten Dateien, nämlich durch Auskommentieren der fehlerträchtigen Statements, verhindern. Siehe auch
https://www.hosteurope.de/faq/server/virtual-server/besonderheiten-firewall-virtual-server/; im Unterschied zu den dortigen Tipps aber beachten, dass auf dem vServer nur einer der sysctl-Befehle problematisch ist.)

Übrigens: Über das Starten von ufw bei einem Reboot des vServers muss man sich nach einem Absetzen von

systemctl enable ufw

keine Gedanken mehr machen. Debian 8 beinhaltet für ufw einen passenden LSB-Service, der beim Hochfahren ausgeführt wird.

Monitoring von ufw-iptables-Meldungen auf dem vServer mit Hilfe von dmesg

Nachdem man in systemd-Journal nichts findet: Gibt es andere Möglichkeiten, die LOG-Messages von ufw-/iptables zu verfolgen?

Da es sich um Kernel-Messages handelt, liegt ein versuchsweiser Blick auf den "dmesg"-Output nahe. Und tatsächlich - auf meinem vServer:

    
root@xxx:~ # dmesg
[1240949.664984] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=45.55.2.201 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=244 ID=54321 PROTO=TCP SPT=40788 DPT=3306 WINDOW=65535 RES=0x00 SYN URGP=0 
[1240954.051018] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=93.174.93.136 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=250 ID=4710 PROTO=TCP SPT=43745 DPT=3128 WINDOW=1024 RES=0x00 SYN URGP=0 
[1240986.448807] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=45.55.1.72 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=244 ID=54321 PROTO=TCP SPT=46822 DPT=1900 WINDOW=65535 RES=0x00 SYN URGP=0 
[1241002.495868] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=88.100.184.82 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=50 ID=13380 PROTO=TCP SPT=35180 DPT=23 WINDOW=44554 RES=0x00 SYN URGP=0 
[1241015.141452] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=445 TOS=0x00 PREC=0x00 TTL=57 ID=32820 DF PROTO=UDP SPT=5180 DPT=5046 LEN=425 
[1241132.233004] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=197.44.69.222 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=239 ID=44476 PROTO=TCP SPT=53226 DPT=1433 WINDOW=1024 RES=0x00 SYN URGP=0 
[1241145.520318] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=208.100.26.228 DST=xxx LEN=40 TOS=0x08 PREC=0x00 TTL=242 ID=51210 PROTO=TCP SPT=47975 DPT=15672 WINDOW=1024 RES=0x00 SYN URGP=0 
[1241185.158299] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=443 TOS=0x00 PREC=0x00 TTL=57 ID=56812 DF PROTO=UDP SPT=5400 DPT=4000 LEN=423 
[1241297.661764] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=186.45.130.20 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=241 ID=12134 PROTO=TCP SPT=63715 DPT=23 WINDOW=14600 RES=0x00 SYN URGP=0 
[1241350.742715] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=446 TOS=0x00 PREC=0x00 TTL=57 ID=14769 DF PROTO=UDP SPT=5320 DPT=5172 LEN=426 
[1241353.098569] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=5.53.113.195 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=51 ID=48667 PROTO=TCP SPT=46919 DPT=23 WINDOW=39535 RES=0x00 SYN URGP=0 
[1241377.620483] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=46.152.41.83 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=240 ID=40038 PROTO=TCP SPT=12600 DPT=23 WINDOW=14600 RES=0x00 SYN URGP=0 
[1241386.187457] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=122.114.187.140 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=238 ID=8477 PROTO=TCP SPT=46170 DPT=23 WINDOW=1024 RES=0x00 SYN URGP=0 
[1241437.193431] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=218.91.210.142 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=4557 PROTO=TCP SPT=45821 DPT=23 WINDOW=27541 RES=0x00 SYN URGP=0 
[1241512.054090] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=443 TOS=0x00 PREC=0x00 TTL=57 ID=37720 DF PROTO=UDP SPT=5179 DPT=1028 LEN=423 
[1241553.246515] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=49.4.143.59 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=104 ID=256 PROTO=TCP SPT=6000 DPT=135 WINDOW=16384 RES=0x00 SYN URGP=0 
[1241632.706391] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=39.71.216.3 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=4841 PROTO=TCP SPT=57398 DPT=22 WINDOW=55725 RES=0x00 SYN URGP=0 
[1241643.559480] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=196.202.5.43 DST=xxx LEN=44 TOS=0x00 PREC=0x00 TTL=48 ID=53691 PROTO=TCP SPT=34866 DPT=23 WINDOW=33710 RES=0x00 SYN URGP=0 
[1241674.241572] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=446 TOS=0x00 PREC=0x00 TTL=57 ID=60393 DF PROTO=UDP SPT=5288 DPT=1029 LEN=426 
[1241683.411659] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=124.167.232.138 DST=xxx LEN=60 TOS=0x00 PREC=0x00 TTL=47 ID=40536 DF PROTO=TCP SPT=57844 DPT=22 WINDOW=14600 RES=0x00 SYN URGP=0 
[1241686.407572] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=124.167.232.138 DST=xxx LEN=60 TOS=0x00 PREC=0x00 TTL=47 ID=40537 DF PROTO=TCP SPT=57844 DPT=22 WINDOW=14600 RES=0x00 SYN URGP=0   

 
Ja, die Welt ist schlecht - und wir tun offenbar gut daran, den Zugang zum Server zu blocken bzw. die Logs auch mal auszuwerten und später Blacklists einzusetzen. "fail2ban" zu konfigurieren schadet nebenbei auch nichts.

Wer periodische Updates des Outputs von dmesg ähnlich zu "tail -f" verfolgen will, probiere mal das Kommando

watch -n 0,2 "dmesg | tail -n $((LINES-6))"

in einem Terminal aus. (Ggf. das Terminalfenster etwas vergößern. Auf englischsprachigen Systemen "0.2" statt wie hier "0,2" ! Auf neueren Kerneln als dem der aktuellen vServer gibt es übrigens auch die dmesg-Option "-w").

Aber das eigentlich Feststellenswerte ist ja, dass wir überhaupt was sehen!

Natürlich ist das, was man unter OpenVZ unter dmesg zu Gesicht bekommt, eingeschränkt (s. etwa https://bugs.openvz.org/browse/OVZ-5328).
Aber:
Der OpenVZ-Kernel liefert dem Container zulässige, relevante Informationen in den lokalen Message-Ringpuffer, die dort von root eingesehen werden können. Darunter auch die ersehnten iptables-Meldungen!

Nun stellt sich die große Frage, wie systemd mit diesen Kernelmeldungen interagiert und warum das, was unter dmesg erschient, nicht ins Journal der OpenVZ-Container-Umgebung eingestellt wird.

Das Problematische an systemd ist, wie immer, dass man das ohne seitenweises Lesen in systemd Blogs etc. und/oder gar Codestudium vermutlich nicht beantworten kann. Logisch erscheint mir das Ganze jedenfalls nicht. OpenVZ sorgt offenbar für eine Reduktion der Kernelinformationen auf das, was root im Container sehen sollte. iptables-Meldungen zur lokalen NIC des Containers werden dabei nicht ausgespart. Sie sollten daher eigentlich auch im systemd-Journal erscheinen!

Monitoring mittels rsyslogd ? !

Durch den dmesg-Test ermutigt, fragte ich mich, was wohl passieren würde, wenn rsyslog auf dem vServer-Debian-System installiert und aktiviert wäre. Das ist insofern interessant, als systemd ja externe Linux System-Logging-Services über Schnittstellen bedient und trotzdem sein eigenes Journal weiter versorgt. Man loggt dann im Normalfall sozusagen zweimal ...

Eigentlich würde man nun erwarten, dass die Meldungen von dmesg auch in den verschiedenen Dateien, die der rsyslog-Dämon bedient, nicht auftauchen sollten. Weil systemd ja schon den Transfer in die eigene Binärdatei verweigert. Also machen wir mal die Probe:

root@xxx:~# apt-get rsyslog
root@xxx:~# systemctl start rsyslog
root@xxx:~# systemctl enable rsyslog

Wenn nun doch etwas passieren sollte, so müssten iptables-Meldungen als Einträge unter "/var/log/kern.log" und/oder in der von ufw vorgesehenen Datei "/var/log/ufw.log" auftauchen.

Und tatsächlich finden wir (wider Erwarten) nach einer Weile in "kern.log" iptables-LOG-Meldungen:

  
Apr  6 13:19:57 xxx kernel: [1245761.082097] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=118.163.90.134 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=14764 PROTO=TCP SPT=33202 DPT=23 WINDOW=44186 RES=0x00 SYN URGP=0 
Apr  6 13:21:03 xxx kernel: [1245827.018789] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=85.90.163.248 DST=xxx LEN=44 TOS=0x00 PREC=0x00 TTL=52 ID=358 PROTO=TCP SPT=21965 DPT=23 WINDOW=12453 RES=0x00 SYN URGP=0 
Apr  6 13:21:16 xxx kernel: [1245840.027789] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=445 TOS=0x00 PREC=0x00 TTL=57 ID=61654 DF PROTO=UDP SPT=5201 DPT=4011 LEN=425 
Apr  6 13:22:26 xxx kernel: [1245910.326051] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=91.98.36.115 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=46 ID=3739 PROTO=TCP SPT=31242 DPT=23 WINDOW=22306 RES=0x00 SYN URGP=0 
Apr  6 13:23:13 xxx kernel: [1245957.077099] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=117.193.182.117 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=29137 PROTO=TCP SPT=12209 DPT=22 WINDOW=52845 RES=0x00 SYN URGP=0 
Apr  6 13:23:54 xxx kernel: [1245997.536218] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=45.55.1.114 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=244 ID=54321 PROTO=TCP SPT=43185 DPT=8123 WINDOW=65535 RES=0x00 SYN URGP=0 
Apr  6 13:23:56 xxx kernel: [1246000.108495] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=192.151.169.29 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=51 ID=46742 PROTO=TCP SPT=54014 DPT=23 WINDOW=49390 RES=0x00 SYN URGP=0 
Apr  6 13:24:05 xxx kernel: [1246008.982092] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=445 TOS=0x00 PREC=0x00 TTL=57 ID=19866 DF PROTO=UDP SPT=5391 DPT=4012 LEN=425 
Apr  6 13:24:08 xxx kernel: [1246011.450635] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=163.172.204.214 DST=xxx LEN=447 TOS=0x00 PREC=0x00 TTL=58 ID=25411 DF PROTO=UDP SPT=5440 DPT=5060 LEN=427 
Apr  6 13:24:18 xxx kernel: [1246022.133966] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=181.193.99.26 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=47683 PROTO=TCP SPT=36520 DPT=23 WINDOW=41856 RES=0x00 SYN URGP=0 
Apr  6 13:24:29 xxx kernel: [1246032.599018] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.248.166.146 DST=xxx LEN=48 TOS=0x00 PREC=0x00 TTL=123 ID=26103 PROTO=TCP SPT=11206 DPT=2083 WINDOW=65535 RES=0x00 SYN URGP=0 
Apr  6 13:24:50 xxx kernel: [1246053.507827] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=71.165.26.106 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=50 ID=381 PROTO=TCP SPT=29725 DPT=23 WINDOW=3178 RES=0x00 SYN URGP=0 
Apr  6 13:25:44 xxx kernel: [1246108.065452] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=139.162.118.251 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=246 ID=54321 PROTO=TCP SPT=56219 DPT=6379 WINDOW=65535 RES=0x00 SYN URGP=0 
Apr  6 13:26:16 xxx kernel: [1246139.839711] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=174.16.249.159 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=240 ID=54734 PROTO=TCP SPT=43074 DPT=23 WINDOW=14600 RES=0x00 SYN URGP=0 
Apr  6 13:26:28 xxx kernel: [1246151.805797] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=117.1.220.212 DST=xxx LEN=44 TOS=0x00 PREC=0x00 TTL=242 ID=2085 PROTO=TCP SPT=14216 DPT=5358 WINDOW=14600 RES=0x00 SYN URGP=0 
Apr  6 13:26:50 xxx kernel: [1246174.013725] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=123.151.42.61 DST=xxx LEN=135 TOS=0x00 PREC=0x00 TTL=47 ID=32696 PROTO=UDP SPT=9019 DPT=1701 LEN=115 
Apr  6 13:27:01 xxx kernel: [1246184.993843] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=445 TOS=0x00 PREC=0x00 TTL=57 ID=44551 DF PROTO=UDP SPT=5365 DPT=4013 LEN=425 
Apr  6 13:27:27 xxx kernel: [1246211.300971] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.120.177.89 DST=xxx LEN=44 TOS=0x00 PREC=0x00 TTL=55 ID=64605 PROTO=TCP SPT=59589 DPT=23 WINDOW=64213 RES=0x00 SYN URGP=0 

 
Die Welt ist inzwischen nicht besser geworden, aber nun können wir das Schlechte wenigstens mal verfolgen. (Dieselben Einträge erscheinen übrigens auch in ufw.log).

Tja, nicht alles im Leben mit systemd ist offenbar nachvollziehbar ....

Fazit

Das erwartete native Zusammenspiel zwischen einem Strato OpenVZ vServer und systemd unter Debian 8 funktioniert bzgl. der Protokollierung der LOG-Target-Meldungen von iptables nicht. Kernel-Meldungen zu iptables-Rules für die Container-NIC erschienen nicht im Journal von systemd.

Workarounds bestehen darin

  • den Output von dmesg kontinuierlich per Skript abzufragen und in eine Datei umzulenken.
  • rsyslog zu installieren und die Arbeit dem Zusammenspiel von systemd mit dem rsyslog-Dämon zu überlassen. Man protokolliert dann doppelt, aber man erhält wenigstens dauerhafte Log-Protokolle, die jeder sicherheitsbewußte Admin zur vorsorglichen Gefahrenabwehr benötigt.

Da die gewünschten Kernel-Meldungen bei gleicher Debian- und Systemd-Version in einem KVM-Gast erscheinen, ist das Problem mit dem systemd-Journal entweder

  • auf einen Fehler oder ein Sicherheitsfeature der OpenVZ-Umgebung,
  • oder auf ein seltsames (gewolltes oder fehlerhaftes) Zusammenspiel des OpenVZ-Kernels mit systemd in den Container-Umgebungen,
  • oder schlicht auf ein fehlerhaftes, bislang nicht erkanntes/bedachtes Verhalten von systemd in einem OpenVZ-Container

zurückzuführen.

Für letzteres spricht die Tatsache, dass der OpenVZ-Kernel iptables-Meldungen zur Container-NIC unter dmesg offenbart und dass systemd die Meldungen, die unter dmesg auftauchen wohl korrekt an weitere System-Logging-Services wie rsyslog weiterleitet.

Eine entsprechende Anfrage bei Strato, die hoffentlich Virtuozzo einschalten, läuft.

Das Fehlen von iptables-Log-Protokolle ist im Sinne der ISO 27000 (Strato hat da ein Zertifikat!) zudem als Sicherheitsproblem einzustufen, das Kunden kommentarlos zugemutet wird und von diesen Kunden selbst gelöst werden muss.

Weiterführende Links

Fehlende Einträge im systemd-Journal
http://linux.debian.user.german.narkive.com/8AbyxJTP/keine-eintrage-von-dmesg-im-journal-systemd

Container, Virtuozzo, OpenVZ und iptables, ufw
http://forum.openvirtuozzo.org/index.php?t=msg&goto=37264&&srch=container
https://openvz.org/Setting_up_an_iptables_firewall
http://askubuntu.com/questions/399624/ubuntu-server-12-04-and-ufw-failure-on-startup-and-several-module-not-found-err
https://www.hosteurope.de/faq/server/virtual-server/besonderheiten-firewall-virtual-server/
https://superuser.com/questions/659236/permission-denied-when-setting-values-in-sysctl-on-ubuntu-12-04
https://help.ubuntu.com/community/UFW
https://help.virtuozzo.com/customer/en/portal/articles/2509437?_ga=1.206607316.635252319.1491384754
ab S. 317 in folgender Referenz
http://www.odin.com/fileadmin/parallels/documents/hosting-cloud-enablement/pvc/Production_Documents/VzLinuxUG_03132013.pdf
https://bugs.openvz.org/browse/OVZ-5328

Namespaces
http://www.netdevconf.org/1.1/proceedings/slides/rosen-namespaces-cgroups-lxc.pdf

LXC vs. OpenVZ
https://www.janoszen.com/2013/01/22/lxc-vs-openvz/
https://en.wikipedia.org/wiki/LXC
https://openvz.org/Comparison

OpenVZ integrates KVM/Qemu
http://openvz.livejournal.com/tag/criu
https://www.heise.de/ix/meldung/Virtualisierungsplattform-OpenVZ-wird-eigenstaendige-Distribution-3278115.html
https://openvz.org/Virtuozzo
https://openvz.org/QEMU
https://www.heise.de/ix/meldung/Virtualisierungsplattform-OpenVZ-wird-eigenstaendige-Distribution-3278115.html
https://openvz.org/FAQ
https://virtuozzo.com/virtual-machines-in-virtuozzo-7/
https://openvz.org/WP/What_are_containers#Networking

Virtualisierungsangebote in D - Vergleich
https://timreeves.de/trip-content/uploads/dokumente/Internet-Mietserver-Typen_im-Vergleich.pdf

Watch dmesg Output
http://unix.stackexchange.com/questions/95842/how-can-i-see-dmesg-output-as-it-changes

SFTP mit Key-Authentication auf (gehosteten) Linux-Servern für Web-Entwickler mit unterschiedlichen Privilegien – II

Im ersten Artikel der Serie zur SFTP-Einrichtung auf gehosteten Servern

SFTP mit Key-Authentication auf (gehosteten) Linux-Servern für Web-Entwickler mit unterschiedlichen Privilegien – I

hatten wir erste grundlegende Aspekte der SSH-Einrichtung diskutiert. Im jetzigen Artikel diskutiere ich zunächst einige Verbesserungen der SSH-Einstellungen und wende mich dann der Einrichtung von 2 Usergruppen in der "/etc/sshd_config" zu.

Sicherheits-Hinweis für den Umgang mit der sshd-config auf Remote Servern

Fehler sind menschlich. Durch Zerstören der SSHD-Konfiguration kann man sich von gehosteten Servern selbst aussperren. Bevor man also an der sshd_config rumspielt, sollte man sich immer einen weiteren Zugangsweg zum Server für Notfälle sichern.

Server-Hoster bieten für den Ernstfall ein Booten in einen Maintenance-Modus an. Dass das funktioniert, sollte man mal getestet haben. Ein Gleiches gilt für evtl. Backup-Verfahren. Ferner sollte man bei sich Kopien aller wichtigen Konfigurationseinstellungen haben. Ich selbst lege vor Änderungen immer eine Kopie der funktionierenden ssd_config an. Die kann man im Ernstfall im Maintenance-Modus wieder zurückspielen.

Ferner sollte man 2 bis 3 andere ssh-Verbindungen offen halten, bevor man den sshd-Dämon neu startet. Der Server setzt normalerweise eine Grace-Time für bereits geöffnete Verbindungen. Dieses Zeitintervall kann man dann im Ernstfall noch für Änderungen der sshd_config oder ein Zurückspielen einer funktionierenden Konfigurationsdatei nutzen!

Von Vorteil ist es auch, eine von der Gruppe, für die die Einstellungen manipuliert werden, unabhängige, SSH-fähige UserID zur Verfügung zu haben.

Verbesserungen der SSH-Enrichtung

Aufgrund der schon seit einiger Zeit erhöhten Sicherheitsanforderungen Anforderungen müssen wir die SSH-Einrichtung verbessern. Ich kann an dieser Stelle leider nicht auf Details eingehen - es sind aber vor allem bekannte Probleme im Bereich des initialen "Key Exchange" [KEX] zu beheben:

Einerseits sind Standardparameter und Schlüssellängen für bestimmte zugehörige asymmetrische Algorithmen, die auf Primfaktorzerlegung und Modulo-Verfahren beruhen, unzulänglich. Leider sieht der Standard selbst Verfahren als Fallback-Optionen verbindlich vor, die aktuellen Anforderungen nicht mehr genügen. Andererseits muss man leider auch hinter Standard-Parameter für elliptische Kryptographie große Fragezeichen hinsichtlich ihrer Zufälligkeit setzen.

Ein Teil der Probleme wurde bereits 2015 adressiert; siehe z.B.:
https://weakdh.org/imperfect-forward-secrecy-ccs15.pdf.
Informationen bzgl. möglicher Maßnahmen findet man etwa hier:
https://stribika.github.io/2015/01/04/secure-secure-shell.html.

Der erste Schritt zur Aufrüstung ist, dass wir uns die aktuelle Version von OpenSSH (z.Z. 7.2p2) beschaffen. Für Opensuse (ab der Version 13.1) nutzt man hierzu das "network"-Repository ; siehe hierzu http://download.opensuse.org/repositories/network/.

Danach lassen wir nur die Protokollvariante 2 und lediglich zwei z.Z. noch als sicher eingeschätzte initiale Schlüsselaustausch-Verfahren des SSH-Protokolls zu. Ferner schränken wir die Klassen der für die Serveridentifikation möglichen Schlüssel ein. Hierzu dienen die folgenden Statements in der Datei "/etc/ssh/sshd_config" unseres Servers "serv":

# We only allow for SSH protocol version 2 
Protocol 2

# We restrict the Key Exchange Algorithms !!!
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256

# Minimum length in DH 
KexDHMin 2048

# We restrict HostKeys types for Host authentification for protocol version 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key

# We restrict Ciphers 
#RekeyLimit default none
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr

# UsePam can be set to "yes" to get more control options via PAM 
# siehe hierzu die Diskussion in einem kommenden Artikel
UsePAM  yes 

 
Man sollte für Zwecke im privaten oder Geschäftsumfeld zudem zugehörige flankierende Einstellungen in der lokalen Client-Konfigurations-Datei "/etc/ssh_config" vornehmen. Siehe den oben angegebenen Link.

Zwei Usergruppen und zweier Beispieluser

Im Folgenden verschaffen wir zwei exemplarischen SFTP-Usern

  • alpha : Mitglied der Entwicklergruppe "devgrp1" und der Gruppe "devgrp2"
  • beta : Mitglied der Entwicklergruppe "devgrp2".

einen ersten elementaren SFTP-Zugang zu den Verzeichnissen "/srv/www/htdocs/webs/project/alpha", "/srv/www/htdocs/webs/project/adm", "/srv/www/htdocs/webs/project/test/beta".

Zugang zu unterschiedlichen chroot-Verzeichnissen

Wir legen in einem ersten Anlauf zunächst das Verzeichnis "/srv/www/htdocs/webs/project/" als Dachverzeichnis an.

Dieses Verzeichnis wird uns gleichzeitig als chroot-Verzeichnis für alle beteiligten SFTP-User der Gruppe "devgrp1" dienen.

Ein weiteres untergeordnetes Verzeichnis "/srv/www/htdocs/webs/project/test" wird dagegen als chroot-Verzeichnis für die Mitglieder der Gruppe "devgrp2" verwendet.

An dieser Stelle muss auf einen wichtigen Punkt hingewiesen werden.

Jedes Verzeichnis, das unter SFTP als chroot-Jail für eine Usergruppe dienen soll, muss root gehören und nur root darf darauf Schreibrechte besitzen.

Ansonsten läuft man bei der Einrichtung des SFTP-Zugangs in Probleme, wie sie etwa hier geschildert sind:
http://superuser.com/questions/394298/sftp-chroot-result-in-broken-pipe

Also geben wir als User root auf dem Web/SFTP-Server "serv" Folgendes ein :

mytux:~ # mkdir /srv/www/htdocs/webs/project
mytux:~ # chgrp devgrp1 /srv/www/htdocs/webs/project
mytux:~ # chmod 750 mkdir /srv/www/htdocs/webs/project
mytux:~ # mkdir /srv/www/htdocs/webs/project/test
mytux:~ # chgrp devgrp2 /srv/www/htdocs/webs/project/test
mytux:~ # chmod 750 mkdir /srv/www/htdocs/webs/project/test
mytux:~ # mkdir /srv/www/htdocs/webs/project/alpha
mytux:~ # chgrp devgrp1 /srv/www/htdocs/webs/project/alpha
mytux:~ # chmod 770 mkdir /srv/www/htdocs/webs/project/alpha
mytux:~ # mkdir /srv/www/htdocs/webs/project/adm
mytux:~ # chgrp devgrp1 /srv/www/htdocs/webs/project/adm
mytux:~ # chmod 770 mkdir /srv/www/htdocs/webs/project/adm
mytux:~ # mkdir /srv/www/htdocs/webs/project/test/beta
mytux:~ # chgrp devgrp2 /srv/www/htdocs/webs/project/test/beta
mytux:~ # chmod 770 mkdir /srv/www/htdocs/webs/project/test/beta

 
Mitglieder der Gruppe "devgrp1" legen wir später auch als Mitglieder der Gruppe "devgrp2" an. Sie dürfen daher mit SFTP alle unter "/srv/www/htdocs/webs/project" liegenden Verzeichnisse einsehen; u.a. auch solche, die "devgrp2" zugänglich sind, aber zusätzlich auch weitere Verzeichnisse. "devgrp1" hat gegenüber der Gruppe "devgrp2" also mehr Privilegien. Mitglieder der Gruppe "devgrp2" sehen theoretisch zunächst nur den Inhalt von Verzeichnissen unterhalb "/srv/www/htdocs/webs/project/test".

Dabei gilt:

Schreiben und Unterverzeichnisse anlegen dürfen Mitglieder von "devgrp1" bzw. "devgrp2" aber nur in den Unter-Verzeichnissen "alpha" bzw. "beta" !

Berücksichtigung der künftigen SFTP-User-Gruppen in der SSHD-Konfigurationsdatei

Wir müssen den Usern "alpha" und "beta" zur Nutzung von SFTP zunächst grundsätzlich die Nutzung von SSH zugestehen. Dies führt zur Modifikation des "AllowUsers"-Eintrags in der Konfigurationsdatei, der im letzten Artikel diskutiert wurde :

AllowUsers usu alpha beta

Bei wenigen einzelnen Usern und Gruppen kann man vielleicht so arbeiten. Bei steigender Useranzahl werden die User aber typischerweise in Gruppen angeordnet. Dann ist es wichtig zu wissen, dass es auch die Direktive "AllowGroups" gibt. Insgesamt werden vom SSH-Daemon 4 Direktiven in folgender Reihenfolge abgearbeitet:

DenyUsers
AllowUsers
DenyGroups
AllowGroups

Das zuerst getroffene Muster zählt dabei unabhängig von nachfolgenden Muster-Treffern! Siehe:
https://en.wikibooks.org/wiki/OpenSSH/Server
Nicht zutreffende Treffer führen automatisch zu einem Default-Ausschluss von der Nutzung.

Beachtet bitte auch, dass host-spezifische Zusätze der Form USER@HOST nur zu User-IDs - nicht aber (!) zu Gruppen-IDs - möglich sind. Siehe:
http://manpages.ubuntu.com/manpages/hardy/man5/sshd_config.5.html
Wildcards in Host-Ergänzungen sind unter obigem Link auch beschrieben:
http://manpages.ubuntu.com/manpages/hardy/man5/ssh_config.5.html

Ist der User "usu" ein Mitglied der Gruppe "adm", so hätten wir in unserem Fall also auch schreiben können:

AllowGroups adm devgrp?

Man beachte, dass kein Komma sondern ein Blank zur Abtrennung mehrerer User oder Usergruppen voneinander benutzt wird.

Begrenzung des Zugriffs auf CHROOT-Verzeichnisse

Nun müssen wir bestimmte Verzeichnisse vorgeben, auf die sich der Zugang beschränken soll. Hierfür sind zwei Direktiven erforderlich:

  • Zum einen eine Einstellung zur Nutzung des internen SFTP-Mechanismus durch den jeweiligen User
  • und zum anderen eine Einstellung zur Definition eines alle Aktionen begrenzenden und kapselnden CHROOT-Verzeichnisses für jeden User.

Ich nehme diese Einstellung in user- und/oder gruppenspezifischen Segmenten der Konfigurationsdatei "/etc/sshd_config" vor. Solche Bereiche leitet man am Ende der Konfiguationsdatei durch die Schlüsselworte "Match Group" (oder "Match User") ein.

Bei den nachfolgenden Direktiven für die Gruppe oder den User wiederhole ich dabei einen Teil der generellen sicherheitsrelevanten SSH-Einstellungen. Der Grund hierfür ist:

Muss ich mal auf die Schnelle und testweise grundlegende SSH-Einstellungen ändern, so setze ich die Direktiven für meine kritischen SFTP-User nicht automatisch außer Kraft.

Also ergänzen wir genau am Ende der Datei "/etc/ssh/sshd_config":

Match Group devgrp1
        ForceCommand internal-sftp
        # ForceCommand internal-sftp -u 0007</strong>
        ChrootDirectory /srv/www/htdocs/webs/project
        RSAAuthentication yes
        PubkeyAuthentication yes
        PasswordAuthentication no 
        X11Forwarding no
        AllowTcpForwarding no
        AllowAgentForwarding no
        GatewayPorts no
Match  Group devgrp2,!devgrp1 
        ForceCommand internal-sftp
        # ForceCommand internal-sftp -u 0007
        ChrootDirectory /srv/www/htdocs/webs/project/test
        RSAAuthentication yes
        PubkeyAuthentication yes
        PasswordAuthentication no 
        X11Forwarding no
        AllowTcpForwarding no
        AllowAgentForwarding no
        GatewayPorts no

 
Interessant ist hier zunächst die zweite Match-Vorgabe

Match Group devgrp2,!devgrp1

Hier drücken wir aus, dass die nachfolgenden Parameter grundsätzlich für die Mitglieder/User der Gruppe "devgrp2" gelten soll, aber nicht für Mitglieder der Gruppe "devgrp1". Die logische Negation erfolgt durch den Operator "!".

In unserem Beispiel gelten die Anweisungen nach der zweiten "Match"-Zeile also lediglich für den User "beta" und evtl. andere User der Gruppe "devgrp2".

Hinweis:

Zwischen den beiden Kriterien für die Gruppenmitgliedschaft ist ein Komma einzufügen, aber kein Blank vor oder nach dem trennenden Komma!

Interessant ist ferner die potentielle Option "-u" hinter der auskommentierten ForceCommand Anweisung:

ForceCommand internal-sftp -u 0007

Diese Direktive setzt für Open-SSH-Versionen ≥ 5.5 gezielt eine "umask", die angeblich systemweite umask-Definitionen überschreibt. Nun ja - stimmt das wirklich? Wir kommen darauf im nächsten Artikel dieser Serie zurück.

Home-Verzeichnisse der User "alpha" und "beta"- und Ausschluss des Shell-Zugangs

Auf die Schritte zur User-Anlage und User-Zuordnung zu Gruppen gehe ich hier nicht genauer ein. Interessanter ist die Frage, wo sich eigentlich die Home-Verzeichnisse der User alpha und beta befinden sollen.

Diverse Artikel im Internet, die sich mit dem Aufsetzen von User-bezogenen Verzeichnissen unterhalb eines Chroot-Verzeichnisses befassen (s. die Links am Ende des Artikels), enthalten für unser Szenario eher verwirrende Information.

Zudem gilt:
Der SSHD-Dämon erwartet später die Public Key Files unserer User bei Default-Einstellungen an bestimmten Stellen in der Verzeichnisstruktur. Experimente mit einer Verlagerung der Home-Verzeichnisse in andere Bereiche des Dateibaums führen nach meiner Erfahrung schnell ins Chaos und zu mühsamem Suchen nach Fehlern. Das gilt selbst dann, wenn man später Pfade zu den Autorisierungsfiles explizit setzt. Also:

Einfach die Home-Verzeichnisse da lassen, wo sie normalerweise erzeugt werden. Wir entziehen unseren Entwicklern sowieso den Shell-Zugriff und engen ihren Wirkungskreis weiter per Chroot ein.

serv:~ # useradd -g devgrp1 -s /sbin/nologin -m -d /home/alpha -k /etc/skel alpha
serv:~ # passwd alpha 
serv:~ # useradd -g devgrp2 -s /sbin/nologin -m -d /home/beta -k /etc/skel beta
serv:~ # passwd beta 
serv:~ # usermod -G devgrp2 alpha

 

Generieren eines SSH-Schlüsselpaars pro SFTP-User

Da wir sicherheitsbewusste Administratoren sind, erlauben wir den eben angelegten Usern SSH/SFTP-Zugang nur auf Basis von SSH-Key-Authentication.

Wir wählen für unsere künftigen SFTP-User natürlich die Erzeugung eines SSH-Schlüssel-Paars, bei der der private Schlüssel mit einem Passwort geschützt wird. Schon aus Gründen einer durchgehenden Sicherheitsphilosophie.

In Übereinstimmung mit den Sicherheitsrichtlinien von https://stribika.github.io/2015/01/04/secure-secure-shell.html führen wir zur Schlüsselgenerierung folgende Kommandos aus - und kopieren danach den jeweiligen Public Keys zum SSH/SFTP-Server.

Wir zeigen das am Beispiel des Users "alpha" auf dem Client "mytux". Wir erzeugen sowohl ein Key-Paar, das auf elliptischer Kryptographie basiert und eines, das bei hinreichender Schlüssel-Länge RSA unterstützt. Schlüssellängen unter 2048 Bit sind für RSA-angelehnte Verfahren (also nicht elliptische Verfahren) nicht mehr als sicher anzusehen.

Dabei setzen wir voraus, dass "alpha" ein Verzeichnis "~/.ssh" angelegt hat.

alpha@mytux:~/.ssh> ssh-keygen -t ed25519 -f ssh_host_ed25519_key
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ssh_host_ed25519_key.
Your public key has been saved in ssh_host_ed25519_key.pub.
The key fingerprint is:
SHA256:wri++5yVtLbMQeinXxdqiduWm2gGAbTNaB8YPFJkNV8 ufo@mytux.mydomain
The key's randomart image is:
+--[ED25519 256]--+
|   =*.o   E      |
|  ..+B o .       |
|   .=o+ .        |
|   . +.o         |
|    . =.S   .    |
|     o.+ + o .   |
|    . ..O =..    |
|   . . OoOoo     |
|    ++=+B.+.     |
+----[SHA256]-----+

alpha@mytux:~/.ssh> ls
known_hosts  ssh_host_ed25519_key  ssh_host_ed25519_key.pub

alpha@mytux:~/.ssh> ssh-keygen -t rsa -b 4096 -f ssh_host_rsa_key
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ssh_host_rsa_key.
Your public key has been saved in ssh_host_rsa_key.pub.
The key fingerprint is:
SHA256:cQfc/m7HrB1fLFsL8TA27FtiYYDJa2BIGoS3JRS607w ufo@mytux.mydomain
The key's randomart image is:
+---[RSA 4096]----+
|  +=..   ...     |
| ..o+.. . +..    |
| ...+. o.+.o.    |
|  +.  . .o..+    |
| o o    So   @   |
|  . .   .   + O. |
|   E         *.*+|
|            . B=O|
|             oo+o|
+----[

 
Analog erzeugen wir ein zweites separates Schlüsselpaar für die Entwickler der Gruppe "devgrp2". Wir legen dann als Schutz gegen Verlust Kopien dieser Schlüsselpaare in einem verschlüsselten Verzeichnis auf einem selbst kontrollierten Backup-Server an.

Dann bringen wir die Public (!) Key Datei für jeden User auf den Server. Dazu nutzen wir einen entsprechend privilegierten Benutzer (hier "usu"), der SSH-Zugang erhalten hat. Wir erinnern uns, dass wir bei der SSH-Einrichtung einen direkten SSH-Zugang des Users "root" verboten hatten. root auf dem System "mytux" kopiert den Public Key zwischenzeitlich in ein Verzeichnis "/home/usu/key_transfer" des Dummy Users "usu". Dann transferieren wir mittels "scp":

usu@mytux:~>scp -P 6xxxx -i ~/.ssh/id_rsa_usu /home/usu/key_transfer/ssh_host_ed25519_key.pub usu@serv.myhoster.net:/home/usu/key_transfer/
Enter passphrase for key '/home/ich/.ssh/id_rsa_usu': 
ssh_host_ed25519_key.pub    100%  390     0.4KB/s   00:00

 
"6xxxx" steht dabei für den verschobenen Port, unter dem der Server SSH anbietet. (Siehe hierzu den letzten Artikel dieser Serie).

Dann als root auf "serv":

serv:~ # mkdir /home/alpha/.ssh
serv:~ # chown alpha.devgrp1 /home/alpha/.ssh
serv:~ # cp /home/usu/key_transfer/ssh_host_ed25519_key.pub /home/alpha/.ssh/ssh_host_ed25519_key.pub
serv:~ # chown alpha.devgrp1 /home/alpha/.ssh/ssh_host_ed25519_key.pub 
serv:~ # rm /home/usu/key_transfer/ssh_host_ed25519_key.pub 
serv:~ # touch /home/alpha/.ssh/authorized_keys
serv:~ # chown alpha.devgrp1 /home/alpha/.ssh/authorized_keys
serv:~ # cat /home/alpha/.ssh/ssh_host_ed25519_key.pub >> /home/alpha/.ssh/authorized_keys
serv:~ # chmod 600 /home/alpha/.ssh/authorized_keys
serv:~ # chmod 600 /home/alpha/.ssh/ssh_host_ed25519_key.pub 
serv:~ # chmod 700 /home/alpha/.ssh

 
Analog für alle anderen Public Keys und User. Andere Verfahren - auch manuelle - um den Public key auf den Server zu bringen, werden hier diskutiert:
https://www.digitalocean.com/community/tutorials/how-to-configure-ssh-key-based-authentication-on-a-freebsd-server

Bitte beachtet:

Die Rechtesetzungen sind wichtig! Bei unzureichendem Schutz wird SSH die Keys ggf. nicht akzeptieren.

Test

Wir sind nun so weit, dass wir einen ersten Test durchführen können. Bevor wir den SSH-Server auf unserem Testsystem neu starten, checken wir nochmal, dass die notwendigen Einstellungen für Key-Authentifzierung in der Datei schon vorgenommen wurden:

AllowUsers usu alpha beta
AllowGroups adm devgrp1 devgrp2 
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile      .ssh/authorized_keys
PasswordAuthentication no
ChallengeResponseAuthentication no

 
Dann erfolgt ein Restart von sshd :

serv:~ # systemctl restart sshd.service 

Wir probieren nun den Zugang mittels des Kommandos "sftp"; man beachte, dass die Option für den Port hier ein großes "P" erfordert !

ich@mytux:~> sftp -P 6xxxx -i ~/.ssh/ssh_host_ed25519_key beta@serv.myhoster.net
Enter passphrase for key '/home/ich/.ssh/ssh_host_ed25519_key': 
Connected to serv.myhoster.net
sftp> ls
beta 
sftp> pwd
Remote working directory: /
sftp> cd ../alpha
Couldn't stat remote file: No such file or directory
sftp> cd beta
sftp> pwd
Remote working directory: /beta
sftp> mkdir classes
sftp> ls -la
drwxr-xr-x    3 beta     devgrp2      4096 Feb 10 17:30 .
drwxr-xr-x    3 root     root         4096 Feb 10 16:30 ..
drwxr-xr-x    2 beta     devgrp2      4096 Feb 10 17:30 classes
sftp> cd classes
sftp> put /home/ich/classes/*
Uploading /home/ich/classes/class_ufo.php to /beta/classes/class_ufo.php
/home/ich/classes/class_ufo.php                                        100%    0     0KB/s   00:00    
Uploading /home/ich/classes/class_ufo2.php to /beta/classes/class_ufo2.php
/home/ich/classes/class_ufo2.php                                       100%    0     0KB/s   00:00    
sftp> ls
class_ufo.php    class_ufo2.php   
sftp>exit 
ich@mytux:~> 

 
Die letzten zwei Testfiles hatte ich als leere Files angelegt; daher die 0-Übertragungsrate!

Nun noch ein Kurztest für den User "alpha":

ich@mytux:~> sftp -P 6xxxx -i ~/.ssh/ssh_host_ed25519_key alpha@serv.myhoster.net
Enter passphrase for key '/home/ich/.ssh/ssh_host_ed25519_key': 
Connected to serv.myhoster.net
sftp> ls
adm    alpha  test 
sftp> ls /test/beta/classes
/test/beta/classes/class_ufo.php   /test/beta/classes/class_ufo2.php
sftp> mkdir /test/beta/uploads
sftp> ls /test/beta
/test/beta/classes   /test/beta/uploads   
sftp> exit
ich@mytux:~>

 
Damit genug für heute. Im nächsten Artikel dieser Serie gehe ich dann etwas genauer auf Rechtethemen beim Anlegen von Files per SFTP ein.

Links

Generelles zu SSH/SFTP
http://en.wikibooks.org/wiki/OpenSSH/Cookbook/SFTP
http://wiki.ubuntuusers.de/SSH
http://www.computerhope.com/unix/sftp.htm

Userbezogene Chroot-Verzeichnisse
https://www.mynakedgirlfriend.de/sichere-chroot-umgebung-fur-ssh-dateiubertragungen-sftp/
http://www.thegeekstuff.com/2012/03/chroot-sftp-setup/
https://wiki.archlinux.org/index.php/Talk:SFTP_chroot

Open Visual Traceroute, Opensuse Leap 42.1 and sudo – howto – II

In the last article
https://linux-blog.anracom.com/2016/08/16/open-visual-traceroute-opensuse-leap-42-1-and-sudo-howto-i/
of this series I discussed basic steps to get OVT running on an Opensuse Leap 42.1 system. All recipes were based on assigning root rights to the Java-execution of the application's jar. Root rights were required to perform network packet capturing.

Now, on a multiuser system

  • we want to restrict the access rights to OVT to a group of selected users,
  • we want to improve the startup - such that the selected users do not need to provide the root password.

Note that none of the steps below solves any security problems. It only makes things more convenient.

Change access rights to the OVT files

As in the first article we assume that the OVT-files were placed in a directory "/PATH/TO/OVT" - e.g. "/opt/ovt".

  • Step 1 - Create a group "ovt" : We create a user group named "ovt" (e.g. with "yast2" or at the commandline with "groupadd"). Then we add the users who later on shall get the privilege to execute "ovtr.sh" - even without giving the root password!
  • Step 2 - Change ownership of "/PATH/TO/OVT" and its subdirectories/files:
    chown -R root.ovt /PATH/TO/OVT
  • Step 3 - Change access rights to "/PATH/TO/OVT" and subdirectories/files:
    chmod -R u+rwx,g+rx-w,o-rwx /PATH/TO/OVT

Changes to /etc/sudoers

We change the file "/etc/sudoers" by using the "visudo" command. (Do NOT edit the "/etc/sudoers"-file directly with an editor - get acquainted with elementary vi-commands if necessary!) I only show options which have an impact on the execution of the "ovtr.sh" file, which starts the OVT Java-program. I do not care about other settings and restrictions in comparison to the standard /etc/sudoers file Opensuse delivers.

  • Step 4 - Add a "Default" definition to the sudoers file:
    Below the last line of existing DEFAULT-definitions in the standard "/etc/sudoers"-file of Opensuse add a line
     
    Defaults!/PATH/TO/OVT/ovtr.sh env_keep += "DISPLAY XAUTHORIZATION XAUTHORITY"
     
    (With the double quotation marks! And, of course, you have to replace /PATH/TO/OVT by the path where you actually installed OVT.) This settings will later allow to keep up the named environment variables (DISPLAY, XAUTHORITY, ...) when the command "ovtr.sh" is executed.
  • Step 5 - Add a group related definition to the sudoers file:
    Add a line at the end of your settings for users and groups saying
     
    %ovt ALL = (root) NOPASSWD: /PATH/TO/OVT/ovtr.sh

The last rule guarantees that all members of the group "ovt" can execute

sudo /PATH/TO/OVT/ovtr.sh

without providing the root passsword (or their own password depending on whether Opensuse's default setting "Defaults targetpw" is kept up in your "sudoers"-file). The first rule preserves the present environment settings of user (member of group "ovt") regarding DISPLAY and XAUTHORITY, thus enabling the access to the presently open X11-screen.

Simplify the contents of "ovtr.sh"

After the changes described above we only need a small modification to ovtr.sh:

#!/bin/bash
java -Djava.awt.headless=false  -Xmx512m -jar org.leo.traceroute.jar

 
This is now all that is required!

Let us test it

me@mytux:/opt/ovt> sudo ./ovtr.sh 
12:43:54.768 [main] INFO  org.leo.traceroute.Main - Open Visual Traceroute 1.6.3 
12:43:54.776 [main] INFO  org.leo.traceroute.install.Env - Java run-time version: 1.8.0_101
12:43:54.777 [main] INFO  org.leo.traceroute.install.Env - NASA World Wind Java 2.0 2.0.0
12:43:54.777 [main] INFO  org.leo.traceroute.install.Env - /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
12:43:54.777 [main] INFO  org.leo.traceroute.install.Env - OS:Linux / arch:amd64
Locale en_GB
12:43:57.230 [SwingWorker-pool-1-thread-1] INFO  o.leo.traceroute.core.geo.GeoService - Use geoip db /root/ovtr/GeoLiteCity.dat which is 0 day(s) old
12:43:58.818 [pool-2-thread-1] INFO  o.leo.traceroute.core.ServiceFactory - Try using device eth0 null
12:43:59.056 [pool-2-thread-2] INFO  o.leo.traceroute.core.ServiceFactory - Try using device br0 null
12:43:59.251 [pool-2-thread-3] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr_vmw null
12:44:00.389 [pool-2-thread-8] INFO  o.leo.traceroute.core.ServiceFactory - Try using device vmnet1 null
12:44:01.488 [pool-2-thread-9] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr1 null
12:44:02.589 [pool-2-thread-10] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr2 null
12:44:03.691 [pool-2-thread-11] INFO  o.leo.traceroute.core.ServiceFactory - Try using device vmnet3 null
12:44:04.799 [pool-2-thread-12] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr3 null
12:44:05.908 [pool-2-thread-13] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr4 null
12:44:07.027 [pool-2-thread-14] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr5 null
12:44:08.124 [pool-2-thread-15] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr6 null
12:44:09.231 [pool-2-thread-17] INFO  o.leo.traceroute.core.ServiceFactory - Try using device lo null
12:44:11.467 [AWT-EventQueue-0] INFO  org.leo.traceroute.Main - Startup completed in 16704ms

 
ovt6

Great !

Final convenience steps

We eventually add the path of our OVT installation to the system path variable or tell the users of group "ovt" to add it to their environment.
Another way for a user to simplify the OVT startup would be to put a small script "ovsh" in his home directory with just the lines :

#!/bin/bash
sudo /opt/ovt/ovtr.sh

Then he/she may start OVT by executing "ovsh". The only difference is that we do not need to type the "sudo".

Security?

In this article we have made the startup of OVT more convenient by using the /etc/sudoers" file. We also restricted access to OVT to members of a group. Still: Java is executed with root rights. This is something I, personally, do not like because of security reasons. The next article, therefore, concentrates on the possibility to start OVT in a chroot jail.