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.

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 “devgrp1und 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:~>
r

 
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