From b691f48f43179ee6b8bd054bb5931539cbeab33b Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Thu, 9 Jul 2026 20:09:41 +0000 Subject: [PATCH] =?UTF-8?q?docs(diary):=20incident=202026-07-09=20?= =?UTF-8?q?=E2=80=94=20"BOOK=20LIVE=20conto=20offline"=20=3D=20cert=20Trae?= =?UTF-8?q?fik=20di=20default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Traefik auto-upgrade (latest+Watchtower -> 3.7.7) ha scartato il resolver ACME per acme.json a 660 (3.x pretende 600) -> cert self-signed su tutto il VPS -> DeribitRead SSLError -> book online=False. Zero trade persi (target flat, gate di sicurezza OK). Fix: chmod 600 acme.json + restart; pin traefik:3.7 nel compose. Diario con diagnosi, verifica end-to-end e runbook. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../2026-07-09-traefik-cert-book-offline.md | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/diary/2026-07-09-traefik-cert-book-offline.md diff --git a/docs/diary/2026-07-09-traefik-cert-book-offline.md b/docs/diary/2026-07-09-traefik-cert-book-offline.md new file mode 100644 index 0000000..5df8a0e --- /dev/null +++ b/docs/diary/2026-07-09-traefik-cert-book-offline.md @@ -0,0 +1,108 @@ +# 2026-07-09 — Incident infra: "BOOK LIVE conto offline" = cert Traefik di default (non un problema del conto) + +**Tipo:** incident operativo (infra VPS), non ricerca. Nessun edge, nessun cambio a strategie/pesi/config +di trading. Documentato qui perché ha **bloccato la lettura del conto del book live** e ha prodotto +l'alert Telegram `⚠️ BOOK LIVE — conto offline`. + +## Sintomo + +Alert dal `cron_book` orario (`scripts/live/book_execute.py --execute`): + +``` +⚠️ BOOK LIVE — conto offline + nota: salto l'esecuzione, non opero a cieco +``` + +Nel log (`logs/cron_book.log`) le run recenti mostravano `conto non leggibile (offline) -> stop, non +eseguo a cieco`. 10 run offline su 382 totali → **regressione recente**, non uno stato storico. + +## Diagnosi (catena completa) + +Il book legge il conto Deribit mainnet in sola lettura via **Cerbero MCP** (`DeribitRead`, +`src/live/deribit.py` → `https://cerbero-mcp.tielogic.xyz`). `book_report` marca `online=False` quando +`DeribitRead.mark_price(BTC)` lancia. Riproduzione diretta: + +``` +mark_price BTC: FAIL -> SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] self-signed certificate +``` + +Il proxy presentava il **cert self-signed di default di Traefik** (`CN = TRAEFIK DEFAULT CERT`, +`notBefore Jul 9 19:55 2026`) al posto del vero Let's Encrypt. `curl -k` → HTTP 401 (backend +`cerbero-mcp` healthy, routing OK): **solo la presentazione del cert TLS era rotta**. `requests` +verifica il cert → fallisce → `online=False` → il book salta l'esecuzione (comportamento di sicurezza +**corretto**: non opera a cieco). + +**Causa a monte** (log di avvio Traefik, 11:37:16Z, container `traefik-traefik-1`): + +``` +ERR The ACME resolve is skipped from the resolvers list + error="unable to get ACME account: permissions 660 for /acme.json are too open, please use 600" + resolver=mytlschallenge +→ (a cascata) Router uses a nonexistent certificate resolver certificateResolver=mytlschallenge + routerName=cerbero-mcp@docker [+ ~14 altri router: git, vault, portfolio, budget, cerbero-bite, ...] +``` + +Sequenza: +1. Immagine `traefik:latest` + **Watchtower** (`com.centurylinklabs.watchtower.enable=true`) → + auto-upgrade a **Traefik 3.7.7** con restart alle 11:37 di oggi. +2. Traefik 3.x **rifiuta** `acme.json` con permessi più larghi di `600`; il file era `660` + (`-rw-rw---- root:adriano`) → **resolver `mytlschallenge` scartato**. +3. Tutti i ~15 router che lo referenziano → "nonexistent certificate resolver" → Traefik serve il + **cert di default self-signed** a ogni host HTTPS del VPS (non solo cerbero-mcp). +4. I cert veri erano **già dentro `acme.json`** (14 domini, incl. `cerbero-mcp.tielogic.xyz`) → nessuna + ri-emissione necessaria, **zero rischio rate-limit** Let's Encrypt. + +## Impatto + +- **VPS-wide:** ogni servizio HTTPS dietro Traefik serviva un cert invalido (warning browser, fallimento + di ogni client che verifica il TLS). Non solo il trading. +- **Trading:** **nessun trade perso.** Target del book **flat** (TP01/SKH01 risk-off) + conto reale + ~$598 (non finanziato al livello nominale): anche online il book avrebbe fatto HOLD. Il doppio gate + di sicurezza ha lavorato come previsto. + +## Fix + +**Immediato** (eseguito dall'utente): +```bash +sudo chmod 600 /opt/docker/traefik/acme.json +docker restart traefik-traefik-1 +``` +Il resolver ricarica i cert già presenti in `acme.json` e li ripresenta subito. + +**Durevole** (pin dell'immagine, `/opt/docker/traefik/docker-compose.yml`): +```yaml +- image: "traefik" # = traefik:latest → Watchtower salta ai major (causa dell'incident) ++ image: "traefik:3.7" # Watchtower resta su 3.7.x: patch sì, salto a 3.8+ breaking no +``` +Applicato con `docker compose up -d` (container ricreato su `traefik:3.7`, 20:05:05Z). + +## Verifica (end-to-end, post-fix) + +| Check | Risultato | +|---|---| +| `acme.json` perms | `600` | +| Cert `cerbero-mcp.tielogic.xyz` | issuer **Let's Encrypt** (fino 2026-09-27) | +| Traefik log | nessun `ACME resolve is skipped` / `too open` | +| Container image | `traefik:3.7` (running) | +| `DeribitRead.mark_price` | BTC 63.193 / ETH 1.746 | +| `book_report.online` | **True** · `eq_basis=mainnet USDC` · `real_equity=$598.06` · `pos_error=None` | + +## Lezioni + +- **`traefik:latest` + Watchtower = auto-upgrade non deterministico.** Un bump di major (qui il giro + di vite sui permessi di `acme.json`) diventa un'interruzione TLS di tutto il VPS senza intervento + umano. Pinnare la minor (`3.7`) rende i restart prevedibili pur ricevendo le patch. +- **Traefik 3.x pretende `acme.json` a `600`** (non solo warning: **scarta il resolver**). Se il file + è group/other-readable, tutti i router cadono sul cert di default. +- **Il gate `online` del book ha fatto il suo lavoro:** un problema *infra di lettura* non ha prodotto + ordini a cieco. L'alert "conto offline" va letto prima come possibile problema di **connettività/cert + al Cerbero MCP**, non del conto Deribit. +- **Runbook rapido** per "BOOK LIVE conto offline": + 1. `python -c "from src.live.deribit import DeribitRead; DeribitRead().mark_price('BTC-PERPETUAL')"` + → se `SSLError`/`CERTIFICATE_VERIFY_FAILED` è il cert del proxy, non il conto. + 2. `openssl s_client -connect cerbero-mcp.tielogic.xyz:443 -servername cerbero-mcp.tielogic.xyz | openssl x509 -noout -issuer` + → se `TRAEFIK DEFAULT CERT`, Traefik non serve il cert reale. + 3. `docker logs traefik-traefik-1 | grep -iE "ACME resolve is skipped|too open|nonexistent"` + → conferma resolver scartato; controlla `stat -c %a /opt/docker/traefik/acme.json` (deve essere `600`). + +Nessun file di trading toccato; `config/live.json`, sleeve e pesi **invariati**.