feat(zerotier): add ZeroTier network governance module
Add comprehensive ZeroTier integration for managing network access: - Portal networks: manager-created ZeroTier network bindings - Device registration: user-owned ZeroTier node endpoints - Approval workflows: request/approve/revoke network access - Activation sessions: time-limited network authorization - Kill switch: emergency access revocation - Reconciliation job: sync portal state with ZeroTier controller Includes ZeroTier client SDK supporting both Central and self-hosted controller APIs, with full CRUD operations for networks and members.
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
"""ZeroTier reconciliation scheduled job.
|
||||
|
||||
This module implements the scheduled job for reconciling portal network state
|
||||
with the ZeroTier controller. It is designed to be run periodically (every
|
||||
1-2 minutes via cron) to:
|
||||
|
||||
1. Expire activation sessions past their TTL and deauthorize the corresponding ZT members
|
||||
2. Sync observed ZeroTier membership state into zerotier_memberships cache
|
||||
3. Reconcile portal membership state against ZT controller state
|
||||
4. Flag unknown ZT members (not in portal)
|
||||
5. Detect and repair drift (ZT says authorized but portal says inactive, and vice versa)
|
||||
|
||||
Usage:
|
||||
python manage.py run_zerotier_reconciliation
|
||||
|
||||
Or call directly:
|
||||
from gatehouse_app.jobs.zerotier_reconciliation_job import run_reconciliation
|
||||
run_reconciliation()
|
||||
|
||||
Cron example (every 2 minutes):
|
||||
*/2 * * * * cd /path/to/app && python manage.py run_zerotier_reconciliation
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional
|
||||
|
||||
from gatehouse_app.services import zerotier_reconciliation_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run_reconciliation() -> dict:
|
||||
"""Run full ZeroTier reconciliation across all networks and activations.
|
||||
|
||||
Returns:
|
||||
Dictionary with reconciliation results:
|
||||
- expired_activations: number of activation sessions expired
|
||||
- networks_processed: number of portal networks reconciled
|
||||
- errors: number of networks that had errors
|
||||
"""
|
||||
logger.info(f"[ZT Reconcile] Starting reconciliation at {datetime.now(timezone.utc).isoformat()}")
|
||||
|
||||
results = {
|
||||
"expired_activations": 0,
|
||||
"networks_processed": 0,
|
||||
"errors": 0,
|
||||
}
|
||||
|
||||
try:
|
||||
expired = zerotier_reconciliation_service.reconcile_expired_activations()
|
||||
results["expired_activations"] = expired
|
||||
except Exception as exc:
|
||||
logger.error(f"[ZT Reconcile] Error expiring activations: {exc}")
|
||||
|
||||
try:
|
||||
summary = zerotier_reconciliation_service.reconcile_all()
|
||||
results["networks_processed"] = summary.get("networks_processed", 0)
|
||||
results["errors"] = summary.get("errors", 0)
|
||||
except Exception as exc:
|
||||
logger.error(f"[ZT Reconcile] Error during network reconciliation: {exc}")
|
||||
results["errors"] += 1
|
||||
|
||||
logger.info(
|
||||
f"[ZT Reconcile] Complete at {datetime.now(timezone.utc).isoformat()}: "
|
||||
f"expired={results['expired_activations']} "
|
||||
f"networks={results['networks_processed']} "
|
||||
f"errors={results['errors']}"
|
||||
)
|
||||
|
||||
return results
|
||||
Reference in New Issue
Block a user