https://github.com/palenaai/litellm-operator
Kubernetes operator for deploying and managing LiteLLM AI Gateway. Declarative CRDs for models, teams, users, and virtual keys with bidirectional config sync, SSO/SCIM user provisioning, and OLM support. Built with Operator SDK.
https://github.com/palenaai/litellm-operator
ai-gateway cloud-native gitops kubernetes kubernetes-operator litellm llm openai openshift operator
Last synced: 10 days ago
JSON representation
Kubernetes operator for deploying and managing LiteLLM AI Gateway. Declarative CRDs for models, teams, users, and virtual keys with bidirectional config sync, SSO/SCIM user provisioning, and OLM support. Built with Operator SDK.
- Host: GitHub
- URL: https://github.com/palenaai/litellm-operator
- Owner: PalenaAI
- License: apache-2.0
- Created: 2026-04-01T19:17:22.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-07-04T19:40:19.000Z (16 days ago)
- Last Synced: 2026-07-04T21:12:14.613Z (16 days ago)
- Topics: ai-gateway, cloud-native, gitops, kubernetes, kubernetes-operator, litellm, llm, openai, openshift, operator
- Language: Go
- Homepage: https://litellm-operator.palena.ai/
- Size: 1.29 MB
- Stars: 6
- Watchers: 0
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
- Security: SECURITY.md
- Cla: CLA.md
Awesome Lists containing this project
README
LiteLLM Operator
Production-grade Kubernetes operator for LiteLLM — declarative AI gateway deployments, bidirectional config sync, and first-class OpenShift support.
---
## Why this operator?
The community LiteLLM Helm chart deploys the proxy, but leaves you with a hard trade-off: manage models and keys through the **Admin UI** (convenient, but not GitOps-friendly) or through `proxy_server_config.yaml` (reproducible, but no UI). Pick one and you lose the other.
This operator dissolves that trade-off. Every resource — instances, organizations, models, teams, users, keys, customers, credentials, guardrails, budget tiers — is a first-class Kubernetes CRD, reconciled continuously against the LiteLLM REST API. Git is the source of truth; Admin-UI drift is detected on every sync interval and resolved per your policy (`crd-wins`, `api-wins`, or `manual`). You get GitOps **and** the Admin UI, backed by the same state.
It also handles the parts a Helm chart can't: finalizer-based cleanup that deletes upstream API objects, generated virtual keys stored as garbage-collected Kubernetes Secrets, enterprise license activation, rollback-on-failure, OpenShift-native routing, six-backend response caching, and external secret-manager integration so provider API keys never touch etcd.
## Architecture at a glance
```text
kubectl apply
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes API │
│ │
│ LiteLLMInstance LiteLLMOrganization LiteLLMModel │
│ LiteLLMTeam LiteLLMUser LiteLLMCustomer │
│ LiteLLMVirtualKey LiteLLMCredential LiteLLMGuardrail│
│ LiteLLMBudget │
└──────────────────────────────┬──────────────────────────────┘
│ watches / reconciles
▼
┌────────────────────┐
│ LiteLLM Operator │
└─────────┬──────────┘
┌───────────────────┬─┴─┬───────────────────────┐
│ Deployment │ │ LiteLLM REST API │
│ ConfigMap │ │ (bidirectional sync) │
│ Secrets / HPA │ │ crd-wins · api-wins │
│ Ingress / Route / │ │ preserve · prune │
│ HTTPRoute │ │ adopt │
│ ServiceMonitor │ │ │
│ PrometheusRule │ │ │
│ Grafana dashboard │ │ │
└─────────┬─────────┘ └───────────┬───────────┘
▼ ▼
┌──────────────────────────────────────────┐
│ LiteLLM Proxy + Postgres + Redis │
└──────────────────────────────────────────┘
```
## Features
| Area | What you get |
| --- | --- |
| **Infrastructure** | Declarative Deployment, ConfigMap, Service, Secrets, HPA v2, PDB, NetworkPolicy; migration Jobs per image tag; auto-rollback on `ProgressDeadlineExceeded`; topology spread constraints; `runAsNonRoot` mode using the official non-root image |
| **Networking** | Kubernetes Ingress, OpenShift Route, Gateway API HTTPRoute — pick one declaratively per instance |
| **Multi-tenancy** | Full Organization → Team → User → Key hierarchy with budgets, member management (`crd` / `sso` / `mixed` modes), and org-scoped model access |
| **API-managed CRDs** | `LiteLLMOrganization`, `LiteLLMModel`, `LiteLLMTeam`, `LiteLLMUser`, `LiteLLMCustomer`, `LiteLLMVirtualKey`, `LiteLLMBudget` — reconciled via the LiteLLM REST API with finalizer-based cleanup and spec-hash change detection |
| **Config-managed CRDs** | `LiteLLMCredential` (reusable provider API keys via `credentialRef`) and `LiteLLMGuardrail` (Aporia, Lakera, Presidio, Bedrock, LLM Guard, Guardrails AI, Azure, Google Text Moderation, custom) — materialized into `proxy_server_config.yaml`, keys injected via `secretKeyRef` (never read into operator memory) |
| **Bidirectional sync** | Periodic drift detection with `crd-wins` / `api-wins` / `manual` resolution and `preserve` / `prune` / `adopt` policies for unmanaged resources |
| **VirtualKey lifecycle** | Generated API keys stored in owner-referenced Kubernetes Secrets; rotation and revocation follow CRD deletion |
| **Authentication** | SSO for Azure Entra, Okta, Google, generic OIDC; SCIM v2 provisioning; JWT and OAuth2 auth for M2M flows; custom SSO handlers via ConfigMap or image |
| **Security** | IP allowlisting with `X-Forwarded-For` support, RBAC via `spec.rbac`, external secret managers (AWS Secrets Manager / KMS, Azure Key Vault, Google Secret Manager / KMS, HashiCorp Vault) with IRSA and workload-identity support |
| **Reliability** | 6-backend response caching (Redis / S3 / GCS / Qdrant / Redis-semantic / local), fallback chains (default, per-model, content-policy, context-window), per-error-type retry policies, tag-based routing, per-provider budget caps |
| **Observability** | ServiceMonitor + PrometheusRule with 6 built-in alerts and runbook annotations; auto-provisioned Grafana dashboard ConfigMap |
| **Data** | Optional CloudNativePG integration with `ScheduledBackup` (snapshot or `barmanObjectStore`) |
| **Admin UI** | Disable, admin-only mode, DB-backed model management, personal-key gating, custom docs URL, logo, email branding, color themes via ConfigMap |
| **Distribution** | OLM bundle for OperatorHub / OpenShift Catalog **and** a Helm chart for clusters without OLM |
| **Enterprise** | Convention-based license Secret detection (`{instance}-license` or `litellm-license`) with `EnterpriseLicenseRequired` status conditions when unlicensed enterprise features are requested |
> **Full documentation:** see the [`docs/`](docs/) folder — guides for [SSO](docs/guide/sso.md), [config sync](docs/guide/config-sync.md), [caching](docs/guide/caching.md), [RBAC](docs/guide/rbac.md), [observability](docs/guide/observability.md), [secret managers](docs/guide/secret-managers.md), and per-CRD reference pages under [`docs/reference/`](docs/reference/).
## Custom Resource Definitions
| CRD | Short Name | Description |
| --- | ---------- | ----------- |
| `LiteLLMInstance` | `li` | Deploys a LiteLLM proxy with database, Redis, networking, and SSO |
| `LiteLLMOrganization` | `lo` | Creates an organization for multi-tenant isolation with budget and model access |
| `LiteLLMModel` | `lm` | Registers a model (e.g., `openai/gpt-4o`) with the proxy |
| `LiteLLMTeam` | `lt` | Creates a team with budget limits and member management |
| `LiteLLMUser` | `lu` | Creates a user (service accounts, bot users, non-SSO environments) |
| `LiteLLMCustomer` | `lcust` | Manages an external end-user (SaaS customer) with budgets and rate limits |
| `LiteLLMCredential` | `lc` | Defines a reusable provider credential (API key + optional base URL) shared across models |
| `LiteLLMGuardrail` | `lg` | Defines a content moderation / safety integration (Aporia, Lakera, Presidio, Bedrock, etc.) |
| `LiteLLMVirtualKey` | `lk` | Generates an API key scoped to a team/user with budget and rate limits |
| `LiteLLMBudget` | `lb` | Declares a reusable budget / rate-limit tier (via `/budget/*`) referenced by `budgetId` from keys, customers, and the instance default |
All secondary resources reference a `LiteLLMInstance` via `spec.instanceRef`. Teams can optionally reference a `LiteLLMOrganization` via `spec.organizationRef`.
## Prerequisites
- Go 1.22+
- Docker 17.03+
- kubectl v1.28+
- Access to a Kubernetes v1.28+ cluster
- A PostgreSQL database for LiteLLM state storage
## Quick Start
### 1. Install CRDs
```sh
make install
```
### 2. Deploy the operator
```sh
make deploy IMG=ghcr.io/palenaai/litellm-operator:latest
```
### 3. Create a database secret
```sh
kubectl create secret generic litellm-db-credentials \
--from-literal=DATABASE_URL='postgresql://user:pass@host:5432/litellm'
```
### 4. Deploy a LiteLLM instance
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
replicas: 2
masterKey:
autoGenerate: true
database:
external:
connectionSecretRef:
name: litellm-db-credentials
key: DATABASE_URL
service:
type: ClusterIP
port: 4000
```
### 5. Register a model
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMModel
metadata:
name: gpt4o
spec:
instanceRef:
name: my-gateway
modelName: gpt-4o
litellmParams:
model: openai/gpt-4o
apiKeySecretRef:
name: openai-credentials
key: OPENAI_API_KEY
```
### Reusable Credentials
When many models share the same provider API key (e.g., several OpenAI deployments), define the credential once and reference it from each `LiteLLMModel` via `credentialRef`:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: openai-credentials
type: Opaque
stringData:
api-key: sk-...
---
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMCredential
metadata:
name: openai-prod
spec:
instanceRef:
name: my-gateway
# The name used under `credential_list` in the generated proxy config.
# Models reference this via `litellm_params.litellm_credential_name`.
credentialName: openai-prod
apiKeySecretRef:
name: openai-credentials
key: api-key
# Optional extras merged into credential_info (api_base / api_version /
# free-form params are supported — params cannot override reserved keys).
apiBase: https://api.openai.com/v1
---
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMModel
metadata:
name: gpt4o
spec:
instanceRef:
name: my-gateway
modelName: gpt-4o
litellmParams:
model: openai/gpt-4o
credentialRef:
name: openai-prod # takes precedence over inline apiKeySecretRef/apiBase
```
The operator injects the API key into the proxy pod via a `secretKeyRef`-backed env var (`CREDENTIAL_OPENAI_PROD_API_KEY`) and writes a matching `os.environ/…` reference to the generated `proxy_server_config.yaml` — the key value itself is never read into the operator's memory. Rotating the key is a Secret update: the operator rolls out a new Deployment pod to pick up the new value.
### 6. Create a team and API key
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMTeam
metadata:
name: engineering
spec:
instanceRef:
name: my-gateway
teamAlias: engineering
models: [gpt-4o]
maxBudgetMonthly: 1000
budgetDuration: "30d"
members:
- email: dev@example.com
role: user
---
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMVirtualKey
metadata:
name: eng-ci-key
spec:
instanceRef:
name: my-gateway
keyAlias: eng-ci-key
teamRef:
name: engineering
models: [gpt-4o]
maxBudget: "100"
```
### Multi-Tenant Organizations
Create an organization to group teams under a shared budget and model access policy:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMOrganization
metadata:
name: acme-corp
spec:
instanceRef:
name: my-gateway
organizationAlias: acme-corp
models: [gpt-4o, claude-4-sonnet]
maxBudget: 5000
budgetDuration: "30d"
members:
- email: admin@acme.com
role: org_admin
- email: user@acme.com
role: internal_user
---
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMTeam
metadata:
name: acme-engineering
spec:
instanceRef:
name: my-gateway
organizationRef:
name: acme-corp
teamAlias: acme-engineering
models: [gpt-4o]
```
### OpenShift / Non-Root Environments
For OpenShift or clusters enforcing Pod Security Standards, enable non-root mode:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
security:
runAsNonRoot: true
# ... rest of spec
```
This automatically switches to the official `litellm-non_root` image (runs as `nobody`, UID 65534) and applies a restricted pod security context compatible with OpenShift's restricted SCC.
### IP Allowlisting (Enterprise)
Restrict API access to specific IP addresses or CIDR ranges:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
security:
ipAllowlist:
enabled: true
allowedIPs:
- "10.0.0.0/8"
- "192.168.1.0/24"
- "203.0.113.50"
useXForwardedFor: true # required behind load balancers
# ... rest of spec
```
### RBAC (Role-Based Access Control)
Enforce route restrictions and key generation controls:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
rbac:
enabled: true
adminOnlyRoutes:
- /model/new
- /model/delete
allowedRoutes:
- /chat/completions
- /embeddings
- /key/info
defaultTeamDisabled: true # force team-based keys
keyGeneration: # enterprise
teamKeyGeneration:
allowedTeamMemberRoles: ["admin"]
rolePermissions: # enterprise
internal_user:
routes: ["/key/generate", "/key/info"]
models: ["gpt-4", "claude-3-haiku"]
# ... rest of spec
```
### OpenShift Route
For OpenShift clusters, create a Route instead of an Ingress:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
route:
enabled: true
host: litellm.apps.example.com
tlsTermination: edge # edge | passthrough | reencrypt
# ... rest of spec
```
### Gateway API HTTPRoute
For clusters using the [Gateway API](https://gateway-api.sigs.k8s.io/) (Istio, Envoy Gateway, Cilium, etc.):
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
gatewayHTTPRoute:
enabled: true
host: litellm.example.com
parentRefs:
- name: my-gateway # Name of the Gateway resource
namespace: istio-system # Optional: namespace of the Gateway
sectionName: https # Optional: specific listener on the Gateway
# ... rest of spec
```
### Observability (Prometheus + Grafana)
Enable ServiceMonitor, alerting rules, and a Grafana dashboard:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
observability:
serviceMonitor:
enabled: true
interval: "30s"
prometheusRule:
enabled: true
# disabledAlerts: ["LiteLLMHighCPUUsage"] # optionally disable specific alerts
grafanaDashboard:
enabled: true
folder: "LiteLLM"
# ... rest of spec
```
Built-in alerts: `LiteLLMInstanceDown` (critical), `LiteLLMInstanceDegraded`, `LiteLLMPodRestarting`, `LiteLLMPodNotReady`, `LiteLLMHighMemoryUsage`, `LiteLLMHighCPUUsage`. Each alert includes a runbook annotation with troubleshooting commands.
### CloudNativePG Backups
When using CloudNativePG for the database, enable scheduled backups:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
database:
cloudnativepg:
clusterName: litellm-db
backup:
enabled: true
schedule: "0 2 * * *" # daily at 2am
retention: 7
method: snapshot # snapshot or barmanObjectStore
# ... rest of spec
```
### Tag-Based Routing
Route requests to different model deployments based on tags. Useful for free/paid tiers or team-specific model access:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
routerSettings:
enableTagFiltering: true
# ... rest of spec
---
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMModel
metadata:
name: gpt4-paid
spec:
instanceRef:
name: my-gateway
modelName: gpt-4
litellmParams:
model: openai/gpt-4
apiKeySecretRef:
name: openai-credentials
key: OPENAI_API_KEY
tags: ["paid"]
---
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMTeam
metadata:
name: paid-tier
spec:
instanceRef:
name: my-gateway
teamAlias: paid-tier
tags: ["paid"]
```
Requests from the `paid-tier` team are routed to model deployments tagged `paid`. Use `tagFilteringMatchAny: true` in `routerSettings` to match requests having ANY of the specified tags (default is ALL must match).
### Fallback Chains
Configure model fallback routing so requests automatically try alternative models on failure:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
fallbacks:
# Global fallbacks applied on any error
defaultFallbacks: ["gpt-4-mini", "claude-3-haiku"]
# Per-model fallbacks for general errors
modelFallbacks:
- model: gpt-4
fallbacks: ["gpt-4-mini", "claude-3-haiku"]
# Fallbacks for content policy violations
contentPolicyFallbacks:
- model: gpt-4
fallbacks: ["claude-3-sonnet"]
# Fallbacks for context window exceeded
contextWindowFallbacks:
- model: gpt-4
fallbacks: ["gpt-4-32k", "claude-3-sonnet"]
maxFallbacks: 3
routerSettings:
# Retry policy by error type (retries on same model before fallback)
retryPolicy:
TimeoutError: 2
RateLimitError: 3
ContentPolicyViolationError: 0
# Per-model-group retry overrides
modelGroupRetryPolicy:
gpt-4:
TimeoutError: 1
RateLimitError: 0
# ... rest of spec
```
### Response Caching
Configure response caching to reduce latency and costs:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
caching:
enabled: true
type: redis # redis, redis-semantic, s3, gcs, qdrant, local
ttl: 600 # cache TTL in seconds
namespace: "my-app" # key isolation namespace
mode: default_on # default_on or default_off
supportedCallTypes: # restrict to specific call types
- acompletion
- aembedding
redis:
host: redis.example.com
port: 6379
passwordSecretRef:
name: redis-secret
key: password
ssl: true
# ... rest of spec
```
When `type: redis` and no `caching.redis` block is provided, the operator reuses the instance's existing `spec.redis` connection — no need to duplicate Redis details.
Other backends: `s3` (with bucket, region, AWS credentials), `gcs` (with bucket, GCS service account), `qdrant` (semantic caching with embeddings), `local` (in-memory, no external dependencies).
### Auto-Rollback
Automatically rollback failed deployments:
```yaml
apiVersion: litellm.palena.ai/v1alpha1
kind: LiteLLMInstance
metadata:
name: my-gateway
spec:
upgrade:
strategy: rolling
autoRollback: true
healthCheckTimeout: "300s"
# ... rest of spec
```
When enabled, the operator tracks the last successful deployment revision. If a new deployment exceeds the progress deadline, the operator triggers a rollback and sets a status condition.
### Enterprise License
To activate LiteLLM Enterprise features, create a Secret with your license key. The operator detects it automatically and injects the `LITELLM_LICENSE` environment variable into the proxy Deployment.
**Per-instance license** (takes precedence):
```sh
kubectl create secret generic my-gateway-license \
--from-literal=license-key='your-litellm-enterprise-license-key'
```
**Namespace-wide license** (fallback for all instances in the namespace):
```sh
kubectl create secret generic litellm-license \
--from-literal=license-key='your-litellm-enterprise-license-key'
```
The operator checks for `{instance-name}-license` first, then falls back to `litellm-license`. License status is reported in `.status.license`:
```sh
kubectl get litellminstance my-gateway -o jsonpath='{.status.license}'
# {"active":true,"secretName":"my-gateway-license"}
```
If a downstream resource (Model, Team, User, VirtualKey) requires an enterprise feature and no license is present, the operator sets `Reason: EnterpriseLicenseRequired` on the resource's status condition without retrying.
### Namespace-Scoped Watching
By default, the operator watches all namespaces. To restrict it to specific namespaces:
**Helm:**
```bash
helm install litellm-operator deploy/charts/litellm-operator/ \
--set watchNamespaces="team-a,team-b"
```
**Flag:**
```bash
/manager --watch-namespaces=team-a,team-b
```
**Environment variable (set automatically by OLM for OwnNamespace/SingleNamespace install modes):**
```bash
WATCH_NAMESPACE=team-a,team-b
```
### 7. Retrieve a generated API key
The generated API key is stored in a Secret (default name: `{name}-key`):
```sh
kubectl get secret eng-ci-key-key -o jsonpath='{.data.api_key}' | base64 -d
```
## Installation Methods
### Direct (Makefile)
```sh
make install # Install CRDs
make deploy # Deploy operator
```
### OLM (OpenShift / clusters with OLM)
```sh
operator-sdk run bundle ghcr.io/palenaai/litellm-operator-bundle:latest
```
### Helm
```sh
helm install litellm-operator deploy/charts/litellm-operator/
```
## Development
### Build
```sh
make build # Build operator binary
make docker-build IMG=... # Build container image
```
### Test
```sh
make test # Unit + integration tests (envtest)
make test-e2e # End-to-end tests (requires cluster)
```
### Generate
```sh
make generate # DeepCopy functions
make manifests # CRD YAMLs, RBAC, webhooks
```
### Run locally (against current kubeconfig cluster)
```sh
make install # Install CRDs first
make run # Run operator outside the cluster
```
## Architecture
Key design points:
- **LiteLLMInstance** controller manages Deployment, ConfigMap, Service, Secrets, Ingress, HPA, PDB, NetworkPolicy, migration Jobs, ServiceMonitor, PrometheusRule, Grafana dashboard ConfigMaps, and CNPG ScheduledBackups
- **Secondary controllers** (Organization, Model, Team, User, VirtualKey) resolve their `instanceRef` to discover the LiteLLM API endpoint and master key, then sync state via the REST API
- **Finalizers** ensure cleanup: deleting a CRD calls the corresponding LiteLLM API delete endpoint before removing the Kubernetes resource
- **Spec hash annotations** (`litellm.palena.ai/sync-hash`) enable change detection to avoid unnecessary API calls
## Project Structure
```text
api/v1alpha1/ CRD type definitions
internal/controller/ Reconciliation controllers
internal/litellm/ LiteLLM REST API client
internal/resources/ Kubernetes resource generators
config/crd/bases/ Generated CRD manifests
config/samples/ Example custom resources
bundle/ OLM bundle manifests
deploy/charts/ Helm chart
```
## License
Copyright 2026. Licensed under the Apache License, Version 2.0.