Secure server management agent for Storm Developments infrastructure
Project description
Storm Pulse Agent
Secure server management agent for Storm Developments. Connects outbound to a Django dashboard over WebSocket with mTLS, pushes system metrics, and executes whitelisted deploy commands. Zero listening ports.
How It Works
- Agent connects outbound to the dashboard. Nginx terminates mTLS.
- Sends a
registermessage (including its available commands list), then pushes metrics every 15s (CPU, memory, disk, load, containers). - Dashboard sends HMAC-signed commands. Agent verifies signature, nonce, and expiry before executing.
- Commands run via
subprocess.run(shell=False)against a strict whitelist. Custom commands can be added via config with optional overridable parameters (regex-validated). No shell injection possible.
Read the Protocol Specification for exact information.
Security
Five layers, each independent:
- Network -- No inbound ports. Agent initiates all connections.
- Transport -- mTLS with per-agent certs from a private CA.
- Application -- HMAC-SHA256 + nonce + expiry on every command.
- Execution -- Whitelisted commands only. Absolute paths.
shell=False. Config placeholders from local config only; runtime params are regex-validated. - OS -- Dedicated user. Systemd sandboxing.
See the Security Architecture wiki page for the full design.
Setup
Requires Python 3.12+. Three runtime deps: websockets, psutil, cryptography.
Install from PyPI:
pip install storm-pulse-agent
For full setup instructions (system user, permissions, systemd, firewall), see the Setup Guide.
CLI
stormpulse enroll ENDPOINT AGENT_ID TOKEN [--creds-dir DIR] [--force]
stormpulse init [--creds-dir DIR] [--force]
stormpulse run [CONFIG]
stormpulse status [CONFIG]
stormpulse garage init [--config PATH] [--garage-config PATH] [--force]
stormpulse logging init [--config PATH]
stormpulse --version
enroll -- One-time enrollment. Generates an EC P-256 keypair, sends a CSR to the dashboard, writes the signed cert + CA cert + HMAC key to /etc/stormpulse/. The private key never leaves the machine.
init -- Interactive setup wizard. Generates config, creates systemd service, sets permissions. Run after enrollment. Auto-detects Garage installations and running Docker containers and offers to enable integration / log shipping.
run -- Starts the agent. Connects to the dashboard, sends heartbeats and metrics, executes commands. Reconnects automatically with exponential backoff.
status -- Local inspection. Shows version, agent ID, config path, dashboard URL, certificate expiry, nonce DB entry count, and whether the agent process is running. No network required.
garage init -- Detects a Garage S3 node and appends a [garage] section to an existing stormpulse.toml. Auto-detects container name from docker-compose.yml. Use --force to overwrite an existing [garage] section.
logging init -- Detects running Docker containers and appends [[log_groups]] blocks for each, using source_type = "docker" and the docker_raw parser. Skips containers already present in the config. See Log Shipping for details.
Configuration
Run stormpulse init to generate a config interactively - see the Setup Guide. Key settings:
| Section | Field | Description |
|---|---|---|
agent |
id |
Unique identifier for this server |
agent |
pulse_token |
UUID from the Server record in the dashboard |
agent |
disabled_commands |
List of command names to remove from the registry (optional) |
dashboard |
url |
WebSocket URL (wss://...) |
project |
project_dir |
Absolute path to the deployed project |
project |
compose_file |
Absolute path to docker-compose.yml |
project |
env_file |
Absolute path to .env file (optional, passed as --env-file to docker compose) |
commands.* |
Custom commands (optional, see example config) | |
garage |
enabled |
Enable Garage S3 integration (optional, default: absent) |
garage |
container_name |
Docker container name for Garage (e.g. garaged) |
garage |
config_path |
Path to Garage config file |
garage |
state_push_interval_seconds |
How often to refresh Garage state (default: 30) |
Documentation
- Setup Guide -- Full install, enrollment, systemd, permissions
- Customize Commands -- How to disable existing commands, or whitelist new commands
- Log Shipping -- Tailing container and file logs to the dashboard
- Garage Integration -- Garage S3 node management
- Protocol Specification -- Message formats, envelope structure, versioning
- Security Architecture -- Threat model, five security layers
Develop
git clone https://git.stormdevelopments.ca/official-public/storm-pulse.git && cd storm-pulse
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
mypy . # strict
make fitness # architecture + security invariants
License
MIT - see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file storm_pulse_agent-0.1.8.tar.gz.
File metadata
- Download URL: storm_pulse_agent-0.1.8.tar.gz
- Upload date:
- Size: 159.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b893bfa498280c661d531fb8c78f7cd9517862feca02935db70eab8cd2cee66f
|
|
| MD5 |
f1bd9100b84c0a3d90c888670d7adec9
|
|
| BLAKE2b-256 |
d39f18dc5c3ecaef8c56f84091bc45d422199717dc8228c376c0289e565268e7
|
File details
Details for the file storm_pulse_agent-0.1.8-py3-none-any.whl.
File metadata
- Download URL: storm_pulse_agent-0.1.8-py3-none-any.whl
- Upload date:
- Size: 157.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bae85eafd5a0a11cca801a1a929293944dd084f7e35122058318f34f9694bdfe
|
|
| MD5 |
ac84488a0cba5519afbd438081bef3b1
|
|
| BLAKE2b-256 |
9a6478889bf44cac765365d9d07a19b580cf16136f9a4e23f4dafb8f61520439
|