IT

Gruppi

Work in progress — content may be incomplete.

Un gruppo collega molti dispositivi a un solo profilo, con una priorità che risolve i conflitti quando un dispositivo appartiene a più gruppi.

Cos’è

Un gruppo è un insieme nominato di dispositivi che condividono la stessa policy di filtro. Invece di fissare i cinque gadget dei bambini uno per uno al profilo kids, dichiari un gruppo kids con profile = "kids" e poi elenchi i dispositivi sul lato gruppo, oppure metti groups = ["kids"] su ogni dispositivo. Funzionano entrambe le direzioni. In ogni caso, quando arriva una query da uno di quei dispositivi, Warden la risolve attraverso il profilo del gruppo al livello 3 della catena.

Questa pagina copre quando creare una voce [[groups]], ogni dimensione che puoi regolare al suo interno, le superfici CLI / TUI / REST che li leggono e li scrivono, e come la priorità rompe i pareggi quando un dispositivo appartiene legittimamente a più gruppi. Per il quadro più ampio di come una query viene abbinata a un profilo, vedi il processo di filtraggio e la sezione ordine di precedenza qui sotto.

Quando ti serve

Usa un gruppo quando un profilo si applica a un insieme di dispositivi, non a uno solo. Un setup domestico tipico ne ha una manciata:

  • Un gruppo family legato a default per i laptop dei genitori e il desktop in cucina.
  • Un gruppo kids legato a kids, che raccoglie ogni dispositivo che i bambini toccano — tablet, il laptop scolastico, la Switch di famiglia.
  • Un gruppo iot legato a iot, che riunisce lampadine smart, la stampante, il robot aspirapolvere — qualunque cosa la cui cloud del produttore non sia di tua fiducia.
  • Un gruppo guests legato a un profilo più stretto per i dispositivi noti della VLAN ospiti (gli altri ricadono sulla subnet).

Non ti serve un gruppo per un singolo dispositivo — fissa il suo profile direttamente sulla riga [[devices]]. Non ti serve un gruppo nemmeno per esprimere un’eccezione per dispositivo — quello è allow_rules / deny_rules sul dispositivo, vedi dispositivi. E non ti serve un gruppo per “ogni host su questa VLAN” — usa [[subnets]], che cattura gli host non mappati come fallback.

Schema

Un gruppo è una voce TOML array-of-tables: [[groups]], la stessa forma di [[devices]] e [[blocklists]]non una mappa come [profiles.<id>].

toml
[[groups]]
id           = "kids"
display_name = "Bambini"
profile      = "kids"
priority     = 10
devices      = ["kids-tablet", "anna-iphone"]

Sei campi, tre dei quali obbligatori. La lista opzionale tags alimenta il modello di intersezione dei tag (ogni dispositivo membro eredita i tag del gruppo); non c’è campo note o description — i gruppi sono volutamente piccoli.

Dimensioni

Un gruppo è un vettore lungo questi assi indipendenti. Le dimensioni obbligatorie sono marcate.

GruppoDimensioneCampo TOMLCosa regola
IdentitàId (obbligatorio)idRiferimento incrociato stabile. Ogni dispositivo che vuole questo gruppo, ogni pianificazione che lo prende come bersaglio, nomina questo id.
Nome leggibile (obbligatorio)display_nameEtichetta operatore mostrata nella scheda laterale della TUI e nelle liste della CLI.
Binding del resolverProfilo (obbligatorio)profileLa policy applicata a ogni membro al livello 3 della catena. Deve referenziare un [profiles.<id>] definito.
Peso di spareggiopriorityQuando un dispositivo appartiene a più gruppi con profili diversi, vince la priorità più alta. Stessa priorità + profili diversi è un errore del validatore.
AppartenenzaRoster direttodevicesLa lista di id di dispositivo iscritti a questo gruppo, scritta dal lato gruppo.
Riferimento inverso (esterno)[[devices]].groupsLa stessa appartenenza scritta dal lato dispositivo. Una direzione sola basta a iscrivere un dispositivo — il resolver fonde entrambe a tempo di caricamento.
Binding di pianificazione (esterno)Pianificazioni che puntano a questo gruppo[[schedules]].target_type = "group" + target_id = "<id>"Una pianificazione cambia il profilo applicato ai membri del gruppo per la durata della sua finestra.

Cose che sembrano dimensioni del gruppo ma non lo sono:

  • Blocklist, admin rule, block response per gruppo. Vivono sul profilo a cui il gruppo è legato. Per bloccare un dominio in più “per i bambini”, aggiungilo al profilo kids con warden profile deny kids … (oppure warden group deny kids …, che è una scorciatoia sullo stesso percorso).
  • Record DNS locali per gruppo. Idem — vivono sul profilo.
  • Un gruppo “solo etichetta” senza profilo. Ogni [[groups]] deve legare un profile — è obbligatorio. Un gruppo porta invece una lista tags che alimenta il filtro (vedi il riferimento dei campi qui sotto), ma non esiste un gruppo che esista puramente come etichetta organizzativa senza effetto sulla risoluzione. Per un’etichetta lato dispositivo che non cambia la risoluzione, usa piuttosto il campo tags a livello di dispositivo.

Riferimento dei campi

CampoTipoObbligatorioDefaultScopo
idstringa, [a-z0-9-], lunghezza 1–64, niente trattino iniziale o finaleRiferimento incrociato stabile.
display_namestringaEtichetta TUI / CLI. Il percorso set della CLI impone non vuoto.
profileid di profiloDeve referenziare un [profiles.<id>] dichiarato.
priorityi32no0Più alto vince quando un dispositivo è in più gruppi. I valori negativi sono accettati.
deviceslista di id di dispositivono[]Ogni id deve referenziare un [[devices]] dichiarato. I gruppi vuoti sono ammessi.
tagslista di slug di tag, ^[a-z][a-z0-9-]{0,31}$no[]Tag di area tematica. Il set di tag effettivo di ogni dispositivo membro li acquisisce (un’unione — un tag di gruppo può solo aggiungere blocklist, mai rimuoverne una). Vedi tag e profili per come l’intersezione decide quali liste si applicano.

#[serde(deny_unknown_fields)] è attivo — i typo falliscono al caricamento con unknown field. Fonte: src/config/schema/group.rs:30-61, src/config/schema/validator.rs:1882 (check_groups).

Appartenenza bidirezionale

Un dispositivo può essere iscritto a un gruppo da entrambi i lati — gli schemi non sono simmetrici nel nome ma il resolver li tratta come un solo insieme:

toml
# Iscrizione lato gruppo
[[groups]]
id      = "kids"
profile = "kids"
devices = ["kids-tablet", "anna-iphone"]
toml
# Iscrizione lato dispositivo — stesso effetto
[[devices]]
id     = "kids-tablet"
groups = ["kids"]

Funzionano entrambe; non ti servono entrambe. Scegli quella che si legge meglio per il file che stai modificando — di solito il lato dispositivo, perché è dove scrive warden device set <id> groups …. Usa il lato gruppo quando aggiungere più dispositivi a un solo gruppo in un colpo solo è più pulito. L’uso misto sulla stessa coppia di appartenenza è innocuo ma invita confusione; per una flotta di più di una decina di dispositivi, scegli una direzione e mantienila.

Esempi

Un gruppo minimo — tre dispositivi condividono la policy kids:

/etc/purge-warden/groups.d/family.toml
toml
[[groups]]
id           = "kids"
display_name = "Bambini"
profile      = "kids"
devices      = ["kids-tablet", "anna-iphone", "school-laptop"]

Due gruppi sovrapposti, con la priorità che decide quale profilo vince per un dispositivo che appartiene a entrambi — Anna è sia in kids (priorità 10) che in school (priorità 20), quindi durante l’orario scolastico passa attraverso il profilo school-allow-classroom, non il più stretto kids:

/etc/purge-warden/groups.d/family.toml
toml
[[groups]]
id           = "kids"
display_name = "Bambini"
profile      = "kids"
priority     = 10
devices      = ["kids-tablet", "anna-iphone", "school-laptop"]

[[groups]]
id           = "school"
display_name = "Dispositivi scolastici"
profile      = "school-allow-classroom"
priority     = 20
devices      = ["anna-iphone", "school-laptop"]

Un gruppo IoT con più dispositivi smart-home, niente priorità perché nessuno appartiene a un altro gruppo:

/etc/purge-warden/groups.d/iot.toml
toml
[[groups]]
id           = "iot"
display_name = "IoT"
profile      = "iot"
devices      = ["smart-tv", "kitchen-bulb", "printer", "robot-vacuum"]

Una pianificazione di buonanotte che prende come target il gruppo kids — ogni membro passa attraverso il profilo kids-night tra le 21:00 e le 07:00:

/etc/purge-warden/schedules.d/famiglia.toml
toml
[[schedules]]
id          = "kids-bedtime"
target_type = "group"
target_id   = "kids"
profile     = "kids-night"
days        = ["mon", "tue", "wed", "thu", "sun"]
start       = "21:00"
end         = "07:00"
Tip
Per più di una manciata di gruppi, dividili su groups.d/*.toml (un file per persona — family.toml, iot.toml, guests.toml). Il config.toml master li include tramite includes. warden group add … --into <file> instrada la scrittura nel file giusto.

CLI

Ogni sottocomando di scrittura attiva un hot reload del daemon (swap atomico della config, niente restart). I sottocomandi di sola lettura funzionano anche senza il daemon.

ComandoCosa fa
warden group listElenca i gruppi configurati con id, nome leggibile, profilo, priorità, e numero di membri.
warden group show <id>Stampa ogni campo di un gruppo, inclusa la lista risolta dei membri (roster diretto + riferimenti inversi dal lato dispositivo).
warden group add <id> --profile <p> [--display-name <n>] [--priority N] [--devices id1,id2] [--into <file>]Crea un nuovo gruppo. --profile è obbligatorio e deve referenziare un profilo definito. I dispositivi elencati sotto --devices devono già esistere. Rifiutato se l’id è già preso.
warden group set <id> <campo> <valore> [--into <file>]Modifica un singolo campo. Campi supportati: display_name, profile, priority, devices (separati da virgola). Non i tag — quelli hanno il proprio verbo tag. Il campo id non è modificabile — vedi rinominare un gruppo.
warden group tag add|remove <id> <tag> [--into <file>]Aggiunge o rimuove un tag di area tematica sul gruppo. Ogni dispositivo membro lo eredita (un’unione — un tag di gruppo può solo aggiungere liste). Idempotente; lo slug è validato al confine della CLI; una modifica reale attiva un hot reload.
warden group remove <id> [--into <file>]Cancella il gruppo. Rifiutato se un dispositivo elenca ancora <id> nel suo campo groups — l’errore nomina ogni dispositivo offendente e ti dice esattamente quale warden device set … lanciare prima.
warden group allow <id> <dominio> [--id <rule_id>] [--remove] [--into <file>]Sintetizza una admin rule `@@
warden group deny <id> <dominio> [...stessi flag]Simmetrico per il deny.

warden group rules e warden group block non sono cablati — non c’è un overlay a livello di gruppo analogo agli allow_rules / deny_rules per dispositivo. Per esprimere un’eccezione per un solo gruppo che non sbordi su ogni dispositivo che condivide il profilo sottostante, ritaglia un profilo dedicato.

Pattern comuni:

bash
# Crea un gruppo da zero con un paio di dispositivi già dentro
sudo warden group add kids --profile kids \
  --display-name "Bambini" \
  --priority 10 \
  --devices kids-tablet,anna-iphone

# Riassegna un gruppo a un profilo diverso (ogni membro lo segue)
sudo warden group set kids profile kids-strict

# Aggiungi un dominio alla policy kids tramite la scorciatoia del gruppo
sudo warden group deny kids tiktok.com

# Rimuovi un gruppo — fallisce a voce alta se un dispositivo lo referenzia ancora
sudo warden group remove guests
# error: group "guests" still appears in the groups field of device(s):
#   guest-laptop, guest-phone. Remove the reference first with
#   `warden device set guest-laptop groups <remaining-list>`.

Dopo ogni modifica con hot-reload, viene stampato esattamente uno di quattro messaggi — gli stessi usati da ogni percorso di scrittura della CLI:

  • daemon reloaded — change is live
  • daemon not running — change will take effect on next start
  • note: change landed on disk but no admin token is available to request a daemon reload. Run warden token generate or restart the daemon to activate.
  • warning: change landed on disk but the daemon rejected the reload (<msg>). Check journalctl -u purge-warden and consider systemctl restart purge-warden.

Fonte: src/cli/commands/groups.rs, src/cli/mod.rs:611-668, src/main.rs:482-559.

Rinominare un gruppo

Non c’è warden group rename. Il percorso set non accetta id come campo. Per rinominare un gruppo, modifica a mano la voce [[groups]] nel TOML, aggiorna ogni [[devices]].groups e [[schedules]].target_id che referenzia il vecchio id, e poi o riavvia il daemon oppure usa il flusso retired-ids così le voci vecchie non rompono il validator. Per un gruppo appena creato a cui non sono ancora attaccate pianificazioni, rimuoverlo e riaggiungerlo sotto il nuovo id è di solito più rapido.

TUI

Non c’è una tab Gruppi dedicata. I gruppi sono un concetto del resolver; la TUI li fa emergere dove sono utili e lascia il loro ciclo di vita alla CLI.

TabCome compaiono i gruppiTasti utili
DispositiviLa scheda di dettaglio a destra della riga del dispositivo focalizzato mostra Group: <name> (singola appartenenza) o Group: <first> + N more (multipla). Sola lettura. Il modal di Edit espone un campo gruppo a selezione singola — la TUI non può autorare appartenenze multi-gruppo, quindi per quelle usa warden device set <id> groups ….e modifica, / muovi il focus.
Dispositivi, asse di group-byIl tasto G cicla l’asse di raggruppamento — noneownerdepartmentprofile. L’appartenenza a un gruppo non è attualmente un’opzione di group-by; tracciala tramite owner o profile, oppure per nome di file se mantieni un groups.d/*.toml per persona.G cicla group-by.
Resolver inspectorRaggiungibile con s da qualsiasi vista. Dato un IP sorgente, stampa il dispositivo abbinato, il livello al quale ha risolto e — se è scattato il livello 3 — Via group: <id>. La risposta più rapida a “perché questo dispositivo è su quel profilo?”.s apri l’inspector, digita l’IP, Enter.

Non c’è un modal TUI per creare, modificare o eliminare un gruppo — e i tags del gruppo allo stesso modo non hanno ancora un editor nella dashboard (esistono nello schema e nella CLI, ma sono fuori scopo per la TUI). Impostali con warden group tag …. Fonte: src/tui/ui.rs:281-288, src/tui/tabs/devices.rs:531-555, src/tui/resolver_modal.rs:250-259.

API REST

I gruppi non sono esposti via REST. Non c’è un endpoint /api/groups, niente CRUD per gruppi, niente vista di lettura specifica. La configurazione fusa restituita da GET /api/config include [[groups]] come JSON, quindi una dashboard esterna può renderizzare il roster su disco — ma le scritture passano per la CLI, mai per l’API.

GET /api/devices (autenticato con Bearer token) restituisce una riga per dispositivo con il nome del profilo risolto; se ti serve la vista per gruppo, raggruppa quelle righe lato client per il loro campo groups.

IPC

Il protocollo del socket Unix non ha verbi specifici per i gruppi — niente IpcCommand::GroupAdd, GroupUpdate, GroupRemove, o GroupList. I gruppi sono solo CLI e disco: warden group … riscrive il TOML, lancia il validator, e poi chiede al daemon in esecuzione di ricaricare via lo stesso IpcCommand::Reload usato da ogni altra mutazione CLI. Se il daemon è spento la scrittura atterra comunque; il daemon prende i nuovi gruppi al prossimo avvio.

L’unico canale IPC che tocca lo stato dei gruppi è DevicePatch.groups: Option<Vec<String>> — usato dal modal Edit della TUI per impostare la lista di appartenenza di un dispositivo per volta. Fonte: src/api/routes.rs:27-58, src/ipc/protocol.rs:56,308-316.

Ordine di precedenza

I gruppi stanno al livello 3 della catena del resolver di Warden, lunga 5 livelli. La catena completa, in ordine di esecuzione — vince il primo match:

  1. Profilo diretto del dispositivo. L’IP sorgente (o il MAC via ARP) abbina una riga [[devices]], e il dispositivo ha profile = "...".
  2. Pianificazione attiva. Una voce [[schedules]] la cui finestra temporale copre adesso prende come bersaglio questo dispositivo o uno dei suoi gruppi. Una pianificazione che bersaglia il dispositivo vince su una che bersaglia uno dei suoi gruppi.
  3. Profilo del gruppo. Il dispositivo non ha un profile diretto ma appartiene a uno o più [[groups]]. Vince il gruppo a priorità più alta; stessa priorità + profili diversi è un errore del validator (vedi Priorità e spareggio qui sotto).
  4. Match della subnet a prefisso più lungo. L’IP sorgente non è in [[devices]] per niente ma ricade dentro un CIDR [[subnets]]. Vince il prefisso più lungo. Un dispositivo configurato con un gruppo non ricade mai sulla subnet — l’essere in [[devices]] è ciò che apre i livelli 1-3, quindi le subnet scattano solo per host non mappati.
  5. Fallback globale. [server].default_profile. Se non impostato, le query non mappate ricevono REFUSED.

Se [server].enforce_device_mac = true (il default, ex enforce_client_mac) e la tabella ARP live mostra un MAC che non corrisponde al mac o a uno dei mac_aliases del dispositivo, il dispositivo viene declassato al livello 4. I livelli 1, 2 e 3 sono tutti saltati — il binding del gruppo viene bypassato, non solo il profilo diretto. Il declassamento è ergonomico, non crittografico; vedi note di sicurezza.

Fonte: src/profiles/resolver.rs:1-46,339-365,394-460,811-857.

Priorità e spareggio

priority è un i32 con default 0. Più alto vince. I valori negativi sono accettati (utili per gruppi di fallback “declassati”).

Quando un dispositivo appartiene a due gruppi con stessa priorità e profili diversi, il validator rifiuta di caricare la config:

text
device "anna-iphone" is in multiple groups with the same priority (10)
but different profiles: kids → kids, school → school-allow-classroom
help: raise the priority of the winning group, remove the device from
      one group, or harmonise the profiles

Stessa priorità + stesso profilo va bene — il dispositivo passa semplicemente attraverso quel profilo condiviso, niente conflitto da rompere. La chiave di sort sui pari, a livello di implementazione, è id ASC, ma il validator cattura il caso ambiguo prima che la risoluzione venga eseguita.

Fonte: src/config/schema/validator.rs:672-712.

Note di sicurezza

  • warden group add, set, e remove sono auditati. Ciascuno scrive un record CliMutation con scope = "group" e action = "group.add" / "group.set" / "group.remove" (src/cli/commands/groups.rs:141-149, 180-189, 250-258). Un operatore che cerca “chi ha creato il gruppo kids?” lo trova in audit.log, non solo nella git history del file. Anche i verbi di scrittura di regole warden group allow / deny sono auditati, con scope = "group", target_id = "<group-id>", action = "rule.add" / "rule.remove" — e così anche i verbi tag: warden group tag add / remove registra un’azione group.tag_add / group.tag_remove. Una modifica a mano del TOML non lascia traccia; i verbi sì.
  • Rimuovere un gruppo referenziato è rifiutato, in due passaggi. Il controllo inline della CLI nomina ogni dispositivo che ancora referenzia il gruppo. Dopo la scrittura, il validator cattura i riferimenti da [[schedules]].target_id, rifiutando il reload e ripristinando il file — emergono come errore schedules[i].target_id "<gid>" is not defined invece che con il messaggio più amichevole stile dispositivo.
  • L’appartenenza a un gruppo non è un confine di sicurezza. Un dispositivo sulla LAN che non corrisponde a nessuna riga [[devices]] ricade sul profilo di subnet o sul profilo di default — essere assente da ogni gruppo significa che si applica il livello 4 o 5, non “bloccato di default”. Per negare i client non mappati, lascia [server].default_profile non impostato così la catena restituisce REFUSED al livello 5.
  • L’enforcement del MAC strappa anche il gruppo. Sotto un mismatch del MAC, il dispositivo cade alla risoluzione a livello di subnet; il profilo del gruppo viene bypassato insieme al profilo diretto. Un attaccante deciso sulla LAN può falsificare un MAC, ma fermerà un adolescente curioso che vorrebbe cambiare il proprio IP statico per scappare al gruppo kids. Vedi il modello delle minacce.
  • warden group allow/deny modificano il profilo sottostante, non il gruppo. La admin rule sintetizzata è condivisa con tutto ciò che è legato a quel profilo — inclusi profili referenziati da altri gruppi, dispositivi, o [server].default_profile. Se vuoi una regola che si applichi a un solo gruppo, ritaglia un profilo dedicato.

Risoluzione problemi

Un dispositivo riceve il profilo sbagliato. Chiedi al resolver direttamente — ti dirà a quale livello ha matchato e, se è scattato il livello 3, in quale gruppo:

bash
warden resolve 10.10.1.107
# Level 3: device 'anna-iphone' → group 'school' → profile 'school-allow-classroom'

Se il livello mostrato non è quello che ti aspettavi, risali la catena: il MAC ha matchato? era attiva una pianificazione? enforce_device_mac sta declassando? il dispositivo dichiara un profile diretto che hai dimenticato?

Un reload fallisce con “device ‘X’ is in multiple groups with the same priority…”. Hai aggiunto il dispositivo a un secondo gruppo la cui priorità è uguale a quella di un gruppo esistente, e i due gruppi sono legati a profili diversi. Il validator non sa scegliere. Sistema una di queste tre: alza una priorità, togli il dispositivo da un gruppo, oppure armonizza i due profili.

Un reload fallisce con groups[i] "X".profile "Y" is not defined. Il gruppo referenzia un profilo che non esiste — typo, oppure il profilo è stato rimosso senza aggiornare il gruppo. Esegui warden config lint per la lista completa, poi sistema il typo o esegui warden group set <id> profile <profilo-esistente>.

Un reload fallisce con devices[i] "X".groups references "Y" which is not defined. Un dispositivo referenzia un gruppo che non è dichiarato. Stessa diagnosi — typo o riferimento stantio. Sistema con warden device set X groups <nuova-lista>, oppure modifica a mano il file del dispositivo.

warden group remove viene rifiutato. Un dispositivo ha ancora il gruppo nel suo campo groups. L’errore nomina ogni dispositivo offendente. O li riassegni con warden device set <device> groups <nuova-lista>, oppure modifichi a mano il devices.d/*.toml rilevante. Se una [[schedules]] punta al gruppo, il controllo a livello di dispositivo passa ma il validator post-write rolla indietro la modifica — sistema la pianificazione prima.

Un dispositivo che è solo in [[groups]].devices non riceve il profilo del gruppo. Dovrebbe — il resolver fonde entrambi i lati a tempo di caricamento. Se non funziona, esegui warden resolve <ip> per vedere il livello effettivo della catena, e controlla che l’id del dispositivo nella lista devices del gruppo combaci esattamente con [[devices]].id (il validator cattura le discrepanze al caricamento, ma riferimenti stantii in un file modificato a mano sono il colpevole abituale).

Per altro, vedi risoluzione problemi.

Vedi anche

  • Dispositivi — le voci che i gruppi tengono insieme.
  • Profili — cosa referenzia il campo profile di un gruppo.
  • Subnet — profilo di fallback per gli host non in [[devices]].
  • Pianificazioni — cambio di profilo basato sull’orario, può prendere come bersaglio un gruppo con target_type = "group".
  • Regole admin — cosa sintetizzano warden group allow/deny.
  • Riferimento TOML — ogni campo, ogni vincolo.
  • Riferimento CLI — la superficie completa di warden group ….