Octelium is a free and open source, self-hosted zero trust access platform. Managed containers let the Cluster deploy, scale and serve your containerized applications as Services, so the thing that runs an application and the thing that decides who may reach it are the same declarative resource.
Unified identity management for humans, workloads and AI agents
Adaptive authentication for humans and non-human identities
Identity-based, application-layer-aware access control
OpenTelemetry-native real-time visibility and auditing
Unified access architecture for private and SaaS resources
Every request from a human, a browser, a CLI, a workload or an AI agent is authenticated against your identity providers, authorized per request at the application layer by the Octelium Service in front of the resource, exported to your SIEM and observability stack whether it is allowed or denied, and only then routed to the upstream HTTP API, database, SSH server, Kubernetes cluster, LLM or MCP server.
The platform
A unified secure access platform
Deployment is the last of them, and the one this page is about. Each capability is described in detail below, in the same order.
Each application is represented by a Service, which is served by an identity-aware proxy. Whether the application is deployed by the Cluster or already running elsewhere is a detail of the upstream, and how it is reached is a separate field.
A client running on this device is asking to log in to acme.com. Approve it only if you have just started a login yourself.
Approve
Reject
Sign in with a passkey
acme.com
J
jane@acme.com
Passkey
Touch the sensor to continueVerifying…Verified
Cancel
~
~❯
New Tab
Search or type a URL
grafana
argocd
jenkins
kibana
Signing in once, then reaching Services with and without a client
A browser opens grafana.acme.com and is redirected to the Cluster sign-in page at acme.com/login.
jane signs in with a passkey verified by a biometric on the device, and the browser returns to the Grafana dashboard at grafana.acme.com with no client installed.
In a terminal, octelium connect -d opens the browser at acme.com/callback/success/approval, where the same browser session approves the login with one click.
~ ❯ octelium connect -d
Please authenticate yourself using Octelium web Portal
Waiting for you to approve the login in your browser. Press Ctrl-C to cancel.
You are now authenticated as jane
Octelium has started running in detached mode.
~ ❯ curl -s my-api/v1/users/42 | jq
{
"id": 42,
"name": "Jane Doe",
"email": "jane@acme.com"
}
~ ❯ psql -h pg-prod -d shop
psql (17.4)
Type "help" for help.
shop=> SELECT * FROM orders LIMIT 3;
id | status | total
-----+---------+--------
981 | paid | 129.00
982 | shipped | 48.50
983 | paid | 310.25
(3 rows)
shop=> \q
~ ❯ ssh bastion
Welcome to Ubuntu 24.04.1 LTS (GNU/Linux 6.8.0-1021-aws x86_64)
Access control
Layer-7 aware access control with policy-as-code
Access is authorized on a per-request basis, using CEL or Open Policy Agent, against the identity behind the request and the content of the request itself. For a deployed application that removes the need to build authentication into it.
jane, a member of the finance Group, runs curl -i billing/invoices/42 and gets HTTP/1.1 200 OK Content-Type: application/json {"id":42,"status":"paid","total":1290}. The access log records ALLOWED GET /invoices/42 with POLICY_MATCH.
jane, a member of the finance Group, runs curl -i -X DELETE billing/invoices/42 and gets HTTP/1.1 403 Forbidden X-Octelium-Unauthorized: true Content-Length: 0. The access log records DENIED DELETE /invoices/42 with NO_POLICY_MATCH.
LLM: the LLM Service openai is configured as follows.
kind: Service
metadata:
name: openai
spec:
mode: LLM
config:
authorization:
inlinePolicies:
- spec:
rules:
- effect: ALLOW
condition:
any:
of:
- match: '"ai-admins" in ctx.user.spec.groups'
- all:
of:
- match: '"ai-agents" in ctx.user.spec.groups'
- match: ctx.request.llm.operation == "GENERATE"
- match: ctx.request.llm.model == "gpt-5-mini"
support-bot, a member of the ai-agents Group, runs curl openai/v1/responses --json '{"model":"gpt-5-mini","input":"Hello"}' and gets { "id": "resp_68e8e1f0c4d0", "object": "response", "created_at": 1791628935, "status": "completed", "model": "gpt-5-mini-2025-08-07",. The access log records ALLOWED RESPONSES gpt-5-mini with POLICY_MATCH.
support-bot, a member of the ai-agents Group, runs curl openai/v1/responses --json '{"model":"gpt-5","input":"Hello"}' and gets {"error":{"message":"Octelium: unauthorized request","type":"permission_error","param":null,"code":"octelium_unauthorized"}}. The access log records DENIED RESPONSES gpt-5 with NO_POLICY_MATCH.
Kubernetes: the KUBERNETES Service k8s-prod is configured as follows.
kind: Service
metadata:
name: k8s-prod
spec:
mode: KUBERNETES
config:
authorization:
inlinePolicies:
- spec:
rules:
- effect: ALLOW
condition:
all:
of:
- match: '"sre-agents" in ctx.user.spec.groups'
- match: ctx.request.kubernetes.verb in ["get", "list"]
ops-agent, a member of the sre-agents Group, runs kubectl get configmaps -n production and gets NAME DATA AGE app-config 4 12d feature-flags 2 3d kube-root-ca.crt 1 12d. The access log records ALLOWED list configmaps · production with POLICY_MATCH.
ops-agent, a member of the sre-agents Group, runs kubectl get secrets -n production and gets Error from server (Forbidden): Octelium: Unauthorized request. The access log records DENIED list secrets · production with NO_POLICY_MATCH.
Secretless access
Configuration and credentials in one place
Secrets are Cluster resources. They fill environment variables in a deployed container, authenticate a pull from a private registry, and authenticate the upstreams that the application itself reaches.
One identity model for humans, workloads and AI agents
Human and workload Users share the same identity management, authentication, access control and visibility model. The pipeline that deploys an application and the people who use it are identities in the same system.
Identity-aware visibility at the application layer
Emit structured, application-layer access logs in real time and export them through OpenTelemetry OTLP to the observability, analytics and SIEM systems your organization already operates.
Logs are exported over OTLP to the log management and SIEM providers you already operate, so a deployment does not come with its own separate observability stack.
A Cluster runs on Kubernetes and uses it to scale its own data plane, place Service proxies across Gateways, and run the containerized applications it deploys.
Cluster resources applied declaratively from YAML with octeliumctl and managed programmatically with the Go, TypeScript, Python and Rust SDKs
GitOps: cluster.yaml in the main branch of the ~/octelium repository describes the desired state of the Cluster. Its diff reads as follows, with + for added, ~ for changed and - for removed lines.
+ kind: Group
+ metadata:
+ name: payments
+ spec: {}
+ ---
+ kind: User
+ metadata:
+ name: alice
+ spec:
+ type: HUMAN
+ email: alice@acme.com
+ groups: ["payments"]
---
kind: User
metadata:
name: bob
spec:
type: HUMAN
~ groups: ["payments"]
---
kind: Service
metadata:
name: billing
spec:
mode: HTTP
config:
upstream:
~ url: http://10.0.3.24:8080
- ---
- kind: Service
- metadata:
- name: billing-legacy
- spec: ⋯
- ---
- kind: User
- metadata:
- name: john
- spec: ⋯
~/octelium ❯ octeliumctl apply --prune .
Group: payments Created
User: alice Created
User: bob Updated
Service: billing.default Updated
Service: billing-legacy.default Deleted
User: john Deleted
Cluster Core resources successfully applied
2 resources created
2 resources updated
2 resources deleted
Go: main.go uses the octelium-go SDK to list the Users of the Cluster and update the email and Policies of linus.
What a deployment platform has to do, and what does each part
Running an application is only the first of the jobs a platform ends up owning. These are the rest, next to the mechanism in an Octelium Cluster that handles each one.
01
Run the container
A container image is set as the Service upstream and scheduled on the Cluster's data-plane nodes, using the Kubernetes infrastructure the Cluster already runs on. Custom commands and arguments are supported where the image needs them.
Public and private registries are both supported, with registry credentials referenced from Cluster Secrets rather than stored as a Kubernetes pull secret you maintain separately.
Environment variables can be literal values, references to Cluster Secrets, or references to an existing Kubernetes secret, so configuration and credentials arrive the same way in every environment.
Replica counts scale an application up and down, and CPU, memory and extended resource limits are set per Service, including requesting a GPU where the Kubernetes cluster can schedule one.
Kubernetes volumes are mounted into managed containers, including persistent volume claims and emptyDir volumes with a size limit, so an application that needs state is not excluded.
A published Service gets its own public FQDN under your Cluster's domain, with the public DNS record and the TLS certificate managed by the Cluster rather than by a separate certificate workflow.
The same Service is either anonymous and public, published behind your identity provider, private to connected clients, or several of those at once, and that is a field rather than a different deployment.
Every request produces an identity-aware, application-layer AccessLog streamed over OpenTelemetry, and health probes and resource limits are part of the same Service definition.
Building and pushing images stays in whatever CI you already use. What this replaces is the layer after that: the ingress, the certificate, the authentication in front, and the audit trail behind.
On every Octelium Cluster
The same platform capabilities ship with every deployment, whichever way you use it.
Any container image that listens on 0.0.0.0 on a known port. That covers web applications built with Next.js, Vite, Astro and similar frameworks, REST and gRPC APIs, MCP servers, inference servers and ordinary background services. Custom commands and arguments, environment variables from Secrets, replica counts, resource limits, security contexts, volumes and health probes are all part of the Service definition.
Does it build images as well?
No. Octelium deploys and serves an image you have already built and pushed to a registry, public or private. Building and pushing stay in whatever CI you already use, and the pipeline that does it can itself be a workload User authorized to apply the change.
How is an application exposed?
Through the same Service that runs it. Publishing it makes the Cluster's internet-facing proxy serve it at its own public FQDN with a managed TLS certificate. It can require an identity from your own identity provider, or be anonymous and open to everyone, and an anonymous Service can still filter on path, method, headers and body content.
Can it use persistent storage?
Yes. Kubernetes volumes are mounted into managed containers, including persistent volume claims and emptyDir volumes with a size limit, with mount paths and read-only flags set per Service.
Do I need Kubernetes experience?
No. An Octelium Cluster runs on top of Kubernetes and uses it to schedule managed containers, but the interface you work with is Octelium's own resources. The quick installer provisions a complete single-node Cluster, including Kubernetes itself, on one fresh Linux VM with 2 vCPUs, 2 GB of RAM and a domain you own.
Is Octelium free and open source?
Yes. Octelium is designed for self-hosting and does not require a proprietary hosted control plane. The core platform is free and open source. An optional enterprise package adds capabilities for organizations with additional operational, identity-management and security requirements, including the web console, SCIM provisioning and Secret encryption at rest.