Regole di Rediacc
Ogni repository Rediacc viene eseguito in un ambiente isolato con il proprio daemon Docker, volume LUKS cifrato e intervallo IP dedicato. Queste regole garantiscono il corretto funzionamento dell’applicazione all’interno di questa architettura.
Rediaccfile
- Ogni repository necessita di un Rediaccfile, uno script bash con funzioni di ciclo di vita.
- Funzioni del ciclo di vita:
up(),down(). Opzionale:info(). up()avvia i tuoi servizi.down()li ferma.info()fornisce informazioni di stato (stato dei container, log recenti, health).- Il Rediaccfile viene sourced da renet; ha accesso alle variabili di shell, non solo alle variabili d’ambiente.
Variabili d’ambiente disponibili nel Rediaccfile
| Variabile | Esempio | Descrizione |
|---|---|---|
REDIACC_WORKING_DIR | /mnt/rediacc/mounts/abc123/ | Percorso root del repository montato |
REDIACC_NETWORK_ID | 6336 | Identificatore di isolamento della rete |
REDIACC_REPOSITORY | abc123-... | GUID del repository |
{SVCNAME}_IP | HEARTBEAT_IP=127.0.24.195 | IP loopback per servizio (nome servizio in maiuscolo) |
Rediaccfile minimale
#!/bin/bash
_compose() {
renet compose -- "$@"
}
up() {
_compose up -d
}
down() {
_compose down
}
Compose
- Usa
renet compose, maidocker compose: renet inietta l’isolamento della rete, host networking, IP loopback ed etichette di servizio. - Non impostare
network_modenel tuo file compose: renet forzanetwork_mode: hostsu tutti i servizi. Qualsiasi valore impostato viene sovrascritto. - Non impostare etichette
rediacc.*: renet inietta automaticamenterediacc.network_id,rediacc.service_iperediacc.service_name. - I mapping
ports:vengono ignorati in modalità host networking. Aggiungi l’etichettarediacc.service_portper il routing HTTP (i servizi senza questa etichetta non ottengono route HTTP). Usa le etichetterediacc.tcp_ports/rediacc.udp_portsper il forwarding TCP/UDP. - Le policy di restart (
restart: always,on-failure, ecc.) sono sicure da usare: renet le rimuove automaticamente per compatibilità con CRIU. Il watchdog del router ripristina automaticamente i container fermi in base alla policy originale salvata in.rediacc.json. - Le impostazioni pericolose sono bloccate per impostazione predefinita:
privileged: true,pid: host,ipc: hoste i bind mount dell’host verso percorsi di sistema vengono rifiutati. Usarenet compose --unsafeper sovrascrivere a tuo rischio.
Variabili d’ambiente all’interno dei container
Renet inietta automaticamente queste in ogni container:
| Variabile | Descrizione |
|---|---|
SERVICE_IP | L’IP loopback dedicato di questo container |
REDIACC_NETWORK_ID | ID di isolamento della rete |
Denominazione e routing dei servizi
- Il nome del servizio compose diventa il prefisso URL della route automatica.
- Repository grand:
https://{service}.{repo}.{machine}.{baseDomain}(es.https://myapp.marketing.server-1.example.com). - Repository fork:
https://{service}-fork-{tag}.{repo}.{machine}.{baseDomain}(es.https://myapp-fork-staging.marketing.server-1.example.com). Il separatore-fork-previene collisioni URL con i nomi dei servizi del repository grand. L’URL del fork usa sempre il certificato wildcard esistente del repository genitore, quindi non è necessario un nuovo certificato. - Per i domini personalizzati, usa le etichette Traefik (nota: i domini personalizzati NON sono compatibili con i fork, il dominio appartiene al repository grand).
Networking
- Ogni repository ottiene il proprio daemon Docker su
/var/run/rediacc/docker-<networkId>.sock. - Ogni servizio ottiene un IP loopback univoco all’interno di una subnet /26 (es.
127.0.24.192/26). - Il binding è automatico: I servizi possono fare bind su
0.0.0.0olocalhost- il kernel riscrive in modo trasparente l’indirizzo all’IP loopback assegnato al servizio. Il binding esplicito con${SERVICE_IP}funziona ancora ma non è più necessario. - Gli health check possono usare
localhosto${SERVICE_IP}. Esempio:healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] - Le connessioni cross-repo sono bloccate dal kernel: Il kernel blocca automaticamente le connessioni agli IP loopback al di fuori della subnet
/26del repository. Un servizio in un repository non può raggiungere servizi in un altro repository. - Comunicazione inter-servizio: Usa i nomi dei servizi (es.
db,redis) - renet inietta automaticamente ogni nome di servizio come hostname che risolve all’IP corretto. I nomi DNS Docker NON funzionano in modalità host, ma i nomi dei servizi tramite/etc/hostssì. Evita di incorporare${DB_IP}o simili in file di configurazione persistenti (es. stringhe di connessione memorizzate in un database) - in caso di fork, l’IP grezzo viene ereditato e punta al repository sbagliato. I nomi dei servizi risolvono sempre correttamente per ogni repository. - I conflitti di porta sono impossibili tra repository, ognuno ha il proprio daemon Docker e intervallo IP.
- Forwarding TCP/UDP: Aggiungi etichette per esporre porte non HTTP:
labels: - "rediacc.tcp_ports=5432,3306" - "rediacc.udp_ports=53"
Storage
- Tutti i dati Docker sono memorizzati all’interno del repository cifrato: il
data-rootdi Docker si trova in{mount}/.rediacc/docker/dataall’interno del volume LUKS. I volumi denominati, le immagini e i layer dei container sono tutti cifrati, inclusi nei backup e nel fork automaticamente. - I bind mount su
${REDIACC_WORKING_DIR}/...sono consigliati per chiarezza, ma i volumi denominati funzionano anch’essi in modo sicuro.volumes: - ${REDIACC_WORKING_DIR}/data:/data # bind mount (consigliato) - pgdata:/var/lib/postgresql/data # volume denominato (anch'esso sicuro) - Il volume LUKS è montato su
/mnt/rediacc/mounts/<guid>/. - Gli snapshot BTRFS catturano l’intero file di backing LUKS, inclusi tutti i dati montati tramite bind.
- Il datastore è un file pool BTRFS a dimensione fissa sul disco di sistema. Usa
rdc machine query --name <name> --systemper vedere lo spazio libero effettivo. Espandi conrdc datastore resize.
CRIU (Live Migration)
- Opt-in tramite etichetta: Aggiungi
rediacc.checkpoint=trueai container di cui vuoi fare checkpoint. I container senza di essa (database, cache) si avviano da zero e si ripristinano tramite i propri meccanismi (WAL, LDF, AOF). repo down --checkpointsalva lo stato del processo prima di fermarsi; il successivorepo upripristina automaticamente. Questo è il flusso principale sulla stessa macchina, verificato funzionante.backup push --checkpointcattura la memoria del processo in esecuzione e lo stato del disco per i container etichettati, poi trasferisce il volume su un’altra macchina. Ripristina sulla macchina di destinazione tramiterepo up.repo fork --checkpointcattura lo stato del processo prima del fork e clona il checkpoint con il fork tramite CoW. ⚠️ Sulla stessa macchina, il successivorepo upsul fork attualmente fallisce concriu failed: type RESTORE errno 0quando il genitore è ancora in esecuzione. Bug CRIU upstream checkpoint-restore/criu#478 / #514. Usarepo down --checkpointper il salvataggio/ripristino in-place, obackup push --checkpointper la migrazione cross-machine.repo uprileva automaticamente i dati di checkpoint e li ripristina se trovati. Usa--skip-checkpointper forzare un avvio da zero.- Ripristino consapevole delle dipendenze: Usa
depends_ondi compose per avviare prima i database (attendere che siano healthy), poi ripristinare i container dell’app tramite CRIU. - Le connessioni TCP diventano obsolete dopo il ripristino; le app devono gestire
ECONNRESETe riconnettersi. CRIU non preserva lo stato attivo delle connessioni TCP attraverso il ripristino in nessun flusso supportato. - La modalità sperimentale di Docker è abilitata automaticamente sui daemon per singolo repository.
- CRIU viene installato durante
rdc config machine setup. /etc/criu/runc.confè configurato contcp-establishedper impostazione predefinita.- Le impostazioni di sicurezza del container vengono iniettate automaticamente per i container etichettati:
renet composeaggiunge quanto segue ai container conrediacc.checkpoint=true:cap_add:CHECKPOINT_RESTORE,SYS_PTRACE,NET_ADMIN(set minimale per CRIU su kernel 5.9+)security_opt:apparmor=unconfined(il supporto AppArmor di CRIU non è ancora stabile upstream)userns_mode: host(CRIU richiede accesso al namespace init per/proc/pid/map_files)
- I container senza l’etichetta vengono eseguiti con una postura di sicurezza più pulita (nessuna capability aggiuntiva).
- Il profilo seccomp predefinito di Docker viene preservato; CRIU usa
PTRACE_O_SUSPEND_SECCOMP(kernel 4.3+) per sospendere temporaneamente i filtri durante checkpoint/restore. - Non impostare manualmente le capability CRIU nel tuo file compose; renet le gestisce in base all’etichetta.
- Consulta il template heartbeat per un’implementazione di riferimento compatibile con CRIU.
Pattern di applicazione compatibili con CRIU
- Gestisci
ECONNRESETsu tutte le connessioni persistenti (pool di database, websocket, code messaggi). - Usa librerie di pool di connessioni che supportano la riconnessione automatica.
- Aggiungi
process.on("uncaughtException")come rete di sicurezza per gli errori di socket obsoleti dagli oggetti interni delle librerie. - Le policy di restart sono gestite automaticamente da renet (rimosse per CRIU, il watchdog gestisce il ripristino).
- Evita di fare affidamento sul DNS Docker; usa gli IP loopback per la comunicazione inter-servizio.
Policy di sicurezza dell’host per OS
Su tutti e cinque gli OS server ufficialmente supportati (vedi Requisiti), il daemon docker per singolo repository e i container che esegue usano etichette container predefinite. rdc config machine setup non installa una policy SELinux personalizzata né un profilo AppArmor.
- Ubuntu 24.04 / openSUSE Leap 16.0: AppArmor è abilitato per impostazione predefinita. I container vengono eseguiti con il profilo docker-container predefinito. L’unica eccezione è CRIU (
apparmor=unconfinedper i container conrediacc.checkpoint=true, come indicato sopra). - Fedora 43 / Oracle Linux 10: SELinux è in modalità enforcing per impostazione predefinita. I container ottengono il contesto standard
container_t. Non è necessaria l’installazione di policy aggiuntive. Se un passaggio di configurazione fallisce con denial AVC, consulta Risoluzione dei problemi → Denial SELinux. - Debian 13: AppArmor è disponibile ma non applicato per impostazione predefinita su tutti i domini. I container usano comunque il profilo docker-container.
Non è richiesto alcun flag di postura di sicurezza per OS; rdc e renet rilevano l’ambiente in esecuzione e producono lo stesso isolamento per singolo repository su tutte le cinque distribuzioni.
Sicurezza
- La cifratura LUKS è obbligatoria per i repository standard. Ogni repository ha la propria chiave di cifratura.
- Le credenziali sono memorizzate nella config della CLI (
~/.config/rediacc/rediacc.json). Perdere la config significa perdere l’accesso ai volumi cifrati. - Non fare mai commit delle credenziali nel version control. Usa
env_filee genera i segreti inup(). - Isolamento dei repository: Il daemon Docker, la rete e lo storage di ogni repository sono completamente isolati dagli altri repository sulla stessa macchina.
- Isolamento degli agenti: Gli agenti AI operano in modalità fork-only per impostazione predefinita. Ogni repository ha la propria chiave SSH con enforcement sandbox lato server (
sandbox-gatewayForceCommand). Tutte le connessioni sono sandboxate con Landlock LSM, OverlayFS home overlay e TMPDIR per singolo repository. L’accesso al filesystem cross-repo è bloccato dal kernel. sudoè disabilitato all’interno di una sandbox di repository per progetto. L’isolamento filesystem Landlock richiedeNoNewPrivs, che impedisce qualsiasi elevazione dei privilegi, quindisudofallirà conno new privileges flag is set. L’utente proprietario del repository ha già i permessi necessari per tutto ciò che si trova nel mount del repository e nel socket Docker. Per operazioni veramente privilegiate (installazione di pacchetti host, tuning del kernel), eseguile fuori dalla sandbox o da una funzioneup()del Rediaccfile eseguita dal percorso dell’infrastruttura.- Il bridge networking Docker è disabilitato su ogni daemon per singolo repository. Il
daemon.jsondi ogni repository contiene"bridge": "none"e"iptables": false, quindi un semplicedocker run <image>crea un container con solo un’interfaccia loopback e nessuna connettività in uscita. Questo non è un bug, è come viene applicato l’isolamento cross-repo: gli hook eBPF a livello kernel che bloccano un repository dall’accesso agli IP loopback di un altro repository si applicano solo ai container che risiedono nel namespace di rete dell’host. Per i servizi di produzione usarenet compose, che iniettanetwork_mode: hostautomaticamente. Per i container one-off ad hoc in una shell, passa--network hostesplicitamente.
Deployment
rdc repo upmonta automaticamente il volume LUKS se non montato, poi esegueup()in tutti i Rediaccfile.rdc repo downeseguedown()e ferma il daemon Docker.rdc repo down --unmountchiude anche il volume LUKS (blocca lo storage cifrato).- I fork (
rdc repo fork) creano un clone CoW (copy-on-write) con un nuovo GUID e networkId, in tempo costante indipendentemente dalle dimensioni del repository. BTRFS reflink duplica i metadati dell’immagine, non i dati, quindi un repository da 100 GB effettua il fork negli stessi pochi secondi di uno da 1 GB. Il fork condivide la chiave di cifratura del genitore. - Takeover (
rdc repo takeover --name <fork> -m <machine>) sostituisce i dati del repository grand con quelli del fork. Il grand mantiene la propria identità (GUID, networkId, domini, autostart, catena di backup). I vecchi dati di produzione vengono preservati come fork di backup. Usa per: testa l’aggiornamento sul fork, verifica, poi esegui takeover in produzione. Ripristina conrdc repo takeover --name <backup-fork> -m <machine>. - Le route proxy diventano attive circa 3 secondi dopo il deployment. L’avviso “Proxy is not running” durante
repo upè informativo negli ambienti ops/dev. rdc repo uperdc repo fork --upstampano il pattern URL per i servizi etichettati conrediacc.service_portal termine del deployment. Sostituisci{service}con il nome del servizio esposto per ottenere l’URL esatto. I servizi senzarediacc.service_port(database, worker) non ottengono route e non vengono mostrati.
Errori comuni
- Usare
docker composeinvece direnet compose: i container non otterranno l’isolamento di rete. - Le policy di restart sono sicure; renet le rimuove automaticamente e il watchdog gestisce il ripristino.
- Usare
privileged: true: non necessario, renet inietta le capability CRIU specifiche al suo posto. - Inserire IP grezzi in file di configurazione persistenti - usa i nomi dei servizi per le connessioni per mantenere l’isolamento del fork.
- Usare
rdc term connect -ccome workaround per comandi falliti: segnala invece i bug. repo deleteesegue una pulizia completa inclusi IP loopback e unità systemd. Eseguirdc machine prune --name <name>per ripulire i residui di eliminazioni legacy.