DEV Community

Feng Zhang
Feng Zhang

Posted on • Originally published at prachub.com

Multi-Tenant Isolation And Sandboxing Explained — Tech Interview Concept (2026)

Multi-tenant sandboxing questions are about boundaries. Can you run code, jobs, sessions, or agents for many customers on shared infrastructure without data leaks, secret exposure, or one tenant eating all the capacity?

That is the core idea behind the original PracHub note on multi-tenant isolation and sandboxing. In interviews, this topic usually shows up as a system design prompt:

  • Design a cloud IDE
  • Design a CI/CD runner
  • Design a multi-tenant workspace app
  • Design a sandbox for user-submitted code
  • Design a tool execution layer for AI agents

A weak answer says, "Add tenant_id everywhere." A strong answer explains which boundary protects against which risk.

Start with the threat model

Before picking Kubernetes, Firecracker, or VMs, say what you are defending against.

For a cloud IDE or CI/CD platform, assume user code is hostile. It may try to:

  • Read files from another tenant
  • Escape the filesystem sandbox
  • Abuse CPU or memory for crypto-mining
  • Steal credentials from environment variables
  • Call cloud metadata endpoints such as 169.254.169.254
  • Scan internal services
  • Poison a shared dependency cache
  • Exploit a kernel or container runtime bug

For a normal SaaS workspace app, the threat model is different. You may care more about authorization bugs, stolen tokens, misconfigured admin access, and data leakage through logs or search indexes.

Do not treat those as the same problem. That leads to bad designs.

Tenant isolation has layers

Tenant isolation is not one control. It is a stack of controls across several layers:

  • Identity: who is the caller?
  • Authorization: what can the caller do?
  • Data: which rows, objects, indexes, and backups can be accessed?
  • Compute: where does code run?
  • Network: what can the runtime connect to?
  • Secrets: which credentials are available?
  • Observability: what appears in logs, traces, metrics, and audits?
  • Billing and quotas: who pays for the work, and who can consume capacity?

tenant_id filtering in Postgres helps with logical data isolation. It does not sandbox a build script. It does not stop SSRF. It does not cap CPU usage. It does not redact a secret from logs.

Good interview answers make that distinction clear.

Choose the right isolation primitive

Isolation primitives sit on a spectrum.

Processes are cheap and fast, but they are weak for untrusted code. Containers add Linux namespaces and cgroups. MicroVMs, such as Firecracker, reduce host kernel sharing compared with containers. Full VMs provide stronger separation, but startup time and memory overhead are higher.

A practical answer often compares them like this:

Primitive Strength Cost
Process Low isolation Very low overhead
Container Namespaces, cgroups, image packaging Fast startup, shared kernel
MicroVM Stronger kernel boundary More overhead than containers
Full VM Strong separation Higher startup and memory cost

For an interactive cloud IDE, containers may give better startup latency and density. For arbitrary public workloads, microVMs may be worth the extra overhead. For regulated or high-risk tenants, full VMs or separate cloud accounts may be justified.

Tie the primitive back to the product constraint. Think about latency, cost, workload duration, risk level, and tenant value.

Know what namespaces and cgroups do

If you mention containers, be ready to name the underlying controls.

Linux namespaces isolate what a process can see:

  • pid: process tree
  • net: network interfaces and routing
  • mnt: filesystem mounts
  • uts: hostname and domain name
  • ipc: interprocess communication
  • user: user and group IDs
  • cgroup: cgroup hierarchy

cgroups limit what a process can consume:

  • CPU shares
  • Memory
  • Process count
  • I/O bandwidth
  • Device access

A simple way to say it: namespaces hide resources, cgroups limit resources.

For sandboxed execution, add hardening:

  • Run as non-root
  • Drop Linux capabilities such as CAP_SYS_ADMIN
  • Use a deny-by-default seccomp profile
  • Apply AppArmor or SELinux
  • Mount filesystems read-only where possible
  • Reject privileged containers
  • Avoid host mounts unless there is a very specific reason

Saying "each job runs in a pod" is not enough. Pods share the host kernel, and unsafe pod settings can break your isolation model.

Resource fairness needs admission control

Multi-tenant systems can fail even without an attacker. One tenant can start too many builds or keep too many IDE sessions open.

You need admission control before scheduling work. A simple capacity model is:

concurrent_jobs <= floor(total_safe_capacity / per_job_reservation)
Enter fullscreen mode Exit fullscreen mode

Then add:

  • Per-tenant quotas
  • Global queues
  • Priority classes
  • Burst limits
  • Timeouts and TTLs
  • Eviction rules for idle sessions

CI/CD systems care heavily about queue fairness. Cloud IDEs care about interactive latency and idle cleanup. Both need limits, or one tenant can become a noisy neighbor.

Data isolation is physical, logical, or hybrid

There are three common data tenancy models.

Separate databases per tenant reduce blast radius and can simplify deletion or export. The tradeoff is operational overhead.

Shared tables with tenant_id are easier to operate at scale, but every query and authorization path must be correct. Use composite indexes such as (tenant_id, object_id), and consider Postgres row-level security as defense in depth.

A hybrid model may put large or high-risk tenants in dedicated storage while smaller tenants share tables.

The interview signal is not that one model is always best. The signal is that you can explain the tradeoff and add safeguards.

Authorization should fail closed

Never trust a client-supplied tenant_id.

Derive tenant context from one of these:

  • Session data
  • Token claims
  • Server-side membership lookup

Then check permissions centrally. Examples:

  • workspace:read
  • workspace:write
  • runner:execute
  • artifact:download
  • admin:invite_user

Every request should carry an authenticated principal and tenant context. If the system cannot determine either one, deny the request.

Cross-tenant authorization bugs are common because teams scatter permission checks across handlers. A central authorization layer reduces that risk.

Use ephemeral runtimes for code execution

Mutable shared workers are dangerous for CI/CD and cloud IDE workloads.

A safer lifecycle looks like this:

  1. Create a fresh runtime from a known image
  2. Attach only the credentials needed for this job or session
  3. Run the workload
  4. Stream logs and terminal output
  5. Persist declared artifacts or workspace changes
  6. Tear down the sandbox

Warm pools can reduce startup time, but they must be scrubbed carefully before reuse. If you cannot prove cleanup is correct, prefer fresh environments.

A useful state machine is:

Queued -> Provisioning -> Running -> Stopping -> Persisting -> Terminated
Enter fullscreen mode Exit fullscreen mode

Add retries and cleanup for every transition. Orphaned sandboxes cost money and create risk, so use heartbeats, leases, TTLs, and a janitor process.

Secrets are often the breach path

Many sandbox escapes start with boring credential leakage.

Do not bake secrets into images, dependency caches, or shared volumes. Inject short-lived credentials at runtime from Vault, a cloud IAM system, or a secret manager.

Scope credentials as tightly as possible:

  • Tenant
  • Repository
  • Branch
  • Job
  • Environment

Redact secrets in logs. Treat terminal output, build logs, traces, and error reports as possible exfiltration channels.

Network isolation needs egress control

A sandbox should not have broad network access by default.

Use per-sandbox network namespaces, Kubernetes network policy, security groups, service mesh policy, or egress proxies. Block access to:

  • Cloud metadata endpoints such as 169.254.169.254
  • Internal admin services
  • Other tenants' private networks
  • Control plane APIs unless explicitly allowed

Ingress matters too, but egress is where many sandbox designs fail. If arbitrary code can reach internal services, SSRF becomes a real incident path.

Cache carefully

Caches are great for build speed and infrastructure cost. They are also a common isolation footgun.

Key dependency caches and Docker layer caches by:

  • Tenant
  • Repository
  • Lockfile hash
  • Architecture
  • Trust level

Cross-tenant read-only public caches can be acceptable. Writable shared caches are risky because one tenant may poison dependencies or artifacts used by another.

For CI/CD platforms, artifact integrity should be part of the design. Signed artifacts and strict cache keys are stronger than "we have a shared cache directory."

A strong cloud IDE answer

For "Design a sandboxed cloud IDE," start with clarifying questions:

  • Are users running arbitrary code?
  • Do sessions need internet access?
  • Which languages must be supported?
  • Is the home directory persistent?
  • What startup latency target matters, such as p95 < 5s?

Then structure the design:

  • Control plane: authenticates users, maps users to tenants and workspaces, schedules sessions, stores metadata in Postgres
  • Execution plane: runs containers or microVMs on isolated node pools with cgroups, seccomp, non-root users, per-session networking, and TTL cleanup
  • Persistence and streaming: stores workspace files on per-tenant volumes or object storage snapshots, streams terminal I/O through WebSocket or server-sent events
  • Operations: quotas, warm pools, autoscaling, audit logs, metrics, and janitor jobs

Call out the container versus microVM tradeoff. Containers are faster and denser. MicroVMs reduce kernel-sharing risk for arbitrary code. A tiered model is often the cleanest answer.

A strong CI/CD answer

For "Design a multi-tenant CI/CD platform," the same principles apply, but the workload is batch-oriented.

Focus on:

  • Ephemeral runners
  • Per-job credentials
  • Tenant-scoped queues
  • Fair scheduling
  • Cache keys tied to lockfiles and trust boundaries
  • Signed artifacts
  • Strict teardown after each pipeline step

The risks are malicious build scripts, dependency cache poisoning, secret exfiltration, and queue starvation.

If you want more prompts in this area, PracHub has related software engineering interview questions that pair well with this topic.

Common mistakes

The biggest mistake is treating tenant_id as the full isolation story. It only covers part of data access.

The second mistake is jumping to Kubernetes without naming the real security boundary. A pod is not automatically safe.

The third mistake is choosing maximum isolation without product context. A full VM per request may be too slow or expensive for an IDE. A shared container may be too weak for hostile public code.

A good answer layers controls and explains tradeoffs. Start with the threat model, pick the isolation primitive, lock down data and secrets, add quotas, restrict networking, and design cleanup as part of the system.

For a more interview-focused version of this breakdown, see the original PracHub guide to multi-tenant isolation and sandboxing.

Top comments (0)