Files
infrastructure/infrastructure
2026-01-09 15:28:44 +00:00
..
2026-01-09 15:28:44 +00:00
2026-01-09 14:08:08 +00:00
2026-01-09 15:21:30 +00:00

Infrastructure Deployment Guide

Dieses Dokument führt dich durch den kompletten Deployment-Prozess ("From Scratch") der Stabify Infrastruktur. Es erklärt sowohl das initiale Setup (Bootstrapping) als auch den automatisierten Regelbetrieb (GitOps).

Übersicht: Wie alles zusammenhängt

Wir nutzen ein GitOps Modell: Der Code in diesem Repository ist die "Source of Truth".

  • Terraform erstellt die Hardware (VMs).
  • Ansible konfiguriert die Software (Docker, Apps).
  • Vault speichert alle Geheimnisse (Passwörter, Tokens).

Der Secret-Flow (Wer bekommt Secrets woher?)

Phase Wer braucht Secrets? Woher kommen sie? Authentifizierung
1. Terraform Dein PC Vault (Remote via HTTPS) Dein VAULT_TOKEN Env-Var
2. Ansible (Push) Dein PC Vault (Remote via HTTPS) Dein VAULT_TOKEN Env-Var
3. Ansible (Pull) Die VM selbst Vault (Intern via HTTPS) Token auf der VM (/root/.vault-token)

Voraussetzungen

  • Zugriff auf Proxmox API und OPNsense API.
  • Installiert: terraform, ansible, sshpass.
  • SSH-Key für Ansible liegt bereit (z.B. ~/.ssh/id_ed25519.pub).

Phase 1: Bootstrap (Henne-Ei-Problem lösen)

Wir wollen Vault nutzen, aber Vault läuft selbst auf einer VM, die wir erst erstellen müssen. Daher müssen wir Terraform und Ansible einmalig "dumm" (ohne Vault) betreiben.

  1. Erstelle eine bootstrap.tfvars (Diese Datei NICHT committen!):

    # terraform/bootstrap.tfvars
    use_vault = false
    
    # Proxmox Credentials
    proxmox_api_url          = "https://10.100.0.2:8006/api2/json"
    proxmox_api_token_id     = "root@pam!terraform"
    proxmox_api_token_secret = "dein-proxmox-token"
    
    # OPNsense Credentials
    opnsense_uri        = "https://10.100.0.1:4443"
    opnsense_api_key    = "dein-opnsense-key"
    opnsense_api_secret = "dein-opnsense-secret"
    
    # VM User Config
    ci_user         = "ansible"
    ci_password     = "InitialPassword123!" # Wird später durch Vault ersetzt
    ssh_public_key  = "ssh-ed25519 AAAA..."
    
  2. Terraform Initialisieren & Anwenden: Dies erstellt die VMs. Da Vault noch nicht existiert, nutzen wir die lokalen Credentials.

    cd terraform
    export VAULT_ADDR="http://127.0.0.1:8200" # Dummy Wert für Bootstrap (wird ignoriert)
    terraform init
    terraform apply -var-file="bootstrap.tfvars"
    

    Ergebnis: Alle VMs (inkl. vm-docker-apps-301) sind erstellt und laufen.


Phase 2: Vault Deployment & Setup

Jetzt nutzen wir Ansible im Push-Modus, um Vault auf dem Zielserver zu installieren.

  1. Ansible Voraussetzungen:

    cd ../infrastructure/ansible
    ansible-galaxy install -r requirements.yml
    
  2. Vault Deployen (Initial): Da Vault noch nicht läuft, wird Ansible Warnungen bei Secrets werfen (Permission Denied/Connection Error), aber das Deployment durchführen und den Container starten.

    # Deploye auf alle Hosts im Inventory
    ansible-playbook -i inventory.ini deploy.yml
    
  3. Vault Initialisieren (Manuell): Der Vault Container läuft nun. Wir müssen die erzeugten Keys abholen.

    • Hole das Root Token vom Server:

      ssh -i ~/.ssh/id_ed25519_ansible_prod ansible@10.100.30.11 "sudo cat /opt/vault/file/init_keys.json"
      

      (Hinweis: Die Datei init_keys.json enthält auch die Unseal-Keys. Speichere diese sicher ab!)

    • Kopiere das Root Token (root_token aus dem JSON).

  4. Vault Befüllen (Automatisch): Führe das Helper-Skript aus, um die Secrets aus bootstrap.tfvars automatisch in Vault zu importieren.

    cd ../.. # Zurück ins Repo-Root
    ./setup_vault_secrets.sh
    
    • Du wirst nach dem Root-Token gefragt.
    • Das Skript importiert die Secrets.
    • Es fragt, ob bootstrap.tfvars gelöscht werden soll (Ja).
    • Es fragt, ob das Root-Token aus der Datei auf dem Server gelöscht werden soll (Ja, empfohlen für Security).
  5. Deployment abschließen (Apps & Secrets): Jetzt, wo Vault gefüllt ist und wir ein Token haben, lassen wir Ansible die eigentlichen Apps (z.B. Traefik) erneut deployen diesmal mit korrekten Secrets.

    cd infrastructure/ansible
    export VAULT_TOKEN='<Dein-Root-Token>'
    
    # Wichtig: Token via Variable übergeben!
    ansible-playbook -i inventory.ini deploy.yml -e "vault_token=$VAULT_TOKEN"
    

    Ergebnis: Alle Apps laufen und haben ihre korrekten .env Files.


Phase 3: Production Mode & GitOps

Ab jetzt ist die Infrastruktur "Self-Contained". Terraform und Ansible holen sich alle Zugangsdaten sicher aus dem Vault.

Terraform (Manuell bei Bedarf)

Änderungen an der Hardware (neue VMs, CPU/RAM) machst du weiterhin von deinem PC aus.

cd terraform
export VAULT_ADDR='https://10.100.30.11:8200'
export VAULT_TOKEN='<Dein-Root-Token>'
export VAULT_CACERT=../vault-ca.crt

terraform plan # Sollte "No changes" zeigen

GitOps Workflow (Automatisch)

Die Server aktualisieren ihre Apps selbstständig (Pull-Prinzip).

  1. Aktivierung (Einmalig): Das Playbook deploy.yml (aus Phase 2) hat bereits einen Systemd-Timer (gitops-sync.timer) auf allen Nodes installiert. Dieser führt alle 5 Minuten ansible-pull aus.

  2. Workflow:

    • Du machst Änderungen am Code (z.B. neue App in apps/ oder Änderung in deployments/).
    • Du pushst den gesamten Code in dein Git-Repo.
    • Innerhalb von 5 Minuten ziehen sich die Server den neuen Stand.
    • Sie führen das lokale Playbook infrastructure/ansible/pull_deploy.yml aus.
    • Dieses Playbook:
      • Installiert neue Apps.
      • Updated existierende Apps.
      • Löscht Apps, die aus der Deployment-Liste entfernt wurden (Pruning).
  3. Voraussetzung: Die Variable git_repo_url in infrastructure/ansible/deploy.yml muss korrekt gesetzt sein.


Troubleshooting

  • Fehler "Permission Denied" bei Ansible (Phase 2): Normal beim ersten Lauf, da Vault noch leer ist. Nach setup_vault_secrets.sh und einem erneuten ansible-playbook Lauf verschwinden sie.

  • Apps werden nicht gelöscht: Die Pruning-Logik greift nur im Pull-Modus (also via Timer auf dem Server), nicht beim manuellen ansible-playbook von deinem PC aus.

  • Terraform fragt nach Variablen: Prüfe, ob VAULT_ADDR und VAULT_TOKEN gesetzt sind und ob die Secrets im Vault unter den korrekten Pfaden (secret/infrastructure/...) liegen.