cause provides a basic and argument-less API for triggering things in remote machines over HTTP with reasonable security.
things to note:
- the process, once triggered, will run to completion/timeout even if the triggering party disconnects
- targets only linux systems
- intended to be behind a reverse proxy
- never expose cause directly to untrusted networks
- a
GET /endpoint returns200 OKfor load balancer probes and container health checks
Usage: cause [OPTIONS]
Options:
-c, --config <CONFIG> Path to the configuration file [default: cause.toml]
-a, --address <ADDRESS> Address to listen on [default: 127.0.0.1]
-p, --port <PORT> Port to listen on [default: 3000]
-h, --help Print help
-V, --version Print versioncause is configured with a TOML file (default: cause.toml).
all fields have defaults; unknown fields are rejected.
| option | default | description |
|---|---|---|
auth_header |
"x-api-key" |
HTTP header carrying the API key |
timeout |
900 |
max runtime (seconds) of a triggered process before it is killed |
trusted_proxies |
[] |
IPs of reverse proxies allowed to set x-forwarded-for; when the peer is trusted, the forwarded client IP is used for rate limiting/failure tracking |
auth_semaphore_size |
4 |
max concurrent password-hash verifications (bounds CPU usage of auth) |
failure_threshold |
10 |
auth failures per IP within failure_window_secs before tarpitting kicks in |
failure_window_secs |
600 |
fixed window (seconds) for counting auth failures: the timer starts at the first failure and the counter resets once the window expires (not a rolling window) |
block_duration_secs |
600 |
duration (seconds) an IP remains blocked after exceeding the failure threshold |
tarpit_duration_ms |
500 |
delay (milliseconds) applied to every failed auth attempt and to requests from blocked IPs |
rate_limit_per_second |
2 |
sustained per-IP request rate |
rate_limit_burst |
5 |
per-IP burst allowance on top of the sustained rate |
kill_grace_secs |
1 |
grace period (seconds) between SIGTERM and SIGKILL when terminating a timed-out process |
drain_grace_secs |
2 |
post-exit grace period for draining the output buffer of the child process |
max_line_length |
65536 |
max length (bytes) of a single output line from the triggered process; lines exceeding the limit are discarded and reported as a [stream truncated] event |
failure_max_entries |
100000 |
max IPs tracked in the failure table (bounds memory) |
auth_acquire_timeout_ms |
2000 |
max time (milliseconds) to wait for an auth verification slot before rejecting |
max_inflight_auth_per_ip |
2 |
max concurrent auth attempts per IP |
max_auth_queue_depth |
64 |
max requests waiting for an auth slot before new ones are rejected |
each route becomes a POST /<name> endpoint. route names may only contain ASCII alphanumerics, _, and -.
| option | required | description |
|---|---|---|
shell |
yes | path to the executable to run; must exist, be a regular file, and have an execute bit set |
args |
yes | arguments passed to the executable |
keys |
yes | path to the keys file (see below) authorized for this route |
concurrency |
no (default 1) |
max concurrent executions of this route |
keys files are read once at startup; adding or revoking a key requires restarting the service.
example (a fully commented copy is provided in config.example.toml):
[global]
auth_header = "x-api-key"
timeout = 900
[routes.hello]
shell = "/bin/bash"
args = [ "examples/hello.sh" ]
keys = "examples/keys"
concurrency = 1for convenience and development, use: ./key.sh <key>
(it is not advised to leave keys in shell history though)
# rolling your own tool for key generation
# generate a yescrypt hash
HASH=$(mkpasswd -m yescrypt super53cr37)
# prepend a random 8-char key id
KEYID=$(head -c 4 /dev/urandom | xxd -p)
# output in the correct format into some key list
echo "${KEYID}:${HASH}" >> keysuse the full key (keyid.secret) as the value in the x-api-key (by default) header.
-
never expose cause directly to untrusted networks; run it behind a reverse proxy that terminates TLS and strips/sets
x-forwarded-for. -
configure the proxy's IPs in
trusted_proxiesso rate limiting and failure tracking see the real client IP. -
the docker image ships with the example configuration at
/etc/cause/cause.tomlso it boots with working demo routes (hello,loop). mount your own config to replace it, e.g.:docker run -p 3000:3000 \ -v "$PWD/cause.toml:/etc/cause/cause.toml:ro" \ -v "$PWD/keys:/etc/cause/keys:ro" \ ghcr.io/avalahee/cause:latest
-
GET /is unauthenticated and returns200 OKfor load balancer probes and container health checks; it is also subject to the per-IP rate limit.
- the example key in
examples/keysisa1b2c3d4.dev. - running the examples:
cargo runcurl -i -XPOST -H 'x-api-key: a1b2c3d4.dev' http://localhost:3000/hellocurl -i -XPOST -H 'x-api-key: a1b2c3d4.dev' http://localhost:3000/loop