ColonyOS uses zero-trust, signature-based authentication: every authenticated
RPC is signed with the caller's secp256k1 private key and the server recovers
the caller's identity from the signature. The only exceptions are the version
and server-info messages (versionmsg, getserverinfomsg), which are answered
before signature verification. There are no cookies or sessions, so CSRF is not a
concern; authorization is checked per handler against the recovered identity.
This document covers the transport- and protocol-level hardening added in v2.0
and the settings that control it. All settings live in the Security config
section and can be set with COLONIES_SECURITY_* environment variables (or the
config file). Defaults are chosen to be safe without breaking existing
executors and SDKs.
| Setting | Env | Default | Notes |
|---|---|---|---|
| Read-header timeout | COLONIES_SECURITY_READ_HEADER_TIMEOUT |
20 s |
Slowloris defense. Does not affect the response side, so the executor long-poll assign is unaffected. 0 disables. |
| Idle timeout | COLONIES_SECURITY_IDLE_TIMEOUT |
120 s |
Keep-alive idle bound. 0 disables. |
| Max body bytes | COLONIES_SECURITY_MAX_BODY_BYTES |
104857600 (100 MiB) |
Caps request bodies so an unauthenticated caller cannot exhaust memory. Also caps a single websocket message. 0 disables. |
| CORS allowlist | COLONIES_SECURITY_CORS_ALLOW_ORIGINS |
empty | Comma-separated browser origin allowlist. Empty installs no CORS middleware, so cross-origin browser requests get no allow header and are blocked by the browser; non-browser clients (executors, SDKs, CLI) send no Origin header and are always allowed. A non-* allowlist permits only GET/POST methods and the Origin, Content-Type, Accept headers. * restores allow-all. |
| WebSocket origin allowlist | COLONIES_SECURITY_WS_ALLOW_ORIGINS |
empty | Same semantics for /pubsub. Empty allows no-Origin (non-browser) and same-origin requests only. * allows any. |
| Rate limit | COLONIES_SECURITY_RATE_LIMIT |
0 (off) |
Per-client-IP requests/second on all routes; only /health is exempt. The assign long-poll and /pubsub subscribe count against the limit, so size it for the number of executors sharing a source IP. |
| Rate-limit burst | COLONIES_SECURITY_RATE_LIMIT_BURST |
0 (= rate) |
Allowed burst above the rate. 0 or negative falls back to the rate value. |
The server always runs gin in release mode. When TLS is configured it is served with a minimum version of TLS 1.2.
Deliberately, no ReadTimeout/WriteTimeout is set on the HTTP server: the
executor long-poll assign holds the response open, and /pubsub websockets are
long-lived, so a blanket read/write deadline would break legitimate connections.
Signed RPC messages carry an optional nonce and timestamp. When the nonce is
non-empty, the signed bytes are payload + "|" + timestamp + "|" + nonce,
binding them against tampering; when the nonce is empty, only the payload is
signed (the legacy scheme). The server rejects a message whose timestamp is
outside the allowed skew window or whose nonce has already been seen.
| Setting | Env | Default | Notes |
|---|---|---|---|
| Mode | COLONIES_SECURITY_REPLAY_PROTECTION |
advisory |
off (aliases disabled, none): ignore replay fields. advisory: check messages that carry replay fields, still accept legacy messages that omit them. enforce (aliases enforced, strict): additionally reject messages that lack replay fields. Any unrecognized value silently falls back to advisory, so a typo will not raise an error. |
| Window | COLONIES_SECURITY_REPLAY_WINDOW |
300 s |
Allowed timestamp skew. Nonces are retained for twice the window, since a message timestamped up to one window in the future stays valid until now + 2x the window. |
Rollout is staged: v2.0 defaults to advisory so v2.0 clients are protected
immediately while pre-v2.0 clients keep working. A later release is expected to
default to enforce. Old clients that sign the payload only remain valid in
off/advisory modes.
Single-node deployments run no relay or etcd. Multi-node clusters do, and those ports must be reachable only from trusted peers.
COLONIES_CLUSTER_SECRETauthenticates the cluster relay: peers HMAC-sign each broadcast (sent in theX-Colonies-Relay-Authheader) and the receiver rejects unsigned or mismatched posts. Set the same value on every node. When unset, the relay logs a warning at startup.- The embedded etcd peer/client ports have no TLS or authentication. Restrict them to a private/firewalled network. The server logs a warning when etcd binds to all interfaces in a multi-node configuration. (Full etcd mTLS is planned; see the modernization backlog.)
S3 credentials are read from server/executor configuration (AWS_S3_*), never
from per-file database records. The server does not persist or return S3 access
keys, secret keys, or encryption keys; a migration blanks any that older
versions stored. See modernization/DB-MIGRATION-NOTES.md.