This page was machine-translated. Spotted a mistake?Help improve it.
Skip to content

Keamanan & Pengerasan

SnapOtter memproses file sepenuhnya di infrastruktur Anda. SnapOtter mengirim analitik produk dan laporan crash yang anonim serta bebas konten secara default untuk membantu meningkatkan proyek. SnapOtter tidak pernah mengirim file Anda, nama file, isi file, output OCR, metadata gambar, atau teks dokumen. Umpan balik opsional dikirim hanya setelah pengguna mengirimkannya, hanya ketika analitik diaktifkan, dan bidang kontak disertakan hanya dengan persetujuan kontak eksplisit. Administrator dapat mematikan penangkapan analitik dan umpan balik dalam satu klik di bawah Settings > System > Privacy, tanpa rebuild diperlukan. Pemrosesan file selalu tetap di dalam kontainer Anda.

Kontainer berjalan sebagai pengguna non-root khusus (snapotter) dengan semua kapabilitas Linux dihapus kecuali set minimum yang diperlukan. Untuk kebijakan pengungkapan kerentanan lengkap dan arsitektur keamanan, lihat SECURITY.md di GitHub.

Pengerasan Kontainer

docker-compose.yml default menyertakan pengerasan keamanan produksi. Berikut rincian setiap opsi dan mengapa itu penting:

yaml
services:
  SnapOtter:
    image: snapotter/snapotter:latest
    ports:
      # Bind to localhost only for internet-facing deployments:
      - "127.0.0.1:1349:1349"
    volumes:
      - SnapOtter-data:/data
      - SnapOtter-workspace:/tmp/workspace
    environment:
      - AUTH_ENABLED=true
      - DEFAULT_PASSWORD=change-me-immediately
      - RATE_LIMIT_PER_MIN=1000
      - DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
      - REDIS_URL=redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

    # --- Resource limits ---
    mem_limit: 6g            # Prevents runaway memory from crashing the host
    memswap_limit: 6g        # No swap - fail fast instead of degrading the host
    cpus: 4                  # Cap CPU usage to 4 cores
    pids_limit: 512          # Prevents fork bombs

    # --- Capability restrictions ---
    cap_drop:
      - ALL                  # Drop ALL Linux capabilities first
    cap_add:
      - CHOWN                # Needed for volume permission setup
      - SETUID               # Needed for gosu privilege drop (root -> snapotter)
      - SETGID               # Needed for gosu privilege drop
      - DAC_OVERRIDE         # Needed for volume permission setup
      - FOWNER               # Needed for volume permission setup

    # --- Logging ---
    logging:
      driver: json-file
      options:
        max-size: "50m"      # Rotate logs at 50 MB
        max-file: "5"        # Keep 5 rotated log files

    # --- Health check ---
    healthcheck:
      test: ["CMD", "curl", "-sf", "--max-time", "5", "http://localhost:1349/api/v1/health"]
      interval: 30s
      timeout: 5s
      start_period: 60s
      retries: 3

    shm_size: "2gb"          # Required for Python ML shared memory
    restart: unless-stopped

  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: snapotter
      POSTGRES_PASSWORD: snapotter
      POSTGRES_DB: snapotter
    volumes:
      - SnapOtter-pgdata:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U snapotter"]
      interval: 10s
      timeout: 5s
      retries: 12
      start_period: 15s

  redis:
    image: redis:8-alpine
    command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
    volumes:
      - SnapOtter-redisdata:/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 12
      start_period: 10s

volumes:
  SnapOtter-data:
  SnapOtter-workspace:
  SnapOtter-pgdata:
  SnapOtter-redisdata:

Mengapa no-new-privileges Tidak Diatur

security_opt: [no-new-privileges:true] sengaja dihilangkan. Entrypoint mulai sebagai root untuk memperbaiki kepemilikan volume, lalu turun ke pengguna snapotter melalui gosu, yang membutuhkan setuid. Setelah penurunan hak istimewa selesai, proses berjalan sebagai snapotter dengan semua kapabilitas kecuali lima yang tercantum di atas dihapus.

Jika Anda menggunakan Kubernetes atau flag --user Docker untuk berjalan sebagai non-root secara langsung (melewati gosu), no-new-privileges aman untuk diaktifkan.

Mengapa read_only Tidak Diatur

read_only: true tidak diatur karena remapping PUID/PGID menulis ke /etc/passwd dan /etc/group saat startup. Jika Anda menggunakan flag --user Docker atau runAsUser Kubernetes alih-alih PUID/PGID, Anda dapat mengaktifkan filesystem root read-only dengan aman.

Isolasi Jaringan

Selama operasi normal, kontainer membuat nol koneksi jaringan keluar. Semua pemrosesan file terjadi secara lokal menggunakan pustaka yang disertakan.

Browser  -->  Reverse Proxy (TLS)  -->  SnapOtter container  -->  (nothing)

Satu-satunya pengecualian adalah unduhan model AI: ketika pengguna memasang bundle fitur AI melalui UI, kontainer mengunduh arsip bundle yang telah dibangun sebelumnya dari Hugging Face, ditambah beberapa file model individual dari GitHub Releases, Google Storage, dan PyPI. Unduhan ini terjadi sekali per bundle dan disimpan di volume /data.

Rekomendasi firewall:

SkenarioAturan keluar
Air-gapped (tanpa AI)Blokir semua lalu lintas keluar dari kontainer
Bundle AI diperlukanIzinkan HTTPS ke huggingface.co, *.xethub.hf.co, cdn-lfs.huggingface.co, github.com, objects.githubusercontent.com, storage.googleapis.com, pypi.org, files.pythonhosted.org selama instalasi, lalu blokir
Setelah instalasi AIBlokir semua lalu lintas keluar, model di-cache secara lokal

Arsip bundle disajikan dari penyimpanan Xet Hugging Face, yang mentransfer melalui endpoint *.xethub.hf.co secara paralel dan itulah yang membuat unduhan bundle multi-GB cepat. Jika firewall Anda mengizinkan huggingface.co tetapi memblokir *.xethub.hf.co, instalasi tetap berhasil tetapi kembali ke unduhan single-stream yang lebih lambat, jadi masukkan host Xet ke allowlist agar tetap di jalur cepat. Instalasi sepenuhnya offline dapat melewati semua ini dan menggunakan Impor Bundle Offline sebagai gantinya.

Untuk konfigurasi reverse proxy (Nginx, Traefik, Caddy, Cloudflare Tunnels), lihat panduan Deployment.

Docker Secrets

Untuk deployment produksi, hindari meneruskan secret sebagai variabel lingkungan teks biasa. Entrypoint mendukung konvensi _FILE Docker: mount sebuah secret sebagai file dan atur variabel _FILE yang sesuai ke path-nya.

Secret yang didukung:

VariabelSetara _FILE
DEFAULT_PASSWORDDEFAULT_PASSWORD_FILE
COOKIE_SECRETCOOKIE_SECRET_FILE
OIDC_CLIENT_SECRETOIDC_CLIENT_SECRET_FILE
S3_ACCESS_KEY_IDS3_ACCESS_KEY_ID_FILE
S3_SECRET_ACCESS_KEYS3_SECRET_ACCESS_KEY_FILE
SNAPOTTER_LICENSE_KEYSNAPOTTER_LICENSE_KEY_FILE

Contoh dengan secret Docker Compose:

yaml
services:
  SnapOtter:
    image: snapotter/snapotter:latest
    environment:
      - AUTH_ENABLED=true
      - DEFAULT_USERNAME=admin
      - DEFAULT_PASSWORD_FILE=/run/secrets/snapotter_password
      - COOKIE_SECRET_FILE=/run/secrets/cookie_secret
    secrets:
      - snapotter_password
      - cookie_secret

secrets:
  snapotter_password:
    file: ./secrets/snapotter_password.txt
  cookie_secret:
    file: ./secrets/cookie_secret.txt

TIP

Secret Docker Compose (tanpa Swarm) membutuhkan Compose v2.23 atau lebih baru.

Deployment Kubernetes

Entrypoint mendeteksi ketika kontainer sudah berjalan sebagai non-root (misalnya, melalui runAsUser Kubernetes) dan melewati penurunan hak istimewa gosu secara otomatis. Dalam kasus itu ia tidak dapat chown volume yang di-mount sendiri, jadi ia memverifikasi bahwa volume dapat ditulis dan keluar lebih awal dengan panduan yang dapat ditindaklanjuti jika tidak, lihat Izin penyimpanan untuk penyiapan fsGroup dan UID asing (TrueNAS, OpenShift).

SecurityContext Pod yang direkomendasikan:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: snapotter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: snapotter
  template:
    metadata:
      labels:
        app: snapotter
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 999
        runAsGroup: 999
        fsGroup: 999
      containers:
        - name: snapotter
          image: snapotter/snapotter:latest
          ports:
            - containerPort: 1349
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: [ALL]
          resources:
            requests:
              cpu: "1"
              memory: 2Gi
            limits:
              cpu: "4"
              memory: 6Gi
          livenessProbe:
            httpGet:
              path: /api/v1/health
              port: 1349
            initialDelaySeconds: 60
            periodSeconds: 30
            timeoutSeconds: 5
          readinessProbe:
            httpGet:
              path: /api/v1/health
              port: 1349
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 5
          volumeMounts:
            - name: data
              mountPath: /data
            - name: workspace
              mountPath: /tmp/workspace
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: snapotter-data
        - name: workspace
          emptyDir:
            medium: Memory
            sizeLimit: 2Gi

Karena runAsUser: 999 diatur pada tingkat pod, entrypoint melewati gosu sepenuhnya. Ini memungkinkan kapabilitas allowPrivilegeEscalation: false dan drop: [ALL] tanpa konflik.

Untuk penentuan ukuran sumber daya, lihat Persyaratan Perangkat Keras.

Pencadangan dan Pemulihan

State persisten dibagi di dua volume:

VolumeIsiKritis?
SnapOtter-pgdataBasis data PostgreSQL (pengguna, pengaturan, pipeline, job, audit log)Ya
/data (volume app)File yang diunggah pengguna, model AI, venv PythonSebagian (lihat di bawah)

Di dalam volume /data:

PathIsiKritis?
/data/uploads/, /data/outputs/File pengguna dan hasil pemrosesanYa
/data/ai/File model AI yang diunduhTidak (dapat diunduh ulang)
/data/venv/Lingkungan virtual PythonTidak (dibangun ulang saat start)

Pencadangan basis data

Gunakan pg_dump untuk mencadangkan basis data selama stack berjalan:

bash
# Dump the database
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql

# Restore into a fresh database
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter

Atau, hentikan stack dan buat snapshot volume SnapOtter-pgdata:

bash
docker compose down
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
  alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .

Pencadangan file pengguna

bash
# Snapshot the app data volume (excluding re-downloadable AI models)
docker run --rm -v SnapOtter-data:/data -v $(pwd)/backup:/backup \
  alpine tar czf /backup/snapotter-files.tar.gz \
    --exclude='ai' --exclude='venv' -C /data .

Model AI berjumlah hingga sekitar 24 GB di semua bundle. Karena dapat diunduh ulang, kecualikan /data/ai/ dan /data/venv/ dari pencadangan untuk menghemat ruang. Hanya basis data dan file pengguna yang kritis.

Artefak Kepatuhan

Setiap rilis SnapOtter menyertakan artefak keamanan berikut:

ArtefakFormatDi mana menemukannya
SBOM (CycloneDX)JSONAset GitHub Release: snapotter-v{version}-sbom.cdx.json
SBOM (SPDX)JSONAset GitHub Release: snapotter-v{version}-sbom.spdx.json
Pemindaian kerentananTrivy JSONAset GitHub Release: snapotter-v{version}-trivy.json
Pemindaian kerentananSARIFTab GitHub Security
Analisis statisCodeQL (JS/TS + Python)Tab GitHub Security, berjalan mingguan + per PR
Tinjauan dependensiGitHub nativePemeriksaan per-PR, gagal pada penambahan severity tinggi
Audit dependensi Pythonpip-auditLog run CI pada setiap push
Kebijakan keamananMarkdownSECURITY.md di repositori
Pembaruan dependensiDependabotPR mingguan otomatis untuk npm, pip, Docker, Actions

Menjalankan pemindaian Anda sendiri:

Unduh SBOM dari rilis dan pindai dengan perkakas pilihan Anda:

bash
# Scan with Grype using the CycloneDX SBOM
grype sbom:snapotter-v1.17.2-sbom.cdx.json

# Scan with Trivy using the SPDX SBOM
trivy sbom snapotter-v1.17.2-sbom.spdx.json

# Scan the Docker image directly
trivy image snapotter/snapotter:1.17.2

INFO

SBOM dan pemindaian kerentanan mencerminkan image persis yang dipublikasikan untuk rilis itu. Bundle model AI yang dipasang setelah deployment tidak disertakan dalam SBOM karena diunduh saat runtime.