LiteLLM Client API Key Setup - Claude Code Integration
File: docs/package-ai-litellm-client-key-setup.md
Purpose: Guide for generating and managing LiteLLM client API keys for Claude Code DevContainer integration
Target Audience: Developers, DevOps engineers using Claude Code in DevContainers
Last Updated: November 23, 2025
📋 Overview
LiteLLM uses a two-key system for security and access management:
- Master Key: Stored in
urbalurba-secrets, used for administrative operations (key generation, management) - Client Keys: Generated via API, stored in LiteLLM's PostgreSQL database, scoped to specific models
This guide covers generating client API keys for developers using Claude Code in DevContainers.
Why Client Keys:
- ✅ Scoped access to specific models only
- ✅ Usage tracking per developer/client
- ✅ Cost attribution and monitoring
- ✅ Independent key rotation without affecting other users
- ✅ Revocable without impacting master key
🚀 Quick Setup
Step 1: Get the Master Key
MASTER_KEY=$(kubectl get secret urbalurba-secrets -n ai -o jsonpath="{.data.LITELLM_PROXY_MASTER_KEY}" | base64 --decode)
echo "Master key retrieved: ${MASTER_KEY:0:10}..."
Step 2: Port Forward to LiteLLM
kubectl port-forward -n ai svc/litellm 4000:4000 &
sleep 3
Note: Keep this running in the background. You can stop it later with pkill -f "kubectl port-forward.*litellm".
Step 3: Generate Client API Key
IMPORTANT: Replace developer-name with the actual developer's name (e.g., john-doe, jane-smith).
DEVELOPER_NAME="developer-name" # CHANGE THIS
curl -X POST http://localhost:4000/key/generate \
-H "Authorization: Bearer $MASTER_KEY" \
-H "Content-Type: application/json" \
-d "{
\"models\": [\"claude-sonnet-4-5-20250929\", \"claude-3-opus-20240229\"],
\"key_alias\": \"claude-code-${DEVELOPER_NAME}\",
\"duration\": null
}"
Response Example:
{
"key": "sk-xxxxxxxxxxxxxxxxxx",
"key_alias": "claude-code-developer-name",
"key_name": null,
"expires": null,
"models": ["claude-sonnet-4-5-20250929", "claude-3-opus-20240229"],
"created_at": "2025-11-23T15:30:00.000000Z",
"...": "..."
}
⚠️ SAVE THE key VALUE! This is the only time you'll see it. The developer needs this for their DevContainer.
Step 4: Provide Key to Developer
Send the developer:
- The
keyvalue (e.g.,sk-xxxxxxxxxxxxxxxxxx) - Instructions to add it to their DevContainer
Developer should run:
# In their DevContainer
bash .devcontainer/additions/config-claude-code.sh
When prompted, they enter the client API key you generated.
Step 5: Clean Up
# Stop the port-forward
pkill -f "kubectl port-forward.*litellm"
🔍 Verification
Test the Client Key
From cluster (Mac host):
CLIENT_KEY="sk-xxxxxxxxxxxxxxxxxx" # The generated key
# Port-forward if not already running
kubectl port-forward -n ai svc/litellm 4000:4000 &
# Test models endpoint
curl -H "Authorization: Bearer $CLIENT_KEY" \
http://localhost:4000/v1/models
# Should return models list including:
# - claude-sonnet-4-5-20250929
# - claude-3-opus-20240229
From DevContainer:
# Test through nginx reverse proxy
curl -H "Authorization: Bearer $CLIENT_KEY" \
http://localhost:8080/v1/models
Expected Response:
{
"data": [
{"id": "claude-sonnet-4-5-20250929", "object": "model", ...},
{"id": "claude-3-opus-20240229", "object": "model", ...}
],
"object": "list"
}
🛠️ Key Management
List All Client Keys
curl -H "Authorization: Bearer $MASTER_KEY" \
http://localhost:4000/key/info
View Specific Key Info
CLIENT_KEY_HASH="1ffd879a..." # From key info response
curl -H "Authorization: Bearer $MASTER_KEY" \
"http://localhost:4000/key/info?key=${CLIENT_KEY_HASH}"
Delete a Client Key
Use when:
- Developer leaves the team
- Key is compromised
- Regular key rotation
curl -X DELETE http://localhost:4000/key/delete \
-H "Authorization: Bearer $MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{"keys": ["sk-key-to-delete"]}'
Rotate Keys
Best Practice: Rotate keys quarterly or when a developer changes roles.
# 1. Generate new key (follow Step 3)
# 2. Provide new key to developer
# 3. Developer updates DevContainer configuration
# 4. Verify new key works
# 5. Delete old key (optional, for security)
🔧 Troubleshooting
Error: "Key not allowed to access model"
Symptom:
{
"error": {
"message": "key not allowed to access model. This key can only access models=['claude-sonnet-4.5', 'claude-3-opus']",
...
}
}
Cause: Key was generated with short model names, but Claude Code requests full names.
Solution: Regenerate key with full model names:
# ❌ Wrong:
"models": ["claude-sonnet-4.5", "claude-3-opus"]
# ✅ Correct:
"models": ["claude-sonnet-4-5-20250929", "claude-3-opus-20240229"]
Error: "Invalid model name"
Symptom:
{
"error": "completion: Invalid model name passed in model=claude-sonnet-4-5-20250929"
}
Cause: LiteLLM ConfigMap doesn't have model name aliases.
Solution: Verify ConfigMap has both short and full model names:
kubectl get configmap litellm-config -n ai -o yaml | grep "model_name:"
Should show:
claude-sonnet-4.5(short name)claude-sonnet-4-5-20250929(full name)
If missing, apply the updated configuration.
Error: "Authentication Error, No api key passed in"
Cause: Master key or client key not provided correctly.
Solutions:
- Verify key copied correctly (no extra spaces/newlines)
- Check Authorization header format:
Authorization: Bearer sk-xxxxx - Verify port-forward is running:
lsof -i :4000
Port-Forward Keeps Dying
Cause: Network interruption or kubectl timeout.
Solution: Run in persistent loop:
while true; do
kubectl port-forward -n ai svc/litellm 4000:4000
echo "Port forward died, restarting in 5 seconds..."
sleep 5
done
🔒 Security Notes
Best Practices
- ✅ Generate unique keys per developer - Use developer name in alias
- ✅ Scope to minimum models needed - Only add models developer will use
- ✅ Set expiration for temporary access - Use
durationparameter (e.g.,"30d") - ✅ Rotate keys quarterly - Regular rotation improves security
- ✅ Revoke on developer departure - Delete keys when team members leave
- ✅ Monitor usage - Check LiteLLM logs for unusual activity
- ✅ Never commit keys to git - Store in
.envfiles (gitignored)
What NOT to Do
- ❌ Never share the master key - Only use for admin operations
- ❌ Don't reuse client keys - Each developer gets unique key
- ❌ Don't commit keys to repos - Always gitignore
.envfiles - ❌ Don't set unlimited duration without reason - Use expiration when possible
- ❌ Don't grant access to all models - Scope to needed models only
Key Storage
Developer DevContainer:
- Keys stored in gitignored
.envfiles - Loaded by DevContainer configuration scripts
- Never committed to version control
LiteLLM Database:
- Client keys stored in PostgreSQL
- Backed up with standard database backups
- Retrievable via master key API calls
📊 Usage Monitoring
Track Key Usage
# Get spending per key
curl -H "Authorization: Bearer $MASTER_KEY" \
http://localhost:4000/spend/tags
View Request Logs
# Check LiteLLM logs for specific key
kubectl logs -n ai deployment/litellm | grep "claude-code-developer-name"
Metrics Tracked:
- Request count per model
- Token usage (input/output)
- Cost per request
- Success/failure rates
- Timestamp and model used
🔗 Related Documentation
- package-ai-litellm.md - Main LiteLLM documentation
- package-ai-readme.md - AI services overview
- DevContainer nginx configuration -
.devcontainer/additions/nginx/
📝 Notes
- Client keys are independent of cluster rebuilds - Stored in LiteLLM's PostgreSQL database
- Master key rotation requires regenerating all client keys
- DevContainer nginx auto-adds
Host: litellm.localhostheader for Traefik routing - Claude Code bug #2182: Host header override workaround via nginx proxy
Generated: 2025-11-23 Maintained by: Platform Engineering Team