Cordium documentation · Latest

Secretless Access

Every Workspace is an Octelium identity. When a Workspace starts, Cordium creates a dedicated Octelium Session for its run, and the Workspace automatically connects to the Cluster via an octelium connect process that uses that Session. As a result, the processes running inside the Workspace can access every Octelium Service that the Workspace's owner is authorized to access, by simply using its name, with no API key, password, private key, kubeconfig or certificate inside the Workspace. The upstream credentials are stored as Octelium Secrets and injected by Octelium's identity-aware proxies on a per-request basis (read more about secretless access here).

Per-request access control
User
human or workload
Vigil
On-the-fly credential injection
Privileged, long-lived API key / access token
Static password
Static password / private key
Long-lived mTLS private key
HTTP resource
PostgreSQL / MySQL
SSH server
Generic resource

Secretless access diagram. A user reaches the Service, implemented by the Vigil identity-aware proxy, using only a fine-grained, short-lived access token under per-request access control. Inside Vigil, the appropriate upstream credential is injected on the fly and never shared with the user: a privileged, long-lived API key or access token for HTTP resources; a static password for PostgreSQL or MySQL databases; a static password or private key for SSH servers; and a long-lived mTLS private key for generic resources.

Accessing Services

Inside a Workspace, you access an Octelium Service exactly as you would from a connected laptop (read more here): via its name if it belongs to the default Namespace (e.g. anthropic), via <SERVICE>.<NAMESPACE> otherwise (e.g. pg-staging.payments), or via its full private FQDN (e.g. pg-staging.payments.local.<DOMAIN>). Here are some examples with standard tools:

# List the Services that you can access octelium get service # HTTP and gRPC APIs, without any API key curl http://ledger-api.payments/v1/health # PostgreSQL and MySQL databases, without any password psql -h pg-staging.payments -c "SELECT now();" mysql -h mysql-analytics # SSH servers, without any private key or password ssh bastion-eu # Kubernetes clusters, without any kubeconfig credentials octelium cfg k8s-staging export KUBECONFIG=~/.kube/k8s-staging.<DOMAIN> kubectl get pods -n payments # LLM providers, with a placeholder API key that is never forwarded ANTHROPIC_BASE_URL=http://anthropic ANTHROPIC_API_KEY=unused claude -p "Summarize the CHANGELOG"

Every request is authorized by Octelium Policies against the full request context (e.g. the HTTP method and path, the SQL query, the Kubernetes verb and namespace, or the LLM model) and logged via OpenTelemetry-native access logs that identify the User, the Workspace, its Space and its Template.

note

octelium connect starts as the first POST_START task of every run. Tasks that access Octelium Services must therefore be POST_START tasks, and they should wait until the Service becomes reachable (read more here). Terminals, cordium exec and SSH sessions do not need to wait since they are typically used once the Workspace is running.

Serving Services

A Workspace can also act as the upstream of Octelium Services (read more about serving Services from connected Users here). This turns any application running inside a Workspace into a full-fledged Octelium Service with its own Policies, secretless access, visibility, and optionally public or anonymous access, which is useful for preview environments, webhooks receivers, demos and internal tools. First, define a Service whose upstream is served by the Workspace's owner (e.g. alice):

kind: Service metadata: name: storefront-preview spec: mode: WEB isPublic: true config: upstream: url: http://localhost:5173 user: alice

And then ask the Workspace to serve it via the spec.runtime.octelium field:

spec: runtime: octelium: serveServices: - storefront-preview

Or serve all the Services assigned to its owner:

spec: runtime: octelium: serveAll: true

You can also use the --serve and --serve-all flags of cordium create workspace:

cordium create ws --template storefront.payments.cordium --serve storefront-preview --start

The Service is now available to the authorized Users at https://storefront-preview.<DOMAIN> while it is served from the Workspace. If several Workspaces (or a Workspace and your laptop) serve the same Service at the same time, Octelium load-balances the requests among them. Read a complete example here.

Policies for Workspaces

The Session of every Workspace run carries the Workspace's identity in its status.ext.cordium field, which is available to Octelium Policies and dynamic configuration rules via ctx.session.status.ext.cordium:

FieldDescription
workspaceRef.nameThe Workspace's name (e.g. x7k2).
spaceRef.nameThe full name of the Workspace's Space (e.g. payments.cordium).
templateRef.nameThe full name of the Workspace's Template (e.g. migrations.payments.cordium).
spaceTypeUSER or ORGANIZATION.

Sessions of the same User that do not belong to a Workspace (e.g. the User's laptop or browser) do not have the cordium entry, which lets you grant or deny access to Workspaces specifically. Since the entry is absent from those Sessions, conditions should check for its presence first. Here is an example of a Service that can only be accessed by the dba Group from Workspaces created from the migrations Template of the payments Space:

kind: Service metadata: name: pg-production.payments spec: mode: POSTGRES port: 5432 config: upstream: url: postgres://pg-production.internal.example.com postgres: user: migrator database: payments auth: password: fromSecret: pg-production-migrator-password authorization: inlinePolicies: - spec: rules: - effect: ALLOW condition: match: >- "dba" in ctx.user.spec.groups && "ext" in ctx.session.status && "cordium" in ctx.session.status.ext && ctx.session.status.ext.cordium.templateRef.name == "migrations.payments.cordium"

And here is an example of a Policy that denies all Workspace Sessions access to the production Namespace, while keeping the access of the same Users from their own machines untouched. It can be attached to Users, Groups or the production Namespace itself (read more about Policies here):

kind: Policy metadata: name: deny-workspaces-in-production spec: rules: - effect: DENY condition: match: >- "ext" in ctx.session.status && "cordium" in ctx.session.status.ext && ctx.namespace.metadata.name == "production"

Dynamic Credential Mapping

Since the Workspace's identity is part of the request context, a single Octelium Service can map different Workspaces to different upstream credentials via its dynamic configuration (read more here). Here is an example where Workspaces of the agents Template use a read-only database user, while everyone else uses the default read-write user:

kind: Service metadata: name: pg-staging.payments spec: mode: POSTGRES port: 5432 config: upstream: url: postgres://pg-staging.internal.example.com postgres: user: app_readwrite database: payments auth: password: fromSecret: pg-staging-readwrite-password dynamicConfig: configs: - name: agents upstream: url: postgres://pg-staging.internal.example.com postgres: user: app_readonly database: payments auth: password: fromSecret: pg-staging-readonly-password rules: - condition: match: >- "ext" in ctx.session.status && "cordium" in ctx.session.status.ext && ctx.session.status.ext.cordium.templateRef.name == "claude-agent.payments.cordium" configName: agents

From the Workspace's perspective, nothing changes: psql -h pg-staging.payments works in both cases, while Octelium transparently chooses the database user based on the Workspace's identity on a per-request basis.