Octelium is a free and open source, self-hosted zero trust access platform. It reaches private VPC resources across accounts and regions, RDS databases, EKS clusters, S3 buckets and Lambda function URLs through one identity model, with the AWS credential held by the Cluster rather than distributed to people and jobs.
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.
Each protected resource is represented as a Service behind an identity-aware proxy that enforces application-layer access control, credential isolation and auditing. Which VPC, account or region an upstream sits in becomes a detail of the Service definition.
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 rather than the security group or subnet it arrived from.
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
AWS credentials that are never distributed
Application-layer credentials are stored in the Cluster as Secrets and used to authenticate upstream once a request is authorized. For AWS that includes signing requests with Signature Version 4 on the caller's behalf.
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 identity management, authentication, access control and visibility model. An ETL job reaching a bucket is authorized and audited exactly as an engineer would be.
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.
Because the request is attributed to an Octelium User rather than to a shared IAM identity, an audit shows which person or job made a call rather than which key was used.
Export structured AccessLogs in real time over OpenTelemetry OTLP to the observability and SIEM systems you already operate.
Self-hosted, Kubernetes-native and fully programmable
Run the Cluster on Kubernetes infrastructure you control, scale the data plane horizontally, manage resources declaratively, automate the platform through APIs and SDKs, and optionally deploy containerized Service upstreams with the Cluster itself.
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.
Access to AWS is rarely one problem. These are the kinds of resource that come up, next to the mechanism in an Octelium Cluster that reaches each one.
01
Private resources inside a VPC
An internal service, an EC2 instance or an internal load balancer becomes a Service with a stable private name, reached over the tunnel. Nothing is exposed publicly and no bastion has to be kept running for people to hop through.
A Service upstream can be an address that is only reachable from the side of a connected host inside that VPC, which serves it over its own outbound tunnel. Accounts, regions and peering arrangements stop being something the person connecting has to know about.
The database password is held as a Secret and injected after authorization, and the Service can force the upstream database user and database regardless of what the client asks for. Queries are recorded with the identity that ran them.
The HTTP mode signs requests upstream with AWS Signature Version 4 using an access key held in the Cluster, so a team or a workload reads a bucket over an ordinary HTTPS client without holding an IAM key.
The same SigV4 mechanism covers Lambda function URLs, with the service field set to lambda, so an invocation is authorized per request against identity and the HTTP request itself.
The Kubernetes mode holds the kubeconfig, client certificate or bearer token and authorizes each API request by verb, resource, namespace, API group and name, so nobody needs a kubeconfig of their own.
SigV4 signing takes the region and service name as configuration, so the same pattern extends to other AWS APIs that a team or an application needs to call without an IAM identity of its own.
An EKS cluster or a CI system that publishes an OpenID Connect issuer can authenticate its own workloads to the Cluster with federated assertions, so no long-lived credential has to be stored alongside the job.
IAM still decides what the Cluster's own credential may do. What changes is that the credential stays in one place, and the decision about who may use it is made per request against an identity you already manage.
On every Octelium Cluster
The same platform capabilities ship with every deployment, whichever way you use it.
No. IAM still governs what the credential held by the Cluster is allowed to do inside AWS. What changes is who holds that credential: it stays in the Cluster and is used to sign or authenticate the upstream request after Octelium has authenticated and authorized the caller, so individual people and jobs do not each need an IAM identity and a key on disk.
How does secretless access to S3 and Lambda work?
The HTTP mode supports AWS Signature Version 4 as an upstream authentication method. An access key ID, a secret access key held as a Secret, a region and a service name are configured on the Service, and the proxy signs each authorized request upstream. Callers use an ordinary HTTPS client and their own Octelium credential.
Can it reach resources in several accounts and regions?
Yes. A Service upstream can be an address that is only reachable from the side of a connected host inside that network, which serves it over its own outbound tunnel, so a VPC in another account or region needs no peering, no transit gateway change and no inbound port. Each resource is still reached through a single stable route on the client.
Does the Cluster have to run inside AWS?
No. An Octelium Cluster runs on any Kubernetes, managed or on-premise, including EKS. 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, which is enough for evaluation.
How do workloads inside AWS authenticate?
Workload Users can authenticate with authentication tokens, the OAuth2 client credentials flow, or secretlessly with federated OpenID Connect assertions issued by the platform hosting them, including an EKS cluster that publishes an OIDC issuer and CI systems such as GitHub Actions. No special SDK or client is required.
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.