Components

ctrl-exec architecture — components and their relationships

ctrl-exec-dispatcher (ced)
The control host binary. Manages the CA, handles agent pairing, dispatches commands to agents, and maintains the agent registry. The CLI is stateless — each invocation opens connections, collects results, and exits.
ctrl-exec-agent (cea)
The daemon running on each remote host. Listens on port 7443 over mTLS. Enforces the local script allowlist. Executes scripts on request, captures output, and returns results. Holds no state that cannot be reconstructed from its configuration files.
ctrl-exec-api
An optional HTTP API server running on the control host. Exposes the same run, ping, and discovery operations as the CLI as JSON endpoints. Shares the same CA and config as ced. Useful for integration with external tools and automation pipelines.

Execution Flow

ctrl-exec request flow — from initiator to structured result

A ced run host-a backup-mysql invocation proceeds as follows:

  1. ced reads its config and the agent registry to resolve host-a to an IP and port.
  2. If an auth hook is configured, it is called with the full request context. A non-zero exit aborts the request.
  3. ced checks the concurrency lock for host-a:backup-mysql. If the script is already running on that host, the request is rejected.
  4. ced opens an mTLS connection to host-a:7443. Both sides verify the peer certificate against the CA. The agent also checks the ctrl-exec cert serial against its stored value.
  5. ced sends a JSON request body containing the script name, arguments, request ID, username, and token.
  6. The agent validates the script name against its allowlist. If not present, the request is denied.
  7. If an agent-side auth hook is configured, it is called after allowlist validation.
  8. The agent forks and executes the script. The full request context is piped as JSON to the script's stdin.
  9. The agent captures stdout, stderr, and exit code, logs the result, and returns it to ced.
  10. ced logs the result with the same request ID and prints output.

For multi-host dispatch, steps 4–10 run in parallel for each host.

The Agent Allowlist

The allowlist is defined in /etc/ctrl-exec-agent/scripts.conf on each agent — a simple key-value file mapping a short name to an absolute script path:

backup-mysql  = /opt/ctrl-exec-scripts/backup-mysql.sh
check-disk    = /opt/ctrl-exec-scripts/check-disk.sh

Only names present in this file can be requested. Script names are restricted to alphanumeric characters and hyphens. The allowlist reloads on SIGHUP without a restart.

All persistent state is files on disk. The dispatcher holds no runtime state. Multiple instances sharing the same state files serve requests interchangeably.

Persistent State

/etc/ctrl-exec/
CA key and certificate, ctrl-exec key and certificate, auth hook. The CA key is the root of trust for the deployment.
/etc/ctrl-exec-agent/
Agent key and certificate, CA certificate, config, allowlist, stored ctrl-exec serial, optional revocation list.
/var/lib/ctrl-exec/agents/
Agent registry. One JSON file per paired agent. Written atomically.
/var/lib/ctrl-exec/locks/
Transient concurrency lock files. One per active host:script pair. Not preserved across restarts.
/var/lib/ctrl-exec/runs/
Run results stored by the API server. Keyed by request ID, retained for 24 hours.

Reference Documentation

Full command reference and all configuration keys: REFERENCE

Internals, module structure, and wire format: DEVELOPER