The modern, unified, open source secure access platform

Replace your VPN and remote access tools with a modern, unified, free and open source, identity-based zero trust platform for humans, workloads and AI agents to access hybrid infrastructure, including internal resources, microservices, AI workloads, IoT and SaaS.

  • Free and open source
  • Designed for self-hosting

Humans, workloads and AI agents reach web and internal APIs, SSH and RDP hosts, Kubernetes clusters, databases, MCP servers and LLM providers through one Octelium Cluster. Every request is identified, authorized against the request itself, authenticated to the upstream by the Cluster rather than by the caller, and logged.

  • ALLOW: jane@acme.com to bastion.prod over SSH, the private key is injected at the proxy and the session is recorded.
  • ALLOW: ci-runner to k8s-prod over KUBERNETES, verb=list resource=pods namespace=production, with no kubeconfig.
  • DENY: agent-07 to tools-mcp over MCP, tools/call name=transfer amount=25000, denied on its arguments.
  • ALLOW: linus@acme.com to reporting.db over POSTGRES, database reporting as readonly, with no password to distribute.
  • ALLOW: svc-billing to payments over HTTP, POST /v1/charges, with the API key injected at the proxy.
Why Octelium

Four challenges of modern secure remote access

As humans, workloads, services, and AI agents converge on the same infrastructure, four challenges become fundamental: identity, authorization, secure connectivity, and visibility. Octelium unifies all four in a single secure access platform.

  1. 01

    Credential sprawl

    API keys, SSH keys, database passwords, kubeconfigs, and cloud credentials must be distributed, stored, rotated, and revoked across a growing fleet.

    In Octelium

    Octelium keeps upstream credentials as Cluster Secrets and injects them only after authorization. Users, workloads and agents never need to hold them.

  2. 02

    Fragmented identity

    Human identity lives in directories and SSO providers, while service accounts, CI jobs, workloads and AI agents accumulate separate credentials and identities elsewhere.

    In Octelium

    Unified identity management for humans and workloads. People authenticate through your OIDC and SAML 2.0 identity providers and native FIDO2, WebAuthn and TPM 2.0 authenticators, while workloads use OAuth2, authentication tokens or federated OIDC assertions.

  3. 03

    Broad network access

    VPNs and network-level controls often make more infrastructure reachable than a user or workload actually needs.

    In Octelium

    Every resource is protected behind an identity-aware proxy. Access control is enforced at the application layer on a per-request basis with policy-as-code.

  4. 04

    Incomplete visibility

    Network and connection logs rarely explain who performed an application action, why it was authorized, and what the request actually contained.

    In Octelium

    OpenTelemetry-native, application-layer-aware, real-time visibility. Structured logs and metrics are exported to your SIEM providers.

Unified Access Platform

A unified architecture for client-based and clientless access

One zero trust architecture built on identity-aware proxies for humans, workloads and AI agents to access internal resources behind NAT in any environments, protected SaaS resources and containerized applications.

Connecting to a Cluster

One stable route, stable private dual-stack addresses and automatic private DNS. Upstreams stay behind NAT, nothing is exposed publicly, and only outbound connectivity is required on both sides.

Client-based access

One stable route, stable private dual-stack addresses and automatic private DNS. Upstreams stay behind NAT, nothing is exposed publicly, and only outbound connectivity is required on both sides.

  • # Connect once. Every Service you are allowed to reach
  • # answers to its own name.
  • octelium connect -d
  • ssh bastion.prod
  • psql -h reporting.db -U readonly
  • curl http://payments/v1/charges
  • # kubectl addresses a cluster by kubeconfig, so the CLI
  • # writes one for the Service.
  • octelium cfg k8s-prod
  • kubectl get pods -n production
  • # Or publish a Service to a local port, as Docker does
  • octelium connect -p reporting.db:5432

Clientless access

The same Services, the same Policies and the same logs, reached without any client, agent or SDK. Anonymous public access is available too, for hosting.

  • # Humans, in a browser
  • https://hr-app.acme.com
  • # Workloads, over standard OAuth2 and bearer tokens
  • curl -H "Authorization: Bearer $TOKEN" \
  • https://payments.acme.com/v1/charges
  • # Kubernetes, gRPC, MCP and LLM over the same FQDN
  • kubectl --server https://k8s-prod.acme.com get pods
  • # Public anonymous access, for hosting
  • https://docs.acme.com
  • # No client, no agent and no SDK on any of these paths.
least-privilege access

Identity-based access control at the application layer

Access is authorized on a per-request basis against the identity behind the request, the context around it and the content of the request itself, rather than against the network path it arrived on.

Read about Policies
Identity, Groups, Device and Session
Attributes of the subject, combined in one expression, evaluated per request

Identity, Groups, Device and Session

Attributes of the subject, combined in one expression, evaluated per request

  • Policy p-sre-console
  • all:
  • of:
  • - match: ctx.user.spec.type == "HUMAN"
  • - match: ctx.session.status.type == "CLIENT"
  • - match: ctx.device.status.osType in ["MAC", "LINUX"]
  • - match: '"sre" in ctx.user.spec.groups'
  • ALLOW: jane@acme.com, CLIENT session, MAC device, Group sre, all four expressions match.
  • DENY: jane@acme.com, CLIENTLESS session from a browser, session type is not CLIENT.
  • DENY: agent-07, WORKLOAD User, no Device, User type is not HUMAN.

HTTP method, path, headers and body

The request itself is part of the decision, not only the connection

  • Policy p-hr-app
  • - effect: DENY
  • condition:
  • match: ctx.request.http.path.startsWith("/admin")
  • - effect: ALLOW
  • condition:
  • match: '"hr" in ctx.user.spec.groups'
  • ALLOW: jane@acme.com, GET /reviews/2026, rule 2, User is in the hr Group.
  • DENY: jane@acme.com, GET /admin/settings, rule 1, DENY rules override ALLOW rules.
  • DENY: contractor-3, GET /reviews/2026, no rule matched, nothing is allowed by default.

Kubernetes verbs, resources and namespaces

Authorization per operation rather than per cluster credential

  • Policy p-k8s-readonly
  • all:
  • of:
  • - match: ctx.request.kubernetes.verb in ["get", "list", "watch"]
  • - match: ctx.request.kubernetes.namespace == "production"
  • - match: ctx.request.kubernetes.resource in ["pods", "services"]
  • ALLOW: ci-runner, list pods in production, verb, namespace and resource all match.
  • DENY: ci-runner, delete pod in production, verb delete is not in the allowed set.
  • DENY: ci-runner, list secrets in kube-system, namespace and resource are outside the rule.

Database users, databases and queries

The same model for databases as for HTTP and Kubernetes

  • Policy p-reporting-db
  • all:
  • of:
  • - match: ctx.request.postgres.connect.database == "reporting"
  • - match: ctx.request.postgres.connect.user == "readonly"
  • - match: '"analysts" in ctx.user.spec.groups'
  • ALLOW: linus@acme.com, connect database=reporting user=readonly, User is in the analysts Group.
  • DENY: linus@acme.com, connect database=payments user=readonly, database is outside the rule.
  • DENY: svc-billing, connect database=reporting user=admin, database user is not readonly.
Dynamic Secretless Access

Access resources without distributing their credentials

Dynamic secretless access where teams and AI agents access protected infrastructure without ever holding a credential.

Read about secretless access

The API key stays in the Cluster. The caller never receives one, and revoking access is a Policy change rather than a rotation across every consumer.

Upstream credentials are kept in the Cluster as Secrets and injected at the identity-aware proxy once a request is authorized, so the caller never holds one and the upstream still receives an ordinary authenticated request.

  • HTTP: the caller runs curl payments/v1/charges and holds no credential. The HTTP Service injects the api key from the Cluster Secret stripe-api-key and authenticates to api.stripe.com. The API key stays in the Cluster. The caller never receives one, and revoking access is a Policy change rather than a rotation across every consumer.
  • SSH: the caller runs ssh bastion.prod 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 shared private keys, no passwords to rotate and no PKI of your own to run. The session is recorded on the way through.
  • PostgreSQL: the caller runs psql -h reporting.db -U readonly and holds no credential. The POSTGRES Service injects the database password from the Cluster Secret reporting-password and authenticates to pg.internal:5432. MySQL works the same way, and the query itself is available to both the Policy and the log.
  • Kubernetes: the caller runs 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. No kubeconfig on any laptop or CI runner, and no cluster credential to revoke one machine at a time.
  • mTLS: the caller runs nats sub "events.>" and holds no credential. The TCP Service injects the client certificate from the Cluster Secret client-crt-nats and authenticates to my-nats.default.svc:9090. Any upstream protected by mutual TLS, including protocols Octelium does not parse.
Any OIDC or SAML 2.0 identity provider
Plus native FIDO2, WebAuthn passkeys, TPM 2.0 and TOTP, required through Policy

Any OIDC or SAML 2.0 identity provider

Plus native FIDO2, WebAuthn passkeys, TPM 2.0 and TOTP, required through Policy

  • Okta: OIDC, SAML 2.0
  • Microsoft Entra ID: OIDC, SAML 2.0
  • Google Workspace: OIDC
  • Keycloak: OIDC, SAML 2.0
  • Auth0: OIDC
  • GitHub: OAuth2
  • Any OIDC provider: OpenID Connect
  • Any SAML 2.0 provider: SAML 2.0
  • FIDO2 and WebAuthn: Passkeys
  • TPM 2.0: Hardware-backed
  • TOTP: Authenticator apps
  • A Session is created for the authenticated User and carries its type, Groups and authenticator.

Workloads and AI agents are Users too

The same Groups, the same Policies and the same audit trail as a person

  • Authentication tokens: A Credential issued to a workload User, revocable from the Cluster.
  • OAuth2 client credentials: The standard flow, in any language, with no client and no SDK.
  • Federated OIDC assertions: GitHub Actions, AWS, Azure and Kubernetes assert the workload's identity, so there is no token to distribute at all.
Every tool call is authorized on its own
The MCP mode parses JSON-RPC, so the method, the tool and its arguments are all in the request context

Every tool call is authorized on its own

The MCP mode parses JSON-RPC, so the method, the tool and its arguments are all in the request context

  • ALLOW: initialize, protocolVersion 2025-06-18, handshake permitted for the finance-agents Group.
  • ALLOW: tools/list, 12 tools returned, rule 2 allows listing.
  • ALLOW: tools/call, name=search_invoices q=overdue, tool is in the allowed set.
  • DENY: tools/call, name=transfer amount=25000, arguments.amount exceeds the ceiling in rule 1.
  • MCP servers can also run as managed containers deployed and scaled by the Cluster itself.

Model, operation, tools and token limits

A protocol-aware gateway for OpenAI and Anthropic APIs, with token usage recorded in the AccessLog

  • ALLOW: CHAT_COMPLETIONS, model=gpt-5-mini stream=false tokens=1284, model and operation are both permitted.
  • ALLOW: MESSAGES, protocol=ANTHROPIC model=claude-sonnet-4-5, the Anthropic Service carries its own Policy.
  • DENY: RESPONSES, model=gpt-5 hasTools=true, the rule requires hasTools == false.
  • ALLOW: EMBEDDINGS, model=text-embedding-3-large inputItemCount=64, within the declared input ceiling.
  • The provider API key stays in the Cluster as a Secret, so no agent ever holds it.
Visibility

Real-time, L7-aware visibility and auditing

OpenTelemetry-native, real-time, structured, L7-aware visibility exported to the log management and SIEM tools your organization already operates.

Read about visibility and logs
A request to an internal application
The method, the path and the response code, not only a connection
ALLOWED

A request to an internal application

The method, the path and the response code, not only a connection

  • ALLOWED HTTP on hr-app.internal: GET /reviews/2026, 200.
  • Method: GET
  • Path: /reviews/2026
  • Response: 200, text/html
  • User: jane@acme.com, HUMAN
  • Session: jane-rqgw1a, CLIENT
  • Device: jane-mbp-14, MAC
  • Decision: ALLOWED, POLICY_MATCH, p-hr-app, rule 2.

A session on a bastion host

The upstream login user, with the session recording on the entry

  • ALLOWED SSH on bastion.prod: deploy@10.0.4.21:22, RECORDED.
  • Log type: SESSION_RECORDING
  • Upstream user: deploy
  • Recording: STDOUT stream
  • User: jane@acme.com, HUMAN
  • Session: jane-rqgw1a, CLIENT
  • Device: jane-mbp-14, MAC
  • Decision: ALLOWED, POLICY_MATCH, p-bastion, rule 1.

A query against a reporting database

The statement itself, and the database user the proxy connected as

  • ALLOWED POSTGRES on reporting.db: select id, total from invoices limit 50, QUERY.
  • Command type: QUERY
  • Database: reporting
  • Database user: readonly
  • User: linus@acme.com, HUMAN
  • Session: linus-4kd2p, CLIENT
  • Device: linus-mbp-16, MAC
  • Decision: ALLOWED, POLICY_MATCH, p-reporting-db, rule 1.

A CI job listing pods in production

The verb, the resource and the namespace, so a review reads operations

  • ALLOWED KUBERNETES on k8s-prod: list pods in production, 200.
  • Verb: list
  • Resource: pods, apiVersion v1
  • Namespace: production
  • User: ci-runner, WORKLOAD
  • Session: ci-runner-8t2b, CLIENT
  • Groups: ci, 2 Policies
  • Decision: ALLOWED, POLICY_MATCH, p-k8s-readonly, rule 2.

An agent calling a tool it may not call

The JSON-RPC method, the tool and the argument that failed the rule

  • DENIED MCP on tools-mcp: tools/call transfer, 403.
  • Method: tools/call
  • Name: transfer
  • Arguments: amount=25000
  • User: agent-07, WORKLOAD
  • Session: agent-07-k91d, CLIENTLESS
  • Groups: finance-agents, 1 Policy
  • Decision: DENIED, POLICY_MATCH, mcp-tools, rule 1.

An inference request to a model provider

The protocol, the operation, the model and the tokens it used

  • ALLOWED LLM on openai: CHAT_COMPLETIONS gpt-5-mini, 1284 in / 612 out.
  • Protocol: OPENAI
  • Operation: CHAT_COMPLETIONS
  • Model: gpt-5-mini, stream false
  • User: agent-07, WORKLOAD
  • Session: agent-07-k91d, CLIENTLESS
  • Groups: ai-users, 1 Policy
  • Decision: ALLOWED, POLICY_MATCH, p-ai-users, rule 1.
service.yaml
A ServiceEvery protected resource is a Service, whatever protocol it speaks and wherever it runs.
A Service. Every protected resource is a Service, whatever protocol it speaks and wherever it runs.
kind: Service
metadata:
  name: hr-app
spec:
  mode: WEB
  config:
    upstream:
      url: http://10.0.3.18:8080
  authorization:
    policies: ["p-hr-app"]
A Policy. Authorization is written as code and evaluated per request, with the request itself in context.
kind: Policy
metadata:
  name: p-hr-app
spec:
  rules:
    - effect: DENY
      condition:
        match: ctx.request.http.path.startsWith("/admin")
    - effect: ALLOW
      condition:
        match: '"hr" in ctx.user.spec.groups'
Secretless access. The upstream credential is a Cluster Secret. Nothing is distributed to the Users who need the resource.
kind: Service
metadata:
  name: reporting
spec:
  mode: POSTGRES
  config:
    upstream:
      url: postgres://pg.internal:5432
    postgres:
      user: readonly
      database: reporting
      auth:
        password:
          fromSecret: reporting-password
A managed container. The Cluster can also deploy, scale and serve the containerized application behind a Service.
kind: Service
metadata:
  name: docs
spec:
  mode: HTTP
  isPublic: true
  config:
    upstream:
      container:
        port: 80
        image: nginx:latest
A workload User. Non-human subjects are Users too, with the same Groups, the same Policies and the same audit trail.
kind: User
metadata:
  name: ci-runner
spec:
  type: WORKLOAD
  groups: ["ci"]
Use cases

Use Octelium across your infrastructure

Start with a VPN replacement or ZTNA deployment, then apply the same identity, Services, Policies and audit model to SSH, Kubernetes, databases, APIs, MCP servers and AI agents.

Secure access

10

Deployment and hosting

04
Questions

Frequently asked

Is it really free and open source?
Yes. Octelium is free and open source and is designed for self-hosting. There is no proprietary cloud-based control plane and it is not a limited edition of a separate paid product. An enterprise package is available for organizations that need capabilities such as a web console, SCIM 2.0 provisioning and Secret encryption at rest, and it is free to use, forever, for personal and evaluation use.
How is this different from a VPN?
A VPN grants access to a network. Octelium represents each protected resource as a Service behind an identity-aware proxy and authorizes every request against the identity behind it, the context around it and the content of the request itself. Client-based access still uses WireGuard and QUIC tunnels, but establishing one grants access to nothing on its own.
Which protocols does it cover?
HTTP, gRPC and web applications, SSH, Kubernetes, PostgreSQL and MySQL, RDP, DNS, SOCKS5, generic TCP and UDP, and the MCP and LLM modes for AI workloads. Each one is covered by the same identity, Policy and auditing model, and the layer-7 aware ones expose their protocol details to both Policies and logs.
Do I need to know Kubernetes to run it?
An Octelium Cluster runs on top of Kubernetes, but you do not need Kubernetes experience to install, operate or use it. The quick installer provisions a complete single-node Cluster, including Kubernetes itself, on one fresh Linux VM/server and a domain you own. Production Clusters run on scalable managed or on-premise Kubernetes installations.
Get started

Install a Cluster on your own infrastructure in minutes

One fresh Linux VM/server, and a domain you own. The installer takes care of the Cluster and all of its dependencies, Kubernetes included.

$ curl -o install-cluster.sh https://octelium.com/install-cluster.sh$ chmod +x install-cluster.sh$ ./install-cluster.sh --domain <DOMAIN>