Connecteur PostgreSQL 🐘
Sauvegarde une base PostgreSQL via
pg_dump(format custom binaire) et la restaure viapg_restore. Tout est chiffré côté bridge ; ILYGO ne voit jamais le contenu.
- Image :
ilygo/bridge-postgres:<version_pg>(ex :ilygo/bridge-postgres:16) - Sous-commande :
ilygo-bridge postgres - Outils embarqués :
pg_dump,pg_restore,psql(client PostgreSQL de la version correspondante) - Versions PostgreSQL : 12 → 16 (alignez le tag d'image sur la version majeure de votre serveur)
Variables d'environnement
En plus des variables communes :
| Variable | Obligatoire | Description |
|---|---|---|
PG_CONN_URL |
oui | DSN libpq, ex : postgres://USER:PASSWORD@HOST:5432/DBNAME |
Le DSN peut aussi être surchargé par commande via payload.dsn (avancé).
Prérequis côté base
Créez un rôle de backup dédié en lecture seule (principe de moindre privilège) :
CREATE ROLE ilygo_backup WITH LOGIN PASSWORD 'un-mot-de-passe-fort';
GRANT CONNECT ON DATABASE appdb TO ilygo_backup;
GRANT USAGE ON SCHEMA public TO ilygo_backup;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO ilygo_backup;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO ilygo_backup;
Pour la restauration, le rôle utilisé doit pouvoir créer une base (
side_by_side) ou écrire dans la base cible (in_place). Vous pouvez utiliser un second DSN plus privilégié au moment de la restauration, ou donnerCREATEDBau rôle.
Déploiement (docker-compose)
services:
app-db:
image: postgres:16-alpine
networks: [app-net] # base invisible depuis Internet
# ... votre config existante
ilygo-bridge:
image: ilygo/bridge-postgres:16
restart: unless-stopped
networks:
app-net: # pour atteindre app-db en interne
default: # pour sortir en HTTPS vers ILYGO
environment:
ILYGO_ENDPOINT: https://backup.example/api/v1
ILYGO_API_KEY: ik_xxxxxxxxxxxxxxxxxxxxxxxx
ILYGO_PASSPHRASE: <généré-dans-votre-navigateur> # jamais transmis à ILYGO
ILYGO_RESTORE_SECRET: <généré-dans-votre-navigateur> # jamais transmis à ILYGO
ILYGO_LABEL: prod-app-db
PG_CONN_URL: postgres://ilygo_backup:secret@app-db:5432/appdb
# Aucun port exposé.
networks:
app-net:
internal: true
Mécanisme de backup
Le bridge exécute, en streaming (pas de fichier temporaire) :
pg_dump --format=custom --no-owner --no-privileges --compress=0 "$PG_CONN_URL"
- Format custom (
-Fc) : archive binaire, restaurable sélectivement avecpg_restore. --compress=0: la compression est faite par le bridge (zstd) avant chiffrement — compresser danspg_dumpserait redondant et le ciphertext est incompressible.- La sortie est découpée en chunks de 16 MiB, chiffrés AES-256-GCM, puis poussés.
Mécanisme de restauration
Déclenché depuis la console (Restaurations) avec un RAT. Le bridge :
- Vérifie le token (signé localement).
- Récupère le manifest chiffré, dérive la clé depuis
ILYGO_PASSPHRASE, déchiffre, décompresse. - Applique selon le mode :
side_by_side (recommandé) — crée une base sœur et y restaure :
DROP DATABASE IF EXISTS "appdb_restored";
CREATE DATABASE "appdb_restored";
pg_restore --no-owner --no-privileges --dbname="postgres://.../appdb_restored" <dump>
Vous comparez appdb_restored à la prod, puis vous promouvez manuellement.
in_place (destructif, exige confirm_destructive) :
pg_restore --no-owner --no-privileges --clean --if-exists --dbname="$PG_CONN_URL" <dump>
Exemple validé en démo : 8 customers / 500 orders / 2000 audit_log restaurés à l'identique dans
demoapp_restored.
Réseau & sécurité
- Le bridge n'écoute aucun port ; il sort en HTTPS vers
ILYGO_ENDPOINT. - Placez
app-dbsur un réseauinternal: true: seul le bridge (multi-réseaux) peut sortir. - En prod, ajoutez sur le service bridge :
read_only: true,tmpfs: /tmp,cap_drop: [ALL].
Dépannage
| Symptôme | Cause probable | Solution |
|---|---|---|
connection refused au backup |
mauvais hôte/port dans PG_CONN_URL, ou bridge pas sur app-net |
Vérifiez l'alias réseau et le DSN |
permission denied for table … |
rôle de backup sans SELECT |
Appliquez les GRANT ci-dessus |
server version mismatch |
tag d'image ≠ version serveur | Utilisez ilygo/bridge-postgres:<majeure> correspondante |
restore DROP DATABASE cannot run inside a transaction |
(corrigé en v1.1) | Mettez à jour l'image |
decrypt manifest (wrong passphrase?) |
ILYGO_PASSPHRASE différent de celui du backup |
Le backup ne peut être restauré qu'avec la passphrase d'origine |
Limites & roadmap
- v1 : dump logique complet (
pg_dump). Convient jusqu'à ~100 Go. - Roadmap v1.2 :
pg_basebackup+ WAL streaming continu → PITR (Point-In-Time Recovery), RPO en secondes, économie de stockage.