BeyondCorp architecture

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
web.yaml
A web applicationOne field publishes a Service over HTTPS, reachable in a browser from any device.
A web application. One field publishes a Service over HTTPS, reachable in a browser from any device.
kind: Service
metadata:
  name: k8s-dashboard
spec:
  mode: WEB
  isPublic: true
  config:
    upstream:
      url: http://dashboard.internal:8080
A Policy. Access is authorized per request, from identity, device state and the request itself.
kind: 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'
A workload credential. Workloads reach the same Services over standard OAuth2, with no client and no SDK.
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.
service-private.yaml
A private resourceA resource behind NAT in any environment, with no inbound port opened anywhere.
A private resource. A resource behind NAT in any environment, with no inbound port opened anywhere.
kind: Service
metadata:
  name: wiki
spec:
  mode: HTTP
  config:
    upstream:
      url: http://10.0.6.18:3000
The same resource, clientlessly. Enabling isPublic makes the internet-facing proxy serve the very same Service.
kind: Service
metadata:
  name: wiki
spec:
  mode: HTTP
  isPublic: true
  config:
    upstream:
      url: http://10.0.6.18:3000
A Kubernetes API server. The clientless mode covers HTTP, WEB, GRPC and KUBERNETES Services, not only web apps.
kind: Service
metadata:
  name: prod-k8s
spec:
  mode: KUBERNETES
  isPublic: true
  config:
    upstream:
      url: https://k8s.internal:6443
    kubernetes:
      kubeconfig:
        fromSecret: kubeconfig-prod
policy-session.yaml
Session and deviceWhether a request came from a browser, a client or a workload is part of the context.
Session and device. Whether a request came from a browser, a client or a workload is part of the context.
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"]
The request itself. Method, path, headers and serialized JSON body are all part of the request context.
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'
Enforced multi-factor. An Authenticator can be required after sign-in, independently of what the provider enforces.
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: ENFORCE
http-auth.yaml
An upstream API keyThe application behind the proxy keeps its own credential, and nobody downstream receives it.
An upstream API key. The application behind the proxy keeps its own credential, and nobody downstream receives it.
kind: Service
metadata:
  name: internal-api
spec:
  mode: HTTP
  isPublic: true
  config:
    upstream:
      url: https://api.internal:8443
    http:
      auth:
        bearer:
          fromSecret: api-key
A SaaS API. Protected public resources are covered too, so a team reaches a SaaS API without holding its key.
kind: Service
metadata:
  name: stripe
spec:
  mode: HTTP
  isPublic: true
  config:
    upstream:
      url: https://api.stripe.com
    http:
      auth:
        bearer:
          fromSecret: stripe-api-key
A different upstream per identity. Identity and request context select which upstream and which credential are used.
kind: 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: prod
idp.yaml
Secretless workload identityWorkloads authenticate with OIDC assertions issued by the platform running them.
Secretless workload identity. Workloads authenticate with OIDC assertions issued by the platform running them.
kind: IdentityProvider
metadata:
  name: github-actions
spec:
  oidcIdentityToken:
    issuerURL: https://token.actions.githubusercontent.com
    audience: https://example.com
A workload User. A microservice reaching a Service is a User with the same groups and Policies as a person.
kind: User
metadata:
  name: microservice1
spec:
  type: WORKLOAD
  groups:
    - services
An MCP gateway. AI agents reach tools clientlessly, through the same identity, Policies and audit trail.
kind: Service
metadata:
  name: tools-mcp
spec:
  mode: MCP
  isPublic: true
  config:
    upstream:
      url: http://mcp.internal:8080
    mcp:
      endpoint: /mcp
      protocol:
        requireVersion: true
Visibility and auditing

Real-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.

Read about visibility and auditing
AccessLogOTLP
ALLOWlinus@acme.compg-prod.dbPOSTGRESquery: select id, email from users limit 50
ALLOWci-runnerprod-k8sKUBERNETESverb=list resource=pods namespace=production
DENYagent-07tools-mcpMCPtools/call name=transfer policy=mcp-tools
ALLOWjane@acme.combastionSSHsession recorded, upstream user=deploy
ALLOWagent-07openaiLLMCHAT_COMPLETIONS model=gpt-5-mini tokens=1284
octeliumctl
octeliumctl apply ./cluster
$ 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 updated
Principles

What 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.

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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.

Questions

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.
Get started

Deploy Octelium on your own infrastructure in minutes

Free and open source. Self-hosted. No vendor lock-in.