Wróć do narzędzi

N3X Vault

Self-hosted menedżer haseł szyfrowany end-to-end w przeglądarce, z YubiKey/FIDO2 i bez dostępu serwera do jawnych sekretów.

SELF-HOSTED · E2EESECURITY ALPHAv0.1.0-alpha.1

Twoje sekrety. Twój serwer. Klucze tylko po Twojej stronie.

N3X Vault to niezależny menedżer haseł z własnym protokołem i szyfrowaniem end-to-end w przeglądarce. Serwer nie otrzymuje hasła głównego ani odszyfrowanego klucza konta.

Stan wydania: security alpha nadaje się do przeglądu protokołu, developmentu i kontrolowanych testów. Nie przechowuj jeszcze sekretów produkcyjnych.

Interfejs aplikacji

Prawdziwy interfejs produktu — kliknij podgląd, aby zobaczyć go w pełnym rozmiarze.

1 / 3

Zaszyfrowany sejf

Loginy, bezpieczne notatki i kody TOTP są szyfrowane po stronie przeglądarki przed wysłaniem do własnego serwera.

Hosting zarządzany przez N3X

Chcesz korzystać, ale nie zajmować się serwerem?

N3X może przygotować i utrzymywać tę aplikację: od uruchomienia i SSL po aktualizacje, monitoring oraz kopie zapasowe.

Zapytaj o hosting N3X

Granice bezpieczeństwa zaprojektowane jawnie

Szyfrowanie po stronie klienta

Argon2id, HKDF i XChaCha20-Poly1305 chronią dane przed wysłaniem ich do API.

YubiKey / FIDO2

Odblokowanie przez WebAuthn PRF, inwentaryzacja kluczy i wymóg przygotowania dwóch urządzeń.

Recovery kit

Szyfrowany eksport i wznawialne odtworzenie do pustej instalacji bez ukrytego klucza uniwersalnego.

Data-blind API

Rust API i PostgreSQL przechowują ciphertext, parametry protokołu i minimalne metadane operacyjne.

Krótkie sesje

15-minutowe sesje przeglądarki są przechowywane tylko w pamięci i można je odwołać po stronie serwera.

Utwardzony Compose

Prywatna sieć bazy, kontenery bez zbędnych capabilities, read-only filesystem i sekrety w wolumenie.

KONFIGURATOR DOCKER

Compose związany z właściwą domeną WebAuthn

Ustaw docelową domenę przed rejestracją YubiKey. Zmiana RP ID po wdrożeniu unieważni istniejące poświadczenia sprzętowe.

Musi być ostateczną domeną reverse proxy, np. vault.firma.pl.

Security alpha: używaj wyłącznie do kontrolowanych testów. Przed sekretami produkcyjnymi wymagany jest niezależny przegląd kryptograficzny i test penetracyjny.
Adres publiczny
https://vault.example.com
WebAuthn RP ID
vault.example.com
Cel reverse proxy
http://127.0.0.1:8793
Test stanu
http://127.0.0.1:8793/api/health

Gotowy docker-compose.yml

name: n3xvault

x-api-security: &api-security
  read_only: true
  security_opt:
    - no-new-privileges:true
  cap_drop:
    - ALL
  tmpfs:
    - /tmp:size=32m,mode=1777

x-web-security: &web-security
  read_only: true
  security_opt:
    - no-new-privileges:true
  cap_drop:
    - ALL
  tmpfs:
    - /tmp:size=32m,mode=1777
    - /app/.next/cache:size=64m,mode=0700,uid=1001,gid=1001

services:
  bootstrap:
    image: alpine:3.22@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce
    restart: "no"
    command:
      - /bin/sh
      - -ec
      - |
        umask 077
        if [ ! -s /run/n3xvault/database_password ]; then
          od -An -N32 -tx1 /dev/urandom | tr -d ' \n' > /run/n3xvault/database_password
        fi
        if [ ! -s /run/n3xvault/bootstrap_token ]; then
          od -An -N32 -tx1 /dev/urandom | tr -d ' \n' > /run/n3xvault/bootstrap_token
        fi
        chmod 0444 /run/n3xvault/database_password /run/n3xvault/bootstrap_token
    volumes:
      - runtime_secrets:/run/n3xvault
    networks:
      - backend
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL

  postgres:
    image: postgres:17-alpine@sha256:18cfe3ef5e6815560c98237d6216d1e5119702fb0f3894c8785dd58b8bbe5d73
    restart: unless-stopped
    depends_on:
      bootstrap:
        condition: service_completed_successfully
    environment:
      POSTGRES_DB: n3xvault
      POSTGRES_USER: n3xvault
      POSTGRES_PASSWORD_FILE: /run/n3xvault/database_password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - runtime_secrets:/run/n3xvault:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n3xvault -d n3xvault"]
      interval: 5s
      timeout: 5s
      retries: 12
    networks:
      - backend

  api:
    image: ghcr.io/nexitpl/n3xvault-api:alpha
    restart: unless-stopped
    depends_on:
      bootstrap:
        condition: service_completed_successfully
      postgres:
        condition: service_healthy
    environment:
      N3XVAULT_BIND: 0.0.0.0:8080
      N3XVAULT_DATABASE_HOST: postgres
      N3XVAULT_DATABASE_NAME: n3xvault
      N3XVAULT_DATABASE_USER: n3xvault
      N3XVAULT_DATABASE_PASSWORD_FILE: /run/n3xvault/database_password
      N3XVAULT_BOOTSTRAP_TOKEN_FILE: /run/n3xvault/bootstrap_token
      N3XVAULT_ENVIRONMENT: ${N3XVAULT_ENVIRONMENT:-development}
      N3XVAULT_PUBLIC_ORIGIN: https://vault.example.com
      N3XVAULT_WEBAUTHN_RP_ID: vault.example.com
      N3XVAULT_SESSION_TTL_SECONDS: ${N3XVAULT_SESSION_TTL_SECONDS:-900}
      N3XVAULT_WEBAUTHN_FLOW_TTL_SECONDS: ${N3XVAULT_WEBAUTHN_FLOW_TTL_SECONDS:-300}
      N3XVAULT_DEVICE_PAIRING_TTL_SECONDS: ${N3XVAULT_DEVICE_PAIRING_TTL_SECONDS:-300}
      RUST_LOG: ${N3XVAULT_LOG_LEVEL:-n3xvault_api=info,tower_http=info}
    volumes:
      - runtime_secrets:/run/n3xvault:ro
    healthcheck:
      test: ["CMD", "curl", "--fail", "--silent", "http://127.0.0.1:8080/health/ready"]
      interval: 15s
      timeout: 3s
      retries: 5
      start_period: 15s
    networks:
      - backend
    <<: *api-security

  web:
    image: ghcr.io/nexitpl/n3xvault-web:alpha
    restart: unless-stopped
    depends_on:
      api:
        condition: service_healthy
    environment:
      N3XVAULT_API_INTERNAL_URL: http://api:8080
    ports:
      - "127.0.0.1:8793:3000"
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api/health"]
      interval: 20s
      timeout: 5s
      retries: 5
      start_period: 20s
    networks:
      - frontend
      - backend
    <<: *web-security

networks:
  frontend:
  backend:
    internal: true

volumes:
  postgres_data:
  runtime_secrets:

Uruchomienie i token bootstrap

mkdir -p n3xvault
cd n3xvault
# Zapisz konfigurację jako docker-compose.yml
docker compose up -d
docker compose ps
docker compose run --rm api print-bootstrap-token
curl -fsS http://127.0.0.1:8793/api/health

Historia zmian

    • WydaniePierwsze wydanie security alpha do kontrolowanych testów i przeglądu protokołu — nie jest jeszcze przeznaczone do sekretów produkcyjnych.
    • NowośćSzyfrowanie end-to-end w przeglądarce: Argon2id, HKDF oraz XChaCha20-Poly1305; serwer przechowuje wyłącznie zaszyfrowane koperty.
    • NowośćLogowanie i odblokowanie przez hasło główne lub YubiKey/FIDO2 WebAuthn PRF, z polityką dwóch kluczy sprzętowych.
    • NowośćSzyfrowany recovery kit oraz bezpieczne, wznawialne odtworzenie do pustej instancji bez uniwersalnego klucza odzyskiwania.

PORADNIK

Instrukcja obsługi N3X Vault

Instalacja, pierwsze kroki, ustawienia i rozwiązywanie problemów.

N3X Vault

N3X Vault to menedżer haseł z szyfrowaniem po stronie klienta, uruchamiany na własnym serwerze.

Security alpha: używaj tej wersji wyłącznie do kontrolowanych testów. Nie jest zatwierdzona do przechowywania sekretów produkcyjnych.

Wymagania i instalacja

Potrzebujesz serwera z Docker Compose, przeglądarki i docelowej domeny HTTPS. PostgreSQL jest dołączony do zestawu. Odblokowanie kluczem sprzętowym wymaga zgodnej przeglądarki oraz klucza FIDO2 obsługującego WebAuthn PRF; odblokowanie hasłem pozostaje dostępne.

  1. W konfiguratorze Compose ustaw docelową domenę, adres nasłuchu i port.
  2. Pobierz wygenerowany plik i zapisz jako docker-compose.yml w osobnym katalogu na serwerze.
  3. W tym katalogu uruchom:
docker compose up -d
docker compose ps
docker compose run --rm api print-bootstrap-token
  1. Skieruj reverse proxy HTTPS na wskazany adres i port (domyślnie 8793). Otwórz skonfigurowaną domenę, wpisz token i utwórz pierwsze konto.

Publiczny adres aplikacji i WebAuthn RP ID muszą odpowiadać docelowej domenie przed rejestracją kluczy. Późniejsza zmiana RP ID uniemożliwi używanie wcześniej zarejestrowanych poświadczeń sprzętowych.

Token pierwszego uruchomienia traktuj jak hasło. Nie zapisuj go w publicznych logach ani definicji stosu. Po utworzeniu pierwszego konta rejestracja właściciela zostaje zamknięta.

Token pierwszego uruchomienia w Portainerze

Portainer może nie udostępniać katalogu roboczego Compose. Token już istnieje w trwałym wolumenie; odczytaj go przez uruchomiony kontener API.

docker ps \
  --filter label=com.docker.compose.service=api \
  --format 'table {{.Names}}\t{{.Label "com.docker.compose.project"}}'

Z listy wybierz kontener API właściwego stosu i zastąp jego nazwą PORTAINER_API_CONTAINER:

docker exec PORTAINER_API_CONTAINER \
  /usr/local/bin/n3xvault-api print-bootstrap-token

Możesz również otworzyć Portainer → Containers → kontener API → Console → /bin/sh i wykonać:

/usr/local/bin/n3xvault-api print-bootstrap-token

Jeżeli API nie działa, znajdź kontener bootstrap właściwego stosu. Zastąp jego nazwą PORTAINER_BOOTSTRAP_CONTAINER; tymczasowy kontener odczyta tylko istniejący wolumen:

docker ps -a \
  --filter label=com.docker.compose.service=bootstrap \
  --format 'table {{.Names}}\t{{.Label "com.docker.compose.project"}}'
docker run --rm \
  --volumes-from PORTAINER_BOOTSTRAP_CONTAINER:ro \
  alpine:3.22 \
  cat /run/n3xvault/bootstrap_token

Użyj referencji obrazu Alpine przypiętej w pobranym Compose, jeśli nie masz lokalnie alpine:3.22. Nie usuwaj wolumenu runtime_secrets ani nie generuj nowego tokenu w ramach rozwiązywania tego problemu.

Klucze sprzętowe i odzyskiwanie

Po odblokowaniu hasłem przejdź do Bezpieczeństwo, dodaj zgodny klucz FIDO2 i wykonaj drugi dotyk wymagany do konfiguracji odblokowania. Zarejestruj dwa klucze przed poleganiem na tej metodzie.

W odblokowanym sejfie wybierz Recovery kit. Zapisz zaszyfrowany plik .n3xvault na chronionym nośniku offline.

Odtwarzanie wymaga pustej instalacji, pliku recovery kit, tokenu instalacji docelowej oraz oryginalnego hasła głównego albo zarejestrowanego klucza z PRF. Odtwarzanie kluczem sprzętowym wymaga tego samego RP ID. Przy zmianie domeny użyj ścieżki hasła i ponownie zarejestruj klucze. Sprawdź odtwarzanie na odizolowanej pustej instalacji.

Utrzymanie i rozwiązywanie problemów

Wykonuj spójne kopie postgres_data i runtime_secrets oraz przechowuj osobny recovery kit. Aktualizację wykonuj zgodnie z opisem wydania, zachowując wolumeny i dotychczasową domenę:

docker compose pull
docker compose up -d
docker compose ps

Przy problemie z uruchomieniem sprawdź stan kontenerów oraz docker compose logs --tail=100 api web. Jeśli klucz nie odblokowuje sejfu, sprawdź HTTPS, domenę, RP ID i obsługę PRF w przeglądarce. Zmienianie adresu między localhost i 127.0.0.1 także zmienia kontekst poświadczeń.

Szyfrowanie i odszyfrowywanie danych odbywa się w kliencie. Sam token instalacji ani sesji nie odszyfruje zawartości sejfu.