Безопасность
How tenant code is isolated, how secrets are stored, what the network allows, and how shell access and API tokens are controlled.
Isolation#
Every service runs in its own sandbox on shared nodes:
- gVisor (default runtime) intercepts syscalls in user space, so the container never talks to the host kernel directly.
- Kata Containers run a service in a lightweight microVM with its own kernel. Builds always run in Kata; pick it for services that need a full kernel (
runtimeClass: kata). - Each project environment is a Kubernetes namespace with a resource quota. Memory is never overcommitted; CPU can be shared up to 3×; disk I/O is capped per namespace.
- Only our system components run with a plain container runtime.
Nodes run in Hetzner data centres in Finland (EU). Data does not leave the EU.
Network#
- Namespaces are isolated with a default-deny network policy: services in different projects cannot reach each other; services in different environments of the same project cannot either.
- Inbound traffic reaches a service only through its public domains (TLS terminated at the edge) or a TCP proxy you created explicitly.
- Outbound traffic is open except port 25 (SMTP): use an email API or a provider's submission port (587) with authentication.
- Nodes accept inbound connections only on 80, 443, SSH for operators and the TCP proxy range.
Secrets and variables#
Variable values are encrypted at rest with AES-256-GCM; the key lives only in the control plane's environment, not in the database. Values are decrypted when a deployment is rendered and passed to the node over an authenticated WebSocket the node opened itself (nodes have no inbound API port). The dashboard shows values to workspace members; the CLI and the MCP server mask them by default.
Build logs and runtime logs are stored as your process wrote them: do not print secrets.
Accounts and tokens#
- Sign-in is GitHub OAuth only; there are no passwords to leak.
- Workspace roles:
owner,admin,member. Billing, tokens and members requireadmin. - API tokens are hashed at rest, shown once, scoped to one workspace with
readorwrite, and can be given an expiry. Project tokens are scoped to one environment and cannot read billing or other projects. - Every mutation is written to the workspace audit log with actor, target and IP.
Shell access#
skiffly ssh and the Terminal tab open a shell inside a running container of your service. The session goes from your client to the API over WebSocket with your token, and from the API to the node over the node's own connection; the container is never exposed to the internet. Sessions require the member role (and the write scope for tokens), are limited to five per user and 30 minutes idle, and are recorded in the audit log as service.exec.
GitHub#
Private repositories are cloned with short-lived installation tokens of the Skiffly GitHub App; no personal access token is stored. Pull requests from forks never deploy into preview environments.
Backups#
Volumes are snapshotted daily to encrypted, EU-hosted object storage with a 7/4/3 retention (daily/weekly/monthly); Postgres and MySQL get logical dumps in the same run. Restores go through support for now. See Volumes & databases.
Reporting#
Found something? Write to security@skiffly.dev. Please do not test against other customers' services.