Ad hoc Apache Log Analyse mit Webalizer per Kommandozeile

Webalizer ist neben "awstats" ein Urgestein zur Analyse des Verlaufs von Webseitenzugriffen. Webalizer wertet Webserver-Log-Dateien aus; letztere müssen dafür eines unter mehreren normierten Formaten (z.B. das clf-Format; s. https://en.wikipedia.org/wiki/Common_Log_Format) aufweisen.

Ergebnis der Auswertung sind HTML-Seiten und Grafiken, die man z.B. über einen Webserver abrufen kann. Man installiert das Tool deshalb normalerweise auf einem zentralen Analyse-Webserver. Über periodische cron-Jobs

  • sammelt man sich dann regelmäßig aktuelle Log-Dateien anderer, zu analysierender produktiver Webserver zusammen,
  • transferiert die Logs dann zu der zentralen webalizer-Installation auf dem Analyse-Server,
  • lässt dort die Analyse durchführen
  • und ruft dann nach Bedarf die aufbereiteten Ergebnis-HTMLs auf.

Hört sich kompliziert an. Tatsächlich kann man sich als Anfänger schon mal im Gestrüpp der Konfigurationsoptionen und des Webserver-Setups verheddern. Die meisten Manuals und "docs" konzentrieren sich auf das obige Szenario - und verstellen so leider ein wenig den Blick auf das Wesentliche. In vielen Fällen geht es nämlich auch viel einfacher:

"webalizer" lässt sich auch auf der Kommandozeile einsetzen und ein Webserver ist überhaupt nicht nötig, wenn man mal ad hoc eine Log-Auswertung durchführen möchte oder muss.

Vor kurzem hatte ich einen solchen Fall - und fand das interessant genug, diesen kleinen Blog-Post zu schreiben.

Die Aufgabenstellung

Vor ein paar Tagen wandte sich ein Bekannter aus Norwegen, dessen Webseite plötzlich über fast 48 Stunden nicht mehr erreichbar war, an meine Frau. Als Ursache ergab sich schließlich, dass der dortige Weg-Hosting-Provider, der interessanterweise über einen sekundären Provider in den USA hosten lässt, Parameter zur Begrenzung der Bandbreite der Webserver-Zugriffe gesetzt hatte. (Off Topic: Dieses gestaffelte Hosting (man spricht auch von "Web-Hotels" - ist in Norwegen Gang und Gebe - ohne dass die Kunden erfahen würden, dass ihre Daten in die USA wandern. Aber da der Durchschnittsnorweger nach meiner Erfahrung an Datenschutz kaum interessiert ist, ist das dort auch kein Thema.)

Gedacht war die Bandbreitenbegrenzung nach erhaltener Auskunft wohl als einfache Sicherheitsmaßnahme; akut führte das Überschreiten der relativ geringen Grenzwerte aber zum Ausfall der Website über fast 2 Tage hinweg.

Nun hätte man ja vielleicht erwarten können, dass sich der norwegische Provider auch um die Ursache der offenbar gestiegenen Bandbreitenanforderungen kümmern würde. Auf Anfrage hatte unser Bekannte aber nur die lapidare Auskunft erhalten, es handele sich wohl um einen "normalen Anstieg des Datenverkehrs auf der Webseite". So etwas macht mich immer misstrauisch. Es ist zwar nicht unser Job, die Webseite zu überwachen, aber wir haben uns dann im Auftrag des Bekannten mal die Apache Log-Dateien vom Provider zuschicken lassen.

Ich war gerade unterwegs und hatte nur meinen Laptop dabei, als die Log-Dateien eines ganzen Jahres per Mail eintrafen. Für eine erste Analyse genügten dann tatsächlich ein

  • Internetzugang (inkl. DNS-Server-Zugang),
  • "webalizer" auf der Kommandozeile
  • und ein Browser.

Einen Internetzugang erhielt ich über das Hotel, in dem ich abgestiegen war. Die bescheidenen Voraussetzungen sind natürlich nützlich, wenn man mal aus der Ferne Ursachenforschung betreiben soll und keinen Zugang zum betroffenen Webserver hat.

Webalizer auf der Kommandozeile

Man hat also einen Haufen von Log-Dateien vorliegen und will die auswerten. Wie geht man vor?

  • Schritt 1: Zunächst muss man sich webalizer natürlich aus einem Paket-Repository seiner Linux-Distribution installieren. Dabei treten nach meiner Erfahrung keine Besonderheiten auf.
  • Schritt 2: Um die Arbeit etwas zu organisieren, sollte man sich ein "Log-Verzeichnis" zur Aufbewahrung der Log-Dateien bzw. ein "Zielverzeichnis" für die von webalizer erzeugten Output-Dateien anlegen. Bezeichnen wir die Pfade für unseren Fall mal mit "Path_To_Logs/logs_nw" bzw. "Path_To_Results/webalizer_nw". Für systematische Arbeiten sollten die Verzeichnisse natürlich sprechende Namen bekommen.
  • Schritt 3: Es schadet nie, einen kurzen filternden Blick in die man-Seiten eines neuen Kommandos zu werfen. Wir lassen uns durch die Vielfalt der dortigen Optionen zu webalizer aber nicht verwirren. Die Kommandostruktur ist einfach:
    "webalizer [Optionen] Pfad_zu_einer_Log-Datei".

    Nun zu den Optionen:

    • "-v" für "verbose" ist für das Experimentiern mit Linux-Kommandos immer gut.
    • Ferner erschient es logisch, dass wir die Ergebnisse irgendwie bezeichnen müssen; wir entdecken hierzu die Optionen "-n" und "-t" .
    • Dann ist klar, dass wir mehrere Dateien hintereinander auswerten müssen, ohne die Ergebnisse vorheriger Arbeit verlieren zu wollen. Wir finden hierzu die Option "-p" für "Incremental".
    • Das Output-Verzeichnis muss bekannt gegeben werden; hierzu dient die Option "-o".

    Für alles andere verlassen wir uns im Moment mal optimistisch auf Standardwerte.

  • Schritt 4: Wir bemühen schließlich die Kommandozeile - in meinem Fall mit:

    ich@mytux:~>webalizer -v -p -n norway-domain -t nw-since-2016 -o Path_To_Results/webalizer_nw   Path_To_Logs/logs_nw/NAME_OF_LOG_FILE

"NAME_OF_LOG_FILE" ist oft von der Form "Domain-Bezeichnung_Monat-Jahr.gz" - z.B.: anracom.com-Jan-2016.gz". Ja, gezippte Dateien sind zulässig; webalizer kümmert sich intern selbst um den Aufruf von "gunzip".

Das war's auch schon. Nun kann man auf der Kommandozeile seine vielen Log-Files händisch aufrufen. Oder aber ein kleines Script schreiben, das den Aufruf der verschiedenen Logdateien und die nötige Variation des Zeitanteils im Dateinamen für einen erledigt.

Während der Auswertung (mit der Option "-v") erhält man auf der Standardausgabe (im Terminalfenster) typischerweise viele Meldungen zur Reverse-DNS-Analyse.

Ergebnisdarstellungen

Sieht man in das Zielverzeichnis und auf die dort erzeugten Dateien, so bietet sich einem ausschnittsweise etwa folgendes Bild

Es gibt also viel Grafik-Dateien, weitere Hilfsdateien und eine "index.html"-Datei. Letztere können wir aber im Browser unserer Wahl (meist über einen Menüpunkt "Datei öffnen") direkt aufrufen.

Die Ergebnisse der Auswertungen werden uns danach in Form einfacher Tabellen und Grafiken im Browserfenster präsentiert. In meinem Fall ergab sich etwa folgende Einstiegsseite:

Extrem auffällig ist hier sofort der ungewöhnlich hohe Wert an transferierten Daten - insbesondere im Februar 2017. Schauen wir uns das mal genau an, indem wir auf den Link für Februar klicken; ich zeige nachfolgend nur Ausschnitte aus der detaillierten Seite für selbigen Monat:

Diese Grafik spricht schon mal dafür, dass die Hauptzugriffe nicht aus einer mitteleuropäischen Zeitzone erfolgen. Faktisch zeigen weitere Graphen, die ich hier nicht abbilde, dass viele Besucher in den USA lokalisiert waren.

Es lohnt sich, danach eine Blick auf die vielen anderen Grafiken zu werfen, die einem webalizer zu anderen Zusammenhängen bzgöl. erfasster Zugriffsdaten anbietet. Als ich mir etwa die Zuordnung der Datentransfermenge zu Ursprungsadressen ansah, ergab sich Folgendes:

Aha, da erkennen wir, dass die großen Dateitransfers von einigen wenigen Hosts erzeugt werden. Eine genauere nachfolgende Analyse führt dann etwa über die Ermittlung der zugehörigen IP-Adressen (z.B. mit ping oder gezielten DNS-Abfragen) und ein systematisches Durchsuchen von Blacklists im Internet.

So erhalten wir für den Hauptbösewicht "ec2-52-3-105-23.compute-1.amazonaws.com" (IP: 52.3.127.144), der sich auf er Website des Bekannten schon in früheren Monaten hervorgetan hatte, einen Eintrag bei https://www.abuseipdb.com/ und http://ipaddress.com/blacklist-check/:

Und auch hier ist der ungebetene Gast des norwegischen Bekannten zu finden: https://myip.ms/view/blacklist/872644496/52.3.127.144 und http://whatismyipaddress.com/blacklist-check

Fazit: This guy is up to no good!

Generell gilt, dass bei anonymen Bot-/Crawler-Systemen, die unter Amazon AWS gehostet sind und die Daten von Webseiten komplett herunterladen, Vorsicht geboten ist.

Unser Plagegeist gehört ferner zu einem Bot-Netz namens "ltx71":
https://udger.com/resources/ua-list/bot-detail?bot=ltx71
https://myip.ms/view/web_bots/1239532/Known_Web_Bots_ltx71_http_ltx71_com.html

Was Gutes ist über "ltx71" im Internet nicht in Erfahrung zu bringen. Die "Homepage" beinhaltet nur 2 Sätze: Ja, wir crawlen das Netz, aber für Sicherheitszwecke. Echt? Menschheitsfreunde? Auch ansonsten findet man auffallend wenig:
http://review.easycounter.com/ltx71-scam-report
http://www.diamantnetz.de/wzn/a_infos/botdestages.php
http://scamanalyze.com/check/ltx71.com.html
http://www.scamaider.com/is-ltx71.com-safe-legal.html

Der größte Traffic zu ltx71 kommt ferner angeblich von russischen Systemen. (Sagen Analyseseiten zu Domainen). Was immer das bedeutet ... Zudem umgehen ltx71-Crawler blockierende Anweisungen in einer evtl. angelegten "robots.txt"-Datei einer Zieldomäne. Alles nicht gut!

Bzgl. der Analyse verfährt man dann genauso mit den anderen, von webalizer ausgewiesenen dubiosen Datengreifern. In unserem Fall stellte sich heraus, dass ein weiterer Besucher auch zu ltx71 gehört.

Für mich gilt in einer solchen, nicht völlig klaren Situation die Leitlinie: Es gibt keine Freunde im Internet.

Schon gar nicht, wenn deren Systeme meine teuer bezahlten Ressourcen für dubiose Zwecke verbrauchen würden.

Gegenmaßnahmen?

Wir konnten unserem norwegischen Bekannten jedenfalls Bericht erstatten und erste Hinweise geben. Kümmern muss sich nun sein Provider.

Nur der Vollständigkeit halber: Sperren könnte man die dubiosen Crawler-Bots zunächst mal über Einträge in einer ".htaccess"-Datei im Hauptverzeichnis auf dem Webserver nach dem Muster

order allow,deny
deny from 52.3.127.144
deny from 52.23.169.223
deny from 52.207.224.143
deny from 54.225.29.79
deny from 52.3.105.23
deny from 54.172.241.121
deny from 104.197.241.64
allow from all

Das wird auf Dauer bei einem Botnetz aber nicht viel helfen; es werden im nächsten Monat mit Sicherheit andere IP-Adressen auftauchen. Dann muss man zu anderen Mitteln greifen, die aber nicht Gegenstand dieses Posts sein sollen.

Jedenfalls kann man Betreibern von Websites, deren Ressourcen in ungewöhnlicher Weise mit Beschlag belegt werden, nur raten, sich die Logs der betroffenen Websites regelmäßig und genau anzusehen. Dabei kann der sehr einfache durchzuführende Einsatz von webalizer bereits erste wertvolle Erkenntnisse zeitigen.

Links

http://www.webalizer.org/
http://www.techrepublic.com/article/analyzing-web-sites-with-webalizer/
https://lf.net/support/techinfo/webserver/webalizer.php
http://www.linux-community.de/Internal/Artikel/Print-Artikel/LinuxUser/2011/04/Zugriffsdaten-auswerten-mit-Webalizer
https://privatstrand.dirkschmidtke.de/2011/05/10/webalizer-auf-logfiles-loslassen/

Fasching, Webhosting bei 1&1 und mein Tränenbecken – I

1&1 war und ist einer der Platzhirsche in Deutschland, was Web-Hosting angeht. Durch den Zukauf von Strato durch den Mutterkonzern hat sich die Marktdominanz noch erhöht. Auch dieser Blog läuft im Rahmen eines Web-Hosting-Pakets bei 1&1. Das PC-Magazin hat diesen Provider als Hoster im Jahr 2016 ausgezeichnet. 1&1 wirbt selbst viel mit einem guten Kundenservice.

Da ist es doch schön, wenn man die Wirklichkeit, wie sie ein Endkunde erlebt, auch mal mit dem werbewirksamen Anspruch des Unternehmens vergleichen kann. Hierzu bot sich mir in den letzten Tagen eine praxisnahe Gelegenheit - im Auftrag einer Kundin "K" von 1&1, die wir in Web-Angelegenheiten immer wieder betreuen.

Die Geschichte ist einfach zu gut, um sie für sich zu behalten. Sie hinterließ bei mir trotz des munteren Faschingstreibens in den letzten Tagen sehr gemischte Gefühle. Immer wieder fühlte ich mich in eine Art Tragik-Komödie versetzt - auch wenn 1&1 nun endlich eine Lösung für besagte Kundin gefunden zu haben scheint. Die Fastenzeit hat offenbar auch ihr Gutes ...

Ich konzentriere mich in diesem Erfahrungsbericht zunächst auf das erlebte Kernproblem meiner Kundin - nämlich die unzureichende Webseiten-Performance - und faktische Ergebnisse von 8 Eskalationsversuchen meiner Wenigkeit.

Das Problem

Kundin "K" hat im letzten Herbst ihre Webseite von uns auf WordPress samt Kadence/Pinnacle-Theme umstellen lassen. Wir haben diese PHP-basierte Technologie verschiedentlich für Kunden im Einsatz. U.a. bei einem weiteren Webhosting-Kunden von 1&1, aber nicht nur dort. Getestet haben wir die erreichbare Performance ursprünglich auf eigenen Webservern unter Stressbedingungen, unter einem 12 Jahre alten Hosting-Vertrag bei Strato und unserem eigenen, ähnlich alten Vertrag bei 1&1. Bislang alles problemfrei.

Nach der Installation lief die Web-Site der Kundin zunächst auch wie erwartet. Antwortzeiten zum Abnahmezeitpunkt zwischen 1.2 und 3 Sek pro Seite - je nach Tageszeit.

Seit dem Jahreswechsel stellte besagte Kundin - nach Beschwerden ihrer eigenen Kundenklientel - jedoch fest, dass die Performance ihrer Site seit Januar immer schlechter wurde und zeitweise "unter aller Sau" war (Zitat; ein später konsultierter 1&1 Berater fand diesen Ausdruck durchaus angemessen).

Punktuelle Zugriffe Mitte/Ende Januar und Mitte Februar aus dem Ausland bestätigten den subjektiven Befund der Kundin. Auf Anforderung der Kundin haben wir das letzte Woche dann genauer überprüft. Während typischer Hauptlastzeiten mussten wir tatsächlich zeitweise Antwortzeiten im deutschen Internet zwischen 10 Sek und 30 Sek pro Webseite feststellen.

Eigene Tests unter einer 1&1-Testdomäne - um Faktoren bessere Antwortzeiten

Wir haben dann selbstverständlich die Site der Kundin für Tests mit identischen PHP-Programmen und (bis auf Links) identische Datenbanktabellen in einen anderen alten 1&1-(!)-Vertrag und auf damit assoziierte Web- und Datenbankserver bei 1&1 gespiegelt. Die Tests ergaben völlig andere Ergebnissen und eine um Faktoren bessere Performance!

Die Kundin hat dieses Ergebnis leider mit großer Verbitterung zur Kenntnis genommen. Sie wollte ihren Vertrag mit 1&1 daraufhin umgehend kündigen und den Anbieter wechseln. Was wegen Mindestvertragslaufzeiten aber zu keiner kurzfristigen Lösung geführt hätte.

Wir selbst vermuteten zunächst eine zu hohe Last auf den 1&1-Datenbankservern. Weitere Tests, die wir im Laufe der Zeit systematisch anstellten, haben diese These jedoch klar widerlegt.

Blieb eigentlich nur eine Überlastung der Webserver oder eine massive Benachteiligung der Kundin im Kampf um die Hosting-Ressourcen bei 1&1 als Erklärungsansatz übrig ...

Dazu muss man wissen, dass die Kundin seit 14 Jahren bei 1&1 knapp 12 Euro/Monat für 3 Domänen ohne SSL-Zertifikat abdrückt und sich durchaus als Stammkundin fühlt. In ihrer Jugend war das noch was wert.

Kontakt zum 24/7-Service von 1&1

Ich wandte mich letzte Woche dann im Auftrag unserer Kundin an 1&1 und hatte seitdem 8 mal Kontakt (zur Hotline und Hosting-Beratern) - mit steigender Eskalationstendenz meinerseits und wachsender Hilflosigkeit der Ansprechpartner (bis auf den letzten). Alle Ansprechpartner konzidierten immerhin ein größeres Problem - der eine oder andere schien geradezu geschockt von den schlechten Antwortzeiten zu sein; erst recht, wenn er dann als Kontrast die Zeiten der gleichen Anwendung auf unserer ebenfalls bei 1&1 gehosteten Testdomäne sah.

Besonders berührt hat das einen 1&1-Mitarbeiter, den wir am Faschingsdienstag um ca 23:00 Uhr konsultierten. Zu diesem Zeitpunkt hatten wir zähneknirschend und ohne jeden Erfolg bereits alle vorhergehenden Ratschläge von 1&1-Mitarbeitern (inkl. einer Vertragsumstellung) befolgt - ohne Erfolg. Der Support-Mitarbeiter hätte angesichts der Fakten gerne die "Techniker" involviert. Leider war trotz 24/7-Service bei der Technik um 23:00 Uhr niemand mehr erreichbar. Alaaf ...

Meine Frau vergnügte sich zu diesem Zeitpunkt zu Recht vor dem TV und auf Facebook. Ich musste mir deshalb mein Tränenbecken aus dem Glasschrank selber holen. In weiser Voraussicht ließ ich es auf meinem Schreibtisch stehen.

1&1 empfiehlt der Kundin stereotyp eine Vertragsumstellung - aber dadurch wird zunächst nichts besser

Als Ursache des Dramas wurde von den ersten 5 Ansprechpartnern vor dem 28.02. ein zu alter Vertrag (mit Speicher- und Performance-Einschränkungen) vermutet bzw. unterstellt. Das ist für das erste Gespräch am 23.02. mit einem 1&1-Vertretern eine außerordentlich freundliche Darstellung des Gesprächsverlaufs! Hier half auch mein Freund - das Tränenbecken - nicht mehr; vielmehr musste im Anschluss der "porcelain god" selbst angerufen werden, um mich wieder in Faschingslaune zu versetzen.

Alle nachfolgenden Berater waren dagegen sehr freundlich und ausgesprochen service-minded. Auch wenn das bis heute Mittag keine Wendung zum Besseren zeitigte, möchte ich bei dieser Gelegenheit doch die Ruhe und Besonnenheit der meisten Ansprechpartner (alles Männer) ausdrücklich loben! Die hatten es angesichts der Fakten ja nun wirklich nicht leicht und stießen regelmäßig an ihre Grenzen.

Geredet haben die Mitarbeiter aus dem Support und auch die Hosting-Berater dann viel über Hauptspeicheranforderungen moderner Web-Anwendungen, tolle SSDs in den aktuellen Datenbankservern und die schlimmen Begrenzungen alter 1&1-Verträge. Ich will das hier gar nicht weiter kommentieren. Ich kenne den relativ geringen Hauptspeicherbedarf der PHP-Applikation WordPress mit diversen Plaugins ganz gut; und der Nutzen von SSDs auf einem gut gepufferten und parametrierten MySQL-Datenbankserver entfaltet sich auch erst unter ganz bestimmten Anforderungen. Ich arbeite da zeitweise mit ganz anderen Kalibern an PHP-Anwendungen.

Die technischen Limits zur Ausführung von PHP-Anwendungen, die für den alten Vertrag der Kundin angeblich angewendet würden, konnte aber keiner der Berater zitieren oder belegen. Natürlich konnte auch nicht bestätigt werden, dass die aktuelle Anwendung die gesetzten Limits überschreiten würde. Ein Berater gab auf Rückfrage vielmehr zu, dass er nicht mal Zugriff auf die alten Vertragskonditionen hätte (interne Serverstörung!).

Vielleicht wäre ja aber ein konfigurierbarer Cloud-Server für unsere Kundin das Richtige?? Na, super! Geringfügige Mehrkosten ... Ach so ... Und wer kümmert sich dann um den Cloudserver und dessen Sicherheit? Und was kostet das dann? ..."Oh - ja, Ihre Kosten hatte ich gerade nicht auf dem Radar ..." Tja... und bevor ich es angesichts der Vielfalt aktueller 1&1-Angebote vergesse : Wieso genau lief und läuft dieselbe Applikation gehostet unter einem anderen aber ebenso alten Vertrag nochmal so viel besser? Weil ich drei Euronen pro Monat mehr zahle, die allein von den 4,99 Euro für ein SSL-Zertifikat aufgefressen werden?

Jeder der 1&1-Berater wurde von uns über die unterschiedlichen Laufzeitergebnisse zwischen der Domäne der Kundin und einer Testdomäne unter einem anderen ebenso alten Vertrag informiert. Die letzten 4 Berater wurden ferner über die Ergebnisse von Cross-Tests zwischen den verschiedenen Vertragsdomänen und und über Datenbanktests unterrichtet, die den Datenbankserver der Kundin als Ursache ausschlossen. Wir haben die 1&1-Berater ferner darauf hingewiesen, dass in Perioden geringer Last (Faschingssonntag, morgens) auch Antwortzeiten < 2 Sek angeboten wurden - und das die festgestellten schlechten Antwortzeiten offenbar an Zeiten hoher Grundlast für die Webserver gekoppelt waren. Und wir stellten immer wieder die Frage, ob es denn nicht sein könne, dass irgendwo bei 1&1 eine zu hohe Last vorläge und ob denn nicht ein Umzug auf einen anderen ihrer (Web-) Server etwas bringen könne ... ?

Mein Tränenbecken füllte sich dann interessanterweise auf magische Weise regelmäßig von selbst, wann immer ich das Stichwort "Stammkundin seit 14 Jahren" in Gesprächen mit dem 1&1-Support anzubringen versuchte. Besonders schnell geschah das, als ein 1&1-Gesprächspartner alte 1&1-Webhosting-Verträge mit alten Telekom-Verträgen verglich. Da würde man für schlechtere Leistung ja auch mehr zahlen als bei einem neuen Vertrag! Gott sei Dank war ein Blumentopf in der Nähe, als mein Freund - das Becken - überquoll. Ach, Deutschland, mein geliebte Servicewüste! Es ist Fasching und ich weiß - ich bin wieder daheim.

Kommentar der 1&1-Technik

Auch die 1&1-"Technik" ( 2nd-level Support ???) wurde dann mal eingeschaltet; das lapidare Resultat entsprechender Anstrengungen kam dann am Faschings-Sonntag per Mail:

Als mir diese Mail von "K" übermittelt wurde, dachte ich spontan an das Land der "alternativen Fakten". Wie schnell das doch über den großen Teich schwappt.... Meine Gattin muss wohl mein Gesicht gesehen haben - sie reichte mir das Tränenbecken unaufgefordert. Die vorhergehenden Spekulationen um Verträge und die prägnante, wie tiefgehenden Problemanalyse durch die 1&1-Technik taten das ihre ...

Umstellung des Vertrags der Kundin

Nach etlichem Hin und Her (dazu mehr in einem anderen Blog-Beitrag) wurde der Vertrag der Kundin dann tatsächlich (bei Mehrkosten) auf ein aktuelles Paket "Unlimited Plus" umgestellt; dies geschah am 28.02. nach einem Sponsoringversuch durch eine geringfügige Gutschrift für bislang durch "K" in 2 Monaten erduldeten Qualen.

Zu den Erlebnissen während der praktischen Vertragsumstellung im nächsten Beitrag mehr; ich habe mir erneut mehrfach die Auffangschale unter tropfende Augen halten lassen. Eigentlich wollte sich unsere Kundin auf eine Vertragsänderung gar nicht mehr einlassen. Wir haben sie mühsam dazu motivieren müssen. "Alternative Chancen für die Schaffung neuer alternativer Fakten" würden heutzutage ja selbst Präsidenten eingeräumt - und den deutschen Verbraucherschutz könne sie ja immer noch einschalten.

Das traurige Ergebnis der Tarifumstellung war leider:
Von einer Verbesserung konnte weder am 28.02. noch am 01.03. die Rede sein. Am 01.03. wurde auf Anraten eines 1&1-Beraters dan zusätzlich die Datenbank auf einen neuen Datenbankserver des aktualisierten Vertrages verlagert. Effekt: Die Antwortzeiten wurden noch schlechter! Zufall oder System? Oder Faschings-Kater der 1&1-Server?

Das Tränenbecken musste erneut mehrfach ausgekippt werden. Erst recht nach dem darauf folgenden Telefonat mit "K".

Performance am heutigen Vormittag (02.03.)

Ich stelle nachfolgend den Stand der Performance am heutigen Vormittag in mehreren Tabellen dar. Diese Zeitreihen verdeutlichen das grundsätzliche Problem, das die Kundin seit Januar hatte, sehr gut; auch wenn hier nur die Spitze des Eisberges schlaglichtartig sichtbar wird.

Die obere Zeile in den nachfolgenden Tabellen entspricht jeweils der Web-Domäne aus dem aktuellen Vertrag "Unlimited Plus" der Kundin [K], die unter einer identisch konfigurierten "Testdomaine" [T] unter einem alten "Business 5.0"-Vertrag.

In beiden Fällen lief zunächst PHP 5.6 und dann (nach einer gezielten Umstellung) PHP 7 auf den gehosteten Web-Servern. Um die Dinge besser vergleichbar zu machen, erfolgte aus der Testdomäne heraus ein Zugriff auf einen Datenbankserver, der dem aktuellen Vertrag der Kundin zugeordnet ist.

Aufgerufen wurde dabei immer dieselben 3 Seiten in 2 Zyklen - abwechselnd für K und T.
Alle Werte in Sekunden !

Zeit 02.03.2017, 11:00 Uhr

K 7,0 3,2 4,4 7,6 3,0 2,7
T 1,1 0,8 0,6 0,9 0,6 0,5

Zeit 02.03.2017, 11:10 Uhr

K 5,9 4,5 6,3 5,9 11,0 6,3
T 0,9 1,9 2,1 2,0 1,1 0,6

Zeit 02.03.2017, 11:14 Uhr

K 11,3 11,3 4,8 7,6 8,9 10,5
T 1,6 1,0 0,7 0,7 0,9 1,3

Zeit 02.03.2017, 11:15 Uhr

K 5,3 9,3 12,8 11,8 8,4 5,4
T 4,3 0,9 1,1 1,0 1,0 1,2

Zeit 02.03.2017, 11:20 Uhr

K 16,0 5,8 9,4 10,2 13,6 14,6
T 0,9 0,9 0,6 0,9 0,8 0,7

Zeit 02.03.2017, 11:25 Uhr

K 15,0 15,5 23,5 21,3 21,4 12,3
T 1,6 1,7 1,0 0,8 0,5 5,6

Zeit 02.03.2017, 11:30 Uhr

K 6,5 8,0 6,6 10,0 8,0 12,1
T 1,5 0,7 2,1 0,9 0,8 0,6

Zeit 02.03.2017, 11:50 Uhr

K 8,5 8,1 7,6 7,8 5,4 5,6
T 0,6 1,2 0,9 0,7 0,6 0,8

Zeit 02.03.2017, 12:00 Uhr

K 15,2 13,3 16,6 11,4 9,2 15,2
T 0,6 1,2 1,2 0,9 0,8 1,0

Ein Kommentar ist eigentlich überflüssig. Antwortzeiten zwischen 6 und 23 Sekunden pro Webseite sind aus Kundensicht unakzeptabel. Erst recht, wenn man zu einer Vertragsumstellung mit Mehrkosten geradezu genötigt wurde.

Und auch "K" kam sich angesichts der Daten natürlich veralbert vor und fand das einen Tag nach Aschermittwoch ziemlich unangemessen. Ich habe ihr angeboten, ihr zeitweise meine Tränenschale auszuleihen.

Fastenzeit und Licht am Ende des Tunnels

Gestern - am Aschermittwoch - gegen Mittag habe ich dann nochmal bei 1&1 angerufen. Der Mitarbeiter der Hotline verstand das Problem sofort und verglich die 20 Sekunden Antwortzeit auch brav mit der entsprechenden Zeit unserer Testdomäne bei 1&1. Dann gab es ein paar (sehr intelligente) Fragen zur Querverbindung auf die Datenbank der Kundin. Nebenbei studierte er die Kommentare seiner Vorgänger - und bat mich irgendwann, ihm Kommentare dazu zu ersparen. Dann fiel das Wort "Überlast". Er kam dann mit einem Lösungsvorschlag, für den wir ihm aber 24 Stunden einräumen müssten. Es gab auch eine wenig transparente Bezeichnung des kostenfreien Lösungsansatzes - irgendwas mit "...-Flat" - im Effekt sollte das zu einer "echten" Verschiebung auf andere Server führen. Ach ne .... Der vorhergehende Vertragswechsel hatte einen solchen grundlegenden Wechsel dann wohl nicht bewirkt??? ... Hm, und komischerweise sei diese Option bei dem Test-Domänen-Vertrag gar nicht aktiviert ...

Es ist Aschermittwoch - und auch ohne die Berichte aus Passau gesehen zu haben, beginne ich zu beten ....

Erlösung

Heute zw. 12.00 und 13:00 Uhr scheint 1&1 dann gerochen zu haben, dass ich an diesem Blog-Artikel schrieb. Jedenfalls flog ich plötzlich aus der FTP-Verbindung zum 1&1-Webspace unserer Kundin raus und kam auch erst wieder rein, nachdem ich eine dynamische IP-Adressbestimmung des 1&1-FTP-Servers in unserer Firewall zuließ. Ein Hinweis auf eine substanzielle Änderung? Erhörung meiner Gebete vom Vortag? Also: neuer Test nach dem obigen Muster. Und plötzlich erhalten wir bereits den ganzen Nachmittag geradezu traumhafte Antwortzeiten. Aktueller Stand:

Zeit 02.03.2017, 17:15 Uhr

K 0,4 0,6 0,6 0,6 0,8 0,4
T 1,0 0,7 1,1 0,6 0,6 0,7

Ich bin jetzt so gerührt, dass ich wieder mein Tränenbecken bemühen muss. Mehr zu einer Bewertung des Vorgang aus ITSM-Sicht daher morgen.

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