Dieser Artikel baut auf meinen vorherigen Artikeln über Namespaces, Die 7 am häufigsten verwendeten Linux-Namespaces und meiner Serie zum manuellen Erstellen eines Linux-Containers mit Namespaces, mit dem Mount-Namespace und mit dem PID-Namespace auf. Dieser Artikel behandelt den UTS-Namespace und seine Beziehung zu Containern.
Der zufällige Beobachter missversteht den Namensraum des Unix Timesharing System (UTS), vor allem weil sein Name nicht mehr seinem Zweck entspricht. Trotz seines Namens kontrolliert der UTS-Namespace tatsächlich den Hostnamen und die NIS-Domäne. So beschreibt die Manpage den UTS-Namespace:
Diese Kennungen werden mit sethostname(2)
gesetzt und setdomainname(2)
, und kann mit uname(2)
abgerufen werden , gethostname(2)
und getdomainname(2)
. An diesen Bezeichnern vorgenommene Änderungen sind für alle anderen Prozesse im selben UTS-Namensraum sichtbar, jedoch nicht für Prozesse in anderen UTS-Namensräumen.
Dies bedeutet, dass einige moderne Tools (systemd und andere) möglicherweise nicht die erwarteten Änderungen bewirken.
Wie Sie sich vorstellen können, kann es mehrere Anwendungsfälle geben, in denen Prozesse unterschiedliche Hostnamen haben sollen. Webserver beispielsweise neigen dazu, eine Warnung auszugeben, wenn der Hostname nicht mit dem SSL-Zertifikat übereinstimmt, das sie bereitstellen. Andererseits können einige Prozesse den Hostnamen an einen Netzwerkprozess anhängen. Ein falscher Hostname kann fehlgeschlagene oder verweigerte Verbindungen oder unzählige andere Probleme verursachen.
Kommen wir nun zu einigen Beispielen.
Erkunden Sie den UTS-Namespace
Sie können den UTS-Namensraum aufrufen mit:
$ unshare --uts /bin/bash
Möglicherweise stellen Sie jedoch fest, dass Sie, sobald Sie sich im neuen Namespace befinden, hostnamectl set-hostname
verwenden ändert den Hostnamen im neuen Namespace nicht.
# unshare --uts
# hostname
bastion.stratus.lab
# hostnamectl set-hostname tux
# hostname
bastion.stratus.lab
Wenn Sie jedoch eine neue Shell öffnen, hat sich der Hostname tatsächlich geändert:
[user@host ~]$ ssh root@bastion
Last login: Tue Dec 7 08:17:48 2021 from 192.168.99.198
[root@tux ~]# hostname
tux
Warum ist das? Systemd führt den sethostname
nicht aus Systemaufruf. Stattdessen schließt systemd die Aufgabe ab, indem es sich mit einem Socket verbindet. Da der Socket mit dem alten Namespace verknüpft ist, wird der Hostname des alten Namespace angepasst, aber nicht der neue Namespace.
Root-Namespaces verwenden
In meinem Mount-Namespace-Artikel schreibe ich:
Jetzt, da Sie sich im neuen Namespace befinden, erwarten Sie möglicherweise nicht, einen der ursprünglichen Einhängepunkte des Hosts zu sehen. Dies ist jedoch nicht der Fall. Der Grund dafür ist, dass systemd standardmäßig die Einhängepunkte rekursiv mit allen neuen Namespaces teilt.
Zufällig leitet systemd viele seiner Informationen von /run
ab , die in den Namensraum geteilt wird, den ich hier erstellt habe.
Im Mount-Namespace-Artikel mounte ich tmpfs
in den neuen Namensraum in einem Verzeichnis, das ich nicht mit dem alten Namensraum teilen möchte.
Ich kann die meisten systemd-Aufrufe deaktivieren, indem ich den neuen Namespace mit den folgenden Optionen einhänge:
$ unshare --mount --uts /bin/bash
Hängen Sie dann /run
erneut ein :
$ mount -t tmpfs tmpfs /run
Der gesamte Prozess sieht folgendermaßen aus:
# unshare --fork --mount --uts /bin/bash
# mount -t tmpfs tmpfs /run
# hostnamectl set-hostname bastion.stratus.lab
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
# hostname tux
# hostname
tux
Ich kann dies bestätigen, indem ich eine neue Shell für die Box öffne:
[user@host ~]$ ssh root@bastion
Last login: Tue Dec 7 08:33:04 2021 from 192.168.99.198
[root@bastion ~]# hostname
bastion.stratus.lab
Ich kann den passenden Namensraum finden, indem ich lsns
verwende Befehl:
[root@bastion ~]# lsns |grep uts
4026531838 uts 133 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026532250 uts 1 645 root /usr/lib/systemd/systemd-udevd
4026532405 uts 1 743 root /usr/lib/systemd/systemd-logind
4026532479 mnt 2 11507 root unshare --fork --mount --uts /bin/bash
4026532480 uts 2 11507 root unshare --fork --mount --uts /bin/bash
Den Namensraum kann ich dann mit dem nsenter
eingeben Befehl:
[root@bastion ~]# nsenter -t 11507 -a
[root@tux /]#
Einen Benutzernamensraum verwenden
In meinem Artikel über Benutzernamensräume erwähne ich einige zusätzliche Überlegungen beim Erstellen von Namensräumen als nicht privilegierter Benutzer:
Wenn Sie einen neuen Benutzernamensraum erstellen, wird Ihr aktueller Benutzer dem Benutzer nobody zugeordnet . Dies liegt daran, dass standardmäßig keine Benutzer-ID-Zuordnung stattfindet. Wenn keine Zuordnung definiert ist, verwendet der Namensraum einfach die Regeln Ihres Systems, um zu bestimmen, wie mit einem nicht definierten Benutzer umzugehen ist.
Weitere Informationen zur Benutzerzuordnung finden Sie in diesem Artikel. In diesem Fall möchte ich den Stamm haben Benutzer automatisch zugeordnet. Auf diese Weise habe ich "root" im neuen Namensraum. (Siehe auch hier den Artikel über Namensräume für Benutzer für eine Diskussion über Namensräume und Berechtigungen).
Wenn ich meine kombinierten Lektionen auf einem CentOS Stream 9-Host in die Praxis umsetze, beobachte ich:
ocp@bastion ~ $ unshare --map-root-user --user --mount --uts --fork /bin/bash
root@bastion ~ $ hostnamectl set-hostname tux
Could not set static hostname: Interactive authentication required.
Das liegt daran, wie polkit
ist auf der RHEL-Familie von Distributionen konfiguriert. Andere Distributionen werfen diesen Fehler nicht unbedingt aus. Arch Linux (ohne spezielles polkit
configuration) erlaubt es dem Container beispielsweise weiterhin, den Hostnamen zu ändern. Daher ist es unabhängig von Ihrer Distribution immer noch eine gute Sicherheitspraxis, /run
neu zu mounten .
Es ist wichtig zu beachten, dass die Ausgabe von lsns
könnte einfacher zu lesen sein, indem Sie --fork
verwenden beim Erstellen von Namespaces.
So sieht es ohne aus --fork
Flagge:
[root@bastion ~]# lsns |grep uts
4026531838 uts 135 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026532250 uts 1 645 root /usr/lib/systemd/systemd-udevd
4026532405 uts 1 743 root /usr/lib/systemd/systemd-logind
4026532414 uts 1 11962 ocp /bin/bash
Und mit dem --fork
Flagge:
[root@bastion ~]# lsns |grep uts
4026531838 uts 134 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026532250 uts 1 645 root /usr/lib/systemd/systemd-udevd
4026532405 uts 1 743 root /usr/lib/systemd/systemd-logind
4026532412 user 2 11939 ocp unshare --map-root-user --user --mount --uts --fork /bin/bash
Während --fork
ist in diesem Szenario nicht unbedingt erforderlich, kann aber nützlich oder sogar erforderlich sein, wenn ein neuer PID-Namespace erforderlich ist (weitere Informationen finden Sie in meinem PID-Namespace-Artikel).
Abschluss
Der UTS-Namespace ist nicht der komplizierteste Linux-Namespace. Es ist jedoch sehr nützlich, insbesondere im Zusammenhang mit Containern.
Um den UTS-Namespace optimal zu nutzen, kombinieren Sie ihn mindestens mit dem Mount-Namespace, wenn Sie den Root-Namespace und Mount- und Benutzer-Namespaces verwenden, wenn Sie von einem nicht privilegierten Benutzer spawnen.
[ Laden Sie den mittleren Linux-Spickzettel herunter, um die wichtigsten Befehle immer griffbereit zu haben. ]
In meinem nächsten Artikel werde ich den Net-Namespace besprechen und wie man ihn verwendet, um Namespaces zu ermöglichen, ihre eigenen IP- und Port-Spaces zu haben.