An open source, self-hosted BeyondCorp architecture
Octelium is a free and open source, self-hosted zero trust access platform. Its clientless mode publishes a protected resource through an internet-facing identity-aware proxy, so people reach it in an ordinary browser from any device and workloads reach it with standard OAuth2, with nothing installed on either side and no inbound port opened towards the resource.
- Free and open source
- Designed for self-hosting
- No client, no inbound ports
kind: Service
metadata:
name: k8s-dashboard
spec:
mode: WEB
isPublic: true
config:
upstream:
url: http://dashboard.internal:8080kind: Policy
metadata:
name: browser-access
spec:
rules:
- effect: ALLOW
condition:
all:
of:
- match: ctx.user.spec.type == "HUMAN"
- match: ctx.session.status.isBrowser
- match: '"employees" in ctx.user.spec.groups'octeliumctl create cred \
--type oauth2 \
--user microservice1 \
cred02
# The application then authenticates at
# https://<DOMAIN>/oauth2/token
# and sends the issued bearer access token
# in the Authorization header.A unified secure access platform
Secure humans, workloads and AI agents with one model for identity, authorization, connectivity, credentials and visibility.
- Unified access platform
One architecture for client-based zero-config VPN-like access over WireGuard and QUIC tunnels and clientless access over browsers for humans and OAuth2 access for workloads.
Read more - L7-aware access control
Identity-based, application-layer aware ABAC access control with policy-as-code via CEL and OPA, applied on a per-request basis.
Read more - Secretless access
Dynamic secretless access where teams and AI agents access protected infrastructure without ever holding a credential.
Read more - Unified identity management
Teams, workloads and AI agents share the same model for identity management, access control, and auditing.
Read more - Real-time visibility and auditing
OpenTelemetry-native, real-time, application-layer-aware visibility and structured logging.
Read more - GitOps-friendly management
Octelium is administered like Kubernetes. Define your resources in YAML files, store them in a Git repository.
Read more
One architecture for both ways of reaching a resource
Each resource is protected by an identity-aware proxy that provides application-layer-aware access control, secretless access, and visibility. Clientless access is one field on that Service rather than a separate product.
- Enabling isPublic makes the internet-facing proxy accept requests for the Service's public FQDN and forward them after authentication and authorization, for HTTP, WEB, GRPC and KUBERNETES Services.
- The same Service can also be reached over a client-based WireGuard or QUIC tunnel, under the same Policies, which covers the protocols a browser cannot speak.
- An upstream behind NAT is served to the Cluster over a connected client's own outbound tunnel, so a resource can be published to the internet without an inbound port or a firewall rule beside it.
kind: Service
metadata:
name: wiki
spec:
mode: HTTP
config:
upstream:
url: http://10.0.6.18:3000kind: Service
metadata:
name: wiki
spec:
mode: HTTP
isPublic: true
config:
upstream:
url: http://10.0.6.18:3000kind: Service
metadata:
name: prod-k8s
spec:
mode: KUBERNETES
isPublic: true
config:
upstream:
url: https://k8s.internal:6443
kubernetes:
kubeconfig:
fromSecret: kubeconfig-prodLayer-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 network path it arrived on.
- Session attributes distinguish a browser from a client-based session and from a workload, so a resource can be reachable from an unmanaged device for reading and from a managed one for everything else.
- Application-layer-aware access control that includes HTTP methods, paths, headers and serialized JSON body content, SSH users, Kubernetes verbs, resources and namespaces, and PostgreSQL and MySQL users and databases.
- Native FIDO2 and WebAuthn passkeys, TOTP and TPM 2.0 authenticators can be required after a sign-in through enforcement rules, independently of what the identity provider enforces.
kind: Policy
metadata:
name: managed-browsers
spec:
rules:
- effect: ALLOW
condition:
all:
of:
- match: ctx.session.status.type == "CLIENTLESS"
- match: ctx.session.status.isBrowser
- match: ctx.device.status.osType in ["MAC", "WINDOWS"]kind: Policy
metadata:
name: api-read-only
spec:
rules:
- effect: ALLOW
condition:
all:
of:
- match: ctx.request.http.method == "GET"
- match: ctx.request.http.path.startsWith("/v1/")
- match: '"partners" in ctx.user.spec.groups'kind: ClusterConfig
metadata:
name: cluster-config
spec:
authenticator:
authenticationEnforcementRules:
- condition:
match: ctx.session.status.isBrowser
effect: ENFORCE
- condition:
match: '"contractors" in ctx.user.spec.groups'
effect: ENFORCECredentials that are never distributed
Application-layer credentials are stored in the Cluster as Secrets and injected into the upstream connection once a request is authorized. The credential the caller presents to the Cluster and the credential the Cluster presents upstream are entirely separate.
- Covers HTTP API keys and access tokens, basic authentication, OAuth2 client credentials and mTLS client certificates for the upstream behind the proxy.
- Protected public resources are covered as well as private ones, so a SaaS API can be reached by a team or a workload without the API key leaving the Cluster.
- The upstream and the credential can be selected dynamically per request from identity and context, so different Users reach the same Service URL with different privileges.
kind: Service
metadata:
name: internal-api
spec:
mode: HTTP
isPublic: true
config:
upstream:
url: https://api.internal:8443
http:
auth:
bearer:
fromSecret: api-keykind: Service
metadata:
name: stripe
spec:
mode: HTTP
isPublic: true
config:
upstream:
url: https://api.stripe.com
http:
auth:
bearer:
fromSecret: stripe-api-keykind: Service
metadata:
name: internal-api
spec:
mode: HTTP
isPublic: true
config:
upstream:
url: https://staging.internal
dynamicConfig:
configs:
- name: prod
upstream:
url: https://prod.internal
http:
auth:
bearer:
fromSecret: prod-api-key
rules:
- condition:
match: '"sre" in ctx.user.spec.groups'
configName: prodA unified identity model for humans and workloads
Human and workload Users share the same identity management, authentication, access control and visibility model. The original BeyondCorp problem was people on untrusted devices, and the same architecture now has to carry services and agents as well.
- Workloads reach clientless Services with the OAuth2 client credentials flow or access tokens, using ordinary libraries in any language, sent as Authorization: Bearer or X-Octelium-Auth.
- They can also authenticate secretlessly with federated OIDC assertions from GitHub Actions, cloud providers and Kubernetes clusters, so no long-lived credential has to be stored on their side.
- The MCP and LLM gateway modes extend the same clientless model to the tools and model providers that AI agents reach, with tool calls authorized individually.
- Cordium, built on Octelium, provides isolated sandboxes for agents and developers, where processes reach authorized Services through the Workspace identity with no secrets inside the sandbox.
kind: IdentityProvider
metadata:
name: github-actions
spec:
oidcIdentityToken:
issuerURL: https://token.actions.githubusercontent.com
audience: https://example.comkind: User
metadata:
name: microservice1
spec:
type: WORKLOAD
groups:
- serviceskind: Service
metadata:
name: tools-mcp
spec:
mode: MCP
isPublic: true
config:
upstream:
url: http://mcp.internal:8080
mcp:
endpoint: /mcp
protocol:
requireVersion: trueReal-time visibility at the application layer
OpenTelemetry-ready, application-layer aware, structured auditing and visibility emitted to your OpenTelemetry OTLP receivers, where they can be exported to your log management and SIEM tools.
- Application-layer detail includes HTTP requests and responses, gRPC services and methods, Kubernetes verbs and resources, MCP methods and tool names, and LLM operations and token usage.
- Logs are exported over OpenTelemetry OTLP in real-time to SIEM providers you already operate.
A scalable platform that also deploys your workloads
A Cluster runs on Kubernetes and uses it to scale its own data plane, place Service proxies across Gateways, and run containerized applications that the Cluster itself deploys.
- Managed containers deploy, scale and serve containerized applications as Service upstreams, so an internal tool can be published clientlessly without being hosted anywhere else first.
- Public DNS records and TLS certificates for published Services are managed by the Cluster, so exposing a resource does not become a separate certificate workflow.
- The Cluster is managed declaratively. Resources are defined in YAML, kept in a Git repository, and applied with a single octeliumctl apply that reproduces the entire Cluster state.
$ octeliumctl apply ./cluster
Secret: api-key Updated
Secret: kubeconfig-prod Updated
IdentityProvider: okta Updated
Policy: browser-access Created
Group: employees Created
Group: services Updated
Service: wiki.internal Created
Service: k8s-dashboard Created
Service: internal-api Created
Namespace: internal Created
Cluster Core resources successfully applied
7 resources created
3 resources updated
ClusterConfig updatedWhat a BeyondCorp architecture requires, and what provides it
BeyondCorp is an architecture rather than a product category. These are the properties it is defined by, next to the concrete mechanism in an Octelium Cluster that carries each one.
- 01
Connecting to a network grants nothing
There is no privileged network to be on. A request is authorized against the identity behind it and the request itself, whether it arrives from an office, a home connection or a mobile network, and whether it came over a tunnel or straight from a browser.
Read more - 02
Applications are reached through an access proxy
Each protected resource is represented by a Service served by an identity-aware proxy, which terminates the request, authenticates it, authorizes it and only then reaches the upstream. The upstream is never directly exposed to the internet.
Read more - 03
Every resource is protected individually
Publishing one Service does not publish anything else. Each has its own public FQDN, its own Policies and its own upstream credential, so an authorization mistake is scoped to a single resource rather than to a network segment.
Read more - 04
People sign in with the identity they already have
Human Users authenticate through any OpenID Connect or SAML 2.0 identity provider, or GitHub OAuth2, in an ordinary browser flow. Group membership from that provider is what Policies are written against.
Read more - 05
Device state is part of the decision
Device information is available in the request context and combines with identity, group membership, session type and time in the same policy expression, so an unmanaged device can be allowed to reach some resources and not others.
Read more - 06
The strength of the authentication can be raised
Native FIDO2 and WebAuthn passkeys, TOTP and TPM 2.0 authenticators can be required after a sign-in through enforcement rules, independently of what the identity provider itself enforces.
Read more - 07
Non-human clients are covered by the same model
Workload Users reach the same clientless Services with the standard OAuth2 client credentials flow or bearer access tokens, using ordinary OAuth2 libraries in any language, with no client and no proprietary SDK.
Read more - 08
Every access is recorded with its identity
Each request produces an identity-aware, application-layer AccessLog naming the User, Session and Device, streamed in real time over OpenTelemetry to your own log management and SIEM providers.
Read more
Putting a login page in front of an application is not a BeyondCorp architecture on its own. What makes it one is that the decision is made per request, from identity and device state, by a proxy the resource sits behind rather than beside.
The same platform capabilities ship with every deployment, whichever way you use it.
Frequently asked
- What does clientless access actually mean here?
- Setting isPublic on a Service makes the Cluster's internet-facing proxy accept requests for that Service's public FQDN and forward them to it after authentication and authorization. A person reaches it in an ordinary browser from any device, including phones and tablets, and a workload reaches it with a standard bearer access token. Nothing is installed on either side.
- Which Service modes can be published this way?
- The HTTP-based modes: HTTP, WEB, GRPC and KUBERNETES, as well as the MCP and LLM gateway modes and browser-based RDP. For human access to a web application the WEB mode is preferable, because the Service is then presented as a web app with a link straight to its homepage.
- How do workloads authenticate without a client?
- Through the standard OAuth2 client credentials flow against the Cluster's own token endpoint, or with an access token Credential used directly as a bearer token. Either can be sent in an Authorization: Bearer header or an X-Octelium-Auth header, so ordinary OAuth2 libraries in any language work without a proprietary SDK. Workloads can also authenticate secretlessly with federated OIDC assertions from the platform hosting them.
- Do I have to choose between clientless and client-based access?
- No. The same Service can be reachable both ways at once, under the same Policies. Client-based access over WireGuard or QUIC tunnels covers protocols a browser cannot speak, such as SSH, PostgreSQL, MySQL and generic TCP and UDP, while clientless access covers the HTTP-based ones from any device.
- What is needed to publish a Service to the internet?
- A public DNS record and a TLS certificate for the Service's public FQDN, both of which the Cluster manages. Nothing has to be opened towards the upstream itself: an upstream behind NAT is served to the Cluster over a connected client's own outbound tunnel, so no inbound port or firewall rule is added on that side.
- Is Octelium free and open source?
- Yes. Octelium is free and open source and is designed for single-tenant 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 provisioning and secret encryption at rest, and it is free for personal, homelab and evaluation use.
Related solutions
Zero Trust Network Access
Octelium as a complete ZTNA and BeyondCorp platform for humans, workloads and AI agents on a single architecture.
Read moreCloudflare Access alternative
The same clientless access model, with the control plane and the data plane running on infrastructure you operate.
Read moreZero trust SaaS and API access
Secretless access to protected public resources, so a team reaches a SaaS API without holding its key.
Read moreDeploy Octelium on your own infrastructure in minutes
Free and open source. Self-hosted. No vendor lock-in.