Episode 38/2017: Fundstück des Tages

Backticks oder Shell-Expansion bei Befehlen auf der Kommandozeile?

Das sagen das IEEE und The Open Group  in The Open Group Base Specifications Ausgabe 7, IEEE Std 1003.1-2008, 2016 Edition. Eine schöne Antwort dazu auch auf Stackexchange.

Meine Entscheidung nach der Lektüre: Ich bevorzuge immer noch die Shell-Expansion-Schreibweise.

Episode 20/2017: In einer fremden Stadt

Notiz an mich: In einer fremden Linux-Stadt, irgendwo in den Wolken, soll ich ein privates Netzwerk konfigurieren. Wie finde ich heraus, wie das private Netzwerkinterface benannt ist, ohne den Support zu kontaktieren?

Die aktuellen Interfaces, z.B.

ifconfig

Dann via Kernel:

ls /sys/class/net
oder
cat /proc/net/dev

Oder über die PCI-Devices („lspci“):

lspci | egrep -i --color 'network|ethernet'

bzw. die Hardware („lshw“):

lshw -class network

Tag 189/2016: namei – follow a pathname until a terminal point is found

DESCRIPTION

namei interprets its arguments as pathnames to any type of Unix file (symlinks, files, directories, and so forth). namei then follows each pathname until an endpoint is found (a file, a directory, a device node, etc). If it finds a symbolic link, it shows the link, and starts following it, indenting the output to show the context.

This program is useful for finding "too many levels of symbolic links" problems.

Example:

# namei -l $(pwd)
f: /usr/local/bin
drwxr-xr-x root root /
drwxr-xr-x root root usr
drwxr-xr-x root root local
drwxr-xr-x root root bin

This short post exists merely for me because everytime this command would be handy I have to waste 10 Google-Minutes to find it („No! Not the ls command“, „No! Not find with arguments“, „No! …“).

For example: Now that you know what it does (see example output) try to search for it not using phrases from the description above. If you have a nice phrase please leave it in the comments…

Tag 84/2016: How to deny requests by filename, extension and patterns with nginx in a comfortably bureaucratic manner

In a current setup where nginx acts as a reverse proxy to some Apaches I want to deny access to some useless Flotsam & Jetsam files.

What I not want is to craft wonderful regular expressions that suffice type 3 of a Chomsky-Hierarchy while learning about Pumping-Lemmata, albeit that sounds very alluring for an annoyingly hot summerday later this year (Todo).

So in order to keep my various location directives specific as they are I create a map like this (example):

map $uri $reqhide {
 default 0;
 "~*robots.txt$" 0;
 "~*\.(md|txt)$" 1;
 "~*liesmich\.html$" 1;
}

This map has to be created in the http context of a config file and can then be used in if-conditions within location blocks. It uses the special parameter default to set the variable $reqhide in case of any non-matching pattern. If I want to hide files later on like all .txt files I set $reqhide to 1. A request for „robots.txt“ is caught by the first matching regular expression, so a request for „foo.txt“ is caught by the second that goes for all .txt files. The complete order of priority is explained in the map-module-docs.

As this wonderfully unknown (to many) article on nginx.com notes, the only 100% safe things in if conditions are return and rewrite statements.

So I just do something like

location / {
  [...]
  if ($reqhide) {
    return 404;
  }
  [...]
}

to make the response a 404-File-not-found lie.

Tag 41/2016: Falsche Spuren

Eine Ansible-Anweisung in einem Webserver-Task hat mir heute den Apache ausgeknipst. Genauer gesagt eine fehlerhafte Anweisung im „lineinfile“ -Modul. Das Modul benutzt man vor allem, um eine einzelne Zeile in einer Datei zu finden und auszutauschen.

Spoiler: Ich wollte in der ports.conf aus „Listen 80“ ein explizites „Listen 127.0.0.1:80“ machen und habe stattdessen bei jedem Durchlauf „Listen 127.0.0.1:80“ hinzugefügt. Irgendwann stand es 5x drin, was 4x zuviel ist.

Ein „apachectl configtest“ meldet leider fröhlich „Syntax OK“ – die manpage weist ja auch darauf hin „This test does not catch all errors“, weil es hauptsächlich die Syntax analysiert.

Beim „service apache2 restart“ kommt dann „Address already in use: AH00072: make_sock: could not bind to address“ und „no listening sockets available, shutting down“ und dann final „the apache2 instance did not start within 20 seconds. Please read the log files to discover problems“. Das Error-Log bleibt leer.

Bei der Fehlersuche habe ich zuerst mit netstat und lsof hantiert und war von der doch eigentlich freien Adresse:Port-Kombi irritiert. Bis die Ansible-Script-Recherche mich auf die ports.conf-Veränderung gebracht hat.

Was könnten die Alternativen auf Apache-Seite sein? Gleiche Konfigurationsanweisungen wie eine einzige Anweisung behandeln? Eine aussagekräftigere Fehlermeldung?

Tag 40/2016: Faschingsdienstag-Erkenntnisse

Dies und das.

  • Auf einem der Mailserver habe ich eine fail2ban-Regel, die jeden via DNSBL abgelehnten Einlieferungsversuch findet und die IP für ein paar Stunden sperrt. Das via Munin geplottete Resultat über die letzten Wochen zeigt das Ansteigen der IP-Sperren immer über die Mittagszeit.
  • HTTP/2-Experimente sind notwendig, um mit dem Protokoll der Zukunft frühzeitig Erfahrungen zu sammeln. Dieser Blog-Post hat mich auf diese Implementierung Nghttp2 gebracht. Als weitere Alternative zum ngx_http_v2-Modul von nginx.
  • Gluster und Ceph kenne ich und ich bin in dem Zusammenhang heute über Sheepdog gestolpert. Bookmark gesetzt. Notiz: Demnächst mal das gluster_volume Modul von Ansible laufen lassen, auf das mich die Readme vom geerlingguy-Repository zur GlusterFS-Rolle gebracht hat.
  • WordPress at Scale hat Potential, ist im Moment aber noch ein bisschen zu Highlevel. Am Besten ergänzen mit highscalability.com.

Tag 19/2016: ssh-Dämon-Konfiguration mit erweiterten Regeln

In vielen Konfigurationsbeispielen für die  sshd_config, der Konfigurationsdatei für den ssh-Dämon, wird mit der AllowUsers-Direktive explizit festgelegt, mit welchen Benutzernamen (und damit Benutzern) man sich überhaupt anmelden darf. Kombiniert mit @HOST gilt der Login eines Benutzers dann sogar nur für den angegebenen Host.

AllowUsers foo bar baz@192.168.1.100

Loginversuche von Unbefugten mit dort nicht aufgeführten Benutzerkonten lassen sich damit, dank eindeutiger Fehlermeldung im Logfile, noch einfacher mit Tools wie fail2ban aufspüren.

sshd[9140]: User system from host.example.com not allowed because not listed in AllowUsers

Hat man den Login so konfiguriert, dass nur das Public-Key-Verfahren erlaubt ist und muss einem Benutzerkonto trotzdem den Login mit Passwort erlauben, kann man sich mit konditionalen Blöcken behelfen, die man mit der Match-Direktive einleitet.

An das Ende der sshd_config kann man beispielsweise ergänzen:

Match Address 192.168.1.100 User bolo
AllowUsers bolo
PasswordAuthentication yes

Hier werden zwei Kriterien geprüft, nämlich ob der Login von einer bestimmten IP-Adresse aus erfolgt („Address 192.168.1.100“) und ob es der zu erlaubende Benutzer ist („User bolo“). Wenn ja, wird diesem Benutzer explizit auch der Login („AllowUsers bolo“) und die Anmeldung via Passwort erlaubt („PasswordAuthentication yes“).  Die im konditionalen Block gelisteten Einstellungen überschreiben die globalen.

Genauso gut kann man also auch schreiben:

# in der "globalen" AllowUsers Liste
AllowUsers foo bar baz@192.168.1.100 bolo@192.168.1.100

PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no

Match User bolo
PasswordAuthentication yes

Tag 18/2016: Python-Repräsentation einer YAML-Datei ausgeben

Zur Zeit kodifiziere ich das Setup einiger alter Server in Ansible-Skripte. Dank Virtualisierung und Cloud ist es mittlerweile einfach, Migrationen auf neue Betriebssysteme und Versionsstände im Vorfeld durchzuspielen. Die neuen Setups profitieren auch vom Know-how aus zahlreichen anderen Ansible-Scripten, z.B. auf Github, weil man immer wieder auf nützliche Vorgehensweisen und Module stößt.

Bei den Core-Modulen copy, file, lineinfile und template setze ich nach Möglichkeit immer explizit group, owner und mode so restriktiv wie möglich – der SuSE-Paranoid-Mode bei den Dateirechten fehlt mir bei Debian/Ubuntu einfach 🙂 Ansonsten Tags setzen mindestens für Packages und Services. Und vor dem Schreiben eigener Rollen lohnt es sich immer, nach bereits erprobten und universellen Rollen Ausschau zu halten.

Zwar ist die Struktur eines YAML-Dokuments leicht zu verstehen, aber trotzdem ist manchmal ein schneller Blick auf die Python-Repräsentation hilfreich. Das kann man beispielsweise mit ein paar Zeilen Python selbst erledigen. „Tag 18/2016: Python-Repräsentation einer YAML-Datei ausgeben“ weiterlesen