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 – I

Da ich immer mal wieder SSH- und SFTP-Verbindungen für gehostete LAMP-Test- und LAMP-Produktiv-Server unter Linux (genauer: Opensuse) konfigurieren muss, stelle ich in einer Artikelserie mal ein paar Hinweise zu den durchzuführenden Überlegungen und administrativen Schritten zusammen.

Ich setze im nachfolgend beschriebenen Fall nur das interne SSH-Subsystem für SFTP und Dateitransfers auf den Test-/Produktiv-Server ein. Bzgl. eventuell vorzusehender unterschiedlicher Zugriffsrechte der (S)FTP User genügt aus meiner Sicht die Diskussion eines Beispiels mit 2 User-Gruppen und zwei unterschiedlichen (Domain-) Verzeichnissen auf dem Server.

Ich gehe im Folgenden davon aus, dass der Leser bereits über etwas Erfahrung mit der Einrichtung von SSH auf einem Remote-System besitzt. Wenn nicht: Siehe
Strato-V-Server mit Opensuse 12.3 – IV – SSH Key Authentication
und vorhergehende Artikel. Im vorliegenden, ersten Artikel der aktuellen Serie behandle ich grundlegende SSH-Einstellungen nur relativ kurz und diskutiere sie hauptsächlich unter Sicherheitsaspekten. Ein zweiter Artikel befasst sich dann mit der konkreten User-Einrichtung für die SFTP-Nutzung.

Abgrenzung SFTP-Uploads von SVN-Updates über SSH

Wir lassen im diskutierten Kontext die Möglichkeiten von SVN (in Kombination mit SSH) für das systematische Füllen von Domain-Verzeichnissen des (Web-) Test-Servers außer acht - obwohl viele Entwickler dies aus Bequemlichkeit nutzen.

Nach meiner Ansicht hat die Code-Versionsverwaltung in Entwicklungsphasen logisch nur wenig mit dem gezielten Upload konsolidierter Dateien einer bestimmten SW-Test- oder -Produktiv-Version in entsprechende Domainen eines Web-Test- oder -Produktiv-Servers zu tun. Letzteres - also der Upload - entspricht eher Export-Vorgängen (z.B. unter Eclipse) oder eben gezielten FTP-Transfers. Unter diesen Prämissen wie auch unter Sicherheitsaspekten hat SVN auf einem exponierten Test- oder Produktivsystem eigentlich wenig verloren. SVN ist vielmehr Teil der Service-Landschaft der Entwicklungsumgebung im lokalen Netz und dient dort der laufenden Protokollierung von Versionsständen einzelner SW-Files sowie deren Konsolidierung.

Elementare Ziele, Anforderungen und Voraussetzungen

Gehosteter Server
Der Server habe die Adresse "serv@myhoster.net" und sei gehostet. Der reguläre SSH-Zugang zu diesem Server für Verwaltungszwecke erfolge zunächst über einen (unpriviligierten) User "usu" über den (high) Port "xxxxx". Über den "usu"-Account und die Shell logt man sich dann bei Bedarf als "root" ein.

Authentifizierung über Private/Public SSH-Keys
Ein sicherheitsrelevanter Aspekt ist im Falle gehosteter Server die Authentifizierung der Entwickler mittels

  • eines privaten SSH-Keys auf dem Client
  • sowie dessen Gegenstück, nämlich eines auf dem Server hinterlegten Public Keys,

anstelle von User IDs und Passwörtern. Ich gehe im ersten Beitrag auf die wichtigsten zugehörigen Anweisungen in der SSHD Konfigurationsdatei ein. Durch Key-Authentication lassen sich Brute Force Angriffe auf den SSH-Zugang eindämmen; als Admin sollte man aber nicht übersehen, dass durch ein solches Verfahren auch die Anforderungen an die sichere Verwahrung der Schlüssel auf den Clients steigen.

Passwortschutz des private Keys auf dem Client - ?
Eine "Private Key"-Datei auf einem Client-System stellt eine potentielle Gefahrenquelle dar:

  • Mobile Clients können gestohlen werden.
  • Desktops wie mobile SSH/SFTP-Clients können gehackt werden.

Ein Passwortschutz des privaten Keys ist deshalb eine Mindestanforderung an die Sicherheit - wenngleich auch das nicht gegen implantierte Key-Logger schützt. Eine interessante Frage ist deshalb:

Was gilt im Zshg. mit Key-Passwortschutz eigentlich für gängige SFTP-Clients?

Welcher SFTP-Client unterstützt den Umgang mit Private Keys, wenn diese im Sinne einer durchgehenden Sicherheit auf den Client-Systemen passwort-geschützt hinterlegt werden sollen? Ich gehe in einem der nachfolgenden Artikel deshalb kurz auf diese Frage ein.

Kein SSH-Shell-Zugang
Die User - hier Entwickler - sollen das SSH-basierte SFTP nur für File-Transfers nutzen; sie sollen auf dem Server jedoch keinen Shell-Zugang über SSH erhalten. Administrative Aufgaben auf Test- oder Produktiv-Servern remote durchzuführen, bleibt in unserem Szenario ausschließlich Server-Administratoren vorbehalten.

Verzeichnisse, Entwicklergruppen und Rechte
Während die Einrichtung des SFTP-Servers für eine Key-Authentifizierung nur wenig von Vorgehensweisen abweichen dürfte, die bereits an anderer Stelle im Internet beschrieben sind, ist in unserem Beispiel ein zusätzlicher Punkt folgender:

In Web-Entwicklungsprojekten ist es sinnvoll, definierte Gruppenrechte und manchmal auch User-Rechte auf bestimmten SFTP-Verzeichnissen des Servers - die dort in der Regel Web-Domain-Verzeichnisse umfassen - zu erzwingen. Warum?

  • Einerseits will man die User (Entwickler) womöglich in Log-Dateien unterscheiden können. Man wird Ihnen (genauer: ihren UIDs) deshalb in jedem Fall unterschiedliche Authentifizierungs-Keys zuordnen. Ferner sollen die Entwickler ggf. aber auch gruppenübergreifend kollaborieren. Deshalb braucht man abgestimmte Lese- und Schreib-Rechte auf Verzeichnissen für eine (oder mehrere) definierte Gruppe(n). Für die Darstellung besonderer Privilegien können auch user-bezogene Rechte erforderlich werden. Das Schreibrecht wird man auf einem exponierten Web-Server in jedem Fall so gut wie nie "others" zuordnen.
  • Zudem ist zu gewährleisten, dass der Webserverprozess selbst transferierte Directories und Files lesen und im Falle der Bereitstellung von dynamisch geschriebenen Download-Dateien auch beschreiben kann. Der User, unter dem der Webserver-Prozess läuft, muss auch dann wieder Teil einer Gruppe werden, wenn man "others" keine Schreibrechte zuordnen will.
  • Es ist durchaus normal, dass unterschiedliche Privilegien des Zugriffs auf Verzeichnisse in ein und derselben Verzeichnis-Hierarchie für die Mitglieder unterschiedlicher Entwicklergruppen gefordert werden. Der Zugang zu bestimmten Verzeichnissen und Subverzeichnissen soll in unserem Beispiel per SFTP Chroot und durch das Setzen von Zugriffsrechten auf bestimmte Verzeichnisse limitiert werden. Die Entwickler sollen in unserem Beispiel in 2 Gruppen mit unterschiedlichen Zugriffsrechten auf die Verzeichnishierarchie unterteilt werden.

Wir lassen ferner Zugriffe nur auf Web-Domain-verzeichnisse zu; wir erlauben den Entwicklern keinen Zugriff auf private Home-Verzeichnisse.

Zwei Entwickler-Gruppen mit unterschiedlichen Privilegien
Wir diskutieren in unserem Beispiel den abgestuften Zugriff zweier unterschiedlich privilegierter Entwicklergruppen auf Verzeichnisse unterhalb eines Chroot-Jails "/srv/www/htdocs/webs/project".

/srv/www/htdocs/webs/project
|
-- test
|
-- adm
|
-- rc

Die Subverzeichnisse entsprechen z.B. verschiedenen Web-Domainen oder Entwicklungsprojekten mit jeweils weiteren Sub-Sub-Verzeichnissen. Da unterschiedliche Berechtigungen für die Domain-Verzeichnisse gegeben sein sollen, werden im Beispiel zwei Usergruppen devgrp1 und devgrp2 eingerichtet.

Zusätzlich wird der Zugriff der Gruppe "devgrp2" auf Inhalte eines weiteren Chroot-Verzeichnis - hier "test" - eingeschränkt. Die Mitglieder der "devgrp1" dürfen dagegen auf alle definierten Domain-Verzeichnisse zugreifen. Sie sind deshalb zugleich sekundäre Mitglieder der "devgrp2".

Als Beispiel-User wählen wir hier die User "alpha" (Mitglied von "devgrp1" und "devgrp2") und "beta" (Mitglied von "devgrp2"). Andere Berechtigungsszenarien lassen sich später aus diesem Beispiel zwanglos ableiten.

  • Mitglieder devgrp1: alpha (Zugriff auf alle Verzeichnisse)
  • Mitglieder devgrp2: beta, alpha (Zugriff nur auf Inhalte von "test")

Grundlegende Konfiguration und Sicherheitsaspekte der SSH-Einrichtung

Wie man einen Opensuse-Server bei einem Hoster wie Strato grundsätzlich für einen SSH-Zugang mit verschobenem Port und Key-Authentifizierung konfigurieren kann, habe ich bereits in früheren Artikeln in diesem Blog besprochen. Siehe etwa:
Strato-V-Server mit Opensuse 12.3 – IV – SSH Key Authentication
und vorhergehende Artikel.

Ich gehe in diesem Artikel entsprechend davon aus, dass es bereits einen elementar eingerichteten SSH-Service gibt und diskutiere nur einige wichtige Optionen der Konfigurationsdatei "/etc/ssh/sshd_config" des einzurichtenden SSHD-Daemons (s.u.).

Ein paar Hinweise und Warnungen:

Je nachdem, was man an Hosting-Paket (Virtual Server etc.) geordert hat, richtet der Provider eine elementares Linux mit SSH-Zugang ein - meistens ausschließlich für den User root. In der Regel wird man das System in einem ersten Schritt upgraden/updaten und danach auch die SSH-Konfiguration remote und schrittweise abändern. Dabei ist Vorsicht angebracht! Man will sich bei Experimenten mit der SSH-Konfiguration ja schließlich nicht selbst vom Systemzugang ausschließen. Bitte beachten Sie die diesbzgl. Hinweise in den oben genannten Artikeln. Unbedingt sollte man sich beim Provider nach Notfall-Maßnahmen im Falle eines nicht mehr möglichen SSH-Zugangs erkundigen. Meist ist das Booten eines Notfall-Systems mit anschließendem Platten- und Dateizugriff möglich .... Die Notfall-Maßnahmen sollte man auch mal ausprobieren ...

Im Zshg. mit SSH- und System-Startup-Modifikationen ist dafür zu sorgen bzw. zu prüfen, dass der SSHD-Daemon bei jedem (automatischen) Systemstart aktiviert wird. Gerade bei gehosteten Servern ist dies ein kritischer Punkt. Provider fahren u.U. die gehosteten Server ohne Rückfrage automatisch rauf und runter, wenn Wartungsmaßnahmen dies erfordern. Nach einem solchen Reboot muss natürlich der SSH-Service auch wieder verfügbar sein.

Jemand der SSH selbst auf einem gehosteten Server konfiguriert, sollte sich deshalb auf Opensuse-, Red Hat- und künftig wohl auch Debian-Systemen mit den entsprechenden Optionen des "systemctl"-Kommandos von "systemd" vertraut machen und überprüfen, dass der SSH(D)-Service für den automatischen Start beim Booten aktiviert ist. Unter Opensuse führt

systemctl enable sshd.service

zur Aktivierung. Den aktuellen Service-Zustand - inkl. Aktvierung - prüft man mit:

mylinux:~ # systemctl status sshd.service
sshd.service - OpenSSH Daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled)
Active: active (running) since Sat 2015-08-08 09:16:50 CEST; 3h 9min ago
Process: 1615 ExecStartPre=/usr/sbin/sshd-gen-keys-start (code=exited, status=0/SUCCESS)
Main PID: 1650 (sshd)
CGroup: /system.slice/sshd.service
└─1650 /usr/sbin/sshd -D
 
Aug 08 09:16:50 mylinux sshd-gen-keys-start[1615]: Checking for missing server keys in /etc/ssh
Aug 08 09:16:50 mylinux sshd[1650]: Server listening on 0.0.0.0 port xxxxx.
Aug 08 09:16:50 mylinux sshd[1650]: Server listening on :: port xxxxx.

Das korrekte Reboot-Verhalten des gehosteten Servers ist nach Systemeingriffen natürlich nicht nur für SSH/SFTP sondern auch andere Serverdienste zu testen.

Ferner gilt:

Bevor man bestimmte User definitiv vom SSH-Zugang ausschließt, sollte man immer die Zugangsmöglichkeit für einen oder mehrere verbleibende User explizit testen. Mindestens ein verbleibender User sollte immer vorhanden sein.

Ähnliches gilt für die Umstellung auf Key Authentication:

Bevor man eine passwort-basierte Authentisierung für alle User abstellt, sollte man zunächst ausschließlich mit userspezifischen Festlegungen arbeiten und für einzelne User die Funktionstüchtigkeit der Key-Authentifizierung testen. Zur Einrichtung userspezifischer SSHD-Konfiguration dienen die "Match"-Anweisung und zugehörige Blöcke am Ende (!) der SSHD-Konfigurationsdatei. Man lese hierzu unbedingt die ssh-man-Seiten.

Auch der nachfolgende Artikel

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

zeigt beispielhaft, wie man userspezifische Anweisungen anlegt und wie diese aussehen können.

SSH-Zugang für root?
Der direkte SSH-Zugang für root sollte auf einem exponierten System i.d.R. nicht zugelassen werden. Er ist auch überhaupt nicht erforderlich. Erlaubt werden soll und muss der SSH-Zugang im Anfangsstadium dagegen für einen bereits erwähnten, unpriviligierten User "usu".

Ein solcher unpriviligierter User muss auf dem gehosteten Server erstmal eingerichtet werden. Meist existiert auf gehosteten Servern anfänglich nur der User root. Bevor man den SSH-Zugang für root sperrt, muss der Zugang inkl. Shell-Nutzung für den neuen unpriviligierten User explizit getestet werden. Die Zugangsdaten des unpriviligierten Users sind vom Admin geheimzuhalten. Dieser Account bleibt sein Weg ins System - über den "usu"-Account erfolgt dann indirekt über "su -" der Login als root.

Für den User "usu" sei auf unserem Server bereits ein Public/Private-Key-Paar eingerichtet. Siehe hierzu den oben erwähnten Artikel. Wie man das für andere Accounts macht, zeigt beispielhaft auch der zweite Artikel dieser Serie.

Begrenzung des SSH-Zugangs auf bestimmte IP-Adressen?
Eine spezielle Sperre des Zugangs für allgemeine Host-IP-Adressen bzw. eine Zugangserlaubnis für definierte IP-Adressen gestalte ich normalerweise über eine Firewall und nicht über die SSH-Konfiguration. Die Firewall erlaubt dann für vordefinierte IPs den Zugang zu einem definierten High Port xxxxx für SSH und zu einem definierten Port für HTTPS.

Es sei an dieser Stelle aber ausdrücklich auch darauf hingewiesen, dass die weiter unten benutzte Anweisung

AllowUsers uid

Zusätze der Form

AllowUsers uid@ip.add.re.ss

erlaubt. Gerade bei wenigen SSH/SFTP-Usern, die immer von Clients mit fixer IP-Adresse aus zugreifen, ist das eine gute Möglichkeit, die Nutzung des SSH-Services weiter einzugrenzen.

An dieser Stelle sei auch angemerkt, dass man auf Systemen mit mehreren Netzwerk-Interfaces eingrenzen kann, auf welchem Interface der SSHD angeboten werden soll. Dies geht über die IP-Adresse, die dem Interface zugeordnet ist und der Direktive "ListenAddress". Für mehr Informationen siehe etwa:
http://www.thegeekstuff.com/2011/05/openssh-options/

Portverschiebung - Obfuscation
Der Nutzen einer Zuordnung des SSH-Services zu einem selbst definierten Port (hoher Portnummer) wird unterschiedlich diskutiert. Ich persönlich ändere den SSH-Port regelmäßig ab, da zumindest meine Erfahrung zeigt, dass die Anzahl bestimmter Angriffsversuche von Skript-Kiddies danach zurückgeht. Nachfolgend steht "xxxxx" für eine 5-stellige High-Port-Nummer.

Ausschnitte aus der SSHD-Konfigurationsdatei "/etc/ssh/sshd_config"

Nachfolgend ein paar Anweisungen aus einer finalen Konfigurationsdatei für den SSHD als Grundlage von SFTP:

Port xxxxx 
# z.B. Port 64311

AllowUsers usu 
PermitRootLogin no
....
....
RSAAuthentication yes
PubkeyAuthentication yes

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile   .ssh/authorized_keys

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no

# Change to no to disable s/key passwords
ChallengeResponseAuthentication no

# Set this to 'yes' to enable PAM authentication, account processing, 
# and session processing. If this is enabled, PAM authentication will 
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  ....
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes

AllowAgentForwarding no
AllowTcpForwarding no
GatewayPorts no
X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
UsePrivilegeSeparation sandbox          # Default for new installations.

# override default of no subsystems
#Subsystem      sftp    /usr/lib/ssh/sftp-server -u 0007
Subsystem       sftp    internal-sftp

# This enables accepting locale enviroment variables LC_* LANG, see sshd_config(5).
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL

MaxSessions 50
MaxAuthTries 20
MaxStartups 20

....
.....

Hinweis zur SFTP-Aktivierung:
Zu beachten ist die Aktivierung des internen SSH SFTP-Subsystems über

Subsystem    sftp    internal-sftp

Das ist zunächst die einzige Stelle, an der SFTP hier überhaupt ins Spiel kommt! Und noch ein Hinweis für für erfahrene Admins: die "-u" Option von internal-sftp wird hier nicht angewendet. Wir kommen darauf im 2-ten Artikel dieser Serie zurück.

Wichtiger Hinweis zum schrittweisen Vorgehen:
Bitte beachten Sie, dass Sie eine solche finale Konfiguration, die den SSH-Port verschiebt sowie root-Zugang und einen passwort-basierten Zugang grundsätzlich ausschließt, im Sinne der obigen Warnungen nur schrittweise etablieren sollten. Sehen Sie hierzu die oben erwähnten anderen Artikel dieses Blogs.

Kommentierung einiger sicherheitsrelevanter Anweisungen in der SSHD-Konfiguration

So absurd sich das anhören mag: Ein grundsätzliches Problem im Zusammenhang mit SFTP ist gerade, dass wir auf dem entsprechenden Server SSH einrichten müssen.

Der Grund für diese Aussage ist: SSH in den Händen gewiefter und böswilliger User stellt ein enormes potentielles Sicherheitsproblem dar. Siehe z.B.:
http://www.informit.com/articles/article.aspx?p=602977
https://threatpost.com/encrypted-tunnels-enable-users-circumvent-security-controls-060109/72742

Eines der größten Probleme ist, dass User mit Shellzugang SSH dazu benutzen können, um sog. "Reverse Tunnels" zu privaten Systemen durch Firewalls hindurch zu etablieren, und in diesem Zusammenhang sogar eigene Port-Forwarding Tools einsetzen. Die aus meiner Sicht wirksamen Sicherheitsmaßnahmen gegen dieses Gefährdungspotential sind in diesem Zusammenhang:

  1. den Zugang zu SSH auf wenige User einzugrenzen
  2. den Usern, die SSH lediglich als Basis von SFTP oder als Basis von geplanten, verschlüsselten Tunneln zu Applikationen einsetzen dürfen, den Shellzugang zu entziehen.
  3. Massive Strafandrohungen bei Verletzung von Policies, wenn Administratoren Shell-Zugangsrechte erteilt werden müssen.

Welche Einstellungen in der obigen Datei sshd_config betreffen die Sicherheit?

Wir erkennen zunächst das Sperren des root-Users für SSH über die Anweisung "AllowUsers". Ein irgendwie geglückter SSH Crack beinhaltet dann zumindest nicht unmittelbar das Risiko einer Betätigung mit Root-Rechten.

Ferner sehen wir die Festlegung eines besonderen Ports "xxxxx" für den SSH-Service. Dieser TCP-Port muss natürlich in der Firewall geöffnet werden. Die Verschiebung des SSH-Services vom Standardport hält gewiefte Angreifer, die ausführliche Portscans unternehmen, deshalb nicht lange ab.

Password-Authentifizierung ist trotz PAM im Sinne der Kommentare im Konfigurationsfile abgeschaltet. Wir lassen PAM hier an, um auf PAM-Ebene noch weitere Möglichkeiten zur User-Einschränkung bzw. User-Überwachung zu bekommen. Wer dem nicht traut, kann die Nutzung von PAM aber auch abschalten.

Die Zeilen

RSAAuthentication yes
PubkeyAuthentication yes

sorgen dagegen für die von uns gewünschte Authentifizierung mit asymmetrischen RSA-Schlüsseln.

Unterbinden von Port Forwarding und Gateways für Tunnel
Da wir für SFTP kein TCP-Forwarding über SSH benötigen, schalten wir es aus Sicherheitsgründen ab. Die Nutzung unseres Servers als SSH-Gateway ist aus Sicherheitsgründen völlig unerwünscht. Wir schalten deshalb auch den Parameter GatewayPorts ab. X11 sollen unsere lieben SFTP-User natürlich auch nicht nutzen.

Das Einrichten und Nutzen von problematischen Reverse Tunnels über unseren Server ist damit künftig für unsere Entwickler schon nicht mehr so ohne weiteres möglich. Wir müssen weiter unten dennoch den Shell-Zugang für die definierten SFTP-User "alpha" und "beta" sperren, denn, wie die SSH-man-page so schön ausführt, gilt

Note that disabling TCP forwarding does not improve
security unless users are also denied shell access, as they can
always install their own forwarders.

U.a. netcat, portfwd und socat sind entsprechende Tools. See
https://www.digi77.com/the-art-of-port-forwarding-on-linux/
http://29a.ch/2009/5/10/forwarding-ports-using-netcat
Aber es geht u.U. auch einfacher:
http://clinging-to-reality.blogspot.com.br/2014/06/reverse-ssh-tunnel-if.html

Ein grundsätzlich wichtiger Punkt ist in diesem Kontext immer auch, dass ein umsichtiger Admin dafür sorgt, dass der sshd-Dämon auf dem Server nicht von jedermann gestartet werden kann:

chmod 754 /usr/sbin/sshd

Zur Sicherheit sollte man auch Compiler deaktivieren, um das Kompilieren eigener Module aus eigenen Source-Quellen zu unterbinden.

Siehe zu einer Diskussion von Gefahren durch SSH und im Besonderen durch SSH Reverse Tunnels etwa:
http://www.techexams.net/forums/off-topic/67117-circumventing-network-security-via-ssh-tunneling.html

Einige Aspekte der Sicherheit werden im Zusammenhang mit verketteten Tunneln auch in folgendem Artikel angesprochen:
http://linux-blog.anracom.com/2013/11/22/ssh-getunnelter-datenbankzugang-fur-gehostete-lamp-server-i/

Sicherheitsanforderungen im Umgang mit privaten Schlüsseln

An dieser Stelle ist der dringende Hinweis angebracht, dass das sichere Verwahren von privaten Schlüsseln auf SSH/SFTP-Clients weiterer Schutzmaßnahmen bedarf. Hinsichtlich der Sicherheit ist immer die gesamte Kette der involvierten Systeme zu betrachten! Ein SSH-Auth-Key auf einem Windows-System in einem privaten oder öffentlichen Netzwerkumfeld ist ohne weitere Schutzmaßnahmen ggf. gefährlicher als eine Authentifizierung mit User IDs und einem generierten Passwort! Ferner:
Es gibt Leute,

  • die die Verwendung ein und desselben Key-Paars für verschiedene Server
  • und die dauerhafte Verwahrung von Keys auf einem System ohne weitere Verschlüsselungskomponenten wie etwa für die Dateisysteme, auf denen die Schlüssel gelagert werden,

für potentiell gefährlich halten. Gerade der zweite Punkt ist im Zusammenhang mit einem oben bereits diskutierten Diebstahl (z.B. eines Laptops) unbedingt zu unterstreichen. Ich meine aber, dass der generellen Absicherung der Client-Systeme im regulären Betriebszustand eine ebenso große Bedeutung zukommt. Auf einem Client-System, das mit Key Loggern und Trojanern kompromittiert wurde, nutzt der Einsatz einer schlüsselbasierten Authentisierung gar nichts.

Es versteht sich aus meiner Sicht von selbst, dass der private Schlüssel zusätzlich durch ein Passwort geschützt sein sollte. Man tut deshalb gut daran, sich nach FTP-Clients umzusehen, die Key-Authentifizierung mittels passwortgeschützten Private Keys unterstützen.

Genug für heute. Der nächste Artikel

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

befasst sich dann mit der konkreten Einrichtung unserer SFTP-User.

Allgemeine Links

http://www.unixlore.net/articles/five-minutes-to-even-more-secure-ssh.html

http://www.thegeekstuff.com/2011/05/openssh-options/

vsftp – temporary FTP access for a defined list of users

We adminster Opensuse servers for some of our customers at server hosters - e.g. at Strato, a Telekom subsidiary. Sometimes some web server files have to be upgraded either by us or by specific users of the customer. But only sometimes. Under normal operative conditions the FTP access to the server shall not be allowed.

To enable a FTP service we have installed "vsftp". We further want the FTP users of our customers not to be able to access a shell on the server and restrict their FTP access to a certain directory. However, some of our own admins shall be able to access other server directories by FTP also.

Some basics of how you may set up and configure a vsftp server on an Opensuse system have already been described in my article
vsftp unter Opensuse 12.2 und 12.3.
The basic settings are valid for Opensuse 13.1, too. The settings discussed in the named article already restricted FTP users to a specific directory.

Sporadic FTP access

We solve the sporadic access requirement as follows:
The firewall on the server blocks all ports (with the exception of a dedicated SSH-Port for certificate based SSH logins and http/https ports) under normal operation conditions. But a trained user at the customer site can open a SSH connection and is allowed to start (but not change) a shell script (running with root rights) that temporarily opens ports for FTP connections for a defined IP (the WAN IP of the customer) to the vsftp server.

A simplified example for such a shell script that manipulates a IP chain called "zugriff" may look like:

#!/bin/bash
iptables -N zugriff 
iptables -F zugriff 
myip=CUSTOMER_IP_ADDRESS 
iptables -A zugriff -p TCP -s $myip --dport ftp -j ACCEPT
iptables -A zugriff -p TCP -s $myip --dport 62050:62100 -j ACCEPT
iptables -t filter -I INPUT 4 -j zugriff
echo "vsftp port and IP rules were set for : " $myip
systemctl start vsftpd.service
echo "vsftp started"

A related simple stop script would be:

#!/bin/bash
iptables -F zugriff
iptables -t filter -D INPUT -j zugriff
systemctl stop vsftpd.service
echo "FTP services stopped. FTP ports blocked in firewall."

The choice of the passive vsftp ports (in our example the range between 62050 and 62200) must of course correspond to the passive port settings in the vsftp configuration. Set the following options in the vsftpd.conf file:

pasv_enable=Yes
pasv_max_port=62050
pasv_min_port=62100

You may also combine the script commands given above with further commands to start a time interval after which the ports are blocked automatically again. (To prevent possible harm if your trained customer user forgets to stop the vsftp service manually by the given stop scipt).

Grant FTP access to users of a defined list

The vsftp configuration given in my previous article vsftp unter Opensuse 12.2 und 12.3. allows for the access of all locally defined users on the server. They get chrooted to a defined chroot directory.

Note that the single FTP user discussed in the named article got the shell "/bin/false". Note further that we did not allow anonymous FTP access.

At our customer several users with different UIDs shall get the right to transfer files to the server. The different UIDs shall give us a chance to distinguish their actions in log protocols. (Note that logging the action of users may require special working contract conditions in Germany).

All of the FTP users become members of a special group. The main FTP directory - let it e.g. be "/srv/www/htdocs/webs" - which becomes their home dir and to which they are restricted by the vsftpd options

chroot_local_user=YES
local_root=/srv/www/htdocs/webs

- gets group ownership of this special group. In addition the SGID bit is set. All of the customer's FTP users get the shell "bin/false".

Now, how to restrict the FTP access to defined users among others (e.g. from our own company) and how to extend the directory access for our own admins?

To restrict FTP access to users of a defined list requires the following options:

userlist_deny=NO
userlist_enable=YES
userlist_file=/etc/vsftpd.user_list

and a file "/etc/vsftpd.user_list" with just the UIDs of the users you want to rant FTP access - each UID in a separate line. The first option tells the vsftpd daemon that the users enlisted in the file "/etc/vsftpd.user_list" get the FTP access granted and shall not be denied it.

Note 1: I had considerable difficulties with my first userlist file, which I had generated and edited with vi on the server. Probably, I did some mistypes whilst editing... Be sure that your userlist file does not contain any special characters not visible on your terminal and that each UID is followed by a line break! Create the file from scratch if you experience unexplainable difficulties or read errors for the file in you FTP client. See: https://groups.google.com/forum/#!msg/alt-f/jtslOMt5aTA/1TW2kGkvmbkJ

Note 2: The file must be readable to the user running the vsftpd process on the server. On Opensuse systems this is presently "root" or "ftpsecure" - depending a bit on how you start the process. You may change ownership of the file to the user "ftpsecure" and drop the standard readability right for "others" - depending on security conditiosn.

Due to the vsftpd option "chroot_local_user=YES" the users get jailed to a certain directory (in our example to directories below "/srv/www/htdocs/webs"). We may want to circumvent this restriction for our own admins whereas for the customer's users it shall hold and work. To define such an exception requires further vsftp options:

chroot_list_file=/etc/vsftpd.chroot_list
chroot_list_enable=YES

If "chroot_local_use" is set to "YES" then UIDs given (one per line) in the file "vsftpd.chroot_list" are NOT jailed to a chroot directory. In this case the file "/etc/vsftpd.chroot_list" defines exceptions from the chroot-rule. Note, however, that if you had set

chroot_local_user=NO

the opposite would be true: In this case the file "/etc/vsftpd.chroot_list" defines users to be explicitly jailed!

So, now we have combined all our objectives:
We open FTP access when we need it, we grant access to a list of users with most of them jailed to a certain directory
and we grant access to all directories for selected admins.

Have much fun with vsftp on Opensuse!