tp-link Omada Controller auf Raspberry Pi installieren

In Anlehnung an die Anleitung hier die Kommandos (Raspberry 4 mit 4 GB RAM, unter 2 eher schmerzhaft, Debian 11):

sudo apt update && sudo apt upgrade
#--------------- MONGODB -------------------
wget https://repo.mongodb.org/apt/ubuntu/dists/focal/mongodb-org/4.4/multiverse/binary-arm64/mongodb-org-server_4.4.18_arm64.deb

sudo dpkg -i mongodb-org-server_4.4.18_arm64.deb

sudo systemctl daemon-reload
sudo systemctl enable mongod
sudo systemctl start mongod

#--------------- JAVA (JDK) ----------------
sudo apt install openjdk-17-jdk-headless

#--------------- JSVC BUILD ----------------
sudo apt install autoconf make gcc
wget https://dlcdn.apache.org/commons/daemon/source/commons-daemon-1.3.4-src.tar.gz
tar xvfz commons-daemon-1.3.4-src.tar.gz
cd src/native/unix
sh support/buildconf.sh
./configure --with-java=/usr/lib/jvm/java-17-openjdk-arm64
make
sudo cp jsvc /usr/bin/

#---------------- OMADA -------------------
#Liste: https://www.tp-link.com/de/support/download/omada-software-controller/
wget https://static.tp-link.com/upload/software/2024/202401/20240112/Omada_SDN_Controller_v5.13.23_linux_x64.deb

sudo dpkg -i --ignore-depends=jsvc Omada_SDN_Controller_v5.13.23_linux_x64.deb

Das letzte dpkg -i sollte den Controller auch gleich starten (Zugriff über Port 8088). Sonst mit sudo tpeap start/stop/status/version steuerbar.

Software, Logs und Configs unter /opt/tplink/EAPController.

Update 2: Versionsupdate ausschließlich das letzte dpkg -i Kommando (inklusive dependency-ignore); macht Stopp, erkennt vorhandene Daten und wirft anschließend wieder an.

ffmpeg Fenster oder single Desktop aufzeichnen

Weil mir die Sucherei jedes mal auf die Nerven geht:

ffmpeg -f gdigrab -framerate 30 -i title="Fenstertitel" -b:v 3M -pix_fmt yuv420p video.mp4

Der einfachste Weg die verfügbaren Fenstertitel kann man über das EXE mit folgender Commandline rausfinden (hier am Beispiel Chrome):

tasklist /v /fi "imagename eq chrome.exe" /fo list|findstr "Window"
(oder "Fenster" auf deutschem System)

Problematisch wirds bei Firmen die meinen irgendwelche in CMD nicht vernünftig übertragbare Zeichen im Fenstertitel haben zu müssen, oder Microsoft? ODER???

Bei Multimonitor kann man das Video um die nicht gewünschten Teile erleichtern, Syntax ist

videobreite:videohöhe:xstart:ystart

bei einem Setup mit 3 1920×1200 Monitoren wäre der volle mittlere Monitor also:

ffmpeg -f gdigrab -framerate 30 -i desktop -vf crop=1920:1200:1920:0 -b:v 3M -pix_fmt yuv420p video.mp4

Cross podman-compose Namensauflösung

Annahme: Zwei Verzeichnisse mit docker-compose.yaml die mit podman-compose ins Leben gerufen werden.

Defaultverhalten: Selbst bei Angabe von “networks:” im docker-compose.yaml sehen sich die zwei Deployments nicht weil sie in zwei Podman Netzwerken erzeugt werden. Die Netzwerke werden immer mit dem Verzeichnisnamen prefixiert (podman network ls).

Ziel: Container aus Deployment A sollen Container aus Deployment B namensmäßig auflösen und auch netzwerkmäßig erreichen können.

Lösung: Identen Projektnamen beim Aufruf von podman-compose für beide Deployments angeben

podman-compose -p meinprojekt up -d

❗ Sollten networks: im yaml verwendet werden müssen die Container die miteinander kommunizieren sollen natürlich auch im gleichen Network sein – der Projektname ist nur der Prefix des Netzwerks.

Debian + fail2ban = Have not found any log file for sshd jail

Gemäß Issue ist das ein Problem von allen systemd-basierten Distros die nur mehr in journald loggen – in /etc/fail2ban/jail.local in Sektion [DEFAULT] das Setting backend auf systemd setzen:

# /etc/fail2ban/jail.local 
# (gemäß Doku von /etc/fail2ban/jail.conf kopiert)

[DEFAULT]
backend = systemd

[sshd]
enabled = true

Damit das funktioniert muss man noch folgendes Paket installieren:

sudo apt install python3-systemd

Wie man im Issue auch nachlesen kann bringt das natürlich alle Jails um die in Logfiles suchen wollen 😐

Inter-Container Kommunikation mit rootless podman auf Debian

Notwendige Pakete für podman

podman
slirp4netns
uidmap
podman-compose

Danach am besten Reboot weil sonst a) die subuids/subguids von uidmap und b) die netns Geschichten von slirp4netns nicht greifen und podman-compose auf die Nase fliegt mit “podman failed to mount runtime directory for rootless netns” failed.

Aber – damit können zwei Container noch nicht miteinander kommunizieren. Podman benutzt dann per default CNI als Netzwerkmethode und das überall beschriebene Paket “podman-plugins” gibts auf Debian offenbar nicht (erlebt auf bookworm), das notwendige Paket mit dem plugin “dnsname” (landet dann auf /usr/lib/cni/) heißt

golang-github-containernetworking-plugin-dnsname

Das installiert eben das dnsname CNI plugin und auch dnsmasq-base damit Inter-Container DNS Lookups darüber geführt werden können.

Das alleine hilft aber noch nicht weil das Default Netzwerk “podman” (podman network ls) hat DNS lookups nicht enabled (podman network inspect podman – Property “dns_enabled” steht auf false).

Erzeugt man aber nach der Installation vom DNSNAME plugin ein Netzwerk hat dieses dns_enabled=true, entweder auf der commandline

podman create network whatevernet
podman run whatever:latest --net whatevernet

oder im compose file als network:

networks:
   whatevernet:


services:
   whatever:
      image: whatever:latest
      networks:
         - whatevernet

UPDATE

Keine Ahnung warum mein podman mit CNI als Netzwerkbackend installiert wurde aber seit 4.0 sollte eigentlich netavark Default sein – welches das alles out of the box kann. Umstellung:

  • podman system reset
    (Reboot um Reste zu entfernen)
  • sudo cp /usr/share/containers.conf /etc/containers/
  • unter [network] Eintrag network_backend entkommentieren und auf “netavark” setzen
  • sudo apt install netavark
  • sudo apt install aavark
  • podman info | grep networkBackend
    (sollte netavark sein)

Custom Moniker (URL Protocol) erzeugen

Um ein beliebiges Programm über eine URL zu starten braucht es nicht viel, am Beispiel outlook:// für überraschenderweise Outlook:

Für den User:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\SOFTWARE\Classes\outlook]
@="URL:outlook"
"URL Protocol"=""
"EditFlags"=dword:00000002
"Source Filter"="{E436EBB6-524F-11CE-9F53-0020AF0BA770}"

[HKEY_CURRENT_USER\SOFTWARE\Classes\outlook\shell]

[HKEY_CURRENT_USER\SOFTWARE\Classes\outlook\shell\open]

[HKEY_CURRENT_USER\SOFTWARE\Classes\outlook\shell\open\command]
@="outlook.exe"

Oder rechnerweit:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\outlook]
@="URL:outlook"
"URL Protocol"=""
"EditFlags"=dword:00000002
"Source Filter"="{E436EBB6-524F-11CE-9F53-0020AF0BA770}"

[HKEY_CLASSES_ROOT\outlook\shell]

[HKEY_CLASSES_ROOT\outlook\shell\open]

[HKEY_CLASSES_ROOT\outlook\shell\open\command]
@="outlook.exe"

Kubernetes: Autoimageupdate mit keel.sh mit private Registry mit custom Root CA

ConfigMap für keel.sh für die custom Root CA erzeugen

apiVersion: v1
kind: ConfigMap
metadata:
  name: ca-gallauner
  namespace: "keel"
data:
   ca-gallauner.pem: |
     -----BEGIN CERTIFICATE-----
     ....
     -----END CERTIFICATE-----

keel.sh via YAML installieren

  • Basic Auth für Dashboard (PortForward 9300 von Pod)
  • ConfigMap für CA mounten
      containers:
        - name: keel
          image: "keelhq/keel:latest"
          imagePullPolicy: Always
          command: ["/bin/keel"]
          env:
            - name: NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            # Basic auth (to enable UI/API)
            - name: BASIC_AUTH_USER
              value: "admin"
            - name: BASIC_AUTH_PASSWORD
              value: "admin"
            # Enable insecure registries
            - name: INSECURE_REGISTRY
              value: "false"
          ports:
            - containerPort: 9300
          livenessProbe:
            httpGet:
              path: /healthz
              port: 9300
            initialDelaySeconds: 30
            timeoutSeconds: 10
          resources:
            limits:
              cpu: 100m
              memory: 128Mi
            requests:
              cpu: 50m
              memory: 64Mi
          volumeMounts:
          - name: ca-gallauner
            mountPath: /etc/ssl/certs/ca-gallauner.pem
            subPath: ca-gallauner.pem
            readOnly: false
      volumes:
      - name: ca-gallauner
        configMap:
          name: ca-gallauner

keel.sh Annotations im Zieldeployment einfügen

    metadata:
      labels:
        app: homer
      annotations:
        keel.sh/policy: all
        keel.sh/trigger: poll
        keel.sh/pollSchedule: "@every 1m"
        keel.sh/approvals: "0"

Private Registry mit Custom Root CA in Kubernetes benutzen

In Kubernetes ImagePullSecret erzeugen:

kubectl create secret docker-registry myregistry --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>

Im Pod/Deployment imagePullSecret hinzufügen

    spec:
      containers:
      - name: nginx
        image: myregistry/gallauner/homer:latest
      ports:
        - containerPort: 443
      imagePullSecrets:
      - name: myregistry

Gitea+Actions zum vollelektrischen Containerupdate hinter Proxy

Gitea von Binary installieren: https://docs.gitea.com/installation/install-from-binary

  • Debian nach eigenem Standard
  • git installieren
  • User “git” erzeugen
  • Verzeichnisse unter /var/lib/gitea erzeugen und schützen
  • /etc/gitea erzeugen und schützen
  • passendes gitea von https://dl.gitea.com/gitea/ holen, auf /usr/local/bin/ kopieren
  • systemd Unit erzeugen – https://docs.gitea.com/installation/linux-service
  • Environment=HTTP_PROXY=xxxx einfügen
  • Environment=HTTPS_PROXY=xxxx einfügen
  • Environment=NO_PROXY=xxxx einfügen

Gitea Actions und Migrations (=Replica) über Proxy erlauben (/etc/gitea/app.ini):

[proxy]
PROXY_ENABLED = true
PROXY_URL =

[migrations]
ALLOW_LOCALNETWORKS = true
ALLOWED_DOMAINS = gitea.com

[actions]
ENABLED=true
DEFAULT_ACTIONS_URL=self
STORAGE_TYPE=local
  • HTTP_PORT, ROOT_URL, CERT_FILE, PROTOCOL für HTTPS

Notwendige actions von Gitea.com replizieren (leicht modifizierte Namen damit alles unter “actions” liegt):

  • Gitea Organisation “actions” erzeugen
  • Migration von https://gitea.com/docker/login-action auf docker-login in actions
  • Migration von https://gitea.com/docker/setup-buildx-action auf docker-setup-buildx in actions
  • Migration von https://gitea.com/docker/build-push-action auf docker-build-push in actions
  • Migration von https://gitea.com/actions/checkout auf checkout in actions

act_runner (ausführendes Organ) konfigurieren (https://docs.gitea.com/usage/actions/quickstart)

  • passendes Binary von https://dl.gitea.com/act_runner/ holen
  • auf passendem Level (Instance, Organization, Repository) Token erzeugen und Runner registrieren
  • –labels linux_x64 beim Register angeben (sollte im config.yaml unter runner:/labels stehen)
  • config erzeugen (./act_runner generate-config > config.yaml)
  • unter “runner:” Block “envs:” mit HTTP_PROXY: xxxx, HTTPS_PROXY: xxxx, NO_PROXY: xxxx einfügen
  • mit config starten: ./act_runner daemon -c ./config.yaml

Action secret GIT_ACCESS_TOKEN erzeugen

  • https://gitea-host/api/swagger#/user/userCreateToken
  • nur für single User sinnvoll weil Token vom User sein muss der git push durchführt

Action secrets für Webserverzertifikat erzeugen

  • CERT_CRT mit public key
  • CERT_KEY mit private key

Im Repository .gitea/workflows/docker.yaml erzeugen:

jobs:
  Homer-Build-and-Push-Docker-Image:
    runs-on: linux_x64
    steps:
      - run: echo "${{ gitea.actor }} did ${{ gitea.event_name }} to ${{ gitea.repository }}, branch ${{ gitea.ref }}"
      - name: Check out repository code
        uses: actions/checkout@v3
        with:
          username: ${{ gitea.actor }}
          password: ${{ secrets.GIT_ACCESS_TOKEN }}
      - run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
      - run: echo "🖥️ The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: ls ${{ gitea.workspace }}
      - name: Login docker
        uses: actions/docker-login@v2
        with:
          registry: ${{ env.DOCKER_REGISTRY }}
          username: ${{ gitea.actor }}
          password: ${{ secrets.GIT_ACCESS_TOKEN }}
      - name: Setup docker buildx
        uses: actions/docker-setup-buildx@v2
        env:
          HTTP_PROXY: ${{ env.HTTP_PROXY }}
          HTTPS_PROXY: ${{ env.HTTPS_PROXY }}
          NO_PROXY: ${{ env.NO_PROXY }}
        with:
           driver-opts: |
             env.http_proxy=${{ env.HTTP_PROXY }}
             env.https_proxy=${{ env.HTTPS_PROXY }}
             "env.no_proxy='${{ env.NO_PROXY }}'" 
           config-inline: |
             [registry."${{ env.DOCKER_REGISTRY }}"]
               ca=["/etc/docker/certs.d/${{ env.DOCKER_REGISTRY }}/GallaunerCA.crt"]             
      - name: Build and push docker image
        uses: actions/docker-build-push@v4
        env:
          ACTIONS_RUNTIME_TOKEN: ''
        with:
          context: .
          push: true
          tags: ${{ env.DOCKER_REGISTRY }}/gallauner/homer
          secrets: |
             "CERT_CRT=${{ secrets.CERT_CRT }}"
             "CERT_KEY=${{ secrets.CERT_KEY }}"
      - run: echo "🍏 This job's status is ${{ job.status }}."
  • runs-on: linux_x64 entspricht dem Label vom act_runner
  • Proxywerte aus dem Environment werden für pull von Basisimages benötigt
  • Custom CA der privaten Registry wird im config-inline von docker-setup-build eingefügt
  • Zertifikat für Webserver wird über secrets von docker-build-push eingefügt (siehe Dockerfile)

Dockerfile

FROM nginx:alpine
COPY homer /usr/share/nginx/html/
RUN --mount=type=secret,id=CERT_CRT \
   cp /run/secrets/CERT_CRT /etc/ssl/certs/homer.crt
RUN --mount=type=secret,id=CERT_KEY \
   cp /run/secrets/CERT_KEY /etc/ssl/private/homer.key
COPY <<EOF /etc/nginx/conf.d/default.conf
server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/ssl/certs/homer.crt;
    ssl_certificate_key /etc/ssl/private/homer.key;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
EOF
  • durch die “secrets” in der Action können die Secrets gemounted und kopiert werden

Zertifikat mit easy-rsa erzeugen

Private key erzeugen

openssl genrsa -out myserver.key 4096

Zertifikatsrequest erzeugen

openssl req -new -key myserver.key -out myserver.req -subj "/C=AT/L=Vienna/O=Gallauner/CN=myserver.fqdn"

Request in easy-rsa importieren

./easyrsa import-req myserver.req myserver

Request in easy-rsa signieren, optional mit SAN(s) – CN wird per default als SAN eingetragen wenn –san nicht extra angegeben ist:

./easyrsa --san=DNS:myserver.fqdn,DNS:alternatename.fqdn sign-req server myserver

Ergebnis in

./pki/myserver.crt