Trust boundaries
Where a Citrix SecurSpaces™ deployment separates one level of trust from another, what enforces each separation, and which side of it you own. This page supports network security review and architecture assessment.
It describes the boundaries the platform implements. It is not a threat model: it does not enumerate adversaries, abuse cases, or risk ratings.
Summary
| Boundary | Enforced by | Owner |
|---|---|---|
| Your network to the cluster | Ingress controller, TLS termination | You |
| Ingress to SecurSpaces services | Kubernetes NetworkPolicy, TLS | SecurSpaces |
| SecurSpaces services to the database | Kubernetes NetworkPolicy | SecurSpaces |
| Workspace to workspace | Kubernetes NetworkPolicy | SecurSpaces |
| Workspace to the internet | A Kubernetes NetworkPolicy confines the workspace to the proxy service, which then enforces the SecurSpaces network policy attached to it | SecurSpaces, configured by you |
| Platform to the Kubernetes API | Kubernetes RBAC | SecurSpaces |
| Cluster to the nodes and the host | Your cluster configuration | You |
Important:
Every in-cluster boundary on this page is a Kubernetes NetworkPolicy, so it holds only if your cluster runs a network plugin that implements the
networking.k8s.io/v1NetworkPolicy API. If it does not, these policies are accepted by the API server and silently do nothing. See Requirements.
The perimeter
Traffic reaches the deployment through the ingress controller. TLS terminates there, so the permitted TLS versions and cipher suites are part of your ingress configuration rather than something SecurSpaces sets.
The load balancer in front of the ingress controller operates at Layer 4 and does not terminate TLS.
For the ports that must be reachable, see Ports and protocols.
Inside the cluster
SecurSpaces labels its pods by type and ships NetworkPolicies that act on those labels.
| Pod type | Label |
|---|---|
| Platform services | strong.network/type: service |
| Database | strong.network/type: database |
| Workspaces and secure browsers |
strong.network/type: workspace, strong.network/type: browser
|
| Workspaces with a network policy attached | strong.network/hardened: no_egress |
Important:
Do not rename these labels. The NetworkPolicies select on them, and a renamed label produces a policy that matches nothing, with no error.
Service pods accept traffic from anywhere
The NetworkPolicy for service pods accepts ingress from any source. This is deliberate — they are the entry
point for the deployment — but it means the perimeter around the platform services is your ingress
configuration, not a NetworkPolicy.
The database policy
SecurSpaces ships a NetworkPolicy that restricts ingress to pods labeled database, accepting connections
only from pods labeled service.
Important:
A NetworkPolicy only covers pods that carry the label it selects on. Whether your database pods carry it depends on how the database is deployed, and a database running outside the cluster is not covered at all. Confirm the label is present on your database pods before treating this policy as the control that isolates them, and apply your own network controls where it is not.
Workspaces accept traffic only from the workspace API
Pods labeled workspace or browser accept ingress only from the workspace API pod.
This is what isolates workspaces from each other. One workspace cannot open a connection to another, and this holds whether or not a network policy is attached, because it is enforced on the receiving side.
Workspace egress depends on the attached policy
Two different mechanisms share the name network policy, and both are involved here.
A workspace carries the label strong.network/hardened: no_egress only while a SecurSpaces network
policy is attached to it. A Kubernetes NetworkPolicy selects pods with that label and permits them to
send traffic only to service pods, which leaves the SecurSpaces proxy service as the workspace’s only
route out. The proxy service then allows or refuses each destination according to the SecurSpaces network
policy.
So the Kubernetes NetworkPolicy decides that a workspace may talk only to the proxy service. The SecurSpaces network policy decides where the proxy service will carry it.
Important:
A workspace with no network policy attached is not labeled as hardened, so this NetworkPolicy does not apply to it and its outbound traffic is not restricted by the platform. Egress restriction is something you turn on by attaching a policy. See Network policies.
Platform access to the Kubernetes API
The workspace API manages workspace lifecycle through the Kubernetes API, using a service account scoped to the release namespace.
| Scope | Access |
|---|---|
| Namespace | Pods, services, secrets, persistent volume claims, config maps, service accounts, events, jobs, deployments and stateful sets, pod logs, and a named lease |
| Cluster-wide | Storage classes and persistent volumes, read-only. Nodes and node metrics, read-only. |
Write access to persistent volumes is not granted by default. It is enabled only when you turn on the
allowPersistentVolumeAccess setting, which the Attach Existing mount point workflow requires.
Host-level changes on workspace nodes
SecurSpaces runs a DaemonSet on nodes that are not labeled as service nodes. Its init container runs as root
with privileged: true, in the host network, PID, and IPC namespaces, and mounts /sys from the host.
It sets these kernel parameters on those nodes:
| Parameter | Value | Purpose |
|---|---|---|
kernel.unprivileged_userns_clone |
1 |
Allows unprivileged user namespaces, which rootless containers in workspaces require |
user.max_user_namespaces |
49152 |
Raises the user namespace limit for the same reason |
fs.inotify.max_user_watches |
1524288 |
Raises the file watch limit that the IDE needs on large repositories |
kernel.yama.ptrace_scope |
0 |
Allows a debugger to attach to a running process. Developers need this to debug compiled binaries, such as C and C++, inside a workspace. This relaxes the default restriction on most distributions. |
fs.suid_dumpable |
0 |
Prevents core dumps from setuid programs |
kernel.core_pattern |
/dev/null |
Discards core dumps rather than writing them to disk |
These are node-level settings and apply to everything scheduled on those nodes. If you run other workloads on the same nodes, take this into account when you plan node pools.
Working from a local IDE
A developer can work in the Cloud IDE in a browser, or connect a local IDE over SSH. The second is a supported access channel rather than a workaround, but it is not equivalent: a local IDE is software running on the endpoint, so it widens the boundary slightly. This section is what a security reviewer needs to judge by how much.
The development environment itself does not move. Code, execution, and credentials stay in the workspace whichever channel is used; what changes is where the editor renders.
Where each artifact resides
| Artifact | Resides | On the endpoint? |
|---|---|---|
| Source code | Workspace filesystem | No. The local IDE edits it remotely and does not write it to local disk |
| Repository credentials | Brokered by the SecurSpaces proxy service | No. Never exposed to the endpoint, and not readable from inside the workspace either |
| SSH key that opens the tunnel | The developer’s endpoint | Yes, necessarily. This is the key that authenticates the developer to the workspace |
| Personal SSH identity, used for any SSH service | Held by the platform and presented by the SecurSpaces proxy service when the connection is made | No. Not written into the workspace, so a process there cannot copy it |
| SSH services attached as project resources | Held by the platform, injected the same way | No |
| Build artifacts | Workspace filesystem | No, unless a developer deliberately copies them out, which egress and transfer controls govern |
| Language package caches, such as npm and pip | Workspace filesystem | No |
| AI model context | Inside the workspace and the policy boundary, attributed per user, project, and workspace | No |
| IDE extension data | Split. Extensions that render UI run on the endpoint; extensions that execute code run in the workspace | Partly. The UI extension host is the one part of the IDE that is genuinely local |
Note:
The two SSH key roles are easy to conflate and the distinction matters. The key that opens the tunnel is the developer’s own and lives on their machine, like any SSH client key. The key the workspace presents when it connects out — its personal SSH identity, or an SSH service attached as a project resource — is held by the platform and reaches neither the endpoint nor the workspace runtime. See How SSH connections are handled.
What the endpoint can still see
Because the IDE renders locally, a compromised endpoint could still capture keystrokes, screen content, or clipboard data, and the extension host runs local code. Clipboard controls still apply, but they are enforced against the session rather than against the operating system.
This is inherent to any SSH-based remote development model rather than specific to SecurSpaces, and it is a smaller surface than a laptop or a VDI session with a local Linux subsystem, where source code, credentials, and package caches are all genuinely local. It is still larger than the Cloud IDE, which is why remote development over SSH is a setting an administrator turns on deliberately. See Workspace policy.
What you own
SecurSpaces is customer-hosted, so the following are outside the boundary the platform controls:
- The ingress controller and its TLS configuration.
- A network plugin that enforces NetworkPolicy. Without one, the in-cluster boundaries above do not hold.
- Cluster and node hardening, and which workloads share a node pool with workspaces.
- Encryption at rest for the database, persistent volumes, and
etcd. - Runtime container scanning and image admission control.
- Network reachability between the cluster and any external dependency, such as the database, registries, repository providers, and your SIEM.