Schlagwortarchiv: osbn

Tag OSBN

RHEL/CentOS 7 – Root Passwort zurücksetzen

In diesem Tutorial wird beschrieben, wie das root-Passwort bei RHEL/CentOS 7 mit Bordmitteln zurückgesetzt werden kann. Mit Bordmitteln bedeutet, dass hierbei keine externen Bootmedien verwendet werden.

Aufgepasst! Macht man bei der Ausführung der folgenden Prozedur Fehler, können diese dazu führen, dass man jeglichen Zugang zu einem System verliert. Möchte man die Vorgehensweise üben, empfehle ich, dies ausschließlich auf Testsystemen zu tun.

Die Ausgangssituation

Das root-Passwort eines RHEL/CentOS 7 Servers ist unbekannt und muss zurückgesetzt werden. Es ist keine geöffnete root-Shell vorhanden und es ist kein Benutzer am System angemeldet, welcher über vollständige sudo-Berechtigungen verfügt.

Das Passwort soll ohne Einsatz externer Bootmedien zurückgesetzt werden.

Update 2019-12-17: Alternativ zur unten beschriebenen Vorgehensweise, kann bei Systemen, mit sehr großen Dateisystemen die in KB4661061 beschriebene Vorgehensweise genutzt werden.

Vorgehensweise

Schritt 1: Es wird ein Neustart des Systems durchgeführt. Sobald das Grub2-Boot-Menü erscheint, wird der Bootloader-Countdown durch Drücken einer beliebigen Taste unterbrochen.

Nun wählt man den gewünschten Eintrag (dies ist meist der erste in der Liste) aus und wechselt mit Drücken der Taste ‚e‘ in den Bearbeitungsmodus (siehe Abbildung 1).

abb1-grub2-menu

Abbildung 1: Grub2-Bootmenü

Schritt 2: Der Cursor wird zur Kernel-Kommandozeile bewegt. Diese beginnt üblicherweise mit dem Wort linux16. Hier wird, wie in Abbildung 2, ein „rd.break“ an das Ende der Zeile angefügt.

edit-kernel-command-line

Abbildung 2: Bearbeitete Startparameter für den Kernel

Die Bearbeitung wird durch Drücken der Tastenkombination Strg+x beendet und der Bootvorgang fortgesetzt. Der Bootvorgang wird an der Stelle angehalten, an der man sich in der Initial-Ram-Disk befindet, direkt bevor das eigentliche System gestartet wird. An dieser Stelle findet man den Inhalt des eigentlichen /-Dateisystems unterhalb von /sysroot.

Schritt 3: Nach Schritt 2 befindet man sich nun in einer root-Shell. Da das eigentliche Dateisystem unterhalb von /sysroot schreibgeschützt eingehängt wurde, muss dieses zunächst remountet werden. Dies geschieht mit dem folgenden Kommando (vgl. Abbildung 3):

switch_root:/# mount -oremount,rw /sysroot
remount-sysroot

Abbildung 3: Remount /sysroot

Schritt 4: In diesem Schritt wechselt man mittels chroot[1. chroot – wiki.ubuntuusers.de] in das /sysroot-Verzeichnis und setzt ein neues Passwort für den Benutzer root.

switch_root:/# chroot /sysroot
sh-4.2# passwd root
Changing password for user root.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.

Wichtig: SELinux[2. Einführung in das grundlegende Konzept von SELinux] ist zu diesem Zeitpunkt noch nicht aktiv. Dies bedeutet, dass alle neuen Dateien ohne einen entsprechenden SELinux-Kontext erstellt werden. Das Programm passwd arbeitet so, dass es erst eine neue Datei erstellt und mit dieser anschließend die alte Datei überschreibt. Die neue Datei /etc/shadow besitzt damit keinen SELinux-Kontext.

Um sicherzustellen, dass alle Dateien (inkl. der /etc/shadow) während des Bootvorgangs mit einem SELinux-Label versehen werden, muss die Datei autorelabel im aktuellen Verzeichnis erstellt werden:

sh-4.2# touch /.autorelabel

Wichtig: Sämtliche Dateien und Verzeichnisse werden erneut mit einem SELinux-Label versehen. Dies kann bei großen Dateisystemen einige Zeit dauern. Um Zeit zu sparen, können Dateisysteme (außer dem Dateisystem auf dem sich die /etc/shadow befindet) in der /etc/fstab auskommentiert werden. Nachdem das SELinux-Relabeling durchgeführt und das System gestartet wurde, können diese wieder eingehängt werden.

Abschließend verlässt man durch zweimalige Eingabe von exit zuerst die chroot-Umgebung und anschließend die Debug-Shell der Ram-Disk (vgl. Abbildung 4). Das System setzt den Bootvorgang an der Stelle fort, an der dieser unterbrochen wurde.

autrelabel

Abbildung 4

Es werden zunächst sämtliche Dateien von SELinux relabelt und anschließend ein Neustart ausgeführt.

Hinweis: Vergisst man die Datei .autorelabel zu erstellen und wird SELinux im Modus „Enforcing“ ausgeführt, kann man sich nach einem Neustart nicht am System anmelden. Man muss dann erneut booten und obige Schritte ausführen, um die Datei erstellen zu können.

Wurden die oben aufgeführten Schritte erfolgreich angewendet, kann man sich nun mit dem vergebenen Passwort am System anmelden und hat damit die Kontrolle zurückgewonnen.

Auch wenn ich diese Anleitung mehrere Male erfolgreich getestet habe, wünsche ich uns allen, dass wir sie möglichst niemals brauchen werden.

SELinux Booleans

Bei SELinux Booleans handelt es sich um kleine Schalter, mit denen sich das Verhalten der SELinux-Richtlinien beeinflussen lässt. Dieser Artikel knüpft an die „Einführung in das grundlegende Konzept von SELinux“ an und erläutert die Verwendung von SELinux Booleans anhand eines einfachen Beispiels.

Hinweis: Das Beispiel aus diesem Artikel wurde auf einem RHEL/CentOS 7.3 getestet. Unter CentOS 7.2 funktioniert die hier gezeigte Konfiguration nicht. Für Details wird auf das Topic[2. Solved SELinux Booleans and httpd_enable_homedirs] im CentOS-Support-Forum verwiesen.

Im Einführungsartikel[3. „Einführung in das grundlegende Konzept von SELinux“] wurde SELinux dazu genutzt, um den Zugriff des Apache auf das DocumentRoot-Verzeichnis /var/www/html zu beschränken. Nun möchte der Webmaster den Benutzern gestatten, Webseiten über ihre HOME-Verzeichnisse zu veröffentlichen und aktiviert dazu die Konfiguration für das Modul Userdir.[4. Linux Basics: How To Enable Apache UserDir In CentOS 7/RHEL 7 {en}] [5. Enable Userdir in CentOS 7 {en}] [6. Apache: Benutzerspezifische Verzeichnisse – wiki.ubuntuusers.de]

[root@centos ~]$ cat /etc/httpd/conf.d/userdir.conf

    UserDir enabled
    UserDir public_html



    AllowOverride FileInfo AuthConfig Limit Indexes
    Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
    Require method GET POST OPTIONS


[root@centos ~]#

Nun kann ein Benutzer in seinem HOME-Verzeichnis den Ordner public_html erstellen und eine test.txt-Datei erstellen:

[jkastning@centos ~]$ mkdir public_html
[jkastning@centos ~]$ sudo chmod 711 /home/jkastning/
[jkastning@centos ~]$ sudo chmod 755 public_html/
[jkastning@centos ~]$ vim public_html/test.txt

Hello User

Nach einem Neustart des Dienstes httpd sollte sich nun die Datei index.html aus dem Benutzerverzeichnis abrufen lassen. Statt dessen wird der Zugriff verweigert.

apache_userdir_forbidden

httpd_enable_homdirs –> off

In den Logdateien finden sich Hinweise, die auf SELinux als Ursache hindeuten.

[root@centos ~]# tail /var/log/audit/audit.log|grep AVC
type=AVC msg=audit(1480446615.354:844): avc:  denied  { getattr } for  pid=23150 comm="httpd" path="/home/jkastning/public_html/index.html" dev="sda1" ino=1052157 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:httpd_user_content_t:s0 tclass=file

[root@centos ~]# tail /var/log/messages | grep SELinux
Nov 29 20:10:44 centos setroubleshoot: SELinux is preventing httpd from getattr access on the file /home/jkastning/public_html/index.html. For complete SELinux messages. run sealert -l 13419731-cedd-4433-abb7-b2e7715d5636

Um weitere Informationen zu erhalten, führen wir das Kommando aus /var/log/messages aus (Ausgabe gekürzt):

[root@centos ~]# sealert -l 13419731-cedd-4433-abb7-b2e7715d5636
SELinux is preventing httpd from getattr access on the file /home/jkastning/public_html/index.html.

*****  Plugin catchall_boolean (24.7 confidence) suggests   ******************

If you want to allow httpd to enable homedirs
Then you must tell SELinux about this by enabling the 'httpd_enable_homedirs' boolean.
You can read 'None' man page for more details.
Do
setsebool -P httpd_enable_homedirs 1

In der obigen Ausgabe wird neben der Ursache auch gleich die Lösung mitgeliefert. Nach der Aktivierung des SELinux Boolean httpd_enable_homedirs kann der Inhalt der Datei index.html im Webbrowser abgerufen werden.

apache_userdir_allowed

httpd_enable_homedirs –> on

Damit wurde eine weitere Funktionalität von SELinux kurz vorgestellt. Für weiterführende Informationen sei auf die Manpages booleans(8)[6. booleans(8) – Linux man page {en}], getsebool(8)[7. getsebool(8) – Linux man page {en}] und setsebool(8)[8. setsebool(8) – Linux man page {en}] verwiesen.

Einführung in das grundlegende Konzept von SELinux

SELinux[1. SELinux – Wikipedia] (Security-Enhanced Linux; engl. „sicherheitsverbessertes Linux“) ist eine Erweiterung des Linux-Kernels, mit der eine zusätzliche Sicherheitsschicht in das Betriebssystem eingezogen wird.

In dieser Einführung wird das zu Grunde liegende Konzept kurz vorgestellt und erläutert, welche Modi SELinux besitzt, wie diese angezeigt und umgeschaltet werden können. An einem einfachen Beispiel mit dem Apache Webserver wird dargestellt, wie SELinux in der Praxis wirkt. Des Weiteren wird mit Hilfe des Beispiels das Vorgehen bei einer Fehleranalyse erläutert.

SELinux ist dazu gedacht, das bestehende Berechtigungskonzept unter Linux zu erweitern, um zu verhindern, dass kompromittierte Dienste auf Daten zugreifen, auf die kein Zugriff erforderlich ist.

Als einfaches Beispiel mag hier der Webserver Apache[2. Apache HTTP Server – Wikipedia] dienen.

Dieser liest die Dateien, welche er ausliefern soll, in der Standardkonfiguration aus dem dem Verzeichnis /var/www/html. Daneben darf der Dienst z.B. auch alle Verzeichnisse und Dateien unterhalb der Verzeichnisse /tmp und /var/tmp lesen.

user@host:~$ ls -ld /tmp
drwxrwxrwt. 5 root root 4096 Nov 27 19:05 /tmp
user@host:~$ ls -ld /var/tmp
drwxrwxrwt. 2 root root 4096 Nov 10 06:34 /var/tmp
user@host:~$

Grundsätzlich hat der Dienst Zugriff auf alle Verzeichnisse und Dateien, welche den Lese- bzw. Schreibzugriff für alle Benutzer erlauben.

SELinux kann nun dazu genutzt werden, um genau diesen Zugriff zu unterbinden. Die folgende Abbildung soll dies verdeutlichen:

selinux-example-apache

Mögliche Zugriffe mit und ohne SELinux am Beispiel des Apache

SELinux stellt einfach gesprochen ein Regelwerk dar, nach welchem bestimmt wird, auf welche Verzeichnisse, Dateien, Prozesse und Ports ein Dienst zugreifen darf. Dazu erhalten diese Objekte ein Label mit einem Security Context. Nur wenn das SELinux-Regelwerk den Zugriff von einer Ressource auf eine weitere Ressource explizit erlaubt, ist der Zugriff gestattet. Andernfalls wird die Interaktion unterbunden. Dabei unterscheidet SELinux die verschiedenen Label nach Kontexten. Diese sind:

  • user
  • role
  • type
  • sensitivity

Im Folgenden wird ausschließlich der Kontext „type“ weiter betrachtet. So besitzt z.B. der Dienst Apache das Label httpd_t, während Dateien unterhalb von /var/www/html das Label httpd_sys_content_t tragen. Da SELinux eine Regel besitzt, welche den Zugriff des Kontext httpd_t auf Dateien und Verzeichnisse mit dem Kontext httpd_sys_content_t gestattet, kann der Apache die Datei index.html aus dem Verzeichnis /var/www/html anzeigen:

output-index-html

Ausgabe der Datei /var/www/html/index.html

Obiger Screenshot enthält neben dem obligatorischen „Hallo Welt“ auch noch die Ausgabe des Verzeichnis-Listings, welches neben den üblichen Angaben wie Berechtigungen, Benutzer und Gruppe auch den SELinux-Kontext mit ausgibt. Wie man SELinux steuert und sich den Kontext von Verzeichnissen, Dateien und Prozessen anzeigen lässt, wird im Folgenden Abschnitt erläutert.

Steuerung von SELinux

SELinux kennt drei Modi:

  • Enforcing
  • Permissive
  • Disabled

In welchem Status sich SELinux befindet, kann mit dem Kommando getenforce abgefragt werden:

[root@centos ~]# getenforce
Enforcing
[root@centos ~]#

Obige Ausgabe bedeutet, dass SELinux im Modus „Enforcing“ ausgeführt wird. In diesem Modus verhindert SELinux Zugriffe, welche nicht explizit durch das Regelwerk erlaubt werden. Im Unterschied dazu werden diese Zugriffe im Modus „Permissive“ nicht verhindert, sie werden jedoch protokolliert. Dieser Modus eignet sich daher hervorragend, um das aktuelle Verhalten von Diensten zu analysieren und die Konfiguration ggf. anzupassen. Die Umschaltung zwischen den Modi „Enforcing“ und „Permissive“ kann zur Laufzeit erfolgen:

[root@centos ~]# getenforce
Enforcing
[root@centos ~]# setenforce 0
[root@centos ~]# getenforce
Permissive
[root@centos ~]# setenforce 1
[root@centos ~]# getenforce
Enforcing
[root@centos ~]#

Der Standard-Modus wird in der Datei /etc/selinux/config festgelegt.

Anzeige der SELinux-Kontexte

Der kleine Punkt (im Screenshot rot markiert) hinter den Berechtigungen zeigt an, dass ein SELinux-Kontext für eine Datei bzw. ein Verzeichnis existiert:

Der Punkt zeigt einen vorhandenen SELinux-Kontext an

Der Punkt zeigt einen vorhandenen SELinux-Kontext an

Welchen Kontext eine Datei bzw. ein Prozess besitzt, kann angezeigt werden, indem bekannte Kommandos mit der Option „-Z“ benutzt werden. Das folgende Listing zeigt einige Beispiele:

[root@centos ~]# ps -eZ | grep httpd
system_u:system_r:httpd_t:s0     2876 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     2920 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     2921 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     2922 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     2923 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     2924 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     2925 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     3152 ?        00:00:00 httpd
[root@centos ~]# ls -lisaZ /var/www/html/
total 12
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 .
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 ..
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html
[root@centos ~]# ls -lisaZ /var/tmp
total 28
drwxrwxrwt. root root system_u:object_r:tmp_t:s0       .
drwxr-xr-x. root root system_u:object_r:var_t:s0       ..
drwxr-xr-x. abrt abrt system_u:object_r:abrt_var_cache_t:s0 abrt
drwx------. root root system_u:object_r:tmp_t:s0       systemd-private-f844adcb52b14995b675d9aa065e925c-colord.service-MczkBW
drwx------. root root system_u:object_r:tmp_t:s0       systemd-private-f844adcb52b14995b675d9aa065e925c-cups.service-c3Aouq
drwx------. root root system_u:object_r:tmp_t:s0       systemd-private-f844adcb52b14995b675d9aa065e925c-httpd.service-oAqhlb
drwx------. root root system_u:object_r:tmp_t:s0       systemd-private-f844adcb52b14995b675d9aa065e925c-rtkit-daemon.service-xpSsO2
[root@centos ~]# ls -lisaZ /tmp |head -n4
total 96
drwxrwxrwt. root      root      system_u:object_r:tmp_t:s0       .
dr-xr-xr-x. root      root      system_u:object_r:root_t:s0      ..
-rw-r--r--. root      root      system_u:object_r:tmp_t:s0       anaconda.log
[root@centos ~]#

Die Datei index.html hat bei ihrer Erstellung im Verzeichnis /var/www/html automatisch den korrekten Kontext httpd_sys_content_t erhalten und kann daher im Webbrowser angezeigt werden. Wird eine Datei im Verzeichnis /tmp erstellt, erhält diese automatisch den Kontext user_tmp_t:

[root@centos ~]# echo 'TEST' > /tmp/test.txt
[root@centos ~]# ls -lisaZ /tmp/test.txt
-rw-r--r--. root root unconfined_u:object_r:user_tmp_t:s0 /tmp/test.txt
[root@centos ~]#

Was tun, wenn’s klemmt?

Um zu erläutern, wie man einem Fehler auf die Spur kommt, baue ich zuerst einen ein. Dazu verschiebe ich die im vorangegangenen Abschnitt erzeugte Datei in das DocumentRoot des Apache und versuche, diese im Browser aufzurufen.

forbidden

Forbidden

SELinux verhindert den Zugriff des Dienstes „httpd“ auf die Datei „text.txt“, da keine Regel existiert, welche den Zugriff vom Kontext httpd_t auf user_tmp_t explizit erlaubt. Doch wie kann man dies feststellen, wenn man nicht bereits zu Beginn um den falschen Kontext weiß?

Zuerst wirft man einen Blick auf die Dateiberechtigungen, welche aber keinen Fehler erkennen lassen:

[root@centos ~]# ls -lZ /var/www/html/
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html
-rw-r--r--. root root unconfined_u:object_r:user_tmp_t:s0 test.txt
[root@centos ~]#

Da die Dateiberechtigungen als Fehlerquelle ausscheiden und in diesem Beispiel keine POSIX-ACL[3. ACL – wiki.ubuntuusers.de] verwendet werden, bleibt nur noch SELinux als Fehlerquelle übrig. Daher suchen wir einmal in /var/log/audit/audit.log nach Ereignissen vom Typ „AVC“:

[root@centos ~]# tail /var/log/audit/audit.log | grep AVC
type=AVC msg=audit(1480277043.225:537): avc:  denied  { open } for  pid=2922 comm="httpd" path="/var/www/html/test.txt" dev="sda1" ino=924457 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_tmp_t:s0 tclass=file

Treffer! Um die Sache weiter zu analysieren, untersuchen wir als nächstes /var/log/messages (Ausgabe gekürzt). Hinweis: Unter RHEL 7 muss das Paket ’setroubleshoot-server‘ installiert sein, damit SELinux-Ereignisse auch in /var/log/messages geloggt werden (siehe Abschnitt 4.2. Which Log File is Used).

Nov 27 21:29:13 centos setroubleshoot: SELinux is preventing /usr/sbin/httpd from open access on the file /var/www/html/test.txt. For complete SELinux messages. run sealert -l 7a6417b8-06e2-4499-8f0f-ed0bb16f2b2a

Hier findet sich eine Bestätigung, dass SELinux den Zugriff blockiert hat und ein Vorschlag, wie dieser Vorfall genauer analysiert werden kann. Damit lassen sich umfassende Informationen abrufen, welche sogar die Lösung mit ausgeben (Ausgabe gekürzt):

[root@centos ~]$ sealert -l 7a6417b8-06e2-4499-8f0f-ed0bb16f2b2a
SELinux is preventing /usr/sbin/httpd from open access on the file /var/www/html/test.txt.

*****  Plugin restorecon (92.2 confidence) suggests   ************************

If you want to fix the label. 
/var/www/html/test.txt default label should be httpd_sys_content_t.
Then you can run restorecon.
Do
# /sbin/restorecon -v /var/www/html/test.txt

*****

Der Bericht gibt an, wie das Standard-Label für die Datei text.txt gesetzt sein sollte. Darüber hinaus ist dem Bericht der Befehl zu entnehmen, mit dem die Label wieder auf den Standardwert zurückgesetzt werden können. Nachdem dieser Befehl ausgeführt wurde, kann die Datei text.txt im Webbrowser geöffnet werden.

[root@centos ~]# /sbin/restorecon -v /var/www/html/test.txt
/sbin/restorecon reset /var/www/html/test.txt context unconfined_u:object_r:user_tmp_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
[root@centos ~]#
correct-selinux-context

Aufruf von test.txt mit korrektem SELinux-Kontext

Schlusswort

Es wurde in das grundlegende Konzept von SELinux und die möglichen Betriebsmodi eingeführt. Darüber hinaus wurde erläutert, wie man sich die zu einem Objekt gehörenden SELinux-Kontexte anzeigen lassen kann und wie diese auf einen Standard-Kontext zurückgesetzt werden können. Abschließend wurde ein kleiner Einblick in das Vorgehen zur Fehleranalyse gegeben.

Damit bin ich am Ende dieser kleinen Einführung angekommen, wobei das Thema SELinux damit noch lange nicht abschließend behandelt ist. Für weiterführende Informationen sei an dieser Stelle auf die Dokumentation der einzelnen Distributionen verwiesen.[4. RHEL 7: SELinux User’s and Administrator’s Guide: Basic and advanced configuration of Security-Enhanced Linux (SELinux) {en}] [5. SELinux – CentOS Wiki {en}] [6. SELinux – Fedora Project {en}]

Quellen und weiterführende Links

Benutzer die Ausführung eines Skripts mit sudo gestatten

In diesem kurzen Tutorial wird beschrieben, wie man einem normalen Benutzer das Recht einräumt, ein einzelnes Skript mit sudo auszuführen. Das Tutorial ist auf alle Linux-Distributionen anwendbar, welche sudo[1. sudo – Wikipedia] unterstützen.

Schritt 1: Skript und Benutzerkonto erstellen

Zuerst wird natürlich das Skript benötigt, welches der neue Benutzer später ausführen soll. Als Beispiel mag hier folgendes einfaches Beispiel dienen:

#!/bin/bash
echo "Hallo Welt."

Wichtig! Der Benutzer, welcher das Skript später ausführen soll, darf selbst keine Schreibrechte darauf besitzen. Andernfalls könnte er das Skript bearbeiten und durch eintragen von bash eine root-shell öffnen. Danke an Gerald für diesen wichtigen Hinweis.

Der Benutzer kann, sofern er nicht schon existiert, mit folgendem Kommando angelegt werden:

sudo adduser USERNAME

Schritt 2: /etc/sudoers konfigurieren

Um einem Benutzer das Recht zu verleihen, gibt es grundsätzlich mehrere Möglichkeiten.

Benutzer einer Gruppe hinzufügen

Auf vielen Linux-Distributionen existiert bereits eine Gruppe, deren Mitglieder die Berechtigung zur Verwendung von sudo besitzen. Unter Ubuntu ist dies z.B. die Gruppe ’sudo‘. Unter RHEL, CentOS und Fedora ist dies bspw. die Gruppe ‚wheel‘. Um welche Gruppe es sich konkret handelt, kann in der Datei /etc/sudoers nachgeschlagen werden. Dort findet sich auf einem Ubuntu 16.04 LTS z.B. folgender Eintrag:

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

Da dem Benutzer im hier beschriebenen Fall jedoch nur erlaubt werden soll, ein einziges Skript mittels sudo auszuführen, ist diese Methode ungeeignet.

Benutzer in /etc/sudoers

Um einem Benutzer das Recht zu gewähren, ein bestimmtes Skript oder Programm mit sudo auszuführen, kann der Benutzer wie folgt in die Datei /etc/sudoers eingetragen werden.

Wichtig! Die Datei /etc/sudoers sollte nur als root mit dem Kommando visudo editiert werden, da hiermit eine Syntaxprüfung erfolgt. Eine Beschädigung der Datei /etc/sudoers, z.B. durch Syntaxfehler, kann dazu führen, dass das gesamte System unbrauchbar wird.

# User privilege specification
USERNAME    ALL=/path/to/script.sh

Mit obiger Zeile wird dem Benutzer ‚USERNAME‘ erlaubt, das Skript unter /path/to/script.sh mit sudo auszuführen.

Diese Methode ist bereits geeignet, um die gestellte Aufgabe zu lösen.

Datei unter /etc/sudoers.d/ erstellen

Unter aktuellen Versionen von Debian, Ubuntu, RHEL, CentOS und Fedora besteht die Möglichkeit, eine Datei im Verzeichnis /etc/sudoers.d/ zu erstellen, welche den Eintrag aus dem vorangegangenen Abschnitt enthält. Voraussetzung dafür ist, dass die Datei /etc/sudoers folgende Direktive enthält:

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d

Beachte: Das Zeichen ‚#‘ vor ‚includedir‘ stellt in diesem Fall kein Kommentarzeichen dar.

Diese Methode hat den Vorteil, dass die Datei /etc/sudoers unverändert bleibt und es bei Updates nicht zu einem Versionskonflikt kommen kann.

Fazit

Mittels /etc/sudoers ist es möglich, sudo-Berechtigungen granular an Benutzer zu delegieren. Neben dem in diesem Tutorial beschriebenen Beispiel existieren noch weitere Möglichkeiten. Beispiele dazu finden sich in der Manpage von sudoers.

ejabberd mit Let’s Encrypt Zertifikat

In diesem Artikel wird dokumentiert, wie ein Let’s Encrypt[1. https://letsencrypt.org/ {en}] [2. Let’s Encrypt – Wikipedia] Zertifikat für ejabberd eingerichtet werden kann. Dabei stütze ich mich auf mein TLS-Kochbuch[3. TLS/SSL Kochbuch: Rezepte für die Verwendung von OpenSSL, HTTP Strict Transport Security (HSTS) und HTTP Public Key Pinning (HPKP)].

Die Dokumentation bezieht sich dabei auf meine konkrete Installation und ist nicht ohne Transferleistung auf andere Installationen übertragbar. Es ist also keine Schritt-für-Schritt-Anleitung! Der Artikel bietet über die Dokumentation hinaus jedoch auch Hintergrundinformationen und Wissenswertes für abweichende Konfigurationen.

Ausgangssituation

In meiner Umgebung ist ejabberd auf einem Ubuntu Server 14.04 LTS[4. Trusty Tahr – wiki.ubuntuusers.de] installiert und nutzt ein TLS-Zertifikat von CAcert[5. https://www.cacert.org/ {en}] [6. CAcert – Wikipedia].

Außer ejabberd läuft auf dem Server auch noch ein Webserver, welcher verschiedene Webseiten ausliefert.

Daneben ist bereits der Let’s Encrypt Client acme-tiny[7. Fork des acme-tiny Clients auf GitHub {en}] installiert, dessen Verwendung in Abschnitt 3.6.2 TLS-Kochbuch erläutert wird.

Der Ablauf im Überblick

Wie vorstehend bereits erwähnt, verwendet ejabberd bereits ein TLS-Zertifikat, welches nun durch ein Let’s Encrypt Zertifikat ersetzt werden soll. Der Ablauf gliedert sich dabei im Wesentlichen in zwei Teile. Zuerst wird ein Let’s Encrypt Zertifikat für den Hostnamen des ejabberd-Servers ausgestellt. Anschließend wird ejabberd konfiguriert, um zukünftig dieses Zertifikat zu nutzen.

Zur Durchführung der Domainvalidierung wird ein VirtualHost für den Hostnamen des ejabberd-Servers konfiguriert. Da sich die genaue Konfiguration je nach verwendeter Webserver-Software unterscheidet, wird hier nicht näher darauf eingegangen, sondern auf die Dokumentation des jeweiligen Webservers verwiesen.

Generierung des TLS-Zertifikats

Nun wird mit Hilfe von OpenSSL[8. OpenSSL: Cryptography and SSL/TLS Toolkit {en}] [9. OpenSSL – Wikipedia] ein privater Schlüssel und eine Zertifikatsanfrage (engl. Certificate Signing Request (CSR)) erstellt. Beide Schritte werden ausführlich in Abschnitt 3.1 TLS-Kochbuch beschrieben.

Ich persönlich generiere den privaten Schlüssel und den CSR stets offline auf einem sicheren Computer. Anschließend lade ich sie zum Server hoch. Die Zugriffsrechte auf den Schlüssel sind so eingeschränkt, dass nur root und der Benutzer, unter dem der Webserver ausgeführt wird, diesen Schlüssel lesen dürfen.

Da bereits eine Installation von acme-tiny auf dem Server existiert und bereits ein Account-Key erstellt wurde, wird dieser in dem Verzeichnis verlinkt, in dem auch der private Schlüssel und der CSR liegen.

Nun kann das TLS-Zertifikat angefordert werden. Wie dies im Detail funktioniert, wird in Abschnitt 3.6.2 im TLS-Kochbuch beschrieben.

Sind bis hier alle Schritte erfolgreich gewesen, liegen nun Schlüssel und Zertifikat in einem Verzeichnis vor.

$ python acme-tiny/acme_tiny.py --account-key /var/www/sites/ssl/account.key --csr /var/www/sites/ssl/request.csr --acme-dir /var/www/sites/public/.well-known/acme-challenge/ > /var/www/sites/ssl/cert.crt
Parsing account key...
Parsing CSR...
Registering account...
Already registered!
Verifying fqdn...
fqdn verified!
Signing certificate...
Certificate signed!

$ ls -l /var/www/sites/ssl/
-rw-r—– 4 root root account.key
-rw-r—– 1 root www-data cert.crt
-rw-r—– 1 root root priv.key
-rw-r—– 1 root root request.csr

Zertifikat für ejabberd präparieren

Der Dienst ejabberd erwartet, dass der private Schlüssel, das Zertifikat und die Zertifikatskette in einer Datei übergeben werden.[10. Ejabberd SSL Certificate – Raymii.org {en}] Dazu wird noch die Zertifikatskette von Let’s Encrpyt[11. Let’s Encrypt: Chain of Trust {en}] heruntergeladen und ebenfalls in /var/www/sites/ssl/ gespeichert.

Das folgende Skript zeigt, wie das Zertifikat erzeugt, die Zertifikatsdatei für ejabberd zusammengesetzt und der Dienst neugestartet wird:

#!/bin/bash
# Datum: 2016-11-13
# Autor: Joerg Kastning <webmaster(aet)my-it-brain(Punkt)de>
#
# Beschreibung:
# Dieses Skript dient der Erneuerung des TLS-Zertifikats fuer
# jabber.my-it-brain.de über Let's Encrypt mit dem Client acme-tiny-by-frezbo.

DIR='/var/www/sites/ssl'

# Erneuerung des Zertifikats
python acme-tiny-by-frezbo/acme_tiny.py --account-key ${DIR}/account.key --csr ${DIR}/request.csr --acme-dir /var/www/sites/fqdn/.well-known/acme-challenge/ > ${DIR}/cert.crt

# Erzeugung der Zertifikatsdatei fuer ejabberd
cat ${DIR}/priv.key ${DIR}/cert.crt ${DIR}/lets-encrypt-x3-cross-signed.pem >${DIR}/ejabberd_cert.pem

sudo chown root:ejabberd ${DIR}/ejabberd_cert.pem
sudo chmod 0640 ${DIR}/ejabberd_cert.pem
sudo mv ${DIR}/ejabberd_cert.pem /etc/ejabberd/ejabberd_cert.pem

# Neustart von ejabberd
sudo service ejabberd restart

Abschluss der Migration

Durch den im vorangegangenen Abschnitt dargestellten Code wird das neue Let’s Encrypt Zertifikat an der gleichen Stelle und unter dem gleichen Dateinamen wie das alte Zertifikat abgelegt. Auf diese Weise muss die Konfiguration von ejabberd nicht weiter angepasst werden. Der Dienst lädt nach einem Neustart das neue Zertifikat. Die Migration ist damit abgeschlossen.

Let’s Encrypt Zertifikate besitzen eine Gültigkeit von 90 Tagen.[12. Let’s Encrypt: Why ninety-day lifetimes for certificates? {en}] Um die Erneuerung des Zertifikats zu automatisieren, wird das Skript „SmartRenew.sh“ verwendet (siehe Abschnitt 5.4 im TLS-Kochbuch).

Quellen und weiterführende Links:

Kurz vorgestellt: Mozilla SSL Configuration Generator

In diesem Artikel möchte ich euch kurz den Mozilla SSL Configuration Generator vorstellen, auf den mich ein Kollege aufmerksam machte.

mozilla_ssl_configuration_generator

Mozilla SSL Configuration Generator

Es handelt sich dabei um eine Seite, die dabei hilft, valide Konfigurationen für verschiedene Webserver wie Apache, NGINX, Lighttpd, HAProxy oder AWS ELB zu erstellen. Man gibt dazu den verwendeten Webserver, dessen Version und die OpenSSL Version an. Die Seite erstellt daraufhin die Konfiguration, welche per Copy&Paste übernommen werden kann. Lediglich die enthaltenen Pfadinformationen sind an die eigenen Bedürfnisse anzupassen.

mozilla_ssl_configuration_generator_nginx

Konfiguration für nginx 1.4.6 | modern profile | OpenSSL 1.0.1e

Neben der Konfiguration erhält man auch noch die Information dazu geliefert, welche Browser mit der erstellten Version kompatibel sind.

In einer ersten Stichprobe scheint die Seite ganz brauchbare Ergebnisse zu liefern. Ich freue mich über eure Meinungen und Erfahrungen zu diesem Dienst.

Bei positiver Resonanz nehme ich einen Hinweis auf diesen Dienst in eine kommende Version meines TLS-Kochbuchs auf.

Mein TLS/SSL-Kochbuch

Heutzutage werden immer mehr Kommunikationsverbindungen im Internet mit TLS/SSL-Verbindungen geschützt. Die Verschlüsselung hilft, die Vertraulichkeit der zwischen Sender und Empfänger übertragenen Daten zu schützen und sollte daher standardmäßig aktiviert sein. Doch bereitet der Einsatz von TLS/SSL-Verschlüsselung noch immer vielen Administratoren und Betreibern verschiedenster Anwendungen Kopfschmerzen. Zu undurchsichtig scheint der Dschungel aus Zertifizierungsstellen, Zertifikaten, Zertifikatsanfragen, öffentlichen und privaten Schlüsseln zu sein. Verschiedenste Validierungsverfahren und Dateiformate für Zertifikate tragen nicht gerade dazu bei, den Durchblick zu behalten. Bereits die Erstellung einer Zertifikatsanfrage gerät dabei häufig genug zu einem Problem. Die richtige Konfiguration der zu sichernden Server bzw. Dienste erscheint kompliziert und Fehler in der Konfiguration führen nicht selten zur Nichterreichbarkeit einer Webseite. Die Folge: Immer noch wird viel zu häufig auf den Einsatz von TLS/SSL-Verschlüsselung verzichtet.

Mit meinem TLS-Kochbuch möchte ich dazu beitragen, etwas Licht ins Dunkel zu bringen. Darin finden sich Rezepte mit praktischen Tipps für die Verwendung von TLS/SSL-Verschlüsselung mittels OpenSSL, HTTP Strict Transport Security (HSTS) und HTTP Public Key Pinning (HPKP).

Aus dem Inhalt

Nach der Einleitung führt Kapitel 2 in das Thema ein und definiert die wesentlichen Begriffe. Es bildet die Grundlage für das Verständnis der daran anschießenden Kapitel.

In Kapitel 3 geht es um die Implementierung von TLS/SSL. Hier werden verschiedene Methoden zur Generierung von privaten Schlüsseln und Certificate Signing Requests vorgestellt. Darüber hinaus werden einige Zertifizierungsstellen kurz vorgestellt, bei denen Zertifikate beantragt werden können. Im Folgenden wird auf die Implementierung von TLS/SSL-Zertifikaten in verschiedenen Diensten eingegangen. Hier wird insbesondere die Implementierung von Zertifikaten der recht jungen Zertifizierungsstelle „Let’s Encrypt“ erläutert, mit deren Hilfe sich der Prozess der Zertifikatserneuerung automatisieren lässt.

Der Implementierung des HTTP Public Key Pinning (HPKP) widmet sich Kapitel 4. Das Pinning-Verfahren wird am Beispiel des Webservers NGINX erläutert und getestet.

Zum Schluss werden die in den einzelnen Kapiteln vorgestellten Techniken und Methoden nochmals zusammenfassend an einem konkreten Beispiel in Kapitel 5 verdeutlicht.

Hier geht es zum Text

Mir persönlich hat die Arbeit an folgendem Dokument geholfen, mich detailliert mit der Thematik auseinanderzusetzen und mein Wissen zu erweitern und zu vertiefen. Ich freue mich, wenn mein Kochbuch auch euch dabei hilft, ein besseres Verständnis für das Thema zu entwickeln.

Dies ist die erste Ausgabe meines TLS/SSL-Kochbuchs und es gibt sicher noch viel mehr, was man zu diesem Thema schreiben kann. Fehler sowie Wünsche zum Inhalt zukünftiger Ausgaben können gern an die E-Mail-Adresse tls-rezepte(aet)my-it-brain(Punkt)de gemeldet werden.

Downloads zum Text

Mein erstes RPM-Paket

Vorwort

Der Inhalt dieses Artikels ist nicht zur Nachahmung empfohlen. Ich halte an dieser Stelle fest, wie ich mein erstes RPM-Paket erstellt habe. Dieses funktioniert zwar und tut was es soll, doch ist es aus qualitativer Sicht noch ein weiter Weg, bis ich es selbst als gut bezeichnen würde. Der Artikel ist daher eher als ein Hilferuf zu verstehen. Ich freue mich, wenn mir geduldige, erfahrene Paketbauer in den Kommentaren Tipps geben, wie ich es besser machen kann.

Was habe ich getan?

Um die Installation des Tivoli TSM-Backup-Client 7.1.6 unter RHEL/CentOS/Fedora zu vereinfachen, habe ich für die Installation ein RPM-Paket erstellt. Der TSM-Backup-Client selbst wird vom Hersteller als TAR-Archiv bereitgestellt, welches die zur Installation benötigten RPM-Pakete enthält. Dazu gibt es eine Dokumentation, welche weitere z.T. optionale Abhängigkeiten aufführt. Darunter z.B. die Installation einiger Bibliotheken und eines Oracle JRE 1.7 oder höher.

All diese Dinge habe ich zusammen mit einem Skript, welches die initiale Installation und Konfiguration vornimmt, in ein RPM-Paket gepackt. Dieses Paket lässt sich auf dem Zielsystem installieren und durch die anschließende Ausführung des (selbst erstellten) Skripts tsm_init.sh werden die benötigten RPM-Pakete und Abhängigkeiten installiert.

Meine SPEC-Datei sieht wie folgt aus:

#---------------------------------------------------------------#
# version for using createRPM_* script
#---------------------------------------------------------------#
Name:      tsm-backup-client
Version:   7.1.6
Release:   1%{?dist}
Packager:  Tronde
Group:     Applications/System
Summary:   Tivoli TSM Backup Client for Linux

License:   non-free
URL:       http://example.com

BuildArch: x86_64
BuildRoot: %{_tmppath}/%{name}-%{version}

# $RPM_SOURCE_DIR : Variable of rpmbuild SOURCE dir
# $RPM_BUILD_DIR  : Variable of rpmbuild BUILD dir
# $RPM_BUILD_ROOT : Variable of rpmbuild BUILDROOT dir
#%define  

#BuildRequires:
Requires: libXrender
Requires: libXtst
Requires: libXp
Requires: xorg-x11-xauth

%description
This package installs the required packages and scripts for the
installation of the Tivoli TSM Backup Client for Linux.

The package contains:
 * bacli
 * tsm_init.sh
 * jre-8u91-linux-x64.tar.gz

#---------------------------------------------------------------#
# not used sections should be be set to comment
#---------------------------------------------------------------#
# The section '%prep' to extract the sourcefile 'Source0'
#%prep

# The section '%build' to build binaries from sources
#%build

# copy files to $RPM_BUILD_ROOT for using in the %files section
%install
cd $RPM_BUILD_ROOT
tar xvzf $RPM_SOURCE_DIR/%{name}.tgz
mv %{name}/* .
rmdir %{name}

# this files will be included in the rpm package
# with path on target host
%files
%defattr(-,root,root)
%doc
/root/bin/tsm_init.sh
/root/bin/start-tivoli-gui.sh
/data/bacli/gskcrypt64-8.0.50.66.linux.x86_64.rpm
/data/bacli/gskssl64-8.0.50.66.linux.x86_64.rpm
%doc /data/bacli/README_api_enu.htm
%doc /data/bacli/README_enu.htm
%doc /data/bacli/README
/data/bacli/cat_README.sh
/data/bacli/TIVsm-API64.x86_64.rpm
/data/bacli/TIVsm-APIcit.x86_64.rpm
/data/bacli/TIVsm-BAcit.x86_64.rpm
/data/bacli/TIVsm-BAhdw.x86_64.rpm
/data/bacli/TIVsm-BA.x86_64.rpm
/data/bacli/TIVsm-filepath-7.1.6-0-rhel59.x86_64.rpm
/data/bacli/TIVsm-filepath-7.1.6-0-rhel64.x86_64.rpm
/data/bacli/TIVsm-filepath-7.1.6-0-rhel7.x86_64.rpm
/data/bacli/TIVsm-filepath-7.1.6-0-sles11sp2.x86_64.rpm
/data/bacli/TIVsm-filepath-source.tar.gz
/data/bacli/TIVsm-JBB.x86_64.rpm
/data/jre-8u91-linux-x64.tar.gz

%clean
rm -rf %{buildroot}

# The section '%pre', for code to be executed prior to install
#%pre

# The section '%prerun' for code to be executed prior to uninstall
%preun

# the section '%post', for code to be executed after install
# normal sh script, prefs variables and macros can be used
%post

# The section '%postun' for code to be executed after uninstall
#%postun

%changelog
*Tue Jul 05 2016  Tronde 7.1.6-1
-- Initial Build.

Bisher erkannte Mängel

Mir sind bisher folgende Mängel aufgefallen:

  1. Nach der Installation des Pakets müssen die enthaltenen RPM-Pakete durch ein weiteres Skript installiert werden.
  2. Das Installationsskript muss manuell auf dem Zielsystem gestartet werden.
  3. Bei der Deinstallation werden die vom tsm_init.sh-Skript installierten RPM-Pakete nicht mit entfernt.

Meine Idee das tsm_init.sh-Skript in die Sektion %post zu packen hat leider nicht funktioniert, da ich die Paketverwaltung damit in einen Deadlock schicke. YUM ist noch durch den Installationsprozess blockiert, welcher mein RPM-Paket installiert und wartet darauf, dass der YUM-Aufruf aus meinem tsm_init.sh-Skript beendet werden kann. So geht es also nicht.

Was möchte ich eigentlich erreichen?

Erreichen möchte ich, dass durch die Installation eines RPM-Paktes die folgenden RPM-Pakete auf dem Zielsystem installiert werden:

  • gskcrypt64-8.0.50.66.linux.x86_64.rpm
  • gskssl64-8.0.50.66.linux.x86_64.rpm
  • TIVsm-API64.x86_64.rpm
  • TIVsm-BA.x86_64.rpm

Das Skript tsm_init.sh soll anschließend nur noch dazu verwendet werden, um den installierten TSM-Backup-Client mit einer initialen Konfiguration zu versehen. Ein zweites Skript soll an einem Ort abgelegt werden, von dem aus es ausgeführt werden kann.

Bisher ist meine einzige Idee, diese Aufgabe zu lösen, die vier genannten RPM-Pakete in ein YUM-Repository zu legen. In meiner SPEC-Datei kann ich sie dann als Abhängigkeiten definieren:

#BuildRequires:
Requires: gskcrypt64-8.0.50.66.linux.x86_64.rpm
Requires: gskssl64-8.0.50.66.linux.x86_64.rpm
Requires: TIVsm-API64.x86_64.rpm
Requires: TIVsm-BA.x86_64.rpm

Allerdings frage ich mich, ob es nicht auch eine Möglichkeit gibt, eine Art Meta-RPM zu erstellen, welches die benötigten RPMs enthält und diese Installiert. Ich könnte die Software auf diesem weg über ein einziges Paket bereitstellen.

Falls ihr Ideen oder Hinweise geben könnt, wie die Anforderung am besten umzusetzen ist, freue ich mich über eure Kommentare unter diesem Artikel.

SSH-Logins in RHEL/CentOS/Fedora auditieren

SSH-Logins werden unter RHEL, CentOS und Fedora in der Datei /var/log/secure protokolliert. Dieser Artikel beschreibt, wie man bei einem Audit den zum im Log protokollierten RSA-Fingerprint passenden SSH-Key identifiziert.

In dem hier beschriebenen Szenario wird angenommen, dass SSH-Logins ausschließlich über Public-Key-Authentifizierung zugelassen sind und die öffentlichen SSH-Schlüssel an zentraler Stelle im Dateisystem abgelegt sind. Darüber hinaus enthält jeder SSH-Schlüssel die E-Mail-Adresse des dazugehörigen Benutzers.

Authentifiziert sich ein Benutzer mit seinem öffentlichen SSH-Schlüssel an einem RHEL-, CentOS- oder Fedora-System, wird dies im Log /var/log/secure wie folgt dokumentiert:

Jun 18 15:34:55 hostname sshd[846]: Accepted publickey for tronde from X.X.X.X port 61362 ssh2: RSA cd:22:29:38:f7:e2:49:b1:a6:2f:8d:8f:cc:69:d7:c2

Neben Datum, Uhrzeit und dem verwendeten Benutzernamen wird hier der RSA-Fingerabdruck des verwendeten SSH-Publickey dokumentiert. Um nun herauszufinden, welcher SSH-Public-Key zu diesem Fingerabdruck gehört, nutze ich ein kleines Bash-Skript[1. Das Skript auf GitHub]:

#!/bin/bash
# Beschreibung:
# Dieses Skript gleicht einen RSA-Hash aus dem Log /var/log/secure mit den
# vorhandenen SSH-Public-Keys ab. Bei Uebereinstimmung wird der entsprechende
# Key ausgegeben.
#
# Der RSA-Hash wird dem Skript als Argument uebergeben.
#
# Autor: Joerg Kastning <joerg.kastning(aet)uni-bielefeld(punkt)de>

# Hauptteil #######################################################
rsa_fprint="$1"
printf "RSA-Fingerprint:\n${rsa_fprint}\n\n"
for key in *.pub
do
  tmp1=`/usr/bin/ssh-keygen -lf ${key}`
  set - $tmp1
  tmp2=`echo "$2"`
  if [[ "${rsa_fprint}" = "${tmp2}" ]]
  then
    printf "Der zugehoerige SSH-Key lautet:\n${tmp1}\n"
    exit 0
  fi
done
printf "Es wurde kein SSH-Key gefunden, welcher zu dem uebergebenen RSA-Fingerprint passt."
exit 0

Diesem Skript wird der RSA-Fingerabdruck als Argument übergeben. Das Skript generiert anschließend den RSA-Fingerabdruck aller SSH-Schlüssel in dem Verzeichnis, in dem das Skript aufgerufen wird und vergleicht diese mit dem übergebenen Fingerabdruck. Bei Übereinstimmung wird der zugehörige SSH-Schlüssel ausgegeben. Beispiel:

$ ./match_ssh-pubkey.sh cd:22:29:38:f7:e2:49:b1:a6:2f:8d:8f:cc:69:d7:c2
RSA-Fingerprint:
cd:22:29:38:f7:e2:49:b1:a6:2f:8d:8f:cc:69:d7:c2

Der zugehoerige SSH-Key lautet:
2048 cd:22:29:38:f7:e2:49:b1:a6:2f:8d:8f:cc:69:d7:c2  foo@example.com (RSA)
$

In diesem Beispiel gehört der verwendete SSH-Schlüssel dem Benutzer Foo. Auf diese Weise kann ein Audit mit einfachen Mitteln durchgeführt werden.