auth/

directory
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 17, 2026 License: Apache-2.0

README

Issuer Configuration Guide

Configure external identity providers (IdPs) for JWT authentication in carbide-rest-api.

Configuration Structure

issuers:
  - name: "my-idp"                              # Unique identifier (required)
    issuer: "https://auth.example.com"          # Expected JWT "iss" claim (required)
    jwks: "https://auth.example.com/.well-known/jwks.json"  # JWKS URL (required)
    jwksTimeout: "5s"                           # Fetch timeout (default: 5s)
    audiences: ["my-api"]                       # Token must have ≥1 (optional)
    scopes: ["openid", "carbide"]               # Token must have ALL (optional)
    claimMappings:                              # Required - see types below
      - orgName: "my-orgA"
        orgDisplayName: "My Organization A"
        roles: ["FORGE_PROVIDER_ADMIN"]
      - orgName: "my-orgB"
        orgDisplayName: "My Organization B"
        roles: ["FORGE_TENANT_ADMIN"]
Key Concepts
  • Only two roles allowed: FORGE_TENANT_ADMIN, FORGE_PROVIDER_ADMIN
  • Audiences: token needs at least one match → 401 on failure
  • Scopes: token needs all configured → 403 on failure (checks scope, scopes, scp claims)

Claim Mapping Types

Type Configuration Limit Use Case
A: Static-Static orgName + roles Unlimited* Fixed org & roles
B: Static-Dynamic orgName + rolesAttribute Unlimited* Fixed org, roles from token
C: Service Account orgName + isServiceAccount: true 1 global** M2M with admin roles
D: Dynamic-Dynamic orgAttribute + orgDisplayAttribute + rolesAttribute 1 global Multi-tenant IdP

*Each orgName must be globally unique across all issuers **1 per issuer URL in connected mode; 1 total in disconnected mode


Type A: Static Org + Static Roles
claimMappings:
  - orgName: "acme-corp"
    orgDisplayName: "ACME Corp"
    roles: ["FORGE_TENANT_ADMIN"]
Type B: Static Org + Dynamic Roles
claimMappings:
  - orgName: "acme-corp"
    orgDisplayName: "ACME Corp"
    rolesAttribute: "roles"
  • Nested paths supported: Use dot notation (e.g., realm_access.roles, data.auth.roles)
  • Role formats: Array ["ROLE"] or space-separated string "ROLE1 ROLE2"
Type C: Service Account
claimMappings:
  - orgName: "automation"
    orgDisplayName: "Automation"
    isServiceAccount: true               # Gets both admin roles automatically
Type D: Dynamic Org + Dynamic Roles
claimMappings:
  - orgAttribute: "org"                  # Claim path for org name
    orgDisplayAttribute: "org_display"   # Claim path for display name
    rolesAttribute: "roles"              # Claim path for roles
  • Nested paths supported: All three attributes support dot notation (e.g., data.org, data.org_display, data.roles)
  • Dynamic orgs cannot claim statically-defined org names (reserved)

Complete Examples

Corporate SSO (Type A)
issuers:
  - name: corporate-sso
    issuer: "https://login.corp.com"
    jwks: "https://login.corp.com/.well-known/jwks.json"
    audiences: ["carbide-api"]
    claimMappings:
      - orgName: "corporate"
        orgDisplayName: "Corporate"
        roles: ["FORGE_TENANT_ADMIN"]
Multi-Tenant IdP (Type D)
issuers:
  - name: saas-provider
    issuer: "https://auth.saas.com"
    jwks: "https://auth.saas.com/.well-known/jwks.json"
    audiences: ["api"]
    scopes: ["carbide"]
    claimMappings:
      - orgAttribute: "tenant_id"
        orgDisplayAttribute: "tenant_name"
        rolesAttribute: "carbide_roles"
Multiple Orgs per Issuer
claimMappings:
  - orgName: "shared"
    orgDisplayName: "Shared Resources"
    roles: ["FORGE_TENANT_ADMIN"]
  - orgName: "main"
    orgDisplayName: "Main Org"
    rolesAttribute: "main_roles"

Validation Rules

Rule Constraint
Issuer name Must be unique across all configs
Issuer URL Can only appear once (no merging)
orgName Must be globally unique across all issuers
Type C (Service Account) 1 total (disconnected) or 1 per issuer (connected)
Type D (Dynamic Org) Only 1 allowed across all issuers
Static orgDisplayName Required for Types A, B, C

Supported Algorithms

RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, EdDSA


Troubleshooting

Error Solution
Token audience mismatch Check aud claim; update audiences or remove to skip
Token scopes mismatch Check scope/scopes/scp claim; ensure all required scopes present
Invalid token Verify jwks URL accessible; issuer matches iss claim exactly
Invalid claim mapping Add roles, rolesAttribute, or isServiceAccount

Keycloak Integration

To use Keycloak as an identity provider, update the Carbide REST API ConfigMap.

Prerequisites
  • Fully Qualified Domain Name (FQDN) for your Keycloak instance
    • Example: https://auth.forge.acme.com
    • This URL must be accessible by both the API server and end users
Ingress Security Requirements

Once Keycloak configuration is finalized, the ingress controller for the Keycloak domain must be restricted to only allow:

Allowed Pattern Purpose
/realms/{realm}/protocol/openid-connect/certs Public JWKS endpoint for token validation
/realms/{realm}/protocol/openid-connect/auth IDP authentication callbacks
/realms/{realm}/broker/*/endpoint Identity provider broker callbacks

Warning: All other paths (especially /admin/* and /realms/{realm}/protocol/openid-connect/token) should be blocked from external access.

Required Configuration Values
Configuration Description Example
keycloak.enabled Enable Keycloak integration true
keycloak.baseURL Internal Keycloak URL (cluster-internal) http://keycloak.keycloak.svc.cluster.local:8082
keycloak.externalBaseURL External Keycloak URL (must match token issuer) https://auth.forge.acme.com
keycloak.realm Keycloak realm name carbide
keycloak.clientID OAuth client ID carbide-cloud
keycloak.clientSecretPath Path to mounted client secret /var/secrets/keycloak/client-secret
keycloak.serviceAccount Enable service account features true
Step 1: Create the Client Secret in Kubernetes
kubectl create secret generic keycloak-client-secret \
  --namespace carbide-rest \
  --from-literal=client-secret="${OAUTH_CLIENT_SECRET}" \
  --dry-run=client -o yaml | kubectl apply -f -
Step 2: Update Carbide REST API ConfigMap

Edit the carbide-rest-api-config ConfigMap in carbide-rest namespace:

kubectl edit configmap carbide-rest-api-config -n carbide-rest

If you applied the kustomize manifests, there should already be a section for KeyCloak auth.

Edit the Keycloak configuration (or add if not present) section to match the following:

# Keycloak integration configuration
keycloak:
  enabled: true
  baseURL: http://keycloak.keycloak.svc.cluster.local:8082
  externalBaseURL: https://auth.forge.acme.com
  realm: carbide
  clientID: carbide-cloud
  clientSecretPath: /var/secrets/keycloak/client-secret
  serviceAccount: true

Key Configuration Notes:

Field Important Consideration
baseURL Use cluster-internal URL for API-to-Keycloak communication (avoids external network hops)
externalBaseURL Must match the iss claim in JWT tokens exactly
Step 3: Mount the Client Secret Volume

Ensure the Carbide REST API Deployment mounts the Keycloak client secret.

If you applied the kustomize manifests without any changes, this step should not be needed. Verify and edit as needed.

spec:
  template:
    spec:
      containers:
        - name: api
          volumeMounts:
            - name: keycloak-client-secret
              mountPath: /var/secrets/keycloak/
              readOnly: true
      volumes:
        - name: keycloak-client-secret
          secret:
            secretName: keycloak-client-secret
Step 4: Apply Configuration and Restart
# Restart the Carbide REST API deployment to pick up changes
kubectl rollout restart deployment/carbide-rest-api -n carbide-rest

# Verify the pods are running
kubectl get pods -n carbide-rest -l app.kubernetes.io/name=carbide-rest-api

# Check logs for Keycloak configuration
kubectl logs -n carbide-rest -l app.kubernetes.io/name=carbide-rest-api --tail=50 | grep -i keycloak

Expected log messages:

Creating new Keycloak configuration
Keycloak configuration created successfully

Directories

Path Synopsis
pkg
api
testing
Package testing provides shared constants and utilities for cloud-auth tests
Package testing provides shared constants and utilities for cloud-auth tests

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL