33800 Docs

← Retour

VPN Profiles System - Implementation Finale

Date: 27-01-2026 Status: TERMINE

Résumé

Système de profils VPN WireGuard réutilisables pour les instances SSH dans Connectors Hub. Le VPN se connecte automatiquement avant toute opération SSH (execute, terminal, SFTP).

Architecture Finale

┌─────────────────────────────────────────────────────────────────┐
│                    Docker Network                                │
│                 (supabase-prod_supabase-prod)                   │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              wireguard-sidecar                           │    │
│  │  ┌─────────────────┐  ┌──────────────────────────────┐  │    │
│  │  │ WireGuard API   │  │ connectors-api               │  │    │
│  │  │ :5410           │  │ :5400                        │  │    │
│  │  │                 │  │ (network_mode: service:...)  │  │    │
│  │  └─────────────────┘  └──────────────────────────────┘  │    │
│  │                                                          │    │
│  │  ┌─────────────────────────────────────────────────────┐│    │
│  │  │ wg-{instanceId} tunnel → VPN Server                 ││    │
│  │  │ Routes: 192.168.10.0/24, 192.168.11.0/24, 10.9.0/24 ││    │
│  │  └─────────────────────────────────────────────────────┘│    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │ supabase-db  │  │ supabase-kong│  │ redis-prod   │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
└─────────────────────────────────────────────────────────────────┘

Point clé : connectors-api utilise network_mode: "service:wireguard-sidecar" pour partager le namespace réseau du sidecar. Ainsi, quand le sidecar crée un tunnel VPN, connectors-api peut l'utiliser directement.

Fichiers de déploiement

/home/gouroubleu/apps/connectors-stack/docker-compose.yml

Stack unifiée contenant :

Variables d'environnement

Variable Description
SSH_ENCRYPTION_KEY Clé AES-256 pour chiffrer passwords/private keys
WIREGUARD_SIDECAR_URL http://localhost:5410 (même namespace)
SUPABASE_* Credentials Supabase

Schema SQL

Table connectors.vpn_profiles

CREATE TABLE connectors.vpn_profiles (
  id                      UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id                 UUID NOT NULL,
  name                    VARCHAR(100) NOT NULL,
  description             TEXT,
  -- Interface config
  private_key_encrypted   TEXT NOT NULL,      -- AES-256 encrypted
  public_key              TEXT NOT NULL,      -- Derived from private key
  address                 TEXT NOT NULL,      -- e.g., "10.9.0.9/32"
  address_ipv6            TEXT,               -- e.g., "fd42:42:42::9/128"
  -- Peer config
  endpoint                TEXT NOT NULL,      -- e.g., "92.154.124.233:11220"
  peer_public_key         TEXT NOT NULL,
  preshared_key_encrypted TEXT,               -- AES-256 encrypted (optional)
  allowed_ips             TEXT NOT NULL,      -- e.g., "192.168.10.0/24, 192.168.11.0/24"
  dns                     TEXT,               -- Ignoré dans Docker
  persistent_keepalive    INTEGER DEFAULT 25,
  -- Timestamps
  created_at              TIMESTAMPTZ DEFAULT now(),
  updated_at              TIMESTAMPTZ DEFAULT now(),

  CONSTRAINT vpn_profiles_user_id_name_key UNIQUE (user_id, name)
);

-- RLS Policy
ALTER TABLE connectors.vpn_profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY vpn_profiles_user_policy ON connectors.vpn_profiles
  USING (user_id = auth.uid());

Modification user_connectors.token_metadata

Le champ JSONB contient maintenant vpn_profile_id pour les instances SSH :

{
  "host": "192.168.11.220",
  "port": 22,
  "username": "rhinov",
  "auth_method": "password",
  "password_encrypted": "iv:encrypted_data",
  "vpn_profile_id": "feb5990f-3c8d-4979-817a-0f3c3ec94e30"
}

API Endpoints

VPN Profiles

Method Endpoint Description
GET /api/vpn/profiles Liste les profils de l'utilisateur
GET /api/vpn/profiles/:id Détails d'un profil
POST /api/vpn/profiles Créer un profil
POST /api/vpn/profiles/import Importer depuis .conf
PUT /api/vpn/profiles/:id Modifier un profil
DELETE /api/vpn/profiles/:id Supprimer un profil

Sidecar (interne - localhost:5410)

Method Endpoint Description
POST /tunnel/connect Créer et démarrer un tunnel
POST /tunnel/disconnect Arrêter un tunnel
GET /tunnel/status/:name Status d'un tunnel
GET /tunnel/list Liste des tunnels actifs
POST /keys/derive Dériver clé publique
POST /keys/generate Générer paire de clés

Flux de connexion SSH avec VPN

  1. User appelle /api/ssh/execute avec instance_id
  2. API récupère l'instance et son vpn_profile_id
  3. Si VPN configuré :
    • Récupère le profil VPN
    • Déchiffre private_key et preshared_key
    • Appelle sidecar /tunnel/connect
    • Sidecar crée interface wg-{instanceId.slice(0,8)}
  4. API établit connexion SSH vers l'host (via tunnel VPN)
  5. Exécute la commande et retourne le résultat

Fichiers modifiés/créés

Backend (connectors-api)

Frontend (connectors-front)

Sidecar (wireguard-sidecar)

Déploiement

Limitations

  1. DNS désactivé : Les DNS configurés dans le profil VPN sont ignorés car resolvconf ne fonctionne pas dans Docker
  2. allowed_ips 0.0.0.0/0 : Router tout le trafic via VPN nécessite des capabilities Docker supplémentaires
  3. Pas de déconnexion auto : Les tunnels restent actifs jusqu'au restart du sidecar

Tests validés