feat(infra): auto-commit con 86 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
---
|
||||
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:<id>' 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`.
|
||||
Reference in New Issue
Block a user