Es kommt schon einmal vor, dass man ein System im Netz hat, welches vom Rest des Netzwerks abgeschirmt sein, aber dennoch überwacht werden und nach außen kommunizieren muss. Der Kunde hat hierbei Zugriff per SSH, um z. B. Daten abzulegen.
Statt eine aufwendige DMZ einzurichten und mit etlichen Firewall-Regeln und Ausnahmen zu arbeiten, setzen wir u. a. auf iptables auf diesem System. Der Kunde hat hierbei selbst keinen root-Zugriff.
Wichtig: Wir gehen hier von einem Debian Stretch als Betriebssystem aus.
Was muss abgesichert werden?
- Restliches Netzwerk
- Prozessinformationen
- root
- Andere administrative Benutzerkonten
Restliches Netzwerk
Wir arbeiten hierbei mit iptables. In unserem Beispiel haben wir ein einfaches 24er Netzwerk: 192.168.0.0 mit Maske 255.255.255.0. Damit das System nicht unbefugt auf andere Systeme in unserem Netzwerk zugreifen kann, verhindern wir den Zugriff darauf mittels iptables. Da das System allerdings allgemein nach außen kommunizieren können muss, können wir nicht einfach die Policy (Richtlinie) auf DROP setzen, sondern wir setzen das DROP nur auf das eigene 24er Netz:
iptables -I OUTPUT -d 192.168.0.0/255.255.255.0 -j DROP
Jetzt kommt allerdings hinzu, dass das Kundensystem einerseits mittels Ansible angsteuert wird, und außerdem greift ein Monitoring-System darauf zu. Beide arbeiten mit SSH. Da die Maschine selbst jedoch nicht per SSH auf die anderen Hosts zugreifen können soll, richten wir Ausnahmen nur auf Antwortpakete ein. Hier die Beispiele: 192.168.0.10 ist der Ansible-Server und 192.168.0.20 ist der Monitoring-Server.
iptables -I OUTUT -d 192.168.0.10 -p tcp --sport 22 -j ACCEPT
iptables -I OUTUT -d 192.168.0.20 -p tcp --sport 22 -j ACCEPT
Jetzt haben wir unser Netzwerk vor unbefugtem Zugriff von dieser Maschine aus geschützt und können sie dennoch per Ansible und Monitoring ansteuern. Hier noch einmal die Übersicht von iptables nach den Befehlen:
iptables -L -n
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 192.168.0.20 tcp spt:22
ACCEPT tcp -- 0.0.0.0/0 192.168.0.10 tcp spt:22
DROP all -- 0.0.0.0/0 192.168.0.0/24
Prozessinformationen schützen
Spätestens mit Kernel-Version 3.3 ist es möglich einzurichten, dass jeder Benutzer ausschließlich seine eigenen Prozesse einsehen kann. Nur root darf alle Prozesse sehen. Dafür brauchen wir nur zwei Dinge: fstab und eine systemd -Ausnahme, damit das Login weiterhin ohne Probleme funktioniert:
In die Datei /etc/fstab fügen wir die folgende Zeile hinzu (ausschlaggebend ist hidepid=2):
proc /proc proc nosuid,nodev,noexec,hidepid=2,gid=proc 0 0
Und in die Datei /etc/systemd/logind.conf fügen wir die folgenden beiden Zeilen hinzu:
[Service]
SupplementaryGroups=proc
Damit sieht der Kunde nur noch seine eigenen Prozesse:
customer@machine:~$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
customer 35986 1.6 1.4 64832 6060 ? Ss 02:14 0:00 /lib/systemd/systemd --user
customer 35994 7.3 1.0 21032 4672 pts/0 Ss 02:14 0:00 -bash
customer 36008 0.0 0.7 38304 3148 pts/0 R+ 02:14 0:00 ps aux
root schützen
Weil der Kunde theoretisch versuchen könnte sich als root anzumelden, mittels des Befehls su, sperren wir einfach den Zugriff auf su, mittels des so genannten Wheel-Tricks: Dabei wird der Zugriff auf su nur für Mitglieder einer bestimmten Gruppe (standardmäßig root) gestattet. Dafür ändern wir die Datei /etc/pam.d/su ab und kommentieren die unterste Zeile des folgenden Abschnitts aus:
# Uncomment this to force users to be a member of group root
# before they can use `su'. You can also add "group=foo"
# to the end of this line if you want to use a group other
# than the default "root" (but this may have side effect of
# denying "root" user, unless she's a member of "foo" or explicitly
# permitted earlier by e.g. "sufficient pam_rootok.so").
# (Replaces the `SU_WHEEL_ONLY' option from login.defs)
auth required pam_wheel.so
Natürlich sollten nun die Benutzerkonten, die von Ansible und dem Monitoring verwendet werden, der Gruppe root hinzugefügt werden:
adduser ansible root
adduser monitoring root
Wenn wir jetzt versuchen als Kundenbenutzer mittels su (und dem richtigen root-Kennwort) administrative Berechtigungen zu erlangen, stoßen wir auf den folgenden Fehler:
customer@machine:~$ su
Passwort:
su: Berechtigung verweigert
Andere Konten mit administrativen Berechtigungen schützen
Andere Konten, wie in unserem Fall ansible und monitoring, kann man zudem damit schützen, dass die Anmeldung nur mittels Zertifikaten stattfindet (indem wir das Kennwort z. B. entfernen):
passwd ansible -d
passwd monitoring -d
Und dadurch, dass wir die Anmeldung dieser Konten per SSH zusätzlich nur von den entsprechenden Maschinen zulassen. Dafür ändern wir die Datei /etc/ssh/sshd_config ab und fügen die folgende Zeile hinzu:
AllowUsers ansible@192.168.0.10 monitoring@192.168.0.20 customer
Der Kunde (customer) kann sich von irgendwo aus anmelden, die anderen Benutzer nur von den entsprechenden Hosts.
Je nachdem, wofür der Kunde die Maschine benutzen können soll, kann man das Ganze noch weiter treiben und z. B. Email-Versand untersagen usw. Das behandle ich hier aber nicht.