Agentic AI

Zero trust identity and access for AI agents

Octelium is a free and open source, self-hosted zero trust access platform. An agent gets an identity of its own rather than a copy of someone's credentials, reaches resources through a proxy that holds the secrets, has each tool call and each inference request authorized on its own, and leaves an audit trail that names it.

  • Free and open source
  • Designed for self-hosting
  • MCP and LLM gateway modes
user.yaml
An agent identityAn agent is a workload User with the same groups, Policies and audit trail as a person.
An agent identity. An agent is a workload User with the same groups, Policies and audit trail as a person.
kind: User
metadata:
  name: release-agent
spec:
  type: WORKLOAD
  groups:
    - agents
The tools it calls. The MCP mode parses JSON-RPC, so each tool call is authorized on its own.
kind: Policy
metadata:
  name: agent-tools
spec:
  rules:
    - effect: ALLOW
      condition:
        all:
          of:
            - match: ctx.request.mcp.method == "tools/call"
            - match: ctx.request.mcp.name == "search_docs"
            - match: '"agents" in ctx.user.spec.groups'
The model it talks to. The LLM mode validates the inference request and injects the provider key upstream.
kind: Service
metadata:
  name: anthropic
spec:
  mode: LLM
  isPublic: true
  config:
    upstream:
      url: https://api.anthropic.com
    llm:
      protocol: ANTHROPIC
      auth:
        custom:
          header: x-api-key
          value:
            fromSecret: anthropic-api-key
mcp-public.yaml
Clientless, over HTTPSAn agent points a standard client at the Service URL and sends its own access token.
Clientless, over HTTPS. An agent points a standard client at the Service URL and sends its own access token.
kind: Service
metadata:
  name: tools-mcp
spec:
  mode: MCP
  isPublic: true
  config:
    upstream:
      url: http://mcp.internal:8080
    mcp:
      endpoint: /mcp
Over a tunnel. An agent running the client reaches private resources the same way an engineer does.
kind: Service
metadata:
  name: pg-staging
spec:
  mode: POSTGRES
  port: 5432
  config:
    upstream:
      url: postgres://10.0.4.40:5432
    postgres:
      user: agent_ro
      database: staging
      auth:
        password:
          fromSecret: pg-staging-password
Servers the Cluster runs. An MCP server can be deployed, scaled and served by the Cluster itself.
kind: Service
metadata:
  name: tools-mcp
spec:
  mode: MCP
  isPublic: true
  config:
    upstream:
      container:
        port: 8080
        image: ghcr.io/acme/mcp:1.4.0
        replicas: 2
    mcp:
      endpoint: /mcp
policy-tool.yaml
A single toolThe JSON-RPC method and the tool name are normalized fields, not substrings of a body.
A single tool. The JSON-RPC method and the tool name are normalized fields, not substrings of a body.
kind: Policy
metadata:
  name: read-only-tools
spec:
  rules:
    - effect: ALLOW
      condition:
        all:
          of:
            - match: ctx.request.mcp.method == "tools/call"
            - match: ctx.request.mcp.name == "search_docs"
            - match: '"agents" in ctx.user.spec.groups'
    - effect: ALLOW
      condition:
        match: ctx.request.mcp.method == "tools/list"
The inference request. Operation, model, streaming, declared tools and token limits are all authorized.
kind: Policy
metadata:
  name: agent-models
spec:
  rules:
    - effect: ALLOW
      condition:
        all:
          of:
            - match: ctx.request.llm.operation == "MESSAGES"
            - match: ctx.request.llm.maxOutputTokens <= 4096
            - match: '"agents" in ctx.user.spec.groups'
Bounds before the provider. Request size, estimated input tokens, output tokens and tool count are enforced up front.
kind: Service
metadata:
  name: anthropic
spec:
  mode: LLM
  config:
    upstream:
      url: https://api.anthropic.com
    llm:
      protocol: ANTHROPIC
      limits:
        maxRequestBytes: 8388608
        maxEstimatedInputTokens: 100000
        maxOutputTokens: 8192
        maxTools: 64
Secretless access

Credentials an agent never holds

Application-layer credentials are stored in the Cluster as Secrets and injected into the upstream connection once a request is authorized. This is the part of the problem that grows fastest with agentic systems, because the number of non-human identities holding credentials grows faster than the number of people.

Read the secretless access guide
llm-secretless.yaml
The model provider keyThe agent authenticates as itself, and never receives the provider API key.
The model provider key. The agent authenticates as itself, and never receives the provider API key.
kind: Service
metadata:
  name: openai
spec:
  mode: LLM
  isPublic: true
  config:
    upstream:
      url: https://api.openai.com
    llm:
      protocol: OPENAI
      auth:
        bearer:
          fromSecret: openai-api-key
The tools' own credential. An MCP server protected by a token is reached without the token leaving the Cluster.
kind: Service
metadata:
  name: tools-mcp
spec:
  mode: MCP
  isPublic: true
  config:
    upstream:
      url: https://mcp.example.com
    mcp:
      endpoint: /mcp
      auth:
        bearer:
          fromSecret: mcp-upstream-token
A different privilege per agent. Identity selects which upstream and which credential a request is proxied with.
kind: Service
metadata:
  name: tools-mcp
spec:
  mode: MCP
  config:
    upstream:
      url: http://general-mcp:8080
    mcp:
      endpoint: /mcp
  dynamicConfig:
    configs:
      - name: privileged
        upstream:
          url: http://admin-mcp:8080
        mcp:
          auth:
            bearer:
              fromSecret: admin-mcp-token
    rules:
      - condition:
          match: '"release" in ctx.user.spec.groups'
        configName: privileged
idp.yaml
Secretless agent identityAn agent in CI authenticates with an OIDC assertion issued by the platform running it.
Secretless agent identity. An agent in CI authenticates with an OIDC assertion issued by the platform running it.
kind: IdentityProvider
metadata:
  name: github-actions
spec:
  oidcIdentityToken:
    issuerURL: https://token.actions.githubusercontent.com
    audience: https://example.com
Binding the assertion. A workload User declares which external identity may authenticate as it.
kind: User
metadata:
  name: release-agent
spec:
  type: WORKLOAD
  groups:
    - agents
  authentication:
    identities:
      - identityProvider: github-actions
        identifier: repo:acme/api
An OAuth2 credential. Agents that cannot use assertions use the standard client credentials flow instead.
octeliumctl create cred \
  --type oauth2 \
  --user release-agent \
  agent-cred

# The agent then authenticates at
# https://<DOMAIN>/oauth2/token
# and sends the issued bearer access token.
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: anthropic-api-key Updated
Secret: mcp-upstream-token Updated
IdentityProvider: github-actions Created
Policy: agent-tools Created
Group: agents Created
User: release-agent Created
Service: tools-mcp.ai Created
Service: anthropic.ai Created
Service: pg-staging.db Updated
Namespace: ai Created
Cluster Core resources successfully applied
 7 resources created
 3 resources updated

 ClusterConfig updated
Requirements

What an autonomous agent needs, and what issues it

An agent that can act on real systems needs the same things a new employee needs, on a shorter timescale and in larger numbers. These are the requirements, next to the mechanism in an Octelium Cluster that provides each one.

  1. 01

    An identity of its own

    An agent is a workload User, not a shared service account and not a copy of a person's session. It has its own groups, its own Policies, its own Session and its own entries in the audit trail, which is what makes revoking one agent a contained action.

    Read more
  2. 02

    A way to prove that identity without a stored secret

    Agents authenticate with federated OpenID Connect assertions issued by the platform running them, such as GitHub Actions, a cloud provider or a Kubernetes cluster, so no long-lived token has to sit in the environment they run in. Authentication tokens and OAuth2 client credentials remain available where assertions are not.

    Read more
  3. 03

    Access to resources it never holds credentials for

    Upstream credentials stay in the Cluster and are injected after a request is authorized, which covers HTTP API keys, SSH passwords and private keys, database passwords, kubeconfigs and mTLS certificates. A prompt injection cannot exfiltrate a credential the agent never had.

    Read more
  4. 04

    Authorization on the tool call, not on the connection

    The MCP mode parses JSON-RPC messages, so the method, the tool name and the tool arguments are each available to a Policy. Discovery can be open while individual tools are restricted, and an argument can be bounded rather than a tool allowed outright.

    Read more
  5. 05

    Authorization on the inference request

    The LLM mode normalizes the operation, requested model, streaming flag, declared tools, input modalities and declared output-token maximum, so which model an agent may use and under what conditions is a policy decision rather than which key it was given.

    Read more
  6. 06

    Bounds that hold regardless of the prompt

    Request body size, streamed event size, estimated input tokens, declared output tokens and declared tool count are enforced by the gateway before a request leaves the Cluster, independently of what the agent was asked to do.

    Read more
  7. 07

    Somewhere isolated to run

    Cordium, built on Octelium, provides reproducible sandboxes for agents and developers on the same Kubernetes infrastructure. Processes inside a Workspace reach authorized Services through the Workspace identity, with no secrets placed inside the sandbox.

    Read more
  8. 08

    A record of what it actually did

    Every request produces an identity-aware AccessLog naming the User and Session alongside the tool called, the arguments, the model used and the tokens consumed, streamed in real time over OpenTelemetry to your own log management and SIEM providers.

    Read more

Most of this is not specific to AI. It is ordinary identity and access management, applied to identities that are created faster, act more often and are harder to interview afterwards.

Questions

Frequently asked

How does an AI agent authenticate?
As a workload User, using the same identity model as a human User. It can present an authentication token, use the standard OAuth2 client credentials flow against the Cluster's token endpoint, use an access token directly as a bearer token, or authenticate secretlessly with a federated OpenID Connect assertion issued by the platform running it, such as GitHub Actions, a cloud provider or a Kubernetes cluster. No proprietary SDK is required.
Can individual tool calls be authorized?
Yes. The MCP mode understands JSON-RPC messages, so the method and the tool, prompt or resource name are separate normalized fields, and the parsed request body is available for arguments that have no normalized field. That lets tools/list stay open for discovery while tools/call is restricted per tool, per group and per argument value.
What stops an agent from leaking a credential?
It never receives one. Upstream credentials are stored in the Cluster as Secrets and injected into the upstream connection after a request has been authorized, and downstream Authorization, X-Api-Key and Api-Key credentials are stripped before proxying. The agent authenticates as itself and reaches the resource through the proxy, so there is no provider API key, database password or SSH key inside its environment to exfiltrate.
Can different agents have different privileges on the same resource?
Yes. Dynamic configuration selects the upstream, the upstream account and the credential per request from identity and request context, so a release agent and a research agent can share one Service URL while reaching different backends with different rights. Policies attach to a Service, a Namespace, a User, a Group or a Credential.
Where do agents actually run?
Wherever you run them. If you want the execution environment as well, Cordium is a free and open source sandbox platform built on Octelium and on the same Kubernetes infrastructure. Workspaces are built from OCI images, Dockerfiles, git repositories or devcontainers, run rootless, and reach authorized Services through the Workspace identity with no secrets inside the sandbox.
Are prompts and tool arguments recorded?
It depends on the mode and is configurable per Service. MCP request and response bodies are captured by default, because inspecting JSON-RPC messages is usually the point of the audit, and can be disabled. LLM request and response bodies are not captured by default, because prompts and outputs commonly contain sensitive data, and can be enabled where the audit backend and its retention policy are appropriate for them.
Get started

Deploy Octelium on your own infrastructure in minutes

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