From ea502d74a9ffed286ac00dd671ff772752f46646 Mon Sep 17 00:00:00 2001 From: "Patrick Asmus (scriptos)" Date: Fri, 23 Oct 2026 19:55:11 +0200 Subject: [PATCH] Initial commit: Bastillion 6 Dockerfile, Multi-Arch CI/CD Workflow & Compose --- .dockerignore | 6 + .gitea/workflows/build-and-release.yaml | 139 +++++++++++++++++++++++ .gitignore | 5 + Dockerfile | 48 ++++++++ LICENSE | 17 +++ README.md | 144 ++++++++++++++++++++++++ docker-compose.yaml | 50 ++++++++ 7 files changed, 409 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitea/workflows/build-and-release.yaml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 docker-compose.yaml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..987d4f6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.git +.gitea +.github +data/ +*.log +*.tmp diff --git a/.gitea/workflows/build-and-release.yaml b/.gitea/workflows/build-and-release.yaml new file mode 100644 index 0000000..d6f074f --- /dev/null +++ b/.gitea/workflows/build-and-release.yaml @@ -0,0 +1,139 @@ +# Bastillion Docker CI/CD - Upstream Release Watcher & Multi-Arch Build +# Prüft regelmäßig auf neue Releases von Loophole-LLC/Bastillion und baut +# Multi-Arch Images (linux/amd64 & linux/arm64) für die Container Registry. +name: Upstream Release Watcher & Multi-Arch Build + +on: + schedule: + # Alle 6 Stunden prüfen + - cron: '0 */6 * * *' + push: + branches: + - main + paths: + - 'Dockerfile' + - '.gitea/workflows/**' + workflow_dispatch: + inputs: + force_version: + description: 'Spezifische Bastillion-Version erzwingen (z. B. 6.0.3) oder leer für neueste' + required: false + default: '' + +env: + IMAGE_NAME: bastillion + UPSTREAM_REPO: Loophole-LLC/Bastillion + +jobs: + check-and-build: + name: Check & Build Docker Image + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Determine upstream version + id: version_check + run: | + set -e + if [ -n "${{ inputs.force_version }}" ]; then + TAG="v${{ inputs.force_version }}" + TAG="v${TAG#v}" + VERSION="${TAG#v}" + echo "Manuelle Version vorgegeben: ${VERSION}" + else + echo "Frage neuestes Release von GitHub (${UPSTREAM_REPO}) ab..." + RELEASE_JSON=$(curl -sSL "https://api.github.com/repos/${UPSTREAM_REPO}/releases/latest") + TAG=$(echo "$RELEASE_JSON" | grep -m 1 '"tag_name":' | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/') + if [ -z "$TAG" ] || [ "$TAG" = "null" ]; then + echo "::error::Konnte neuestes Release von ${UPSTREAM_REPO} nicht ermitteln." + exit 1 + fi + VERSION="${TAG#v}" + echo "Neuestes Upstream-Release gefunden: ${TAG} (Version: ${VERSION})" + fi + + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + + # Prüfen, ob dieses Git-Tag im lokalen Repo bereits existiert + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Tag ${TAG} existiert bereits im Repository." + if [ "${{ github.event_name }}" = "schedule" ]; then + echo "Kein neues Release vorhanden. Workflow beendet." + echo "should_build=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "Build wird trotz existierendem Tag fortgesetzt (Event: ${{ github.event_name }})." + fi + + echo "should_build=true" >> "$GITHUB_OUTPUT" + + # Registry-URL ermitteln (Fallback auf aktuellen Server / Host) + REGISTRY="${{ vars.REGISTRY_URL || github.server_url }}" + REGISTRY="${REGISTRY#https://}" + REGISTRY="${REGISTRY#http://}" + echo "registry=${REGISTRY}" >> "$GITHUB_OUTPUT" + + - name: Set up QEMU + if: steps.version_check.outputs.should_build == 'true' + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + if: steps.version_check.outputs.should_build == 'true' + uses: docker/setup-buildx-action@v3 + + - name: Login to Container Registry + if: steps.version_check.outputs.should_build == 'true' + uses: docker/login-action@v3 + with: + registry: ${{ vars.REGISTRY_URL || github.server_url }} + username: ${{ secrets.REGISTRY_USER || github.actor }} + password: ${{ secrets.REGISTRY_TOKEN || secrets.GITHUB_TOKEN }} + + - name: Build & Push Multi-Arch Docker Image + if: steps.version_check.outputs.should_build == 'true' + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + build-args: | + BASTILLION_VERSION=${{ steps.version_check.outputs.version }} + tags: | + ${{ steps.version_check.outputs.registry }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:latest + ${{ steps.version_check.outputs.registry }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ steps.version_check.outputs.version }} + ${{ steps.version_check.outputs.registry }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ steps.version_check.outputs.tag }} + labels: | + org.opencontainers.image.title=Bastillion + org.opencontainers.image.description=Modern web-based SSH console and key management tool + org.opencontainers.image.version=${{ steps.version_check.outputs.version }} + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} + + - name: Create Git Tag and Release + if: steps.version_check.outputs.should_build == 'true' + run: | + TAG="${{ steps.version_check.outputs.tag }}" + VERSION="${{ steps.version_check.outputs.version }}" + API_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases" + + echo "Erstelle Release ${TAG}..." + PAYLOAD=$(cat < [!IMPORTANT] +> **Sofortige Maßnahmen nach dem ersten Login:** +> 1. Passwort ändern unter **Settings → Change Password**. +> 2. Zwei-Faktor-Authentifizierung (TOTP) unter **Settings** für den Admin-Account aktivieren. + +--- + +## ⚙️ Wichtige Umgebungsvariablen + +| Variable | Standard | Beschreibung | +| :--- | :--- | :--- | +| `CONFIG_DIR` | `/data` | Zentraler Ordner für H2-Datenbank, Keystores und SSH-Schlüssel. | +| `PORT` | `8080` | Interner HTTP/HTTPS Listen-Port. | +| `TLS_ENABLED` | `false` | `false` für Betrieb hinter Reverse Proxy (Traefik/Nginx); `true` für direktes SSL. | +| `GEN_DB_PASS` | `true` | Erzeugt beim Erststart automatisch ein kryptografisch sicheres H2-DB-Passwort. | +| `CLIENT_IP_HEADER` | `X-Forwarded-For` | Liest die echte Client-IP aus dem Proxy-Header für Audit-Logs. | +| `KEY_MANAGEMENT` | `manage` | Modus für `authorized_keys` (`manage`, `append` oder `off`). | + +--- + +## 💾 Backup & Wiederherstellung + +Da Bastillion durch `CONFIG_DIR=/data` alle Zustände (H2-Datenbank, SSH-Keypair, Einstellungen) an einem Ort bündelt, reicht eine einfache Dateisicherung: + +```bash +# Backup des Datenordners erstellen +tar -cpzf bastillion_backup_$(date +%Y%m%d_%H%M%S).tar.gz ./data +``` + +--- + +## 🔄 Automatisierter Release-Watcher + +Dieses Repository nutzt CI/CD Actions, um alle 6 Stunden die offizielle [Loophole-LLC Bastillion Release API](https://github.com/Loophole-LLC/Bastillion/releases) abzufragen. + +Sobald ein neues Upstream-Tag erscheint, baut die Pipeline vollautomatisch Multi-Arch Images (`linux/amd64` und `linux/arm64`) und pusht sie in die Container Registry. + +--- + +## 📜 Lizenz + +* Bastillion steht unter der **Prosperity Public License 3.0.0** von [Loophole, LLC](https://loophole.company/). +* Das Docker-Packaging und die CI/CD-Skripte sind unter der **Apache 2.0 Lizenz** veröffentlicht. diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..f735302 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,50 @@ +version: "3.8" + +services: + bastillion: + image: bastillion:latest + container_name: bastillion + hostname: bastillion + restart: unless-stopped + networks: + bastillion_net: + ipv4_address: 172.28.0.10 + volumes: + - ./data:/data + environment: + # Konsolidiertes Datenverzeichnis (H2 DB, Keystore, SSH Keys) + - CONFIG_DIR=/data + # Interner HTTP-Port (hinter Reverse Proxy) + - PORT=8080 + # Intern unverschlüsselt (Reverse Proxy übernimmt HTTPS & Zertifikate) + - TLS_ENABLED=false + # Automatisches Generieren des DB-Passworts beim ersten Start + - GEN_DB_PASS=true + # Client-IP-Header für echte Quell-IPs in den Audit-Logs + - CLIENT_IP_HEADER=X-Forwarded-For + # Zeitzone + - TZ=Europe/Berlin + labels: + - "traefik.enable=true" + # HTTP zu HTTPS Redirect + - "traefik.http.routers.bastillion-http.rule=Host(`bastillion.example.com`)" + - "traefik.http.routers.bastillion-http.entrypoints=web" + - "traefik.http.routers.bastillion-http.middlewares=redirect-to-https@file" + # HTTPS Router + - "traefik.http.routers.bastillion.rule=Host(`bastillion.example.com`)" + - "traefik.http.routers.bastillion.entrypoints=websecure" + - "traefik.http.routers.bastillion.tls=true" + - "traefik.http.routers.bastillion.tls.certresolver=letsencrypt" + - "traefik.http.routers.bastillion.service=bastillion-svc" + - "traefik.http.services.bastillion-svc.loadbalancer.server.port=8080" + +networks: + bastillion_net: + name: bastillion.dockernetwork.local + driver: bridge + ipam: + driver: default + config: + - subnet: 172.28.0.0/24 + gateway: 172.28.0.1 + ip_range: 172.28.0.128/25