Authenticate tools
Tool backends usually require a credential. Omnia configures this with the
handler-level auth stanza on a ToolRegistry handler. This stanza is not
exposed in the dashboard UI — it is CRD-only.
auth is a sibling of httpConfig/openAPIConfig/grpcConfig/mcpConfig, so
the same shape applies across handler types. The runtime attaches the resolved
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,grpc, ormcphandler - For
bearer/basic: a Kubernetes Secret in the same namespace as the AgentRuntime holding the credential - An AgentRuntime that references the ToolRegistry via
toolRegistryRef
Auth types
Section titled “Auth types”auth.type |
Credential | Sent as |
|---|---|---|
none (default) |
— | no credential |
bearer |
secretRef value |
Authorization: Bearer <token> |
basic |
secretRef value user:password |
Authorization: Basic <base64> |
serviceAccount |
projected, audience-bound SA token | Authorization: Bearer <token> |
workloadIdentity |
pod’s ambient Azure identity (no stored secret) | Authorization: Bearer <token> (or custom header) |
Bearer / basic token
Section titled “Bearer / basic token”Create the credential Secret, then reference it from the handler:
apiVersion: v1kind: Secretmetadata: name: weather-credentials namespace: agents # same namespace as the AgentRuntimetype: OpaquestringData: token: "sk-live-abc123" # 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]How the credential is handled
Section titled “How the credential is handled”When an AgentRuntime references this registry, the operator resolves each
handler’s secretRef into a single operator-managed Secret named
<agentruntime-name>-tool-secrets, with one key per authenticated handler
(the key is the handler name). That Secret is mounted read-only into the runtime
container at /etc/omnia/tool-secrets.
The token value never enters the tools ConfigMap — the ConfigMap references it only by path. For the example above, the rendered tool config contains:
authType: bearerauthTokenPath: /etc/omnia/tool-secrets/weatherendpoint: https://api.weather.example/v1/forecastThis keeps the secret out of the (non-secret) ConfigMap while still making it available to the runtime at call time.
A missing Secret or key fails the AgentRuntime reconcile — the runtime is not started with a broken auth config, and it never silently sends an unauthenticated request.
To source a second secret header (beyond Authorization) from a Secret, see
headersFromSecret
— it uses this same companion-Secret mechanism.
Verify
Section titled “Verify”# The operator-managed companion Secret exists, keyed by handler name:kubectl get secret <agentruntime>-tool-secrets -n agents -o jsonpath='{.data}'
# 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 in-cluster backends that can validate a Kubernetes token, use an audience-bound projected ServiceAccount token. The operator projects the token into the runtime; the backend validates it via 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 # the backend validates the token against this audience tool: name: internal_action description: "Call the internal API" inputSchema: type: objectThe token is sent as Authorization: Bearer <token>. serviceAccount.audience
is required.
Backend validation
Section titled “Backend validation”The backend must validate the incoming Authorization: Bearer <token> via
the Kubernetes TokenReview API and check that the token’s audience
matches the configured serviceAccount.audience. That means the backend’s
own ServiceAccount needs RBAC to create tokenreviews in the
authentication.k8s.io API group — TokenReview is a cluster-scoped
subresource, so this is 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: agentsworkloadIdentity (Azure)
Section titled “workloadIdentity (Azure)”auth.type: workloadIdentity authenticates a tool call as the agent pod’s
ambient Azure identity — no credential is stored by Omnia. Only cloud: azure
is supported today, on http, grpc, openapi, and MCP sse/streamable-http
handlers (not stdio).
- 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/.default" # token scope/audience # header: Authorization # optional; default Authorization tool: name: whoami description: "Read the caller's Graph profile" inputSchema: type: objectThe runtime acquires a token for audience (via DefaultAzureCredential) and
sets it on header (default Authorization: Bearer <token>). Tokens are acquired
per call, so they survive expiry. If a token can’t be acquired, that tool call
fails rather than calling the backend unauthenticated.
Cluster setup (once per agent identity — same ambient identity keyless Azure
provider auth uses): label the pod azure.workload.identity/use: "true", annotate
its ServiceAccount with azure.workload.identity/client-id: <client-id>, and
create a federated identity credential trusting the cluster OIDC issuer + subject
system:serviceaccount:<namespace>:<serviceAccount>. Because one pod identity is
shared across the model provider and all WIF tools, grant it the union of every
WIF tool’s API. See the reference’s
Authenticating tools for the
full setup note.
Transport constraints
Section titled “Transport constraints”- Auth works on
http,openapi,grpc, and MCPsse/streamable-httptransports. - Auth on an MCP
stdiotransport is rejected — a subprocess has no header channel.
Migrating off the deprecated fields
Section titled “Migrating off the deprecated fields”The per-config httpConfig.authType / httpConfig.authSecretRef (and the
openAPIConfig equivalents) are deprecated. They still work and are normalized
into the auth stanza, but setting both an auth stanza and a legacy
authType/authSecretRef on the same handler is rejected. Prefer the auth
stanza for new registries.
# 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: tokenSee also
Section titled “See also”- ToolRegistry CRD reference
- Advanced HTTP tools
- Build a tool backend — the request/response contract your backend must implement
- Configure tool policies — CEL allow/deny and header injection on top of authenticated tools