Inhaltsverzeichnis

Notizen der Admin Grundlagen Schulung (Suse) vom Dezember 2022

Hilfe

Pager

* Suchen mit /

                                

Notizen

    
debootstrap --arch=amd64 stretch /srv/container/debian/
systemd-nspawn -D /srv/container/debian
Passwort im Container für den Benutzer "root" setzen: 
      host$ systemd-nspawn -D /srv/container/debian
      container$ passwd
      container$ exit
Container booten: systemd-nspawn -bD /srv/container/debian
 
 
Flatpak:
 1) Installation: zypper install flatpak
 2) Repository hinzufügen: 
    flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
 3) Software suchen: flatpak search <suchbegriff>
    Beispiel:        flatpak search logseq
 4) Software installieren: flatpak install <Applikation-ID>
    flatpak install com.logseq.Logseq
 5) Software starten (als normaler Benutzer): flatpak run <Applikation-ID>
 
Update aller Suse Pakete: zypper update
 
Docker:
1)  Docker Engine installieren: zypper install docker
2)  Docker Engine starten: systemctl enable --now docker
3)  Docker testen: docker run hello-world
 
Docker Aufgabe: Wir installieren einen Webserver im Docker. Wir testen die Software 'caddy'
  1) Suche im Docker Hub nach einem Image mit dem Caddy Webserver: 
     docker search caddy
  2) Lade das Image 'abiosoft/caddy' in das lokale Docker Image Repository: 
     docker pull abiosoft/caddy
  3) Starte einen neuen Container mit dem Caddy-Webserver - Verbinde 
     Port 80 auf dem Laptop mit Port 2015 im Container:
     docker run -d --name=caddy-webserver -p 80:2015 abiosoft/caddy
  4) Prüfe, das der Container läuft
     docker ps
  5) Teste mit dem Firefox Browser auf dem Laptop, lade die Webseite 
     von http://localhost:80
  6) Ein paar Befehle zum Testen von Docker Funktionen
     docker logs caddy-webserver
     docker top  caddy-webserver
     docker stats caddy-webserver
     docker exec -it caddy-webserver /bin/sh
 
Docker Aufgabe: Daten ausserhalb des Docker Containers
 1) Verzeichnis für eigene Webseite erstellen
    mkdir -p /srv/webseite
 2) Schreibe mit einem Text-Editor eine einfacht Webseite unter /srv/webseite/index.html
 3) Stoppe den laufenden Caddy-Container
    docker stop caddy-webserver
 4) Lösche den caddy-webserver Container
    docker rm caddy-webserver
 5) Starte einen neuen Caddy-Container - in diesem Container wird das Verzeichnis /srv/webseite vom Linux (Suse) Host in der Verzeichnis /srv im
    Container verbunden
    docker run -d --name=caddy-webserver -p 80:2015 -v /srv/webseite:/srv  abiosoft/caddy
 6) Besuche die Webseite mit der URL http://localhost/ mit dem Firefox Browser - es sollte die eigene Webseite angezeigt werden
 7) Ändere mit einem Text-Editor vom Suse-Linux (ausserhalb des Containers) die Datei /srv/webseite/index.html, lade dann die Seite im Browser neu - 
    die Änderungen sollten sichtbar werden
 
Übung: Eigenes Image mit Dockerfile erstellen
 1) Stoppe und lösche den Caddy-Container
 2) Erstelle ein Arbeitsverzeichnis für die Docker-Dateien
    mkdir ~/Docker-work
    cd ~/Docker-work
 3) Erstelle eine Datei mit dem Namen "Dockerfile" mit dem folgenden Inhalt
    
    # Debian mit NGINX Webserver
    FROM debian:latest
   
    MAINTAINER: Linuxhotel Trainer <info@linuxhotel.de>
 
    # Pakete aktualisieren
    RUN apt -y update && apt -y upgrade
 
    # NGINX Webserver installieren
    RUN apt -y install nginx
   
    # Hostnamen für den Container festlegen
    RUN echo "webserver.example.com" > /etc/hostname
 
    # NGINX Start-Befehl für den Container
    CMD ["nginx", "-g", "daemon off;"]
 
  4) Neues Docker Image mit den Anweisungen aus dem Dockerfile bauen
     docker build -t debian-nginx --no-cache .
 
  5) Docker Images auflisten
     docker images
 
  6)  Docker Container aus dem Image starten (Auf Port 80, mit dem eigenen Web-Dateien Verzeichnis)
      docker run -d --name=nginx01 -p 80:80 -v /srv/webseite:/var/www/html debian-nginx
 
1 Das "ip" Kommando
===================
 
  * der Befehl `ip' ersetzt viele der Low-Level
    Netzwerk-Konfigurationsbefehle traditioneller Unix/Linux Systeme:
    arp, route, ifconfig, netstat ...
 
 
1.1 Link-Layer
~~~~~~~~~~~~~~
 
  * Statistiken anzeigen
  ,----
  | # ip -s link show <dev>
  | # ip -s -s link show <dev>
  `----
  * Konfiguration
  ,----
  | # ip link set <dev> down
  | # ip link set <dev> up
  | # ip link set <dev> address <mac-addr>
  | # ip link set <dev> name <neuer-name>
  | # ip link show <neuer-name>
  `----
 
 
1.2 IPv4 Konfiguration
~~~~~~~~~~~~~~~~~~~~~~
 
  ,----
  | # ip address add a.b.c.d/pre broadcast x.x.x.x dev <dev>
  | # ip address add a.b.c.d/pre broadcast + dev <dev>
  | # ip address delete a.b.c.d/pre dev <dev>
  | # ip -4 address flush label <dev>
  `----
  * primary und secondary adressen
  ,----
  | # ip address add a.b.c.d/pre broadcast + dev <dev>
  | # ip address add a.b.c.e/pre broadcast + dev <dev>
  | # ip address add a.b.c.f/pre broadcast + dev <dev>
  | # ip a s
  | # ip address add a.b.d.d/pre broadcast + dev <dev>
  | # ip address add a.b.d.e/pre broadcast + dev <dev>
  | # ip address add a.b.d.e/pre broadcast + dev <dev>
  | # ip a s
  `----
  * ARP
  ,----
  | # ip n s
  | # ip neighbour delete 192.168.1.2 dev <dev>
  | # ip neighbour add 192.0.2.10 dev <dev> lladdr <mac-addr> nud permanent
  | # ip n s
  | # ip -s n s
  | # ip -s -s n flush <ip>
  `----
  * IPv6 Konfiguration
  ,----
  | # ip -6 addr show dev <interface>
  | # ip -6 addr add <ipv6address>/<prefixlength> dev <interface>
  | # ip -6 addr del <ipv6address>/<prefixlength> dev <interface>
  | # ip -6 route show [dev <device>]
  | # ip -6 route add <ipv6network>/<prefixlength> via <ipv6address> [dev <device>]
  | # ip -6 route del <ipv6network>/<prefixlength> via <ipv6address> [dev <device>]
  | # ip -6 route add <ipv6network>/<prefixlength> dev <device> metric 1
  | # ip -6 route del <ipv6network>/<prefixlength> dev <device>
  | # ip -6 neigh show [dev <device>]
  | # ip -6 neigh add <IPv6 address> lladdr <link-layer address> dev <device>
  | # ip -6 neigh del <IPv6 address> lladdr <link-layer address> dev <device>
  `----
  * Routing
  ,----
  | # ip route show
  | # ip route add <netz>/<pre> via <gateway>
  | # ip route add <netz>/<pre> dev <dev> via <gateway>
  | # ip route delete <netz>/<pre>
  | # ip route flush cache
  `----
 
 
1.3 Netzwerk Namespaces
~~~~~~~~~~~~~~~~~~~~~~~
 
  * <http://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/>
  * <http://man7.org/linux/man-pages/man8/ip-netns.8.html>
  * <https://lwn.net/Articles/580893/>
 
  * Benutzung:
    - Isolierung von Prozessen vom Netzwerk
    - Virtuelle Netzwerke zwischen Containern (LXC/Docker)
    - Admin-Netze "unsichtbar" machen
 
  * Achtung: *root* kann innerhalb eines Namespaces auf die Namespace
    "1" (Default-Namespace) zugreifen.
 
  ,----
  | # ip netns add netns1
  | # ip netns list
  | netns1
  | # ip netns exec netns1 ip link list
  | 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT
  |     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  | # ip netns delete netns1
  | # ip netns exec netns1 ping 127.0.0.1
  | connect: Network is unreachable
  | # ip netns exec netns1 ip link set dev lo up
  | # ip netns exec netns1 ping 127.0.0.1
  | PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
  | 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.051 ms
  | # ip link add veth0 type veth peer name veth1
  | # ip link
  | # ip link set veth1 netns netns1  # auch physische NICs koennen in Namespaces verschoben werden
  | # ip link
  | # ip netns exec ip link
  | # ip netns exec netns1 ip link
  | # ip a
  | # ip netns exec netns1 ifconfig veth1 10.1.1.1/24 up
  | # ip netns exec netns1 ip a
  | # ping 10.1.1.1
  | # ip netns exec netns1 ping 10.1.1.2
  | # ip netns exec netns1 route
  | # ip netns exec netns1 iptables -L
  | # ip netns delete netns1
  `----
 
 
1.4 Multicast Routing
~~~~~~~~~~~~~~~~~~~~~
 
  ,----
  | # ip mroute show
  | # ip mroute show from a.b.c.d/pre
  | # ip mroute show to a.b.c.d/pre
  `----
 
 
1.5 GRE Tunnel
~~~~~~~~~~~~~~
 
  * GRE (Generic Route Encapulation) ist ein Standardverfahren um
    IP-Pakete über IP-Netze zu tunneln
  * Damit können Netze über Gateway-Rechner, welche gegenseitig
    erreichbar sind, verbunden werden (auch mit privaten
    IP-Adressen). Ein VPN (aber ohne Verschlüsselung)
  * <http://www.deepspace6.net/docs/iproute2tunnel-en.html>
  ,----
  | NetA
  | network 10.110.1.0
  | netmask 255.255.255.0
  | router  10.110.1.1
  | 
  | NetB
  | network 10.110.2.0
  | netmask 255.255.255.0
  | router  10.110.2.1
  `----
  * Firewalld stoppen
  ,----
  | systemctl stop firewalld
  `----
  * Auf dem Router/Rechner NetA (IP 192.168.1.yyy)
  ,----
  | # ip tunnel show
  | # ip tunnel add netb mode gre \
  |    remote 192.168.1.xxx local 192.168.1.yyy ttl 64
  | # ip link set netb up
  | # ip addr add 10.110.1.1/24 dev netb
  | # ip route add 10.110.2.0/24 dev netb
  `----
  * Auf dem Router/Rechner NetB (IP 192.168.1.xxx)
  ,----
  | ip tunnel show
  | ip tunnel add neta mode gre \
  |   remote 192.168.1.yyy local 192.168.1.xxx ttl 64
  | ip link set neta up
  | ip addr add 10.110.2.1/24 dev neta
  | ip route add 10.110.1.0/24 dev neta
  `----
  * Tunnel entfernen
  ,----
  | # ip tunnel del <device>
  `----
  * Firewalld wieder starten
  ,----
  | systemctl start firewalld
  `----
 
 
1.6 IPSec VPN
~~~~~~~~~~~~~
 
  * IPSec Verbindungsparameter werden vom Linux-Kernel verwaltet. IPSec
    Programme wie StrongSWAN oder LibreSWAN benutzen IKE und andere
    Protokolle um die IPSec Parameter mit der Gegenstelle auszuhandeln
    und in den Linux-Kernel einzutragen. Die IPSec Parameter können
    jedoch auch direkt über den `ip' Befehl verwaltet werden.
  * das folgende Beispiel erzeugt einen IPSec Tunnel mit statischen
    Authentisierungs- und Verschlüsselungs Schlüsseln. Eine solche
    Konfiguration kann für /Ad-Hoc/ VPN Verbindungen benutzt werden,
    sollte aber nicht für Produktions-VPN-Installationen eingesetzt
    werden.
 
 
1.6.1 Beispiel: Ad-Hoc IPSec VPN
--------------------------------
 
  * in diesem Beispiel richten wir das IPSec VPN zwischen dem Laptop und
    der VM ein. Der IPSec Tunnel kann zwischen zwei Rechnern erstellt
    werden, welche über das IP-Protokoll kommunizieren können.
  * Node1: Laptop
  * Node2: VM
  * IPSec Konfiguration des Linux-Kernels anzeigen
  ,----
  | ip xfrm state
  | ip xfrm policy
  `----
  * ggf. alte IPSec Konfiguration löschen
  ,----
  | ip xfrm state flush
  | ip xfrm policy flush
  `----
  * Shell-Variable mit dem Authentisierungs-Schlüssel erstellen (auf
    beiden Endpunkten)
  ,----
  | export AUTHKEY=$(echo "passwort1" | openssl dgst -sha256 | cut -d ' ' -f 2)
  | echo $AUTHKEY
  `----
  * Shell-Variable mit dem Verschlüsselungs-Schlüssel erstellen (auf
    beiden Endpunkten)
  ,----
  | export ENCKEY=$(echo "passwort2" | openssl dgst -sha256 | cut -d ' ' -f 2)
  | echo $ENCKEY
  `----
  * IPSec Authentisierungs- und Verschlüsselungs-Paremeter zwischen
    beiden Endpunkten festlegen. Diese Befehle werden auf beiden
    Endpunkten ausgeführt:
  ,----
  | ip xfrm state add src <ip-node1> dst <ip-node2> \
  |    proto esp spi 0x00000001 reqid 0x1 mode tunnel \
  |    auth sha256 0x$AUTHKEY \
  |    enc aes 0x$ENCKEY
  | ip xfrm state add src <ip-node2> dst <ip-node1> \
  |    proto esp spi 0x00000001 reqid 0x1 mode tunnel \
  |    auth sha256 0x$AUTHKEY \
  |    enc aes 0x$ENCKEY
  `----
  * IPSec Tunnel mit den Tunnel-Adressen definieren
  * Node1:
  ,----
  | ip xfrm policy add src <tunnel-ip-node1> dst <tunnel-ip-node2> \
  |    dir out tmpl src <ip-node1> dst <ip-node2> proto esp reqid 0x1 mode tunnel
  | ip xfrm policy add src <tunnel-ip-node2> dst <tunnel-ip-node1> \
  |    dir in  tmpl src <ip-node2> dst <ip-node1> proto esp reqid 0x1 mode tunnel
  `----
  * Node2:
  ,----
  | ip xfrm policy add src <tunnel-ip-node2> dst <tunnel-ip-node1> \
  |    dir out tmpl src <ip-node2> dst <ip-node1> proto esp reqid 0x1 mode tunnel
  | ip xfrm policy add src <tunnel-ip-node1> dst <tunnel-ip-node2> \
  |    dir in  tmpl src <ip-node1> dst <ip-node2> proto esp reqid 0x1 mode tunnel
  `----
  * Tunnel-IP lokal auf das Loopback-Interface binden und
    Routing-Eintrag für die Tunnel-IP erstellen
  * Node1:
  ,----
  | ip addr add <tunnel-ip-node1> dev lo
  | ip route add <tunnel-ip-node2> dev virbr0 src <tunnel-ip-node1>
  `----
  * Node2:
  ,----
  | ip addr add <tunnel-ip-node2> dev lo
  | ip route add <tunnel-ip-node1> dev eth0 src <tunnel-ip-node2>
  `----
  * IPSec Status anzeigen
  ,----
  | ip xfrm state
  | ip xfrm policy
  `----
  * Testen (von Node1)
  ,----
  | ping <tunnel-ip-node2>
  `----
  * IPSec Pakete im `tcpdump' anschauen
  ,----
  | tcpdump -i virbr0
  `----
 
 
1.7 Netzwerkänderungen überwachen
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  ,----
  | # ip monitor all
  | # ip -t -s monitor link
  | # ip monitor address a.b.c.d/pre
  | # ip monitor route a.b.c.d/pre
  | # rtmon file /var/log/rtmon.log
  | # ip monitor file /var/log/rtmon.log
  `----
 
SSH mit Schlüssel
 
 1) Erstelle ein SSH-Schlüsselpaar auf dem Client (eigenes
    Notebook). Bestaetige den Pfad der Schlüssel-Dateien und vergebe eine
    Passphrase (langes Passwort). Der private Schlüssel wird mit diesem
    Passwort verschlüsselt
    ssh-keygen -t ed25519
 2) Port 22 (SSH) in der Firewall auf dem Laptop freischalten
    firewall-cmd --add-service=ssh --permanent
    firewall-cmd --reload
 3) Sicherstellen das der SSH-Dienst gestartet ist
    systemctl status sshd
 4) Den eigenen öffentlichen SSH-Schlüssel auf den entfernten Rechner (Laptop
    des Partner-Teilnehmers) kopieren (XX=Nummer des Partner-Teilnehmers)
    ssh-copy-id nutzerXX@192.168.1.2XX
 5) SSH-Verbindung testen. Statt des Passwortes sollte nun die Passphrase des
    privaten Schlüssels gefragt werden
    ssh nutzerXX@192.168.1.2XX
 6) Wenn die Anmeldung des Partner-Teilnehmers per SSH-Schlüssel am eigenen
    Laptop funktioniert, dann in der SSH-Dienst Konfiguration die
    Passwort-Anmeldung deaktivieren. In der Datei /etc/ssh/sshd_config
    Alt -> PasswordAuthentication yes / UsePAM yes
    Neu -> PasswordAuthentication no  / UsePAM no
 7) SSH-Dienst neu starten
    systemctl restart sshd
 8) Den Partner-Teilnehmer bitten, die Anmeldung per Schlüssel zu testen. Wenn
    die Anmeldung per Schlüssel funktioniert, die Gegenprobe durchführen
    (Anmeldung per Passwort). Für die Gegenprobe versuchen sich am Rechner per
    SSH mit einem unbekannten Benutzer anzumelden (es sollte nicht nach einem
    Passwort Gefragt werden):  ssh unbekannt@192.168.1.2XX
 
 
SSH mit SSH-Agent
 
 0) Lokalen SSH-Agent laden (gilt nur in der aktuellen Shell, notwenig wenn
    man nicht als an der grafischen Oberfläche angemeldeter Benutzer in der
    Shell arbeitet)
    eval $(ssh-agent)
 1) Privater Schlüssel in den SSH-Agent laden
    ssh-add
 2) Schlüssel im Agent auflisten
    ssh-add -l
 3) Wenn nun eine SSH Verbindung mit Schlüssel aufgebaut wird, so wird nicht
    mehr nach der Passphrase gefragt. Bitte einmal ausprobieren
    ssh nutzerXX@192.168.1.2XX
 4) SSH-Agent mit einem Passwort sperren (z.B. wenn man den Laptop einige Zeit
    unbeaufsichtigt lässt)
    ssh-add -x
 5) SSH-Agent wieder entsperren (grosses 'X')
    ssh-add -X
 6) Alle Schlüssel aus dem SSH-Agent löschen
    ssh-add -D
 
BTRFS Dateisystem
 
1 BTRFS Dateisystem erstellen
=============================
 
  * Ein 1 Gb grosses BTRFS-Dateisystem erstellen
  ,----
  | mkfs.btrfs -b 1G /dev/sda4
  `----
 
 
2 btrfs Mount-Optionen
======================
 
  * thread_pool=<nummer> - Anzahl der "worker-threads" für dieses
    Dateisystem. Insgesamt sollte die Anzahl der "worker-threads" aller
    BTRFS-Dateisysteme in System die Anzahl der CPU-Kerne nicht
    übertreffen
  * discard - DISCARD/TRIM Befehl für Flash-Speichermedien (SSD)
    anschalten
  * noacl - Keine Posix-ACLs auf dem Dateisystem erlauben
  * space_cache - Die Datenstruktur der freien Bloecke im Dateisystem
    auch auf die Platte schreiben. Dies beschleunigt das Caching für
    Block-Gruppen nach dem Einhängen des Dateisystems.
  * nospace_cache - Space-Cgache ausschalten
  * clear_cache - Space-Cache auf der Platte leeren. Der Space-Cache
    muss neu erstellt werden. Diese Mount-Option solle nur einmalig
    benutzt werden, nachdem des Probleme bei der Berechnung des freien
    Speichers in einem BTRS-Dateisystem gegeben hat
  * compress - Komprimiert Daten 'on-the-fly'
 
 
3 btrfs Dateisysteme vergroessern/verkleinern
=============================================
 
  * btrfs Dateisysteme koennen im laufenden Betrieb vergrössert oder
    verkleinert werden
  * der neue Grössenwert kann absolut gesetzt werden, z.b. "20g"
  * die Grössenveraenderung kann relativ angegeben werden, "-2g" um das
    Dateisystem um 2GB zu schrunmpfen, "+2g" um das Dateisystem um 2GB
    zu vergrössern. Bei einem Wert von "max" vergrössert sich das
    Dateisystem auf die maximale Grösse des freien Platzes auf dem
    Block-Gerät.
  ,----
  | # btrfs filesystem resize <amount> /mount-point
  `----
 
 
4 RAID mit stripe / mirror
==========================
 
  * BTRFS implementiert Software-RAID Varianten:
    - RAID 0 = Stripe
    - RAID 1 = Mirror
    - RAID 01 = Mirror of Stripes
    - RAID 10 = Stripe of Mirrors
  * die Unterstützung fuer RAID 5 (Block-Level Striping mit verteilter
    Paritätsinformation) oder RAID 6 (Block-Level Striping mit doppelter
    verteilter Paritätsinformation) sind in BTRFS implementiert, aber
    noch fehlerbehaftet und sollten *nicht* in Produktionssystemen
    eingesetzt werden! (siehe
    <https://btrfs.wiki.kernel.org/index.php/RAID56>)
  * Daten-Striping ueber 2 Platten (RAID 0), Metadaten gespiegelt
  ,----
  | mkfs.btrfs /dev/device1 /dev/device2
  `----
  * Metadaten und Daten als RAID 0 (stripe, nicht empfohlen)
  ,----
  | # mkfs.btrfs -m raid0 /dev/device1 /dev/device2
  `----
  * Spiegel mit 2 Platten (RAID 1)
  ,----
  | mkfs.btrfs -m raid1 -d raid1 /dev/device1 /dev/device2
  `----
  * RAID 0 - Dateisystem über 4 Platten (metadata mirrored, data
    striped).
  ,----
  | # mkfs.btrfs /dev/device1 /dev/device2 /dev/device3 /dev/device4
  `----
  * RAID 10 (ein RAID 0 über mehrere RAID 1)
  ,----
  | # mkfs.btrfs -m raid10 -d raid10 /dev/device1 /dev/device2 /dev/device3 /dev/device4
  `----
  * ein Block-Gerät zu einem bestehenden BTRFS-Dateisystem hinzufügen
  ,----
  | # btrfs device add /dev/device2 /mount-point
  | # btrfs filesystem balance /mount-point
  `----
  * Ein einfaches BTRFS-Dateisystem zu einem BTRFS-Spiegel erweitern
    (RAID 1)
  ,----
  | # mount /dev/sdb1 /mnt
  | # btrfs device add /dev/sdc1 /mnt
  | # btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt
  `----
  * Block-Gerät aus einem BTRFS-RAID entfernen
  ,----
  | # btrfs device delete /dev/sdc /mnt
  `----
  * Ausgefallende Platte aus einem RAID entfernen
  ,----
  | # mount -o degraded /dev/sdb /mnt
  | # btrfs device delete missing /mnt
  `----
  * Ausgefallendes Gerät um laufenden Betrieb durch eine neue Platte
    ersetzen
  ,----
  | # btrfs replace start /dev/old /dev/new /mnt
  | # btrfs replace status
  `----
 
5 btrfs scrub
=============
 
  * BTRFS "scrub" liest alle Daten im Dateisystem, vergleicht die
    Checksummen und repariert defekte Dateibereiche (bei RAID 1, RAID 10
    etc)
  ,----
  | # btrfs scrub start /path
  | # btrfs scrub start -B /path  # im Vordergrund ausfuehren
  | # btrfs scrub status /path
  `----
 
 
6 btrfs Dateisystem defragmentieren
===================================
 
  * BTRFS kann Daten defragmentieren. Dabei werden die Daten auf neue
    Positionen im Dateisystem geschrieben
  ,----
  | # btrfs filesystem defragment -r -v /mnt
  `----
  * Defragmentierung bei gleichzeitiger Komprimierung der Daten
  ,----
  | # btrfs filesystem defragment -c -r -v /mnt
  `----
 
 
7 btrfs Datenkompression
========================
 
  * BTRFS kann Daten "on-the-fly" komprimieren (beim Speichern) und
    dekomprimieren (beim Laden). Unterstützte Kompressions-Algorithmen
    sind zlib (Standard) und lzo (Lempel-Ziv-Oberhumer
    <https://de.wikipedia.org/wiki/Lempel-Ziv-Oberhumer>).
  ,----
  | # mount -o remount,compress=lzo /mnt/
  `----
  * Defragmentierung mit gleichzeitiger Komprimierung der Daten
  ,----
  | # btrfs filesystem defragment -r -v -clzo /mnt
  `----
  * Abfrage des erweiterten Attributs "C" (Compression)
  ,----
  | # lsattr /mnt/file
  `----
 
 
8 Filesystem-Informationen
==========================
 
  * mit dem Befehl `btrfs filesystem' können Informationen über das
    Dateisystem angezeigt werden. Informationen über die Belegung von
    Speicher auf Copy-on-Write Dateisystemen wie `btrfs' (oder auch ZFS)
    sind nie ganz exakt sondern Näherungswerte.
  ,----
  | # btrfs filesystem show
  | # btrfs filesystem df
  | # btrfs filesystem usage
  `----
  * Der Befehl `btrfs filesystem sync' sorgt aehnlich wie der `sync'
    Befehl dafuehr das daten aus den Hauptspeicher-Puffern in das
    Dateisystem geschrieben werden. Auch wird Speicher von geloeschten
    Subvolumes wieder freigegeben. `filesystem sync' sollte vor
    `filesystem df' oder `filesystem usage' ausgerufen werden, wenn
    genauere Werte ueber die Belegung des btrfs-Dateisystems benoetigt
    werden.
  ,----
  | btrfs filesystem sync /pfad
  `----
 
 
9 Dateisystem Label setzen
==========================
 
  * Das Label des Dateisystems kann mit dem Sub-Befehl `btrfs filesystem
    label' gesetzt werden
  ,----
  | # btrfs filesystem label /path <label>
  `----
 
 
10 Subvolumes/Snapshots
=======================
 
  * Sub-Volumes sind eigenständige Dateisysteme, welche innerhalb eines
    bestehenden BTRFS-Dateisystems existieren. Während bei
    traditionellen Dateisystemen (ext4, XFS ...) die Dateisysteme nur in
    eigenen Block-Geräten oder Dateien erstellt werden können, sind
    BTRFS-Dateisysteme "schachtelbar". Alle geschachtelten Dateisysteme
    teilen sich den freien Speicherplatz des Mediums.
  ,----
  | # btrfs subvolume create <name>
  | # btrfs subvolume show /path/to/subvolume
  | # btrfs subvolume list /path
  `----
  * Ein Snapshot ist eine Sonderform eines Sub-Volumes. Ein Snapshot ist
    ein (schreibbares) 1-zu-1 Abbild eines bestehenden
    BTRFS-Dateisystems. Ein Snapshots verbraucht nur Speicher fuer die
    Differenzen zwischen dem Original und dem Snapshot-Dateisystem.
 
  * Einsatzszenarien fuer Dateisystem-Snapshots
    - Klonen von virtuellen Maschinen (Image-Dateien)
    - Klonen von Container-Verzeichnissen
    - inkrementelle Backups mit online Zugriff auf alle gesicherten
      "Generationen" des Backup (wie Apple Timemachine)
    - als Quelle fuer BTRFS "send/receive" (s.u.)
    - temporäre Arbeitsverzeichnisse (Software-Entwicklung etc)
  ,----
  | # btrfs subvolume snapshot /old /new
  `----
  * Ein "read-only" Snapshot erstellen
  ,----
  | # btrfs subvolume snapshot -r /old /new
  `----
  * ein BTRFS-Subvolume separat anhaengen
  ,----
  | # mount -o subvol=name /dev/sdX /mountpoint
  | # mount -o subvolid=num /dev/sdX /mountpoint
  `----/dev/sda3
  * Snapshot loeschen. Das Subvolume wird als geloescht markiert, das
    Speicher wird allerdings nicht sofort freigegeben sondern von BTRFS
    im Hintergrund verzoegert "eingesammelt" (Aktualisierung des
    Space-Cache).
  ,----
  | btrfs subvolume delete /pfad
  `----
  * auf das "Commit" warten, bis BTRFS den Speicher des Subvolumes
    wieder freigegeben hat
  ,----
  | btrfs subvolume delete -c /pfad
  `----
  * Manuell den als geloescht markierten Speicher wieder freigeben
  ,----
  | btrfs subvolume sync
  `----
 
 
11 BTRFS send/receive
=====================
 
  * Einen "read-only" snapshot erzeugen, in eine Datei "senden"
    (serialisieren) und dann loeschen
  ,----
  | # btrfs subvolume snapshot -r /mnt/kernel/4.x/ /mnt/kernel/4.2r
  | # btrfs send /mnt/kernel/4.2r | gzip > /root/btrfs.send.gz
  | # btrfs subvolume delete /mnt/kernel/4.2r
  `----
  * Snapshot aus einer Datei empfangen und zuruecksichern. Das Ziel darf
    noch nicht existieren, es wird ein neues Subvolume (read-only)
    angelegt
  ,----
  | # zcat /root/btrfs.send.gz | btrfs receive -v /mnt
  | At subvol 4.2r
  | receiving subvol 4.2r uuid=daebdf0d-c46c-1848-b122-a865be93ac75, stransid=17
  `----
 
Firewalld
 
* Sicherheits "Zonen"
* Konfiguration in `/usr/lib/firewalld/' und `/etc/firewalld/'
,----
| # systemctl status firewalld
`----
* Panik-Modus
,----
| # firewall-cmd --panic-on
| # firewall-cmd --panic-off
`----
* FirewallD Informationen
,----
| # firewall-cmd --state
| # firewall-cmd --reload
| # firewall-cmd --get-default-zone
| # firewall-cmd --set-default-zone <zone>
| # firewall-cmd --get-active-zones
| # firewall-cmd --get-zones
| # firewall-cmd --list-all-zones
| # firewall-cmd --get-services
| # firewall-cmd --get-zone-of-interface=enp0s25
`----
* Service-Definitionen
,----
| ls /usr/lib/firewalld/services/
`----
* Sicherheits-Zonen anpassen
,----
| # firewall-cmd --zone=<zone> --list-all
| # firewall-cmd --zone=<zone> --add-service=<service>
| # firewall-cmd --zone=<zone> --add-service=<service> --permanent
| # firewall-cmd --zone=<zone> --remove-service=<service>
| # firewall-cmd --zone=<zone> --list-ports
| # firewall-cmd --zone=<zone> --add-port=<portnum>[-portnum]/proto
| # firewall-cmd --zone=<zone> --remove-port=<portnum>[-portnum]/proto
| # firewall-cmd --zone=<zone> --add-port=<portnum>[-portnum]/proto --timeout=<timeval>
| # firewall-cmd --zone=<zone> --add-port=<portnum>[-portnum]/proto --permanent
| # firewall-cmd --zone=<zone> --add-masquerade
| # firewall-cmd --zone=<zone> --remove-masquerade
| # firewall-cmd --zone=<zone> --add-forward-port=port=22:proto=tcp:toport=422
| # /usr/sbin/sshd -D -p 422
| # firewall-cmd --zone=<zone> --add-forward-port=port=22:proto=tcp:toaddr=192.0.2.55
| # firewall-cmd --zone=<zone> --add-forward-port=port=22:proto=tcp:toport=422:toaddr=192.0.2.55
`----
* Rich-Rules
,----
| # firewall-cmd --zone=<zone> --list-rich-rules
| # firewall-cmd --zone=<zone> --add-rich-rule='rule' [--timeout]
| # firewall-cmd --zone=<zone> --remove-rich-rule='rule' [--timeout]
`----
* Direkter-Modus (iptables)
,----
| firewall-cmd --direct --remove-rule ipv4 filter IN_public_allow \
|       0 -m tcp -p tcp --dport 666 -j ACCEPT
`----
* Netzwerk-Schnittstellen
,----
| # firewall-cmd --zone=<zone> --list-interfaces
| # firewall-cmd --zone=<zone> --add-interface=interface
| # firewall-cmd --zone=<zone> --change-interface=interface
| # firewall-cmd --zone=<zone> --remove-interface=interface
`----
* Quellen
,----
| # firewall-cmd --zone=<zone> --list-sources
| # firewall-cmd --zone=<zone> --add-source=source[/mask]
| # firewall-cmd --zone=<zone> --change-source=source[/mask]
| # firewall-cmd --zone=<zone> --remove-source=source[/mask]
`----
* Lockdown und Whitelists
,----
| # firewall-cmd --lockdown-on
| # firewall-cmd --lockdown-off
| # firewall-cmd --add-lockdown-whitelist-command='/usr/bin/python -Es /usr/bin/command'
| # firewall-cmd --add-lockdown-whitelist-uid=uid
| # firewall-cmd --add-lockdown-whitelist-user=user
`----
 
Übung Backup-Restore:
 
 Anleitung im Wiki unter "Backup / Bare-Metal Restore Suse Linux"
 https://wiki.lab.linuxhotel.de/doku.php/admin_grundlagen:systemsicherung#backup_bare-metal_restore_suse_linux
 
 Eigene Daten (Notizen, Konfigurationen etc) auf dem Laptop vorher
 sichern (z.B. in das Etherpad kopieren oder per "scp" auf einen
 anderen Laptop sichern) !
 
 In 2er Teams zusammen an der Übung arbeiten. Jeden Schritt gemeinsam
 besprechen und gegenseitig prüfen. Bei Fehlern beim Backup kann
 später der Laptop nicht wiederhergestellt werden und muss neu
 installiert werden.
 
 Erst ein Backup eines Laptops auf den Laptop des anderen
 Team-Mitglieds durchführen. Danach diesen Laptop unbrauchbar machen
 und wiederherstellen. Nach erfolgreicher Wiederherstellung die Rollen
 tauschen und den anderen Laptop Sichern, unbrauchbar machen und
 wiederherstellen.
 
Subvolumes welche gesichert werden:
   /
   /home
   /opt
   /srv
   /var
   /root
   /usr/local
   /tmp
   /boot/grub2/x86_64-efi
   /boot/grub2/i386-pc
 
Beispiel Datei /etc/fstab nach Wiederherstellung
 
/dev/nvme0n1p3  /                        btrfs  defaults                          0  0
/dev/nvme0n1p3  /.snapshots              btrfs  subid=279               0  0
/dev/nvme0n1p3  /var                     btrfs  subvol=var                     0  0
/dev/nvme0n1p3  /usr/local               btrfs  subvol=usr-local               0  0
/dev/nvme0n1p3  /tmp                     btrfs  subvol=tmp                     0  0
/dev/nvme0n1p3  /srv                     btrfs  subvol=srv                     0  0
/dev/nvme0n1p3  /root                    btrfs  subvol=root                    0  0
/dev/nvme0n1p3  /opt                     btrfs  subvol=opt                     0  0
/dev/nvme0n1p3  /home                    btrfs  subvol=home                    0  0
/dev/nvme0n1p3  /boot/grub2/x86_64-efi   btrfs  subvol=x86_64-efi   0  0
/dev/nvme0n1p3  /boot/grub2/i386-pc      btrfs  subvol=i386-pc      0  0
 
/dev/nvme0n1p1  /boot/efi       vfat    rw      0       2
/dev/nvme0n1p2  none    swap    sw      0       0
 
BTRFS
 1) Erstelle ein RAID 10 (Stipe of Mirror) ueber die Partitionen 4-7 (4 Geräte)
    mkfs.btrfs -f -m raid10 -d raid10 /dev/nvme0n1p4 /dev/nvme0n1p5 /dev/nvme0n1p6 /dev/nvme0n1p7
 2) Erstelle einen Eintrag in der Datei /etc/fstab welche dieses BTRFS Dateisystem nach /srv/data
    einhängt. Dabei sollen die Daten per 'zstd' Algorithmus transparent komprimiert werden
    /dev/nvme0n1p4      /srv/data     btrfs    compress=zstd   0 0
 3) Teste den Eintrag in der Filesystem-Tabelle (kann das Dateisystem angehangen werden?)
    mount -a
 4) Führe ein Reboot des Laptops durch. Prüfe nach dem Reboot, das /srv/data eingehangen ist
 5) Das Dateisystem sollte eine Kapazität von ~4GB (unkomprimiert) besitzen. Teste die Komprimierung, 
    eine neue Datei von 6 GB bestehend aus vielen NULL Bytes erstellt wird (sollte ideal komprimiert werden) 
    dd if=/dev/zero of=/srv/data/grosse-datei-mit-nullen.dat bs=1M count=6000
 6) Vergleiche die Ausgaben dieser Befehle
    df -Th
    du -sh /srv/data
    btrfs filesystem show /srv/data
    btrfs filesystem usage /srv/data
    btrfs filesystem df /srv/data
 
BTRFS Quota
 1) Erstelle ein Subvolume /srv/data/subvol
    btrfs subvol create /srv/data/subvol
 2) Schalte Quota-Support für dieses BTRFS Dateisystem an
    btrfs quota enable /srv/data
 3) Setze ein Limit von 100 MB auf das neue Subvolume
    btrfs qgroup limit 100M /srv/data/subvol
 4) Test des Quota (Schreibe eine neue 150 MB Datei)
    dd if=/dev/urandom of=/srv/data/subvol/test.dat bs=1M count=150
 5) Der Test sollte mit eine "Quota exceeded" Fehlermeldung abbrechen
 
Logical Volume Management
 1) Finde die Dokumentation zu LVM im Linuxhotel Wiki https://wiki.lab.linuhotel.de/
 2) Hänge das BTRFS Dateisystem aus /srv/data aus
 3) Benutze den Befehl 'wipefs' (siehe Wiki) um die BTRFS Dateisysteme von Partition 4-7 zu löschen
 4) Erstelle ein neues PV (Physical Volume) auf Partition 4
 5) Erstelle eine neue Volume Group auf dem PV
 6) Erstelle ein Logical Volume (LV) von 1GB in der Volume Group
 7) Formatiere das Logical Volume mit dem XFS Dateisystem (mkfs.xfs /dev/...)
 8) Binde dieses LV unter /srv/data ein (mount)
 9) Vergrössere das LV im laufenden Betrieb um 500 MB
 10) Lege ein 2tes PV auf der Partition 5 an
 11) Füge diese 2te PV der Volume Group hinzu
 12) Wandle das Logical Volume in ein RAID1 (Mirror) um
 13) Binde das LV in die Datei /etc/fstab ein (ersetze die alte BTRFS Konfiguration-Zeile)
 14) Teste die Filesystem-Tabelle mit "mount -a"
 15) Teste ein Reboot des Laptops. Das Dateisystem auf dem LV sollte automatisch unter /srv/data eingehangen sein
     (mit "mount" oder "df -TH" testen)
 
Übung: CUPS Netzwerk-Druckdienst
 1) Der CUPS Netzwerkdruckdienst läuft unter Suse nur auf der Loopback-Schnittstelle
    Wir wollen die CUPS Konfiguration ändern, so das der Dienst auch über das Netzwerk erreichbar ist
 2) In der Datei /etc/cups/cupsd.conf den Befehl "Listen 127.0.0.1:631" so ändern, das der Dienst auch
    auf alle Netzwerkschnittstellen horcht
    Listen 0.0.0.0:631
 3) In der Datei /etc/cups/cupsd.conf für die Lokation (Location) "/" das Netz 192.168.1.0/24 erlauben
    <Location />
      Order allow,deny
      Allow from 192.168.1.*
    </Location>
 4) Datei sichern und den CUPS-Dienst neu starten
    systemctl restart cups
    systemctl status cups
 5) Prüfen, das der Cups-Prozess nun auf allen IPv4 Adressen Daten entgegennimmt (Port 631)
    lsof -Poni :631
 6) Einen anderen Teilnehmer bitten, mit dem Firefox auf die eigene IP-Adresse auf Port 631 zu verbinden
    http://192.168.1.2XX:631
    Dies sollte noch nicht möglich sein, da die Firewall die Verbindung unterbindet
 7) Port 631 in der Firewall freischalten
    firewall-cmd --add-port=631/tcp
    firewall-cmd --add-port=631/tcp --permanent
 8) Nochmals von einem anderen Rechner aus testen. Nun sollte die CUPS Admin Webseite erscheinen
 
Übung: NGINX Webserver
  1) Installiere den NGINX Webserver aus den Suse Paketquellen
  2) Passe die NGINX Konfiguration an, so das der Webserver auf der IP-Adresse des Laptops (Port 80) horcht
  3) Erstelle eine einfache HTML Webseite für den Webserver
  4) Erlaube den Webserver (per Port oder per Service) in der Firewall
  5) Starte den NGINX Webserver Dienst, stelle sicher das der Dienst erfolgreich gestartet wurde
  6) Lasse die Webseite von einem anderen Teilnehmer per http://192.168.1.2XX/ testen
 
Übung zu RSyslog:
 
 1) Erzeuge eine neue Syslog-Regel-Datei unter /etc/rsyslog.d mit der Dateiendung ".frule".
    Diese Regel soll alle Log-Meldungen der Facility (Anwendung) "local3" und der Wichtigkeit (Severity) "info"
    in die Datei /var/log/mylogfile.log schreiben
 
Lösung:  local3.info      -/var/log/mylogfile.log
 
 2) Den RSyslog-Dienst neu starten
    systemctl restart rsyslog
 3) Lese die "man-page" Dokumentation zum Befehl "logger". Sende eine oder mehrere Log-Meldungen mit dem Befehl "logger"
    mit der Facility "local3" und der Severity "info". Prüfe das diese Log-Informationen in der Log-Datei /var/log/mylogfile.log
    erscheinen
 4) Schaue die Konfigurationsdatei /etc/rsyslog.d/remote.conf im Text-Editor an. Erstelle eine Regel in dieser Datei, welche
    die Log-Meldungen der Facility "local3" (jede Severity) via UDP an den Laptop des Trainers (192.168.1.246) zum Syslogport (514) sendet
 
Lösung: local3.*        @192.168.1.246
 
 5) Starte den Dienst RSyslog neu
 6) Sende eine Log-Meldung für die Facility "local3" mit dem Befehl "logger"
 7) Schaue das diese Log-Meldung am Bildschirm des Trainers angezeigt wird
 
SSH mit Schlüssel
 
 1) Erstelle ein SSH-Schlüsselpaar auf dem Client (eigenes
    Notebook). Bestaetige den Pfad der Schlüssel-Dateien und vergebe eine
    Passphrase (langes Passwort). Der private Schlüssel wird mit diesem
    Passwort verschlüsselt
    ssh-keygen -t ed25519
 2) Port 22 (SSH) in der Firewall auf dem Laptop freischalten
    firewall-cmd --add-service=ssh --permanent
    firewall-cmd --reload
 3) Sicherstellen das der SSH-Dienst gestartet ist
    systemctl status sshd
 4) Den eigenen öffentlichen SSH-Schlüssel auf den entfernten Rechner (Laptop
    des Partner-Teilnehmers) kopieren (XX=Nummer des Partner-Teilnehmers)
    ssh-copy-id nutzerXX@192.168.1.2XX
 5) SSH-Verbindung testen. Statt des Passwortes sollte nun die Passphrase des
    privaten Schlüssels gefragt werden
    ssh nutzerXX@192.168.1.2XX
 6) Wenn die Anmeldung des Partner-Teilnehmers per SSH-Schlüssel am eigenen
    Laptop funktioniert, dann in der SSH-Dienst Konfiguration die
    Passwort-Anmeldung deaktivieren. In der Datei /etc/ssh/sshd_config
    Alt -> PasswordAuthentication yes / UsePAM yes
    Neu -> PasswordAuthentication no  / UsePAM no
 7) SSH-Dienst neu starten
    systemctl restart sshd
 8) Den Partner-Teilnehmer bitten, die Anmeldung per Schlüssel zu testen. Wenn
    die Anmeldung per Schlüssel funktioniert, die Gegenprobe durchführen
    (Anmeldung per Passwort). Für die Gegenprobe versuchen sich am Rechner per
    SSH mit einem unbekannten Benutzer anzumelden (es sollte nicht nach einem
    Passwort Gefragt werden):  ssh unbekannt@192.168.1.2XX  
 
SSH mit SSH-Agent
 0) Lokalen SSH-Agent laden (gilt nur in der aktuellen Shell, notwenig wenn
    man nicht als an der grafischen Oberfläche angemeldeter Benutzer in der
    Shell arbeitet)
    eval $(ssh-agent)
 1) Privater Schlüssel in den SSH-Agent laden
    ssh-add
 2) Schlüssel im Agent auflisten
    ssh-add -l
 3) Wenn nun eine SSH Verbindung mit Schlüssel aufgebaut wird, so wird nicht
    mehr nach der Passphrase gefragt. Bitte einmal ausprobieren
    ssh nutzerXX@192.168.1.2XX
 4) SSH-Agent mit einem Passwort sperren (z.B. wenn man den Laptop einige Zeit
    unbeaufsichtigt lässt)
    ssh-add -x
 5) SSH-Agent wieder entsperren (grosses 'X')
    ssh-add -X
 6) Alle Schlüssel aus dem SSH-Agent löschen
    ssh-add -D