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.
Prerequisites
Section titled “Prerequisites”- A ToolRegistry with at least one
http,openapi,grpcormcphandler. Aplatformhandler cannot setauth. - For
bearerorbasic, a Secret holding the credential in the same namespace as the AgentRuntime. - An AgentRuntime that references the ToolRegistry through
toolRegistryRef.
Auth types
Section titled “Auth types”auth.type | Credential | Sent as |
|---|---|---|
none (default) | none | no credential |
bearer | secretRef value | Authorization: Bearer <token> |
basic | secretRef value user:password | Authorization: Basic <base64> |
serviceAccount | projected, audience-bound ServiceAccount token | Authorization: Bearer <token> |
workloadIdentity | the pod’s ambient Azure identity, with no stored secret | Authorization: Bearer <token>, or the custom header |
See the ToolRegistry reference for every auth field.
Bearer / basic token
Section titled “Bearer / basic token”Create the credential Secret and reference it from the handler:
apiVersion: v1kind: Secretmetadata: name: weather-credentials namespace: agents # same namespace as the AgentRuntimetype: OpaquestringData: token: "sk-live-abc123" # illustrative value; for basic auth, use "username:password"---apiVersion: omnia.altairalabs.ai/v1alpha1kind: ToolRegistrymetadata: name: weather-tools namespace: agentsspec: 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.
Verify
Section titled “Verify”# 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}'ServiceAccount token (serviceAccount)
Section titled “ServiceAccount token (serviceAccount)”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: objectBackend validation
Section titled “Backend validation”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/v1kind: ClusterRolemetadata: name: internal-api-tokenreviewrules: - apiGroups: [authentication.k8s.io] resources: [tokenreviews] verbs: [create]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: internal-api-tokenreviewroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: internal-api-tokenreviewsubjects: - kind: ServiceAccount name: internal-api # the backend's own ServiceAccount namespace: agentsThe 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.
workloadIdentity (Azure)
Section titled “workloadIdentity (Azure)”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: objectThe 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.
Cluster setup
Section titled “Cluster setup”The identity is the same one keyless Azure provider auth uses. Set it up once per agent identity:
- Label the agent pod
azure.workload.identity/use: "true"and run it as a ServiceAccount annotated withazure.workload.identity/client-id: <client-id>. Set both for every agent in a workspace withspec.runtime.podLabelsandspec.runtime.serviceAccountNameon the Workspace. An AgentRuntime that setsspec.podOverrides.serviceAccountNameopts out of both. - 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>. - Grant the identity access to the API of every
workloadIdentitytool. The pod has one identity, shared with the model provider.
Migrating off the deprecated fields
Section titled “Migrating off the deprecated fields”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
# afterhttpConfig: endpoint: https://api.example/v1auth: type: bearer secretRef: name: creds key: tokenRelated pages
Section titled “Related pages”- ToolRegistry CRD reference
- Advanced HTTP tools
- Build a tool backend — the request and response contract your backend implements
- Configure tool policies — allow, deny and header injection on top of authenticated tools
- Delegation tokens — tell a tool which user and agent a call was made for