Aegis Orchestrator
Deployment

IAM & Identity Federation

Keycloak realms, AegisRole claims, M2M service accounts, SAML federation, JWKS cache, and GrpcIamAuthInterceptor.

IAM & Identity Federation

AEGIS uses Keycloak as its OIDC identity provider. Keycloak issues JWTs for all human operators and machine-to-machine (M2M) clients. The orchestrator validates these JWTs on every API request via the GrpcIamAuthInterceptor.


Realm Structure

AEGIS uses multiple Keycloak realms:

RealmPurposeAudience
aegis-systemOperator and admin identities, API accessDevOps / SRE / SDK clients
tenant-{slug}Per-enterprise consumer tenant (optional)Enterprise end-users

For most self-hosted deployments, only the aegis-system realm is required.


AegisRole Claims

The aegis-system realm issues JWTs containing an aegis_role claim that determines operator authorization level:

RolePermissions
aegis:adminFull read/write on all objects; daemon configuration; user management
aegis:operatorDeploy/manage agents and workflows; start/cancel executions; manage volumes
aegis:readonlyRead any object; list executions; stream events; no write access

Configure roles in Keycloak using the aegis-system realm's client roles and a protocol mapper to include them as a flat array in the JWT claim aegis_role.


Setting Up the aegis-system Realm

1. Create the Realm

In the Keycloak Admin console, create a new realm named aegis-system.

2. Create the AEGIS Client

Create an OpenID Connect client:

  • Client ID: aegis-orchestrator
  • Client authentication: ON (confidential)
  • Valid redirect URIs: http://localhost:* (dev), your production Zaru client URL
  • Standard flow: ON (for human operators via browser)
  • Service accounts: ON (for M2M clients)

3. Create Client Roles

In the aegis-orchestrator client, create three roles:

  • aegis:admin
  • aegis:operator
  • aegis:readonly

4. Add Protocol Mapper

Add a roles protocol mapper to include client roles in the JWT:

  • Mapper type: User Client Role
  • Client ID: aegis-orchestrator
  • Token claim name: aegis_role
  • Claim JSON type: String
  • Add to: ID token ✓, access token ✓

5. Configure AEGIS

spec:
  iam:
    realms:
      - slug: "aegis-system"
        issuer_url: "https://keycloak.example.com/realms/aegis-system"
        jwks_uri: "https://keycloak.example.com/realms/aegis-system/protocol/openid-connect/certs"
        audience: "aegis-orchestrator"
        kind: system
    jwks_cache_ttl_seconds: 300
    claims:
      zaru_tier: "zaru_tier"
      aegis_role: "aegis_role"

M2M Service Accounts (SDK / CI-CD)

For SDK clients and CI/CD pipelines that need programmatic API access:

Create a Service Account Client

In Keycloak, create a new client:

  • Client ID: my-sdk-client
  • Client authentication: ON
  • Service accounts: ON
  • Standard flow: OFF

Assign the aegis:operator role to the service account.

Obtain a Token

# Client Credentials grant
curl -X POST https://keycloak.example.com/realms/aegis-system/protocol/openid-connect/token \
  -d grant_type=client_credentials \
  -d client_id=my-sdk-client \
  -d client_secret=$CLIENT_SECRET

Use the returned access_token as a Bearer token on AEGIS API requests:

curl -H "Authorization: Bearer $ACCESS_TOKEN" \
  http://localhost:8088/v1/agents

SAML Federation for Enterprise Tenants

For enterprise deployments with an existing IdP (Azure AD, Okta):

  1. Create a tenant-{slug} realm in Keycloak.
  2. Configure a SAML Identity Provider in that realm pointing to the enterprise IdP.
  3. Map enterprise groups to Keycloak roles via identity provider mappers.
  4. Add the tenant-{slug} realm to AEGIS configuration.

AEGIS then validates tokens from both aegis-system (operators) and tenant-{slug} (tenant users) JWTs automatically.


JWKS Cache

The GrpcIamAuthInterceptor maintains a per-realm JWKS cache (fetched from https://{keycloak}/realms/{realm}/protocol/openid-connect/certs).

Default cache TTL is 300 seconds (configurable via spec.iam.jwks_cache_ttl_seconds). When Keycloak rotates signing keys, the cache is refreshed automatically on the next TTL expiry. Key rotation completes without any AEGIS downtime.

If you rotate keys manually and need the cache cleared immediately, restart the daemon:

aegis daemon stop
aegis daemon start --config aegis-config.yaml

Operator Identity → SecurityContext Mapping

When an operator authenticates via the aegis-system realm, the orchestrator resolves their identity and SecurityContext through the following chain:

aegis-system realm JWT
  → aegis_role claim extracted
  → IdentityKind::Operator resolved
  → aegis-system-operator SecurityContext assigned

The aegis_role claim determines the operator's read/write scope within that SecurityContext:

RoleIdentity KindSecurityContextMutations
aegis:adminIdentityKind::Operatoraegis-system-operatorFull — all safe, destructive, and orchestrator commands
aegis:operatorIdentityKind::Operatoraegis-system-operatorLimited — safe commands and restricted destructive commands
aegis:readonlyIdentityKind::Operatoraegis-system-operatorNone — read-only access, no mutations

All three roles map to the same aegis-system-operator SecurityContext (which defines the tool capabilities ceiling). The role-based differentiation happens at the API handler level: aegis:readonly operators can invoke read tools (aegis.system.info) but not write tools (aegis.agent.delete, aegis.system.config).

This is distinct from consumer identity resolution. Consumer users authenticate via the shared zaru-consumer Keycloak realm, but each user has their own per-user tenant (slug format u-{uuid}) provisioned at signup. The orchestrator extracts the user's tenant_id from a custom JWT claim (injected by a tenant_id protocol mapper on the zaru-consumer realm) and their zaru_tier claim to resolve IdentityKind::ZaruUser with a tier-specific SecurityContext (zaru-free, zaru-pro, etc.).


Authentication Flow (HTTP API)

Client sends request:
  GET /v1/agents
  Authorization: Bearer <keycloak-issued-jwt>


GrpcIamAuthInterceptor
  1. Extract Bearer token from Authorization header
  2. Fetch JWKS from cache (or refresh if stale)
  3. Verify JWT signature
  4. Check exp claim (not expired)
  5. Resolve aegis_role claim → AegisRole


axum middleware
  6. Attach UserIdentity to request context
  7. Forward to handler


Handler
  8. Check AegisRole against required permission for this endpoint
  9. Process request

Requests without a valid Bearer token receive 401 Unauthorized. Requests with a valid token but insufficient role receive 403 Forbidden.


OpenBao OIDC Integration

OpenBao can be configured to use Keycloak as its human operator authentication backend. This allows vault administrators to log in with their Keycloak credentials rather than maintaining separate OpenBao tokens. See the Secrets Management page for configuration details.

On this page