Add terraform-provider-litellmvaultsecret implementation

Populate the repo with the Terraform/OpenTofu provider that manages the LiteLLM
dynamic secrets engine on Vault/OpenBao via the Vault API.

- Provider (VAULT_ADDR/VAULT_TOKEN) with resources litellmvaultsecret_secret_backend
  (mount + config) and litellmvaultsecret_secret_backend_role (models, max_budget,
  ttl/max_ttl in seconds, metadata)
- Unit tests against a mock Vault API
- End-to-end test: builds the sibling plugin, boots Vault + LiteLLM + Postgres,
  and runs a real terraform apply/destroy asserting key generation works
- Makefile, woodpecker CI (build/test/pre-commit), examples, README
This commit is contained in:
2026-07-02 23:23:13 +10:00
commit 8ca6c39c66
24 changed files with 2004 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
# E2E stack for the provider: Postgres + LiteLLM + a Vault dev server with the
# litellm plugin mounted. Bind mounts use ":z" for SELinux (Fedora/RHEL).
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: litellm
POSTGRES_PASSWORD: litellm
POSTGRES_DB: litellm
healthcheck:
test: ["CMD-SHELL", "pg_isready -U litellm"]
interval: 3s
timeout: 3s
retries: 20
litellm:
image: ghcr.io/berriai/litellm:main-stable
depends_on:
postgres:
condition: service_healthy
environment:
LITELLM_MASTER_KEY: sk-master-e2e-1234
DATABASE_URL: postgresql://litellm:litellm@postgres:5432/litellm
STORE_MODEL_IN_DB: "True"
command: ["--config", "/app/config.yaml", "--port", "4000"]
volumes:
- ./litellm/config.yaml:/app/config.yaml:ro,z
ports:
- "4000:4000"
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:4000/health/liveliness').status==200 else 1)"]
interval: 5s
timeout: 5s
retries: 40
vault:
image: hashicorp/vault:1.18
depends_on:
litellm:
condition: service_healthy
cap_add:
- IPC_LOCK
environment:
VAULT_DEV_ROOT_TOKEN_ID: root
VAULT_ADDR: http://127.0.0.1:8200
VAULT_TOKEN: root
command: ["server", "-dev", "-dev-listen-address=0.0.0.0:8200", "-config=/vault/vault.hcl"]
volumes:
- ./plugins:/vault/plugins:ro,z
- ./vault/vault.hcl:/vault/vault.hcl:ro,z
ports:
- "8200:8200"
healthcheck:
test: ["CMD", "vault", "status", "-address=http://127.0.0.1:8200"]
interval: 3s
timeout: 3s
retries: 20
+29
View File
@@ -0,0 +1,29 @@
terraform {
required_providers {
litellmvaultsecret = {
source = "git.unkin.net/unkin/litellmvaultsecret"
}
}
}
provider "litellmvaultsecret" {
address = "http://127.0.0.1:8200"
token = "root"
}
resource "litellmvaultsecret_secret_backend" "litellm" {
path = "litellm"
description = "LiteLLM dynamic virtual keys (e2e)"
# Reachable from inside the vault container, where the plugin runs.
base_url = "http://litellm:4000"
master_key = "sk-master-e2e-1234"
}
resource "litellmvaultsecret_secret_backend_role" "team_a" {
backend = litellmvaultsecret_secret_backend.litellm.path
name = "team-a"
models = ["gpt-3.5-turbo"]
max_budget = 10
ttl = 3600
max_ttl = 86400
}
+17
View File
@@ -0,0 +1,17 @@
model_list:
- model_name: gpt-3.5-turbo
litellm_params:
model: openai/gpt-3.5-turbo
api_key: sk-fake-openai-key
mock_response: "hello from the mock model"
- model_name: gpt-4
litellm_params:
model: openai/gpt-4
api_key: sk-fake-openai-key
mock_response: "hello from the mock model"
general_settings:
master_key: sk-master-e2e-1234
litellm_settings:
drop_params: true
+4
View File
@@ -0,0 +1,4 @@
# Combined with `-dev` so the dev server has a plugin_directory to register the
# litellm plugin binary mounted from ./plugins.
plugin_directory = "/vault/plugins"
api_addr = "http://127.0.0.1:8200"