-
-
Notifications
You must be signed in to change notification settings - Fork 0
Secrets
Nenya loads secrets from JSON files. Multiple sources are supported with priority ordering.
| Priority | Path | Description |
|---|---|---|
| 1 | $CREDENTIALS_DIRECTORY/secrets |
systemd single file |
| 2 | $CREDENTIALS_DIRECTORY/secrets.d/*.json |
systemd directory |
| 3 | $NENYA_SECRETS_DIR/*.json |
configurable via env var |
| 4 | /run/secrets/nenya/*.json |
K8s/Docker standard path |
If multiple JSON files exist in a directory, they are merged alphabetically (last-wins for duplicate keys).
{
"client_token": "nk-...",
"provider_keys": {
"gemini": "AIza...",
"deepseek": "sk-...",
"openai": "sk-proj-..."
},
"api_keys": {
"dev-user": {
"name": "dev-user",
"token": "nk-...",
"roles": ["user"],
"allowed_agents": ["build", "plan"],
"enabled": true
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
client_token |
string | Yes | Bearer token for /v1/* endpoints |
provider_keys |
object | No | Provider name → API key |
api_keys |
object | No | Client RBAC keys |
openssl rand -hex 32
# Output: abc123def456... (48 hex chars)Prefix with nk- for convention:
echo "nk-$(openssl rand -hex 32)"Nenya supports role-based access control (RBAC) via per-API key configuration. Keys defined in api_keys have roles, agent allowlists, and endpoint allowlists.
Generate a key:
go run ./cmd/nenya keygen --name "dev-user" --roles user,read-only --agents build,planManual configuration:
{
"api_keys": {
"dev-user": {
"name": "dev-user",
"token": "nk-...",
"roles": ["user"],
"allowed_agents": ["build", "plan"],
"allowed_endpoints": ["GET /v1/models", "POST /v1/chat/completions"],
"enabled": true
}
}
}Roles:
-
admin— Unrestricted access (bypasses RBAC) -
user— Access to configured agents, all non-admin endpoints -
read-only— GET requests only (/v1/models,/healthz,/statsz,/metrics)
Agent Scoping:
-
allowed_agentslist restricts which agents the key can access - Empty list grants access to all agents (backward compatible)
- Admin keys bypass agent restrictions
Endpoint Restrictions:
-
allowed_endpointslist allows fine-grained allowlisting (method + path) - Overrides default role-based permissions when set
- Empty list uses role-based default permissions
- Admin keys bypass endpoint restrictions
[Service]
LoadCredential=secrets:/etc/nenya/secrets.jsonmkdir -p /etc/nenya/secrets.d
cat > /etc/nenya/secrets.d/01-client.json << 'EOF'
{"client_token": "nk-..."}
EOF
cat > /etc/nenya/secrets.d/02-providers.json << 'EOF'
{"provider_keys": {"deepseek": "sk-...", "gemini": "AIza..."}}
EOFservices:
nenya:
volumes:
- ./secrets:/run/secrets/nenya:ro
environment:
- NENYA_SECRETS_DIR=/run/secrets/nenyasecrets/
├── 01-client.json → {"client_token": "nk-..."}
├── 02-providers.json → {"provider_keys": {"deepseek": "sk-..."}}
└── 03-keys.json → {"api_keys": {...}}apiVersion: v1
kind: Secret
metadata:
name: nenya-secrets
type: Opaque
stringData:
01-client.json: |
{"client_token": "nk-..."}
02-providers.json: |
{"provider_keys": {"deepseek": "sk-...", "gemini": "AIza..."}}Mount at /run/secrets/nenya and set NENYA_SECRETS_DIR env var.
- Never commit secrets to version control
- Set
chmod 600on secrets files - Use systemd credential mechanism for secure in-memory storage
- Rotate tokens periodically
- Path traversal (
..) is rejected for all secret paths
Nenya uses mlock to keep tokens in RAM, preventing them from swapping to disk. Requires:
[Service]
LimitMEMLOCK=infinitySee Security for implementation details.
Environment variables (NENYA_CLIENT_TOKEN, NENYA_PROVIDER_KEY_*) are no longer supported. Migrate to JSON files.
Before (deprecated):
export NENYA_CLIENT_TOKEN="nk-..."
export NENYA_PROVIDER_KEY_DEEPSEEK="sk-..."After:
// 01-client.json
{"client_token": "nk-..."}
// 02-providers.json
{"provider_keys": {"deepseek": "sk-..."}}# Restrict secrets directory to root/nenya user
sudo mkdir -p /etc/nenya
sudo chown root:nenya /etc/nenya
sudo chmod 750 /etc/nenya
# Load credentials via systemd (prevents file reads by other processes)
sudo mkdir -p /etc/nenya/secrets.d
sudo chmod 700 /etc/nenya/secrets.d
cat > /etc/nenya/secrets.d/01-client.json << 'EOF'
{"client_token": "nk-..."}
EOF
sudo chmod 600 /etc/nenya/secrets.d/*The LoadCredential mechanism in systemd passes files via memfd (anonymous memory), avoiding disk reads after boot.
When running outside systemd, protect the secrets file manually:
mkdir -p creds
chmod 700 creds
cat > creds/secrets.json << 'EOF'
{"client_token": "nk-...", "provider_keys": {"gemini": "..."}}
EOF
chmod 600 creds/secrets.json
CREDENTIALS_DIRECTORY=$(pwd)/creds ./nenya -config config.jsonmacOS does not support systemd credentials. Recommended approaches:
Option A: Named file with strict permissions
mkdir -p ~/.config/nenya/secrets.d
chmod 700 ~/.config/nenya/secrets.d
cat > ~/.config/nenya/secrets.d/01-client.json << 'EOF'
{"client_token": "nk-...", "provider_keys": {"gemini": "..."}}
EOF
chmod 600 ~/.config/nenya/secrets.d/*
CREDENTIALS_DIRECTORY=~/.config/nenya/secrets.d ./nenya -config config.jsonOption B: macOS Keychain (preferred)
Store the full JSON blob as a generic password in the login keychain:
security add-generic-password -s "nenya-secrets" -a "$USER" \
-w "$(cat creds/secrets.json)" -URetrieve at runtime (note: no helper script yet — use a wrapper):
#!/usr/bin/env bash
# wrapper.sh — retrieve secret from Keychain, then launch nenya
export CREDENTIALS_DIRECTORY=$(mktemp -d)
security find-generic-password -s "nenya-secrets" -a "$USER" -w \
> "$CREDENTIALS_DIRECTORY/secrets"
chmod 600 "$CREDENTIALS_DIRECTORY/secrets"
exec ./nenya -config config.jsonKeychain storage encrypts the secret at rest with the user's login password and prevents accidental exposure via file reads or version control.
- Security — Security policy and vulnerability reporting
- Deployment — Container and Kubernetes deployment
- Configuration — Config reference
Getting Started
- Home — Project overview
- Quick Start — Install and run in 5 minutes
- Client Setup — OpenCode, Cursor, and other clients
- Deployment — Bare metal, container, Kubernetes
Core Concepts
- Configuration — Config reference and examples
- Providers — 22 providers, capabilities, special behaviors
- Routing — Latency-aware routing and fallback chains
- Architecture — Package overview and request lifecycle
- MCP Integration — MCP server integration
Reference
- Passthrough Proxy — Raw provider endpoint proxying
- Secrets — Systemd credentials and container secrets
- Model Discovery — Dynamic model catalog fetching
- API Endpoints — Endpoint reference
Operations
- Demo — Test all pipeline tiers
- Troubleshooting — Common issues and solutions
- FAQ — Frequently asked questions
- Security — Security policy and vulnerability reporting
Project
- Roadmap — Planned features
- Disclaimer — Legal disclaimer