Automatisierter Container-Import mit Podman

28 Mai 2025 Lesezeit: 3 Minuten

Container-Workflows bestehen aus vielen kleinen Schritten – besonders wenn Images aus einer Backup- oder Build-Strecke geliefert werden und vorbereitet in eine Registry wandern sollen. Manuell ist das fehleranfällig und lästig. Umso schöner, wenn sich der Prozess mit einem einfachen Bash-Skript automatisieren lässt.

Hier ein kleiner Helfer aus dem Werkzeugkasten: Ein Skript, das aus einem Verzeichnis heraus Container-Images im .tar.gz-Format entpackt, importiert, auf Basis des Dateinamens taggt – und optional auch gleich in eine Registry pusht.


Was das Skript erledigt:

  • Erstellt temporäre Verzeichnisse für Verarbeitung und Podman-Storage
  • Entpackt alle .tar.gz-Container-Backups
  • Erwartet eine klare Namenskonvention: imagename_tag.hash.tar.gz
  • Nutzt podman mit eigenem Storage-Verzeichnis zum Importieren
  • Liest die Image-ID beim Import direkt aus
  • Taggt das Image mit einem Remote-Namen für eine Registry
  • Optional kann das Image direkt gepusht werden (Push-Zeile aktuell auskommentiert)

Namenskonvention

Ein wichtiger Aspekt: Das Skript basiert auf einem regulären Ausdruck zur Trennung von Image-Namen und Tags aus dem Dateinamen. Beispiel:

nginx_1.21.6.abc1234.tar.gz

wird zu:

  • Image: nginx
  • Tag: 1.21.6
  • Hash: ignoriert (nur zur Erkennung im Dateinamen)

Damit das funktioniert, muss der Dateiname dem Muster folgen: name_tag.hash.tar(.gz)

#!/bin/bash

set -e

REGISTRY=""
IMAGE_DIR=""
export TMP_DIR="$IMAGE_DIR/TEMP"
STORAGE_DIR="$IMAGE_DIR/storage"

mkdir -p "$TMP_DIR" "$STORAGE_DIR"

cd "$IMAGE_DIR"

# Entpacke alle .tar.gz-Dateien mit gunzip
if ls *.tar.gz 1> /dev/null 2>&1; then
    for archive in *.tar.gz; do
        gunzip "$archive"
    done
else
    echo "Keine .tar.gz-Dateien gefunden."
fi

# Importiere, tagge und pushe jedes Image
for tarfile in "$IMAGE_DIR"/*.tar; do
    filename=$(basename "$tarfile" .tar)

    if [[ $filename =~ ^([a-zA-Z0-9\-]+)_([0-9a-zA-Z._\-]+)\.[a-z0-9]{7,}$ ]]; then
        name="${BASH_REMATCH[1]}"
        tag="${BASH_REMATCH[2]}"
        echo "Image-Name: $name"
        echo "Tag:        $tag"
    else
        echo "Dateiname $filename entspricht nicht dem erwarteten Muster"
        continue
    fi

    image_local="${name}:${tag}"
    echo $image_local
    image_remote="${REGISTRY}/${image_local}"
    echo $image_remote
    image_id=$(podman --root "$STORAGE_DIR" load -i "$tarfile" 2>&1 | awk '/^Copying config / { print $3 }')
    echo $image_id
    podman --root "$STORAGE_DIR" tag "$image_id" "$image_remote"
    podman --root "$STORAGE_DIR" push "$image_remote"
done

Das Servicemesh des kleinen Mannes

14 Mai 2025 Lesezeit: 3 Minuten

Manchmal braucht’s kein großes Servicemesh mit fancy features, keine fancy Sidecars und kein full-blown Istio, linkerd, consul oder so.
Manchmal reicht einfach nur stunnel – das gute alte Schweizer Taschenmesser für TLS-Tunnel.
Ein "Servicemesh des kleinen Mannes" eben. Einfach, stabil, unauffällig.


Worum geht’s?

Wenn Services im internen Netz unverschlüsselt sprechen, aber man Transportverschlüsselung für eine ertifizierung braucht (und es eigentlich ohne nicht mehr Zeitgemäß ist – ohne alles neu zu erfinden –, dann hilft ein einfacher Trick:

Loopback + stunnel = TLS

Die Idee:

  • Die App redet über localhost, denkt also, alles ist wie immer.
  • stunnel nimmt die Daten entgegen und tunnelt sie verschlüsselt zum Gegenüber.
  • Am anderen Ende steht wieder ein stunnel, das den Datenstrom an den echten Dienst weitergibt.

Warum das Ganze?

  • TLS mit minimalem Aufwand
  • Dienste müssen nicht TLS können
  • Kein Code ändern
  • Rollout mit Ansible/Salt/etc. easy
  • PSK statt PKI möglich -> Macht es einfach zu rollieren und einzurichten

Beispiel: Frontend spricht mit Backend über stunnel

PSK-Datei (beide Seiten)

app1:supergeheimespasswort

Client (Frontend): /etc/stunnel/backend_client.conf

lient = yes
foreground = no

[backend-tls]
accept  = 127.0.0.1:23904
connect = backend.internal:23904
PSKsecrets = /etc/stunnel/psk.txt
PSKidentity = app1

Server (Backend): /etc/stunnel/backend_server.conf

client = no
foreground = no

[backend-tls]
accept  = 0.0.0.0:23904
connect = 127.0.0.1:80
PSKsecrets = /etc/stunnel/psk.txt

Immer das gleiche Prinzip. Einfach PSK setzen, Config ausrollen, fertig.

was ich daran mag ist, das man entweder mit Hilfe von Zertifikaten oder eben mittels PSK arbeiten kann. Des Weiteren kann man auch zentral eine Konfig hinterlegen und so alle notwendigen Connections bereithalten. Klar, alles ausbaufähig. Aber wie oft kann eine Anwendung nicht ordentlich oder gradlinig mit TLS umgehen oder man will es einfacher haben. Da passt stunnel ganz gut in die Werkzeugkiste.


SSH-Zugriff mit signierten Zertifikaten

13 Mai 2025 Lesezeit: 4 Minuten

Ziel

Benutzer sollen sich per SSH auf Linux-Servern anmelden können, ohne dass ihre Public Keys manuell auf jedem Server eingetragen werden müssen. Stattdessen signieren sie ihren eigenen Public Key bei einer zentralen SSH Certificate Authority (CA). Die Server akzeptieren dann automatisch alle gültigen, signierten Zertifikate.


SSH-Zertifikate

OpenSSH unterstützt neben gewöhnlichen Public Keys auch sogenannte SSH-Zertifikate. Diese funktionieren ähnlich wie TLS-Zertifikate:

  • Ein Benutzer erzeugt ein eigenes Keypair
  • Eine SSH-CA signiert den Public Key
  • Der Zielserver prüft, ob das Zertifikat gültig ist und ob die CA vertrauenswürdig ist.
  • Der Zugriff wird anhand von im Zertifikat hinterlegten Informationen (z. B. Benutzername, Ablaufzeit) gewährt oder verweigert.

Vorteile

  • Kein Deployment von Public Keys auf jedem Server
  • Zugriffskontrolle zentral über die CA
  • Zertifikate können zeitlich begrenzt werden (z. B. nur 1 Stunde gültig)
  • Prinzipal (Benutzername) wird im Zertifikat festgelegt - kein Spoofing

Einrichtung

1. CA-Schlüssel erzeugen (einmalig)

ssh-keygen -f /etc/ssh/ca_key -C "SSH CA" -t rsa

Erzeugt zwei Dateien:

  • /etc/ssh/ca_key – privater CA-Schlüssel (geheim halten)
  • /etc/ssh/ca_key.pub – öffentlicher CA-Schlüssel (wird auf Server verteilt)

2. Zielserver konfigurieren

CA Public Key auf den Server kopieren, z. B. nach /etc/ssh/ca_key.pub.

Dann in /etc/ssh/sshd_config folgenden Eintrag ergänzen:

TrustedUserCAKeys /etc/ssh/ca_key.pub
# Dienst neu starten
systemctl reload sshd

3. Benutzerkey erzeugen

Jeder Benutzer generiert lokal einen eigenen Key:

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "user@example.com"

4. Key signieren lassen

Der Benutzer sendet seinen Public Key zur Signierung an die CA. Die CA signiert den Key:

ssh-keygen -s /etc/ssh/ca_key \
  -I user@example.com \
  -n <username> \
  ~/.ssh/id_ed25519.pub

kurze Gedankenstütze: -I Identifier (frei wählbar, z. B. E-Mail) -n Principal (Benutzername auf dem Zielsystem)

Erzeugt: id_ed25519-cert.pub - die geht wieder zurückzum Benutzer.

5. Verbindung zum Server

ssh -i ~/.ssh/id_ed25519 \
    -o CertificateFile=~/.ssh/id_ed25519-cert.pub \
    user@zielserver

Oder dauerhaft in ~/.ssh/config:

Host zielserver
  HostName server.example.com
  User <username>
  IdentityFile ~/.ssh/id_ed25519
  CertificateFile ~/.ssh/id_ed25519-cert.pub

Kurzlebige Zertifikate

Warum? Weil es geil ist!

  • Reduzieren Angriffsfläche bei Kompromittierung
  • Erzwingen regelmäßige Re-Authentifizierung
  • Kein manuelles Entfernen veralteter Keys nötig

Umsetzung

Bei der Signierung wird die Gültigkeit angegeben:

ssh-keygen -s ca_key -I user -n user -V +1h user.pub

Alternativ absolute Zeitspanne:

ssh-keygen -s ca_key -I user -n user -V "20250513T100000:20250513T180000" user.pub

Das wiederum würde sich auch ganz gut eigenen um sich automatisieren zu lassen. Webportal oder CLI für Benutzer, um ein Zertifikat per SSO oder Token zu erhalten