--- name: wg_peer_revoke kind: function lang: go domain: infra version: "1.0.0" purity: impure signature: "func WGPeerRevoke(deviceID, operator, reason string, configPath, auditDBPath string) (WGPeerRevokeAudit, error)" description: "Kill switch: revoca peer permanentemente. Anade a blacklist + audit log hash-chained inviolable (SHA256 chain). Para dispositivos perdidos/comprometidos." tags: [wireguard, hub, revoke, kill-switch, audit, security] uses_functions: - wg_peer_remove_go_infra uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [] params: - name: deviceID desc: "Identificador unico del dispositivo a revocar. Debe coincidir con '# DeviceID:' en wg0.conf." - name: operator desc: "Nombre del operador que ejecuta la revocacion. Se guarda en audit log. No puede ser vacio." - name: reason desc: "Motivo de la revocacion (ej. 'dispositivo perdido', 'comprometido'). No puede ser vacio. No incluir PII." - name: configPath desc: "Ruta absoluta al wg0.conf del hub. El peer se elimina del config activo via syncconf." - name: auditDBPath desc: "Ruta al SQLite de audit. Se crea con schema si no existe. Contiene la cadena de hashes inviolable." output: "WGPeerRevokeAudit con DeviceID, PublicKey, RevokedAt (unix), RevokedBy, Reason, PrevHash y ThisHash. ThisHash = SHA256(PrevHash|DeviceID|PublicKey|RevokedAt|Operator|Reason)." tested: true tests: - "audit DB contiene registro con this_hash != prev_hash" - "segunda revoke del mismo peer → error already revoked" test_file_path: "functions/infra/wg_peer_revoke_test.go" file_path: "functions/infra/wg_peer_revoke.go" --- ## Ejemplo ```go audit, err := infra.WGPeerRevoke( "device-laptop-alice", "operator-bob", "dispositivo perdido en viaje", "/etc/wireguard/wg0.conf", "/var/lib/wg-hub/revoked.db", ) if err != nil { log.Fatal(err) } fmt.Printf("revoked: device=%s pubkey=%s hash=%s\n", audit.DeviceID, audit.PublicKey, audit.ThisHash) ``` ## Cuando usarla Cuando un dispositivo esta perdido, robado o comprometido y NO debe poder volver a conectarse nunca. Deja registro inmutable en audit DB con hash chain SHA256 y escribe la PublicKey en `/etc/wireguard/wg_revoked.list`. Para baja temporal (rotar claves, reconfigurar) usa `wg_peer_remove_go_infra`. ## Gotchas - **Reason obligatorio**: reason vacio devuelve error antes de tocar nada. - **Idempotencia**: revocar el mismo deviceID dos veces devuelve `already revoked`. La comprobacion es sobre la audit DB, no sobre el config. - **Audit DB borrada**: si auditDBPath se borra, la chain se reinicia desde genesis (prev_hash vacio). El break de integridad es visible (primer registro sin prev_hash). El sistema lo acepta pero queda evidencia del gap. - **Blacklist `/etc/wireguard/wg_revoked.list`**: requiere permisos de escritura en `/etc/wireguard/`. Si falla, el audit DB ya tiene el registro (no se revierte) pero la funcion devuelve error indicando el gap. - **Reason no debe contener PII**: se guarda en texto plano en SQLite y en la blacklist. Usar referencias internas en vez de nombres reales. - **syncconf**: hereda el requisito de privilegios de WGPeerRemove. Ver gotchas de `wg_peer_remove_go_infra`.