Two halves
respirecloudd serves the panel and the API as an unprivileged system user. Everything that needs root is
done by respirecloud-agent, which accepts only typed operations declared in module manifests. Operations
carry validated parameters and run programs as argument lists; there is no shell string anywhere for input to break
out of. The panel cannot ask the agent to "run this command".
-
Browser, CLI or API token
Signs in with a passkey or a scoped token. Every method and path is denied unless an action allows it.
-
respirecloudd unprivileged user
Checks permission, plan limits and risk; validates parameters against the action's schema; writes the audit row.
-
Bus TLS 1.3, per-server keys
Each server can only receive its own operations. A compromised server cannot see another's.
-
respirecloud-agent root, minimal
Runs typed operations from module manifests only. Commands are argument lists, never shell strings.
Servers and the bus
- Agents dial out to the panel over TLS 1.3 with the panel's certificate authority pinned. It works through NAT; no inbound port on the server is needed.
- Each server is enrolled with a one-time token (valid one hour, stored only as a hash) and generates its own key, which never leaves the machine.
- Each server may publish only its own heartbeat and receive only its own operations. Everything else on the bus is denied by omission, so a compromised server cannot read another server's work.
- The enrolment endpoint is rate-limited per address and every attempt is audited without the token.
Modules
- Each module runs as its own process and is launched only after its checksum is verified.
- Each module owns one database schema through its own database role, and reaches other modules only through their actions.
- Parameters are validated against strict schemas by the host before the module sees them. Unknown fields are refused.
- Agent-side code re-validates anything that reaches a server (nginx snippets, compose files, firewall rules), so a compromised control plane still cannot push something the agent would refuse.
Signing in
- Passkeys (WebAuthn), passwords hashed with Argon2id, authenticator codes and one-time recovery codes.
- Two-step sign-in is required for administrators and resellers.
- High-risk and critical actions need a fresh confirmation; the session is rotated when it is given.
- Sessions are listed per device and can be ended at once. Suspending a person ends their sessions and tokens in the same transaction.
- Lockout and throttling on repeated failures. Browser calls need a CSRF header on top of the session cookie.
- Acting as a customer requires a reason and a fresh confirmation, is time-limited, cannot change their credentials, and is audited under both identities.
Secrets
Credentials for storage connections, backup repositories, DNS servers, registries and stored database passwords live in the panel's vault, not in module tables, logs or events. Private keys for TLS and DKIM are generated on the server that uses them. Passwords, tokens and keys are redacted from the audit log and masked in shipped logs.
The audit chain
Every change is written with the actor, the person they were acting as, the source and the parameters, and each row carries the hash of the one before it. A scheduled check recomputes the chain and raises an event on the first row that does not match. No action edits or deletes audit rows. Detecting the removal of the newest rows needs an anchor outside the server; that is on the roadmap.
Customer isolation
- Every hosting account is a Linux user with its own systemd slice (cgroup v2 limits) and its own PHP-FPM masters.
- File operations run in a helper that is the account's user; paths are resolved with
openat2(RESOLVE_BENEATH), so escapes through symlinks or..are refused by the kernel. - nginx refuses to serve symlinks to files owned by someone else; per-account PHP sockets cannot be reached by other accounts.
- Metrics and logs are separated by the stores themselves: one log tenant per account, and metric queries forced to the account's own series.
- Containers run with dropped capabilities, no-new-privileges, user-namespace remapping and the account's limits; compose files are rebuilt from an allow-list.
Untrusted input
- The browser terminal needs a single-use, 30-second ticket bound to your browser session, a matching Origin and the session cookie; it re-checks the session every 15 seconds.
- Webmail rebuilds every HTML message from an allow-list, blocks remote content by default and is tested against a corpus of XSS vectors and a fuzzer. The mail screens will add a sandboxed frame as a second layer.
- Archives are extracted with size, count and ratio limits and never create links or devices.
- Reverse-proxy sites cannot point at private addresses unless an administrator allows it.
Reporting a vulnerability
Please email info@respiresoft.com with the subject "RespireCloud security report". Please do not test against servers you do not own. More in our security overview.