Inja LLM Gateway
Get started

WIF & workload identity

Short-lived upstream tokens via token_file sidecars, OpenAI WIF, GCP, AWS/Azure brokers, and GitHub Actions OIDC.

Run the gateway without long-lived sk-… keys in the process environment by feeding short-lived access tokens from outside the hot path.

What it is

The gateway is stateless and does not implement cloud STS / IMDS. Something else (sidecar, init container, CI step, Vault agent) obtains a token; the gateway only consumes it.

Mechanism Config
OAuth2 client / refresh auth: oauth2 — see OAuth & upstream auth
Google SA JSON JWT auth: service_account + service_account_file
Plain access token file auth: adc + token_file
In-process inject proxy.Server.SetTokenSource

Pattern A — token_file (universal)

A sidecar refreshes a file the gateway can read:

providers:
  openai:
    kind: openai
    base_url: "https://api.openai.com/v1"
    auth: adc
    token_file: /var/run/secrets/openai-access-token

File format

  • Raw access token only (no Bearer prefix)
  • Whitespace trimmed
  • Cached ~2 minutes, then re-read (rotation-friendly)
  • Mount read-only, mode 0600
  • Never log file contents

Works for OpenAI WIF, cloud OIDC exchanges, Vault agents — anything that can write a token file.

Kubernetes sketch

volumeMounts:
  - name: provider-token
    mountPath: /var/run/secrets
    readOnly: true
# sidecar writes openai-access-token into the shared volume

Pattern B — OpenAI workload identity federation

  1. Configure OpenAI project workload identity (OIDC → OpenAI access token).
  2. Exchange the cloud OIDC JWT for an OpenAI access token (sidecar or CI).
  3. Write the access token to token_file, or use auth: oauth2 against your broker’s token URL.
auth: oauth2
oauth:
  token_url: "https://your-broker.example/token"
  client_id_env: BROKER_CLIENT_ID
  client_secret_env: BROKER_CLIENT_SECRET

GitHub Actions sketch

permissions:
  id-token: write
  contents: read
steps:
  - name: Exchange OIDC → provider access token
    run: |
      # use your broker / OpenAI WIF exchange here
      echo "$OPENAI_ACCESS_TOKEN" > /tmp/oai.token
      chmod 600 /tmp/oai.token
  - name: Run gateway with token_file
    run: ./llm-gateway -config gateway.yaml

Do not commit tokens or upload them as artifacts.


Pattern C — Google Cloud (Vertex)

Service account JSON (simple)

providers:
  vertex:
    kind: google
    base_url: "https://us-central1-aiplatform.googleapis.com/v1/projects/PROJECT/locations/us-central1/publishers/google"
    auth: service_account
    service_account_file: /secrets/vertex-sa.json

Build the base URL with config.VertexBaseURL(project, location) in Go, or copy from Vertex AI dual-path.

GKE Workload Identity (no JSON key)

  1. Bind Kubernetes SA → Google SA (roles/aiplatform.user or tighter).
  2. Sidecar / metadata helper writes access token to token_file.
  3. Config:
auth: adc
token_file: /var/run/secrets/gcp-access-token

GOOGLE_APPLICATION_CREDENTIALS pointing at SA JSON also auto-wires for auth: adc.


Pattern D — AWS / Azure → provider token

The gateway does not call STS/IMDS.

  1. Use IRSA / Managed Identity to get a cloud credential.
  2. Exchange via your broker for the LLM provider access token.
  3. Feed the gateway via token_file or auth: oauth2.

Keep exchange out of the per-request path (sidecar refresh loop).


Pattern E — GitHub Actions OIDC

GHA OIDC JWT → broker / vendor token URL → access token → token_file or env
  • Restrict aud / sub on the trust policy.
  • Short TTL; never upload tokens as workflow artifacts.

Multi-tenant vs operator-held

Mode Use when
oauth2 / SA / token_file Operator holds the credential; clients use edge auth only
client_bearer Each client presents their own upstream OAuth token
api_key_env Classic static keys

Threat model

  • Process with SA keys or refresh tokens is high privilege.
  • Mis-mounted token_file can be world-readable — use secret volumes.
  • Prefer short-lived access tokens and rotate aggressively.

Type to search…

↑↓ navigate↵ selectEsc close