
Proxy bastione SSH a fiducia zero con gestione delle chiavi basata su Vault, applicazione delle policy RBAC, registrazione completa delle sessioni e TUI di amministrazione per un accesso verificabile all'infrastruttura di produzione.
Un bastion host SSH self-hosted e rinforzato con gestione delle chiavi basata su Vault, applicazione delle policy RBAC, registrazione completa delle sessioni e una TUI amministrativa interattiva — progettato per team che necessitano di accesso verificabile e zero-trust all'infrastruttura di produzione.
I team di ingegneria moderni hanno bisogno di un modo per dare agli sviluppatori l'accesso minimo necessario per svolgere il loro lavoro — né più, né meno. La distribuzione tradizionale delle chiavi SSH è soggetta a errori: le chiavi vengono condivise, dimenticate sui laptop e revocate con giorni di ritardo.
ZTTP risolve questo problema fungendo da unica porta verso la tua infrastruttura:
Laptop dello Sviluppatore
│
│ zttp
│ (Sotto il cofano: SSH sulla porta 2224)
▼
┌─────────────────────────────────────────────────────────┐
│ Proxy ZTTP │
│ │
│ ① Gate di Autenticazione — TUI di login bcrypt/Argon2id│
│ ② Motore RBAC — controllo policy per ambiente │
│ ③ Recupero da Vault — recupero chiave SSH effimera │
│ ④ Bridge — tunnel TCP trasparente │
│ ⑤ Scrittore di Audit — registratore frame ttyrec │
└──────────┬──────────────────────────────────────────────┘
│ ssh (IP privato, chiave effimera)
▼
Server di Destinazione
Servizi infrastrutturali (Docker Compose):
.ttyrec con frame timestampatiServer (host proxy):
2224make (opzionale, ma consigliato)Sviluppatore (client):
ssh)git clone https://gitlab.com/Nihal799/zttp.git
cd zttp
cp .env.example .env
Modifica .env e imposta come minimo:
PROXY_NODE_IP=<ip-pubblico-del-tuo-server>
POSTGRES_PASSWORD=<una-password-forte>
VAULT_TOKEN=<un-token-vault-forte>
⚠️ Non committare mai il tuo file
.env. È elencato in.gitignore.
make docker-up
# oppure direttamente:
docker compose -f deploy/docker-compose.yml up -d --build
make docker-ps
curl http://localhost:8080/healthz
make release PROXY_ADDR=<ip-del-tuo-server>:2224
Questo compila in modo incrociato i client per tutte le piattaforme e aggiorna automaticamente dist/install.sh e dist/install.ps1 con l'URL corretto del server. Il container Nginx li serve all'indirizzo http://<ip-del-tuo-server>:8555/.
curl -fsSL http://<ip-proxy>:8555/install.sh | bash
irm http://<ip-proxy>:8555/install.ps1 | iex
Una volta installato, connettiti al gateway ZTTP:
zttp
# oppure direttamente:
ssh -p 2224 <tuo-username>@<ip-proxy>
Ti verrà presentata una schermata di login a terminale. Dopo l'autenticazione, vedrai un elenco dei server a cui sei autorizzato ad accedere.
Tutta la configurazione avviene tramite variabili d'ambiente (o file .env). Consulta .env.example per il riferimento completo.
ZTTP utilizza un modello basato sui ruoli. A ogni utente viene assegnato un ruolo; ogni ruolo ha una policy che definisce a quali ambienti server può accedere.
I ruoli e le assegnazioni dei server vengono gestiti tramite la Console Amministrativa (vedi sotto). Il motore RBAC esegue tutti i controlli in un'unica query PostgreSQL — non espone mai il motivo per cui l'accesso è stato negato al client (protezione dall'enumerazione).
Connettiti al server zttp-admin dal menu del gateway, oppure accedi con un account che ha il ruolo security-admin.
La Console Amministrativa offre:
Tutte le azioni amministrative vengono registrate in
admin-actions.logall'interno del volume di audit.
Tutte le sessioni vengono memorizzate nel volume Docker zttp-audit-logs (/var/log/zttp/audit/ all'interno del container).
security-adminCtrl+C per tornare indietro# Elenca le registrazioni
sudo ls /var/lib/docker/volumes/zttp-audit-logs/_data/
# Riproduci una registrazione con ttyplay
sudo ttyplay /var/lib/docker/volumes/zttp-audit-logs/_data/<id-sessione>.ttyrec
# Leggi il log delle azioni amministrative
sudo cat /var/lib/docker/volumes/zttp-audit-logs/_data/admin-actions.log
Requisiti: Go 1.25+, Docker (per la compilazione incrociata)
# Compila proxy + CLI per la piattaforma corrente
make build
# Compila in modo incrociato la CLI per tutte le piattaforme (Linux, macOS, Windows)
make release PROXY_ADDR=<ip-proxy>:2224
# Esegui i test
make test
# Esegui il proxy localmente (richiede Postgres + Vault già in esecuzione)
make run-proxy
(Clicca per riprodurre la demo)
(Clicca per riprodurre la demo)
(Clicca per riprodurre la demo)
(Clicca per riprodurre la demo)
(Clicca per riprodurre la demo)
zttp/
├── cmd/
│ ├── proxy/ # Punto di ingresso del server proxy
│ └── zttp/ # Punto di ingresso del client CLI
├── db/
│ └── migrations/ # Migrazioni dello schema PostgreSQL
├── deploy/
│ ├── docker-compose.yml
│ ├── Dockerfile.proxy
│ └── vault-seed.sh # Inserisce chiavi SSH di test in Vault
├── dist/
│ ├── install.sh # Script di installazione Linux/macOS
│ └── install.ps1 # Script di installazione Windows
├── internal/
│ ├── audit/ # Registrazione delle azioni amministrative
│ ├── auth/ # Autenticazione utenti (bcrypt, blocco)
│ ├── cli/ # TUI del client CLI e logica di connessione
│ ├── config/ # Configurazione basata su variabili d'ambiente
│ ├── killswitch/ # Servizio gRPC kill-switch
│ ├── proxy/ # Proxy SSH, TUI del gateway, TUI amministrativa, bridge
│ ├── rbac/ # Motore di controllo degli accessi basato sui ruoli
│ ├── ratelimit/ # Limitazione della frequenza per IP
│ ├── session/ # Tracciamento delle sessioni e store DB
│ └── vault/ # Client chiavi SSH HashiCorp Vault
├── proto/ # Definizioni del protocollo gRPC
├── tools/
│ └── hashpw/ # Strumento CLI: genera hash password bcrypt
├── .env.example # Modello di configurazione
├── go.mod
└── Makefile
git checkout -b feat/tua-funzionalitàmake testPer favore, non committare:
.env o qualsiasi file contenente segretizttp nella root è in .gitignore)Questo progetto è proprietario. Tutti i diritti riservati.
Realizzato con Go, PostgreSQL, HashiCorp Vault e Docker.
| Problema | Soluzione ZTTP |
|---|
| Chiavi SSH condivise sui laptop | Le chiavi risiedono solo in HashiCorp Vault — mai su disco |
| Nessuna visibilità su chi ha fatto cosa | Ogni tasto premuto viene registrato in formato .ttyrec |
| Accesso indiscriminato alla produzione | Il motore di policy basato sui ruoli applica regole per ambiente |
| Nessun modo per interrompere una sessione attiva | Endpoint gRPC kill-switch termina qualsiasi sessione live |
| Accesso opaco per gli auditor | TUI amministrativa con riproduzione delle sessioni, log testuali e log delle azioni amministrative |
| Servizio | Scopo |
|---|
zttp-proxy | Il bastion SSH (binario Go) |
zttp-postgres | Database del piano di controllo (utenti, server, policy RBAC) |
zttp-vault | HashiCorp Vault — memorizza le chiavi private SSH |
zttp-nginx | Serve gli installer CLI in /release/ |
zttp-init-audit | Container monouso che corregge i permessi dei volumi |
| Variabile | Default | Descrizione |
|---|
PROXY_LISTEN_ADDR | 0.0.0.0:2222 | Indirizzo di bind del proxy SSH |
HTTP_LISTEN_ADDR | 0.0.0.0:8080 | Indirizzo HTTP per i health check |
GRPC_LISTEN_ADDR | 0.0.0.0:9090 | Indirizzo gRPC del kill-switch |
PROXY_NODE_IP | 127.0.0.1 | IP esterno incorporato nei binari CLI |
DATABASE_URL | postgres://zttp:... | Stringa di connessione PostgreSQL |
VAULT_ADDR | http://localhost:8201 | URL del server Vault |
VAULT_TOKEN | dev-root-token-zttp | Token root di Vault (solo dev — usa AppRole in produzione) |
MAX_FAILED_ATTEMPTS | 5 | Soglia di blocco |
LOCKOUT_DURATION | 15m | Durata del blocco dell'account |
RATE_LIMIT_PER_MIN | 10 | Numero massimo di tentativi di login al minuto per IP |
AUDIT_LOG_DIR | /var/log/zttp/audit | Percorso della directory di registrazione delle sessioni |
SOC_WEBHOOK_URL | (vuoto) | Webhook opzionale per gli alert SOC |
| Ruolo | Accesso |
|---|
security-admin | Accesso completo a tutti gli ambienti + Console Amministrativa |
sre-tier1 | Tutti gli ambienti inclusa la produzione |
sre-tier2 | Solo staging e sviluppo |
dev | Solo ambiente di sviluppo |
readonly | Ambiente di sviluppo, set di comandi limitato |
| Opzione di Menu | Descrizione |
|---|
| Aggiungi Utente | Crea un nuovo utente con assegnazione del ruolo |
| Aggiungi Server | Registra un server di destinazione (hostname, IP, ambiente, utente SSH) |
| Gestisci Accesso Server | Concedi o revoca l'accesso degli utenti a server specifici |
| Visualizza Utenti | Elenca tutti gli utenti e i loro ruoli |
| Visualizza Server | Elenca tutti i server registrati |
| Visualizza Log di Audit | Sfoglia le sessioni, riproduci le registrazioni, leggi i log testuali |
| [ Indietro ] | Torna al gateway dei server |
| Comando | Descrizione |
|---|
make build | Compila proxy e CLI per la piattaforma corrente |
make release | Compila in modo incrociato i binari CLI per tutte le piattaforme |
make release-docker | Compila in modo incrociato all'interno di un container Docker (evita problemi snap/WSL) |
make docker-up | Avvia tutti i servizi Docker Compose |
make docker-down | Ferma tutti i servizi ed elimina i volumi |
make docker-logs | Segue i log del proxy |
make docker-ps | Mostra lo stato dei container |
make test | Esegue tutti i test Go |
make migrate | Applica le migrazioni del database |
make seed | Inserisce i dati di sviluppo |
make hashpw PW=miapassword | Genera un hash bcrypt per il seeding manuale del DB |
make clean | Rimuove i binari compilati e la cache di build |
| Livello | Meccanismo |
|---|
| Trasporto | Tutte le connessioni client sono SSH (crittografate in transito) |
| Autenticazione | bcrypt (costo 12) / Argon2id — il testo in chiaro è strutturalmente vietato nello schema |
| Protezione brute-force | Blocco dell'account (5 tentativi / 15 min) + limitatore di frequenza per IP |
| Autorizzazione | Query RBAC a JOIN singola — i dinieghi sono sempre generici ("Permesso negato") |
| Gestione dei segreti | Le chiavi private SSH sono memorizzate esclusivamente in HashiCorp Vault, recuperate in modo effimero |
| Traccia di audit | Registrazione completa dei tasti premuti in formato .ttyrec, log amministrativo append-only immutabile |
| Isolamento dei processi | Il proxy viene eseguito come non-root (UID 65532) all'interno di un container distroless |
| Kill switch | Qualsiasi sessione live può essere terminata tramite gRPC senza riavviare il proxy |