Octelium is a free and open source, self-hosted zero trust access platform. It provides identity-based, layer-7 aware access control on a per-request basis, dynamic secretless access, and a unified architecture for both client-based and clientless access, for humans, workloads and AI agents alike.
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
Secure humans, workloads and AI agents with one model for identity, authorization, connectivity, credentials and visibility.
Protect resources individually, not entire networks
Every application, API, SSH server, database, Kubernetes cluster or other protected resource is represented as a Service behind an identity-aware proxy. A tunnel or network location grants no access by itself; the same identity, Policy and audit model applies to both private client-based and public clientless access.
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)
Identity-aware access control
Authorize every request with identity and application context
Octelium evaluates who is making the request, the state and context around that identity, and what the application request is attempting to do. Policies are explicit, deny by default and are evaluated independently for each protected request.
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
Keep upstream credentials out of users and workloads
Store application credentials in the Cluster and inject them only after access is authorized. Users, workloads and AI agents reach protected resources without receiving the upstream API key, password, private key, certificate or other credential.
Upstream credentials injected per request by identity in the HTTP, SSH and PostgreSQL modes
HTTP: the HTTP Service stripe proxies https://api.stripe.com and picks the upstream credential of every request with dynamic configuration rules.
elena, a member of the finance-eu Group, runs curl -s stripe/v1/account | jq '{id, country}' without holding any credential. The rule "finance-eu" in ctx.user.spec.groups selects the eu config, so Octelium injects the Secret stripe-eu and the upstream authenticates the request as acct_1Pq8EuGmbH2bXvK3. The terminal shows { "id": "acct_1Pq8EuGmbH2bXvK3", "country": "DE" }
pay-agent, a member of the finance-us Group, runs curl -s stripe/v1/account | jq '{id, country}' without holding any credential. The rule "finance-us" in ctx.user.spec.groups selects the us config, so Octelium injects the Secret stripe-us and the upstream authenticates the request as acct_1Nf2UsQ7cLm4RtW9. The terminal shows { "id": "acct_1Nf2UsQ7cLm4RtW9", "country": "US" }
SSH: the SSH Service web-01 proxies ssh://10.0.4.21 and picks the upstream credential of every request with dynamic configuration rules.
sam, a member of the sre Group, runs ssh web-01 without holding any credential. The rule "sre" in ctx.user.spec.groups selects the root config, so Octelium injects the Secret root-key and the upstream authenticates the request as root. The terminal shows Welcome to Ubuntu 24.04.3 LTS (GNU/Linux 6.14.0-1015-aws x86_64) root@web-01:~# id uid=0(root) gid=0(root) groups=0(root)
noah, a member of the developers Group, runs ssh web-01 without holding any credential. The rule "developers" in ctx.user.spec.groups selects the deploy config, so Octelium injects the Secret deploy-key and the upstream authenticates the request as deploy. The terminal shows Welcome to Ubuntu 24.04.3 LTS (GNU/Linux 6.14.0-1015-aws x86_64) deploy@web-01:~$ id uid=1001(deploy) gid=1001(deploy) groups=1001(deploy)
PostgreSQL: the POSTGRES Service orders-db proxies postgres://10.0.2.8:5432 and picks the upstream credential of every request with dynamic configuration rules.
priya, a member of the backend Group, runs psql -h orders-db orders without holding any credential. The rule "backend" in ctx.user.spec.groups selects the rw config, so Octelium injects the Secret pg-rw and the upstream authenticates the request as app_rw. The terminal shows psql (17.2) Type "help" for help. orders=> UPDATE orders SET status = 'shipped' WHERE id = 42; UPDATE 1
bi-agent, a member of the analytics Group, runs psql -h orders-db orders without holding any credential. The rule "analytics" in ctx.user.spec.groups selects the ro config, so Octelium injects the Secret pg-ro and the upstream authenticates the request as app_ro. The terminal shows psql (17.2) Type "help" for help. orders=> UPDATE orders SET status = 'shipped' WHERE id = 42; ERROR: permission denied for table orders
Identity
One identity model for humans, workloads and AI agents
Human and workload Users share the same Groups, Policies, access controls and audit model while authenticating through mechanisms appropriate to each identity type.
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.
Run and automate ZTNA on infrastructure you control
Full self-hosted on your own infrastructure with no vendor lock-in. Manage the Cluster declaratively or automate it through APIs and SDKs rather than depending on a mandatory hosted control plane.
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.
NIST defines zero trust as a set of architectural principles rather than a product certification. The mapping below shows the Octelium mechanism that corresponds to each of the seven basic tenets in NIST SP 800-207.
01
1. Treat data and services as resources
Octelium represents protected applications, APIs, SSH servers, databases, Kubernetes clusters, DNS and other reachable resources as Services. Policy is attached to the resource boundary instead of assuming that an entire network segment shares one trust level.
2. Secure communication regardless of network location
Client-based access uses encrypted WireGuard or QUIC tunnels and clientless access uses HTTPS. Being on an internal network, connected to a tunnel or otherwise close to the resource does not by itself grant access.
Access is evaluated for the target Service rather than granted broadly to a network. Octelium authorizes requests individually, so authentication to one Service or establishment of a tunnel does not authorize access to another Service.
Policies can combine User and Group identity, Session state, Device information, authentication strength, Service and Namespace attributes, geolocation, time, application-layer request data and attributes supplied by external systems.
When a Session is associated with a Device, current Device information can participate in Policy decisions. Device-management, endpoint-security and other posture signals can also be incorporated into the attributes used for authorization.
6. Authenticate and authorize dynamically before access
Session tokens are not treated as sufficient stateless proof of authorization. Current User, Group, Session, Device and Policy state is resolved during authorization, so disabling a User, deleting a Session or changing Policy can affect subsequent requests without waiting for a long-lived access credential to expire.
7. Collect telemetry and use it as security context
Allowed and denied requests produce structured AccessLogs with identity, resource, authorization outcome, matching Policy information and protocol-specific details. Logs can be exported in real time through OpenTelemetry, while external security and operational systems can feed attributes back into Policy decisions.
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.
How is Octelium ZTNA different from a traditional VPN?
A traditional remote-access VPN primarily establishes network reachability. Octelium can use WireGuard or QUIC as the transport for private client-based access, but establishing the tunnel grants access to nothing by itself. Every protected resource is a Service, and each request is still evaluated against identity-aware Policies at the application layer.
Does Octelium support clientless ZTNA?
Yes. A Service can be exposed for clientless access over HTTPS. Human Users can access browser applications through their identity provider, while workloads can authenticate with standard bearer or OAuth2 credentials. Client-based and clientless access use the same Service, identity, Policy and auditing model.
Do I have to replace my identity provider?
No. Octelium supports OpenID Connect and SAML 2.0 identity providers, as well as GitHub OAuth2. Native FIDO2/WebAuthn passkeys, TOTP and TPM-backed authenticators can provide additional authentication that can be enforced independently for sensitive access.
How granular is ZTNA access control?
Policies can evaluate identity and context together with protocol-specific request data. Examples include HTTP methods, paths and JSON fields; Kubernetes verbs, resources and namespaces; SSH users; database users and queries; MCP methods, tools and arguments; and LLM operations, models, tools and token limits.
Which resources can Octelium protect with ZTNA?
Octelium Services can protect web applications and HTTP APIs, gRPC, SSH, Kubernetes, PostgreSQL and MySQL, RDP, DNS, generic TCP and UDP resources, as well as MCP servers and LLM providers. The same identity, Policy and auditing model applies across these Service modes.
How are workloads and AI agents handled?
Non-human identities such as workloads and AI agents are first-class Octelium Users and use the same Groups, Policies and AccessLogs as human Users. They can authenticate with individual access tokens, OAuth2 client credentials or federated OIDC assertions from platforms such as GitHub Actions, cloud providers and Kubernetes. AI agents can use the same workload identity when accessing ordinary infrastructure, MCP Services and LLM Services.
Do I need Kubernetes experience to run Octelium?
No. Octelium runs on Kubernetes, but Kubernetes expertise is not required for a basic deployment. The quick installer provisions a complete single-node Cluster, including Kubernetes, on a fresh Linux VM or server. Larger production deployments can run on managed or on-premises multi-node Kubernetes.