Security
An honest isolation story, stated plainly: this is a platform for your applications, or your customers' applications under your operation, not for anonymous hostile code. celld's own security page says it is not safe for hostile multi-tenant use; the operator's design takes that seriously instead of papering over it.
The isolation model
celld adds no sandbox beyond V8, so the design assumes the worst case: a V8 isolate escape hands an attacker the entire node process. The operator's answer is fleet-per-app blast-radius containment:
- Each app runs in its own fleet, with its own pods, namespace-scoped resources, and NetworkPolicies.
- Each fleet holds one bucket credential, scoped to that fleet's prefix
(
…/apps/<app>/) and nothing else. - A full runtime compromise inside one fleet therefore reaches only that app's pods and that app's prefix.
Two limits belong next to that claim. Within a fleet there is no per-cell resource quota:
upstream notes that a defective cell can access only its own database but can still
consume its fleet nodes' resources, so a runaway cell starves its neighbours in the same
app. And WorkerApp exposes no scheduling fields — no
nodeSelector, affinity, or tolerations — so
pinning fleets to dedicated node pools for kernel-level separation needs a cluster-level
mechanism (a namespace default node selector, or a mutating admission policy), not a
field on the resource.
The internal listener
celld's internal listener — which the operator pins to :8081; celld itself
defaults to an ephemeral loopback port — carries the peer protocol and an
operator API that is unauthenticated by upstream design. Anyone who can
reach it can inspect state, evict cells, stop the process, activate a cell, and send it a
direct Durable Object request: that is application code execution and state mutation, not
just inspection. The operator fences it in depth:
- NetworkPolicy: ingress to :8081 only from fleet pods and the operator's namespace.
- Istio AuthorizationPolicy (when Istio is present): :8081 pinned to
the fleet's ServiceAccount plus the operator's principal
(
--operator-principal). - Never routed: no ingress mode ever exposes :8081.
Peer requests on that listener keep celld's own protocol authentication (HMAC with the
fleet secret, body-bound signatures, clock limits, replay protection). celld terminates
no TLS, so confidentiality on the peer network is the cluster's job: the operator neither
installs nor requires a mesh, and without one it reports
MeshPolicyReady: False and leaves NetworkPolicy as the only guard. Where you
do add a mesh, prefer Istio ambient mode for mTLS. Ambient specifically, not sidecars: celld makes
outbound peer and bucket calls during termination, and a sidecar exiting first
would break the handoff; an L7 proxy also has no business touching the HMAC-signed,
body-bound peer protocol.
Bucket credentials
The bucket credential is fleet-admin authority. The bucket holds deployments, cell state, ownership leases, and the peer-auth secret; whoever holds the credential controls the fleet. Credential scoping is the tenancy enforcement.
- Prefer
credentialsFrom.iamRole, which the operator renders as the EKS IRSA annotationeks.amazonaws.com/role-arnon the fleet's ServiceAccount; celld's credential chain accepts the resulting web identity token. Scope one role per fleet to that fleet's prefix — the operator copies the ARN you give it and does not validate its scope. GKE Workload Identity is not wired yet, so on GKE this field has no effect; andiamRole: auto(operator-provisioned roles) is not implemented — it reportsBucketCredentialsReady: Falseand asks you to annotate the ServiceAccount yourself. credentialsFrom.secretRef(staticAWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY) exists for stores without role-based auth. Static keys spread; treat them as a fallback.- Rotate immediately after suspected disclosure. celld does not read
~/.awsprofiles or SSO logins; it takes credentials from theAWS_*environment or from explicit managed credentials, which includes instance metadata and web identity tokens — the two paths the operator drives.
TLS and application auth
- celld terminates no TLS anywhere. Public TLS belongs to the Gateway; the pod network should be encrypted (ambient mesh, or a CNI with WireGuard).
- The deployed Worker owns every public path except
/__celld/health. Application authentication is the application's job; celld does not authenticate end users.
Trust boundaries at a glance
| Boundary | Mechanism |
|---|---|
| Internet → Worker | Gateway TLS + per-host routing; app-level auth in the Worker |
| Tenant ↔ tenant | Namespaces, NetworkPolicy, fleet-scoped IAM (node-pool separation via cluster-level policy) |
| Anything → operator API (:8081) | NetworkPolicy + AuthorizationPolicy; never routed |
| Node ↔ node | celld HMAC/replay auth; transport encryption from your mesh or CNI, if any |
| Fleet → bucket | Per-fleet, prefix-scoped IAM role |
| Operator → fleets | NetworkPolicy admits the whole operator namespace; the Istio policy, where installed, narrows it to the operator's ServiceAccount |
Support and disclosure
Upstream ships security fixes for the latest celld release only; the operator's support policy mirrors it: current celld, current operator. Report operator vulnerabilities per the repository's SECURITY.md; report celld issues upstream at denoland/celld.