Additional Changes to VPN Tunneling

This commit is contained in:
2026-01-11 19:02:53 -07:00
parent 6ceb59f717
commit df14a1e26a
18 changed files with 681 additions and 175 deletions

View File

@@ -47,11 +47,11 @@ def _b64decode(value: str) -> bytes:
def _resolve_shell_port() -> int:
raw = os.environ.get("BOREALIS_WIREGUARD_SHELL_PORT")
try:
value = int(raw) if raw is not None else 47001
value = int(raw) if raw is not None else 47002
except Exception:
value = 47001
value = 47002
if value < 1 or value > 65535:
return 47001
return 47002
return value

View File

@@ -22,13 +22,22 @@ import os
import subprocess
import threading
import time
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Optional
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import x25519
from signature_utils import verify_and_store_script_signature
try:
from signature_utils import verify_and_store_script_signature
except Exception: # pragma: no cover - fallback for runtime path issues
import sys
from pathlib import Path as _Path
base_dir = _Path(__file__).resolve().parents[1]
if str(base_dir) not in sys.path:
sys.path.insert(0, str(base_dir))
from signature_utils import verify_and_store_script_signature
ROLE_NAME = "WireGuardTunnel"
ROLE_CONTEXTS = ["system"]
@@ -88,18 +97,31 @@ def _generate_client_keys(root: Path) -> Dict[str, str]:
return {"private": priv, "public": pub}
@dataclass
class SessionConfig:
token: Dict[str, Any]
virtual_ip: str
allowed_ips: str
endpoint: str
server_public_key: str
allowed_ports: str
idle_seconds: int = 900
preshared_key: Optional[str] = None
client_private_key: Optional[str] = None
client_public_key: Optional[str] = None
def __init__(
self,
*,
token: Dict[str, Any],
virtual_ip: str,
allowed_ips: str,
endpoint: str,
server_public_key: str,
allowed_ports: str,
idle_seconds: int = 900,
preshared_key: Optional[str] = None,
client_private_key: Optional[str] = None,
client_public_key: Optional[str] = None,
) -> None:
self.token = token
self.virtual_ip = virtual_ip
self.allowed_ips = allowed_ips
self.endpoint = endpoint
self.server_public_key = server_public_key
self.allowed_ports = allowed_ports
self.idle_seconds = idle_seconds
self.preshared_key = preshared_key
self.client_private_key = client_private_key
self.client_public_key = client_public_key
class WireGuardClient:
@@ -150,6 +172,19 @@ class WireGuardClient:
if port < 1 or port > 65535:
raise ValueError("Invalid token port")
if not signature:
if sig_alg or signing_key:
raise ValueError("Token signature missing")
stored_key = None
if signing_client is not None and hasattr(signing_client, "load_server_signing_key"):
try:
stored_key = signing_client.load_server_signing_key()
except Exception:
stored_key = None
if isinstance(stored_key, str) and stored_key.strip():
raise ValueError("Token signature missing")
return
if signature:
if sig_alg and str(sig_alg).lower() not in ("ed25519", "eddsa"):
raise ValueError("Unsupported token signature algorithm")
@@ -292,6 +327,11 @@ class Role:
self._log("WireGuard start payload missing/invalid.", error=True)
return None
payload_agent_id = payload.get("agent_id") or payload.get("agent_guid")
if payload_agent_id:
if str(payload_agent_id).strip() != str(self.ctx.agent_id).strip():
return None
token = payload.get("token") or payload.get("orchestration_token")
if not isinstance(token, dict):
self._log("WireGuard start missing token payload.", error=True)
@@ -351,6 +391,9 @@ class Role:
async def _vpn_tunnel_stop(payload):
reason = "server_stop"
if isinstance(payload, dict):
target_agent = payload.get("agent_id")
if target_agent and str(target_agent).strip() != str(self.ctx.agent_id).strip():
return
reason = payload.get("reason") or reason
self._log(f"WireGuard stop requested (reason={reason}).")
self.client.stop_session(reason=str(reason))

View File

@@ -1,5 +1,7 @@
import os
import importlib.util
import sys
from pathlib import Path
from typing import Dict, List, Optional
@@ -37,8 +39,27 @@ class RoleManager:
self.config = config
self.loop = loop
self.hooks = hooks or {}
self._log_hook = self.hooks.get('log_agent')
self.roles: Dict[str, object] = {}
# Ensure role helpers alongside Roles/ are importable (e.g., signature_utils.py).
try:
base_path = Path(self.base_dir).resolve()
parent_path = base_path.parent
for candidate in (base_path, parent_path):
if candidate and str(candidate) not in sys.path:
sys.path.insert(0, str(candidate))
except Exception:
pass
def _log(self, message: str, *, error: bool = False) -> None:
if callable(self._log_hook):
try:
target = "agent.error.log" if error else "agent.log"
self._log_hook(message, fname=target)
except Exception:
pass
def _iter_role_files(self) -> List[str]:
roles_dir = os.path.join(self.base_dir, 'Roles')
if not os.path.isdir(roles_dir):
@@ -56,7 +77,8 @@ class RoleManager:
mod = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(mod)
except Exception:
except Exception as exc:
self._log(f"Role load failed during import path={path} error={exc}", error=True)
continue
role_name = getattr(mod, 'ROLE_NAME', None)
@@ -75,10 +97,12 @@ class RoleManager:
if hasattr(role_obj, 'register_events'):
try:
role_obj.register_events()
except Exception:
pass
except Exception as exc:
self._log(f"Role register_events failed name={role_name} error={exc}", error=True)
self.roles[role_name] = role_obj
except Exception:
self._log(f"Role loaded name={role_name} context={self.context}")
except Exception as exc:
self._log(f"Role init failed name={role_name} path={path} error={exc}", error=True)
continue
def on_config(self, roles_cfg: List[dict]):
@@ -96,4 +120,3 @@ class RoleManager:
role.stop_all()
except Exception:
pass