The open source, identity-based, secretless sandbox platform
Run isolated, reproducible sandboxes for developers, AI agents and automated workloads on your own infrastructure, with identity-based, policy-driven, secretless access to databases, SSH servers, APIs and Kubernetes clusters, without credentials ever reaching the sandbox.
- Free and open source
- Designed for self-hosting
- Built on Octelium
Cordium runs every Workspace as an isolated sandbox. Above the sandboxes, the Octelium access layer connects each Workspace to the databases, SSH servers, Kubernetes clusters, HTTP APIs and LLM APIs it is authorized to reach, on a per-request basis and through its own identity, while the upstream credentials stay at the access layer and never reach the sandbox.
Isolated execution is only half of the problem
Sandboxes for developers, AI agents and automated workloads need isolated, reproducible execution as well as access to real infrastructure. Existing platforms solve one side and leave the other to the user. Cordium unifies both in a single platform.
- 01
Credentials inside the sandbox
API keys, database passwords, SSH private keys and kubeconfigs end up in environment variables, files and shell history, where a leaked log or a prompt injection can exfiltrate them.
In CordiumUpstream credentials stay at the Octelium identity-aware proxy and are injected at the protocol layer once a request is authorized. The Workspace never holds them.
- 02
Isolation without identity
Most sandbox platforms isolate processes but leave infrastructure access to whatever credential the sandbox holds, so the credential itself becomes the authorization boundary.
In CordiumEvery Workspace run gets a dedicated Octelium Session as its identity, and every request it makes is authorized against that identity with policy-as-code.
- 03
One tool per workload
Remote development environments, AI agent sandboxes and CI runners are usually separate products, each with its own identities, its own credentials and its own audit trail.
In CordiumThe same Workspace serves long-lived coding sessions and short-lived automated runs, through the browser, SSH, the CLI and the SDKs.
- 04
Incomplete visibility
Network and container logs rarely explain which agent ran which query against which database, or why it was allowed to.
In CordiumOpenTelemetry-native, L7-aware access logs tie every request back to the Workspace Session, its owner and the Policy that decided it.
One sandbox platform for developers, AI agents and automation
A Workspace is an isolated, rootless container sandbox on standard Kubernetes. The same Workspace serves as a remote development environment for engineers and as an execution sandbox for AI agents, CI/CD jobs and automated scripts.
- Access Workspaces through the browser-based terminal, the cordium CLI, standard SSH for VS Code, Zed and JetBrains, or programmatically through the gRPC API and SDKs.
- Persistent Workspaces preserve their filesystem across restarts, while ephemeral Workspaces start clean every time and can stop on their own once their tasks complete.
- Full root capability inside the sandbox to install packages, run services and run nested containers, with no VMs, bare-metal nodes or specialized hardware.
The same terminal is available in the browser through the Cordium web portal, with nothing to install.
Terminal
The same terminal is available in the browser through the Cordium web portal, with nothing to install.
- # Create a Workspace and attach a terminal
- $ cordium run --image node:22 \
- --repository https://github.com/acme/web
- ✓ Workspace status: PREPARING (12s)
- octelium@cordium:~$ cd /workspace/repo && ls
- README.md package.json src test
- octelium@cordium:/workspace/repo$ npm test
- Test Files 14 passed (14)
- Tests 186 passed (186)
Exec
Output is streamed back and the exit code is propagated, which is what scripts and CI/CD jobs depend on.
- # Run a command in a running Workspace
- $ cordium exec abc -w /workspace/repo -- go test ./...
- ok github.com/acme/api/billing 0.412s
- ok github.com/acme/api/invoices 0.388s
- ok github.com/acme/api/payments 0.531s
- $ echo $?
- 0
- # Capture remote output locally
- $ cordium exec abc -- cat /workspace/repo/report.json > report.json
SSH
SSH is authenticated at the Cluster with your own identity, so Workspaces never need authorized keys or passwords.
- # Connect once to use native SSH tooling
- $ octelium connect -d
- $ cordium ssh abc --print-config >> ~/.ssh/config
- # VS Code, Zed, JetBrains, rsync and scp work as usual
- $ code --remote ssh-remote+cordium-abc /workspace/repo
- $ rsync -avz ./dist/ cordium-abc:/workspace/repo/dist/
- # Or forward ports with the embedded client
- $ cordium ssh abc -N -L 5432:localhost:5432
Ephemeral
An ephemeral Workspace starts from fresh storage every time, so nothing carries over from one run to the next.
- # A disposable sandbox, deleted when the terminal exits
- $ cordium run --ephemeral --rm \
- --image python:3.13-slim --cpu 2000 --memory 4096
- ✓ Workspace status: PREPARING (6s)
- octelium@cordium:~$ python -c 'print(6 * 7)'
- 42
- octelium@cordium:~$ exit
Workspaces
Persistent Workspaces keep their filesystem across stops and restarts, and resume exactly where they left off.
- $ cordium get workspaces
- ┌──────┬─────────┬──────────┬─────────┬─────────┬──────────────┐
- │ NAME │ CREATED │ TEMPLATE │ SPACE │ STATE │ LAST STARTED │
- ├──────┼─────────┼──────────┼─────────┼─────────┼──────────────┤
- │ abc │ 3d │ default │ default │ RUNNING │ 2h │
- │ x7k2 │ 12d │ backend │ acme │ RUNNING │ 41m │
- │ ci4m │ 6m │ ci │ acme │ STOPPED │ 6m │
- └──────┴─────────┴──────────┴─────────┴─────────┴──────────────┘
- $ cordium stop x7k2
- Successfully stopped the Workspace: x7k2
- $ cordium start x7k2
- Successfully started Workspace: x7k2
Access infrastructure without credentials inside the sandbox
Every Workspace run gets a dedicated Octelium identity. Processes inside the Workspace reach authorized resources with standard tools, while the upstream credentials stay at the Octelium identity-aware proxy.
- Covers HTTP API keys and access tokens, SSH passwords and private keys, PostgreSQL and MySQL passwords, kubeconfigs and mTLS client certificates.
- psql, ssh, curl and kubectl work unmodified, with no SDK, no credential injection and no secrets in environment variables.
The Workspace connects without a password. The proxy authenticates to the database on its behalf, and MySQL works the same way.
A Workspace reaches authorized Octelium Services with standard tools. The upstream credential is kept in the Cluster as a Secret and injected at the identity-aware proxy once the request is authorized, so it never reaches the Workspace.
- PostgreSQL: the Workspace runs psql -h reporting.db -c "select count(*) from invoices" and holds no credential. The POSTGRES Service injects the database password from the Cluster Secret reporting-password and authenticates to pg.internal:5432. The Workspace connects without a password. The proxy authenticates to the database on its behalf, and MySQL works the same way.
- SSH: the Workspace runs ssh bastion.prod uptime and holds no credential. The SSH Service injects the ssh private key from the Cluster Secret bastion-key and authenticates to 10.0.4.21:22. No private keys or passwords inside the Workspace, and the session is recorded at the proxy on the way through.
- Kubernetes: the Workspace runs octelium cfg k8s-prod then kubectl get pods -n production and holds no credential. The KUBERNETES Service injects the kubeconfig from the Cluster Secret kubeconfig-prod and authenticates to k8s.internal:6443. The kubeconfig inside the Workspace only points at the Service. The cluster credential itself never leaves the Cluster.
- HTTP: the Workspace runs curl http://payments/v1/charges?limit=1 and holds no credential. The HTTP Service injects the api key from the Cluster Secret stripe-api-key and authenticates to api.stripe.com. A prompt injection cannot exfiltrate an API key the agent never had, and revoking access is a Policy change rather than a rotation.
- mTLS: the Workspace runs nats -s events-bus:4222 sub "orders.>" and holds no credential. The TCP Service injects the client certificate from the Cluster Secret events-bus-crt and authenticates to nats.internal:4222. Any upstream protected by mutual TLS, including protocols that Octelium does not parse at the application layer.
Identity-based access control on every request
Access from a Workspace is authorized on a per-request basis against the identity behind it, the context around it and the content of the request itself, with policy-as-code using CEL and OPA.
- Application-layer access control on HTTP methods, paths and bodies, database names and users, Kubernetes verbs, resources and namespaces, and MCP and LLM operations.
- Humans authenticate through OIDC and SAML 2.0 identity providers, GitHub OAuth2 and passkeys, while agents and workloads use OAuth2 or federated OIDC assertions.
- Zero standing privileges. There is no admin or superuser User, and all access must be granted by a Policy that can be revoked on the next request.
Database names and database users
An agent's Workspace reaches one database, as one database user
- Policy p-agents-reporting
- all:
- of:
- - match: '"agents" in ctx.user.spec.groups'
- - match: ctx.request.postgres.connect.database == "reporting"
- - match: ctx.request.postgres.connect.user == "readonly"
- ALLOW: agent-07 · Workspace abc, connect database=reporting user=readonly, all three expressions match.
- DENY: agent-07 · Workspace abc, connect database=payments user=readonly, database is outside the rule.
- DENY: agent-07 · Workspace abc, connect database=reporting user=admin, database user is not readonly.
HTTP methods, paths and bodies
Agents read from the payments API, but never write to it
- Policy p-agents-payments
- - effect: DENY
- condition:
- match: ctx.request.http.method != "GET"
- - effect: ALLOW
- condition:
- match: '"agents" in ctx.user.spec.groups'
- ALLOW: agent-07 · Workspace abc, GET /v1/charges?limit=10, rule 2, User is in the agents Group.
- DENY: agent-07 · Workspace abc, POST /v1/refunds, rule 1, DENY rules override ALLOW rules.
- DENY: linus@acme.com · Workspace m3p, GET /v1/charges, no rule matched, nothing is allowed by default.
Kubernetes verbs, resources and namespaces
CI Workspaces can read production, and nothing more
- Policy p-ci-readonly
- all:
- of:
- - match: '"ci" in ctx.user.spec.groups'
- - match: ctx.request.kubernetes.verb in ["get", "list", "watch"]
- - match: ctx.request.kubernetes.namespace == "production"
- ALLOW: ci-runner · Workspace ci4m, list pods in production, Group, verb and namespace all match.
- DENY: ci-runner · Workspace ci4m, delete deployment in production, verb delete is not in the allowed set.
- DENY: agent-07 · Workspace abc, list pods in production, User is not in the ci Group.
The same Service, different reach
People and agents use the same Workspaces, under different Policies
- Policy p-bastion
- all:
- of:
- - match: ctx.user.spec.type == "HUMAN"
- - match: '"sre" in ctx.user.spec.groups'
- ALLOW: jane@acme.com · Workspace x7k2, ssh bastion.prod, HUMAN User in the sre Group.
- DENY: agent-07 · Workspace abc, ssh bastion.prod, User type is WORKLOAD.
- DENY: linus@acme.com · Workspace m3p, ssh bastion.prod, User is not in the sre Group.
Real-time, L7-aware visibility for every Workspace
Every request a Workspace makes to infrastructure is logged in real time with its full identity context and exported to your OpenTelemetry OTLP receivers.
- Application-layer detail in every entry: HTTP methods and paths, database queries, Kubernetes operations, recorded SSH sessions, and MCP and LLM calls with token usage.
- Every entry correlates back to the Workspace Session and its owner, which is what post-incident analysis of an agent run actually needs.
- OpenTelemetry-native visibility. Logs go to the log management and SIEM tools your organization already operates.
A programmable sandbox platform for agents and automation
Everything the CLI and the web portal do is available over the gRPC API, with official SDKs for Go, TypeScript, Python and Rust. Create, start, drive and destroy sandboxes from a CI pipeline, a scheduler, an internal developer platform or an AI agent.
- Run commands and stream their output, move files, attach to persistent terminals, follow initialization logs and watch Workspace state changes.
- Manage Templates and pre-builds, snapshots, Volumes, Spaces, Secrets and Memberships through the same clients.
- Authenticate workloads secretlessly with OIDC assertions from platforms such as GitHub Actions and Kubernetes, or with OAuth2 and access tokens.
Credentials are read from the environment, including OIDC assertion files for workload identity federation, so the same code runs on a laptop, in CI and inside a Workspace.
c, err := cordium.New(ctx)
if err != nil {
return err
}
defer c.Close()
ws, err := c.Workspaces().Run(ctx,
cordium.WithImage("python:3.13"),
cordium.Ephemeral(),
)
if err != nil {
return err
}
defer ws.Delete(context.WithoutCancel(ctx))
res, err := ws.Exec(ctx, "python -c 'print(6 * 7)'")
if err != nil {
return err
}
fmt.Println(res.Output(), res.ExitCode) // 42 0import { Cordium, argv } from "@octelium/cordium";
const client = new Cordium();
const workspace = await client.workspaces.run({
image: "node:22",
ephemeral: true,
});
try {
const result = await workspace.exec(argv("node", "-p", "6 * 7"));
console.log(result.stdout); // 42
} finally {
await workspace.delete();
client.close();
}from cordium import Cordium
with Cordium() as client:
workspace = client.workspaces.run(
image="python:3.13",
ephemeral=True,
)
try:
result = workspace.exec(["python", "-c", "print(6 * 7)"])
print(result.stdout) # 42
finally:
workspace.stop().wait_until_stopped()
workspace.delete()use cordium::{Client, Command, WorkspaceOptions};
let client = Client::from_env().await?;
let workspace = client
.workspaces()
.run(WorkspaceOptions::new().image("python:3.13").ephemeral(true))
.await?;
let result = workspace
.exec(Command::argv(["python", "-c", "print(6 * 7)"]))
.await?;
println!("{}", result.stdout_text()); // 42
workspace.delete().await?;Declarative, reproducible environments
Workspace environments are defined in YAML specs covering the container image, repository cloning, lifecycle tasks, environment variables, resource limits, variable substitution and application ports.
- Build Workspace filesystems from OCI images, Dockerfiles, git repositories and devcontainers, with multi-repository cloning including private repositories.
- Templates reuse one configuration across many Workspaces, and variables let a single Template serve many different tasks.
- Spaces group Workspaces, Templates, Secrets and Volumes, with resource limits resolved across the Workspace, Space and Cluster levels.
spec:
image:
registry:
url: python:3.12-bookworm
repository:
url: https://github.com/acme/api
runtime:
tasks:
- name: install
type: ON_CREATE
workingDir: /workspace/repo
run: pip install -r requirements.txt
onFailure: ON_FAILURE_ABORTspec:
image:
dockerfile:
inline: |
FROM node:22-bookworm
RUN apt-get update && apt-get install -y \
podman postgresql-client
RUN npm install -g @anthropic-ai/claude-code
limit:
cpu:
millicores: 4000
memory:
megabytes: 8192
storage:
megabytes: 20480spec:
repository:
url: https://github.com/acme/web
image:
repository:
devcontainer:
dirPath: .devcontainer
applications:
- name: web
port: 3000
isDefault: truespec:
vars:
- name: BRANCH
value: main
- name: TASK
value: Fix the failing tests.
repository:
url: https://github.com/acme/api
cloneOptions:
branch: ${{ vars.BRANCH }}
runtime:
autoStop: true
tasks:
- name: run-agent
type: POST_START
workingDir: /workspace/repo
run: claude "${{ vars.TASK }}"Kubernetes-native storage, snapshots and Volumes
Workspace storage is backed by Kubernetes persistent volumes on any CSI driver, including Longhorn, Ceph, OpenEBS, AWS EBS, GCP Persistent Disk and Azure Disk.
- Snapshots capture a Workspace's storage while it keeps running, so it can be cloned into new Workspaces or restored after a risky change.
- Volumes outlive the Workspaces that mount them, mounted by one Workspace at a time or shared by several, read-only or read-write per mount.
- Template prebuilds that reduce cold startup for heavy Workspaces from minutes to near instant.
- Storage classes and snapshot classes are selected through CEL rules, routing different Workspaces to different storage backends.
A running Workspace yields a crash-consistent snapshot and a stopped one a clean snapshot. Both outlive their source.
Snapshots
A running Workspace yields a crash-consistent snapshot and a stopped one a clean snapshot. Both outlive their source.
- # Snapshot a Workspace while it keeps running
- $ cordium create snapshot before-upgrade --workspace abc
- Started taking the WorkspaceSnapshot: before-upgrade of the Workspace: abc
- # Restore it into a brand new Workspace
- $ cordium run --snapshot before-upgrade
- ✓ Workspace status: PREPARING (6s)
- octelium@cordium:~$ git -C /workspace/repo status --short
- M src/billing/invoice.go
- ?? migrations/0042_add_tax_rates.sql
Volumes
Exclusive Volumes are mounted by one running Workspace at a time. Shared Volumes need a shared filesystem backend such as NFS, CephFS or EFS.
- # Volumes have a lifecycle of their own
- $ cordium create volume datasets --size 50000
- Successfully created the Volume: datasets of 50000 MB
- $ cordium create volume build-cache --size 20000 --shared
- Successfully created the Volume: build-cache of 20000 MB
- # Mount read-only or read-write, per Workspace
- $ cordium run --volume datasets:/data:ro --volume build-cache:/cache
- ✓ Workspace status: PREPARING (9s)
- octelium@cordium:~$ ls /data
- eval images labels train
Pre-builds
A pre-build runs a Template's initialization once and snapshots the result, so dependency-heavy Templates start in seconds.
- # Pre-build a Template into a VolumeSnapshot
- $ cordium build ml-env.research
- Started a build for Template: ml-env
- # New Workspaces restore from it instead of starting cold
- $ cordium run --template ml-env.research
- ✓ Workspace status: PREPARING (5s)
- octelium@cordium:~$ python -c 'import torch; print(torch.__version__)'
- 2.8.0
Rootless sandboxes with egress network policies
Each Workspace runs as a rootless container inside a restricted outer container, with dropped capabilities, a custom seccomp profile and enforced resource limits. Egress network policies decide where it can connect.
- Egress rules allow or deny destinations by CIDR and port. By default public networks are reachable and private ones are not, and DENY rules always take precedence.
- Read-only root filesystems and per-Workspace Linux capabilities, merged with the Space and Cluster configuration.
Public networks only, by default
With no rules, a Workspace reaches the internet but not private networks
- egress:
- # no rules, so every destination falls
- # back to the default action
- defaultAction: ALLOW_PUBLIC
- ALLOW: pip install requests to 151.101.0.223:443, public destination, default action.
- DENY: psql -h 10.0.4.40 to 10.0.4.40:5432, private network, default action.
- DENY: curl http://169.254.169.254 to 169.254.169.254:80, protected network, denied whatever the rules say.
Deny everything except what a job needs
A DENY default with explicit ALLOW rules by CIDR and port
- egress:
- defaultAction: DENY
- rules:
- - action: ALLOW
- cidrs: ["140.82.112.0/20"]
- ports: [443]
- ALLOW: git clone https://github.com/acme/api to 140.82.112.4:443, matches the ALLOW rule.
- DENY: pip install requests to 151.101.0.223:443, no rule matched, default action.
- DENY: ssh -T git@github.com to 140.82.112.4:22, port 22 is outside the rule.
DENY rules always take precedence
A destination matched by a DENY rule is denied even if an ALLOW rule matches it
- egress:
- rules:
- - action: ALLOW
- cidrs: ["10.0.0.0/8"]
- ports: [5432]
- - action: DENY
- cidrs: ["10.0.9.0/24"]
- ALLOW: psql -h 10.0.4.40 to 10.0.4.40:5432, private, but allowed by a rule.
- DENY: psql -h 10.0.9.12 to 10.0.9.12:5432, the DENY rule overrides the ALLOW rule.
- DENY: redis-cli -h 10.0.4.7 to 10.0.4.7:6379, outside the rules, private by default.
Use Cordium across development and automation
Start with remote development environments or AI agent sandboxes, then apply the same Workspaces, identities, Policies and audit trail to CI/CD, automation and secretless access to infrastructure.
Development
04- Remote development environmentsPersistent Workspaces for VS Code, Zed and JetBrains over standard SSH, or a full terminal in the browser.
- Reproducible project environmentsTemplates, devcontainers and pre-builds, so every engineer starts from the same initialized filesystem.
- Nested containersRun Podman inside a Workspace, including databases and services for integration tests.
- Secretless infrastructure accessReach databases, SSH servers, Kubernetes clusters and internal APIs from a Workspace without distributing credentials.
AI agents and automation
06- Claude Code sandboxesRun Claude Code in an isolated Workspace with policy-controlled, secretless access to the infrastructure it works on.
- Codex sandboxesRun OpenAI Codex against real APIs, databases and clusters, with no raw credentials inside the Workspace.
- OpenCode sandboxesLet OpenCode plan, modify repositories and run tests inside an isolated, auditable execution environment.
- CI/CD executionEphemeral, auto-stopping Workspaces that build, test and deploy with secretless access to clusters and registries.
- Sandboxes from codeCreate, drive and destroy Workspaces from Go, TypeScript, Python and Rust in any orchestration system.
- Identities for AI agentsAgents act under their own identities and Policies, rather than holding long-lived, over-privileged credentials.
The same capabilities ship with every installation, from a single VM to a multi-node production cluster.
Frequently asked
- Is Cordium free and open source?
- Yes. Cordium is free and open source under the Apache 2.0 license and is designed for self-hosting. There is no proprietary cloud-based control plane, no tiered feature set, and it is not a limited version of a separate paid SaaS product. Cordium is built on Octelium, whose Cluster components are licensed under AGPLv3.
- How is Cordium different from other sandbox platforms?
- Remote development environments such as GitHub Codespaces and Coder, and sandbox platforms such as E2B and Daytona, provide the execution environment and leave infrastructure access to whatever credentials are placed inside it. Cordium additionally gives every Workspace its own identity and provides secretless, policy-driven access to SSH servers, databases, HTTP APIs, Kubernetes clusters and mTLS services, so no upstream credential is ever exposed, distributed or managed inside the sandbox.
- How are Workspaces isolated?
- Each Workspace runs as a rootless container inside a restricted outer container, with all Linux capabilities dropped except a small explicit set, a custom seccomp profile, a restricted /proc and enforced CPU, memory and storage limits. It runs on standard Kubernetes with no VMs, bare-metal nodes or specialized hardware, and egress network policies decide which destinations it can reach.
- Can AI agents use Cordium programmatically?
- Yes. Everything the CLI and the web portal do is available over the gRPC API, with official SDKs for Go, TypeScript, Python and Rust. Agents and orchestrators authenticate as workload Users, including secretlessly through OIDC assertions issued by platforms such as GitHub Actions and Kubernetes, and every Workspace they run gets its own Session identity.
- Do I need an existing Octelium Cluster?
- Cordium runs on top of Octelium. The quick installer can automatically set up a complete Octelium Cluster and installs Cordium on top of it. If you already run an Octelium Cluster, Cordium can be installed on it as a package.
- Do I need Kubernetes experience to run Cordium?
- No. Cordium runs on Kubernetes, but the quick installer provisions a complete single-node Cluster, Kubernetes included, on any Linux machine or VM with at least 4GB of RAM and 20GB of disk storage. Production installations can run on managed or on-premises multi-node Kubernetes.
Install Cordium on your own infrastructure in minutes
One fresh Linux VM/server and a domain you own. The installer takes care of Octelium, Cordium and all of their dependencies, Kubernetes included.
$ curl -o install-cluster.sh https://octelium.com/install-cluster.sh$ chmod +x install-cluster.sh$ ./install-cluster.sh --domain <DOMAIN> --cordium