Skip to content

Authenticate tools

Give a tool backend the credential it needs by setting the handler-level auth stanza on a ToolRegistry handler. The dashboard does not expose this stanza, so you set it in the manifest.

auth sits beside httpConfig, openAPIConfig, grpcConfig and mcpConfig, so the same shape works on every handler type. The runtime sends the credential as an HTTP Authorization header, gRPC authorization metadata or an MCP transport header.

  • A ToolRegistry with at least one http, openapi, grpc or mcp handler. A platform handler cannot set auth.
  • For bearer or basic, a Secret holding the credential in the same namespace as the AgentRuntime.
  • An AgentRuntime that references the ToolRegistry through toolRegistryRef.
auth.typeCredentialSent as
none (default)noneno credential
bearersecretRef valueAuthorization: Bearer <token>
basicsecretRef value user:passwordAuthorization: Basic <base64>
serviceAccountprojected, audience-bound ServiceAccount tokenAuthorization: Bearer <token>
workloadIdentitythe pod’s ambient Azure identity, with no stored secretAuthorization: Bearer <token>, or the custom header

See the ToolRegistry reference for every auth field.

Create the credential Secret and reference it from the handler:

apiVersion: v1
kind: Secret
metadata:
name: weather-credentials
namespace: agents # same namespace as the AgentRuntime
type: Opaque
stringData:
token: "sk-live-abc123" # illustrative value; for basic auth, use "username:password"
---
apiVersion: omnia.altairalabs.ai/v1alpha1
kind: ToolRegistry
metadata:
name: weather-tools
namespace: agents
spec:
handlers:
- name: weather
type: http
httpConfig:
endpoint: https://api.weather.example/v1/forecast
method: GET
auth:
type: bearer
secretRef:
name: weather-credentials
key: token
tool:
name: get_weather
description: "Get the weather forecast for a city"
inputSchema:
type: object
properties:
city: { type: string }
required: [city]

Apply both and let the AgentRuntime reconcile.

The operator copies each handler’s secretRef value into a Secret named <agentruntime-name>-tool-secrets, with one key per authenticated handler (the key is the handler name). It mounts that Secret read-only into the runtime at /etc/omnia/tool-secrets. The tools ConfigMap holds only the path, for example authTokenPath: /etc/omnia/tool-secrets/weather, never the value.

If the Secret or key is missing, the AgentRuntime reconcile fails and the runtime does not start with a broken config. To send a second secret header, use headersFromSecret.

Terminal window
# The operator-managed companion Secret exists, keyed by handler name:
kubectl describe secret <agentruntime>-tool-secrets -n agents
# The tools ConfigMap references the token by path, not value:
kubectl get configmap <agentruntime>-tools -n agents -o yaml | grep authTokenPath
# The runtime Deployment mounts the companion Secret:
kubectl get deployment <agentruntime> -n agents \
-o jsonpath='{.spec.template.spec.volumes[*].secret.secretName}'

For an in-cluster backend that can validate a Kubernetes token, send an audience-bound projected ServiceAccount token. The operator projects the token into the runtime and the backend validates it through the TokenReview API. No long-lived secret is stored.

- name: internal-api
type: http
httpConfig:
endpoint: http://internal.svc.cluster.local/api
auth:
type: serviceAccount
serviceAccount:
audience: internal-api # required; the backend checks the token against this audience
tool:
name: internal_action
description: "Call the internal API"
inputSchema:
type: object

The backend must validate the incoming Authorization: Bearer <token> with the Kubernetes TokenReview API and check that the token’s audience matches serviceAccount.audience. Its own ServiceAccount needs permission to create tokenreviews in the authentication.k8s.io API group. TokenReview is cluster-scoped, so grant it with a ClusterRole:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: internal-api-tokenreview
rules:
- apiGroups: [authentication.k8s.io]
resources: [tokenreviews]
verbs: [create]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: internal-api-tokenreview
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: internal-api-tokenreview
subjects:
- kind: ServiceAccount
name: internal-api # the backend's own ServiceAccount
namespace: agents

The operator projects the token with a one-hour lifetime at /var/run/secrets/omnia/tool-sa/<handler>/token. The kubelet rotates it before it expires and the runtime re-reads the file on every tool call.

auth.type: workloadIdentity authenticates a tool call as the agent pod’s ambient Azure identity, so Omnia stores no credential. cloud accepts azure only. The type works on http, grpc, openapi and mcp handlers.

- name: graph-api
type: http
httpConfig:
endpoint: https://graph.microsoft.com/v1.0/me
method: GET
auth:
type: workloadIdentity
workloadIdentity:
cloud: azure
audience: "https://graph.microsoft.com" # required; the runtime requests <audience>/.default
# header: Authorization # optional; default Authorization
tool:
name: whoami
description: "Read the caller's Graph profile"
inputSchema:
type: object

The runtime gets a token for audience through DefaultAzureCredential, resolving it on every call from a cache that refreshes five minutes before expiry, and sets it on header as Bearer <token>. If it cannot get a token, that tool call fails instead of reaching the backend unauthenticated.

The identity is the same one keyless Azure provider auth uses. Set it up once per agent identity:

  1. Label the agent pod azure.workload.identity/use: "true" and run it as a ServiceAccount annotated with azure.workload.identity/client-id: <client-id>. Set both for every agent in a workspace with spec.runtime.podLabels and spec.runtime.serviceAccountName on the Workspace. An AgentRuntime that sets spec.podOverrides.serviceAccountName opts out of both.
  2. Create a federated identity credential on the Entra ID app or user-assigned managed identity. Trust the cluster’s OIDC issuer and the subject system:serviceaccount:<namespace>:<serviceAccount>.
  3. Grant the identity access to the API of every workloadIdentity tool. The pod has one identity, shared with the model provider.

httpConfig.authType and httpConfig.authSecretRef, and their openAPIConfig equivalents, are deprecated. They still work and are normalized into auth, but a handler that sets both auth and a legacy field is rejected. Move to auth:

# before (deprecated)
httpConfig:
endpoint: https://api.example/v1
authType: bearer
authSecretRef:
name: creds
key: token
# after
httpConfig:
endpoint: https://api.example/v1
auth:
type: bearer
secretRef:
name: creds
key: token