Agent Internals
Subsystems
These subsystems are initialized and started by plexd up:
| Subsystem | Package | Reference |
|---|---|---|
| Control Plane Client | internal/api | Control Plane Client |
| Registration | internal/registration | Registration |
| Event Verification | internal/api (Ed25519Verifier) | Event Verification |
| WireGuard | internal/wireguard | WireGuard Tunnel Management |
| NAT Traversal | internal/nat | NAT Traversal via STUN |
| Peer Exchange | internal/peerexchange | Peer Endpoint Exchange |
| Network Policy | internal/policy | Network Policy Enforcement |
| Secure Tunneling | internal/tunnel | Secure Access Tunneling |
| SSE Manager | internal/api (SSEManager) | Control Plane Client |
| Reconciler | internal/reconcile | Configuration Reconciliation |
| Heartbeat | internal/agent (HeartbeatService) | Heartbeat Service |
| Integrity | internal/integrity | Integrity Verification |
| Actions | internal/actions | Remote Actions and Hooks |
| Node API | internal/nodeapi | Local Node API |
| Metrics | internal/metrics | Metrics Collection & Reporting |
| Log Forwarding | internal/logfwd | Log Forwarding |
| Audit Forwarding | internal/auditfwd | Audit Forwarding |
| Bridge (bridge mode) | internal/bridge | Bridge Mode |
Startup Sequence (plexd up)
The runUp function in cmd/plexd/cmd/up.go performs initialization before entering steady state:
Initialization:
- Parse config — read YAML, apply CLI flag overrides, apply
PLEXD_*env overrides - Set up logger — structured
sloglogger with configured level - Create control plane client —
api.NewControlPlane()with API config and build version - Register —
registrar.Register()loads or creates node identity (fatal on failure) - Create Ed25519 verifier — decode the control plane's signing public key from identity 5a. Initialize WireGuard — create WireGuard interface, configure address and MTU, bring interface up 5b. Initialize NAT + Peer Exchange — create STUN client, NAT discoverer, and peer exchanger 5c. Initialize Network Policy — create policy engine, firewall controller, and enforcer 5d. Initialize Tunnel — load/generate host key, create JWT verifier and mesh server 5e. Initialize Bridge (bridge mode only) — create bridge manager, ACME, ingress, user access, site-to-site managers; run Setup on each
- Create SSE manager —
api.NewSSEManager()with handlers for signing key rotation, WireGuard peer events, tunnel events, policy events, and bridge events (bridge mode) - Create reconciler —
reconcile.NewReconciler()with handlers for WireGuard, policy, and bridge reconciliation - Create heartbeat service —
agent.NewHeartbeatService()with subsystem status enrichment, auth-failure callback, and key-rotation callback - Create integrity store + verifier —
integrity.NewStore()andintegrity.NewVerifier()for hook checksums - Create action executor —
actions.NewExecutor(), register 11 built-in actions, registeraction_requestSSE handler, report capabilities to control plane - Create hook watcher —
actions.NewHookWatcher()for filesystem hook scanning - Create node API server —
nodeapi.NewServer(), wire action provider, hook reloader, and reconcile handler - Create metrics collectors + manager — system collector, agent stats collector,
metrics.NewManager() - Create log sources + forwarder — journald source, file sources from
file_patterns,logfwd.NewForwarder() - Create audit sources + forwarder — process source,
auditfwd.NewForwarder()
Goroutines (10 in node mode, 11 in bridge mode):
After initialization, goroutines are started via a sync.WaitGroup:
- SSE Manager —
sseMgr.Start()— event stream connection - Heartbeat —
heartbeat.Run()— periodic heartbeats - Reconciler —
reconciler.Run()— periodic state reconciliation - Node API —
nodeAPISrv.Start()— Unix socket + optional HTTP server - Hook Watcher —
hookWatcher.Watch()— filesystem watching for hook changes - Metrics Manager —
metricsMgr.Run()— collect and report metrics - Log Forwarder —
logForwarder.Run()— collect and forward logs - Audit Forwarder —
auditForwarder.Run()— collect and forward audit events - Peer Exchange —
exchanger.Run()— STUN discovery and endpoint exchange loop - Mesh Server —
meshServer.Start()— tunnel SSH server - Bridge Relay (bridge mode only) —
bridgeMgr.StartRelay()— UDP relay listener
Shutdown Sequence
On SIGTERM or SIGINT:
- Context cancel — the signal-notify context is cancelled, which signals all goroutines to stop
sseMgr.Shutdown()— close the SSE connectionexecutor.Shutdown()— drain running actionsmeshServer.Shutdown()— stop tunnel SSH server and drain sessionsingressMgr.Teardown()— close ingress listeners (bridge mode)userAccessMgr.Teardown()— remove user access peers and interface (bridge mode)s2sMgr.Teardown()— remove site-to-site tunnels and interfaces (bridge mode)acmeMgr.Teardown()— stop ACME certificate management (bridge mode)bridgeMgr.Teardown()— remove bridge routes and forwarding (bridge mode)enforcer.Teardown()— remove firewall chains and ruleswgMgr.Teardown()— delete WireGuard interface (last, others depend on it)wg.Wait()with 30s timeout — wait for all goroutines to exit; force exit if timeout exceeded
Authentication Flow
- Bootstrap — node registers using a bootstrap token (file, env var, or metadata service)
- Node Secret Key — registration returns a
NodeSecretKeyused for all subsequent API authentication - Heartbeat Auth — each heartbeat uses the node secret key; on 401 Unauthorized, the
onAuthFailurecallback triggers re-registration - Key Rotation — on
signing_key_rotatedSSE events or heartbeatRotateKeysflag, the Ed25519 verifier keys are updated
SSE Event Types
The SSE manager processes these event types:
| Event | Handler | Description |
|---|---|---|
signing_key_rotated | Updates Ed25519 verifier keys | Fired when the control plane rotates its signing key pair |
action_request | Dispatches to action executor | Requests execution of a built-in action or hook |
peer_added | wireguard.HandlePeerAdded | Adds a new WireGuard peer |
peer_removed | wireguard.HandlePeerRemoved | Removes a WireGuard peer |
peer_key_rotated | wireguard.HandlePeerKeyRotated | Rotates a peer's public key |
peer_endpoint_changed | wireguard.HandlePeerEndpointChanged | Updates a peer's endpoint (via peer exchange) |
policy_updated | policy.HandlePolicyUpdated | Triggers policy reconciliation |
ssh_session_setup | tunnel.HandleSSHSessionSetup | Creates a new tunnel session |
session_revoked | tunnel.HandleSessionRevoked | Closes a revoked tunnel session |
bridge_config_updated | bridge.HandleBridgeConfigUpdated | Triggers bridge reconciliation (bridge mode) |
relay_session_assigned | bridge.HandleRelaySessionAssigned | Assigns a relay session (bridge mode) |
relay_session_revoked | bridge.HandleRelaySessionRevoked | Revokes a relay session (bridge mode) |
ingress_rule_assigned | bridge.HandleIngressRuleAssigned | Assigns an ingress rule (bridge mode) |
ingress_rule_revoked | bridge.HandleIngressRuleRevoked | Revokes an ingress rule (bridge mode) |
ingress_config_updated | bridge.HandleIngressConfigUpdated | Triggers ingress reconciliation (bridge mode) |
user_access_peer_assigned | bridge.HandleUserAccessPeerAssigned | Assigns a user access peer (bridge mode) |
user_access_peer_revoked | bridge.HandleUserAccessPeerRevoked | Revokes a user access peer (bridge mode) |
user_access_config_updated | bridge.HandleUserAccessConfigUpdated | Triggers user access reconciliation (bridge mode) |
site_to_site_tunnel_assigned | bridge.HandleSiteToSiteTunnelAssigned | Assigns a site-to-site tunnel (bridge mode) |
site_to_site_tunnel_revoked | bridge.HandleSiteToSiteTunnelRevoked | Revokes a site-to-site tunnel (bridge mode) |
site_to_site_config_updated | bridge.HandleSiteToSiteConfigUpdated | Triggers site-to-site reconciliation (bridge mode) |
See Also
- Architecture — High-level architecture diagrams, platform support
- Agent Lifecycle — Lifecycle phases, operational behavior, deregistration
- Configuration Reference — Full YAML configuration schema
- CLI Reference — Command-line interface and subcommands
- Environment Variables Reference — All
PLEXD_*overrides