Gruppi
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
familylegato adefaultper i laptop dei genitori e il desktop in cucina. - Un gruppo
kidslegato akids, che raccoglie ogni dispositivo che i bambini toccano — tablet, il laptop scolastico, la Switch di famiglia. - Un gruppo
iotlegato aiot, che riunisce lampadine smart, la stampante, il robot aspirapolvere — qualunque cosa la cui cloud del produttore non sia di tua fiducia. - Un gruppo
guestslegato 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>].
[[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.
| Gruppo | Dimensione | Campo TOML | Cosa regola |
|---|---|---|---|
| Identità | Id (obbligatorio) | id | Riferimento incrociato stabile. Ogni dispositivo che vuole questo gruppo, ogni pianificazione che lo prende come bersaglio, nomina questo id. |
| Nome leggibile (obbligatorio) | display_name | Etichetta operatore mostrata nella scheda laterale della TUI e nelle liste della CLI. | |
| Binding del resolver | Profilo (obbligatorio) | profile | La policy applicata a ogni membro al livello 3 della catena. Deve referenziare un [profiles.<id>] definito. |
| Peso di spareggio | priority | Quando un dispositivo appartiene a più gruppi con profili diversi, vince la priorità più alta. Stessa priorità + profili diversi è un errore del validatore. | |
| Appartenenza | Roster diretto | devices | La lista di id di dispositivo iscritti a questo gruppo, scritta dal lato gruppo. |
| Riferimento inverso (esterno) | [[devices]].groups | La 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
kidsconwarden profile deny kids …(oppurewarden 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 unprofile— è obbligatorio. Un gruppo porta invece una listatagsche 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 campotagsa livello di dispositivo.
Riferimento dei campi
| Campo | Tipo | Obbligatorio | Default | Scopo |
|---|---|---|---|---|
id | stringa, [a-z0-9-], lunghezza 1–64, niente trattino iniziale o finale | sì | — | Riferimento incrociato stabile. |
display_name | stringa | sì | — | Etichetta TUI / CLI. Il percorso set della CLI impone non vuoto. |
profile | id di profilo | sì | — | Deve referenziare un [profiles.<id>] dichiarato. |
priority | i32 | no | 0 | Più alto vince quando un dispositivo è in più gruppi. I valori negativi sono accettati. |
devices | lista di id di dispositivo | no | [] | Ogni id deve referenziare un [[devices]] dichiarato. I gruppi vuoti sono ammessi. |
tags | lista 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:
# Iscrizione lato gruppo
[[groups]]
id = "kids"
profile = "kids"
devices = ["kids-tablet", "anna-iphone"]# 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:
[[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:
[[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:
[[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:
[[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"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.
| Comando | Cosa fa |
|---|---|
warden group list | Elenca 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:
# 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 livedaemon not running — change will take effect on next startnote: 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.
| Tab | Come compaiono i gruppi | Tasti utili |
|---|---|---|
| Dispositivi | La 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-by | Il tasto G cicla l’asse di raggruppamento — none → owner → department → profile. 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 inspector | Raggiungibile 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:
- Profilo diretto del dispositivo. L’IP sorgente (o il MAC via ARP) abbina una riga
[[devices]], e il dispositivo haprofile = "...". - 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. - Profilo del gruppo. Il dispositivo non ha un
profilediretto 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). - 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. - Fallback globale.
[server].default_profile. Se non impostato, le query non mappate ricevonoREFUSED.
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:
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 profilesStessa 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, eremovesono auditati. Ciascuno scrive un recordCliMutationconscope = "group"eaction = "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 gruppokids?” lo trova inaudit.log, non solo nella git history del file. Anche i verbi di scrittura di regolewarden group allow/denysono auditati, conscope = "group",target_id = "<group-id>",action = "rule.add"/"rule.remove"— e così anche i verbi tag:warden group tag add / removeregistra un’azionegroup.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 erroreschedules[i].target_id "<gid>" is not definedinvece 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_profilenon impostato così la catena restituisceREFUSEDal 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/denymodificano 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:
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
profiledi 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 ….