ktms-admin

Repository: ai-process/ktms-admin
Docker Hub: coyl/llm-proxy-admin

A small web console for KTMS (the LLM gateway, formerly llm-proxy) and light-tokenmeter (the usage meter). Use it with both, or with either one alone.

llm-proxy-admin Architecture

*Interactive diagram: diagrams/llm-proxy-admin.html Dark theme: diagrams/llm-proxy-admin-dark.png*

Contents

Quick start

You need a Google OAuth client (how) and, for the gateway pages, an llm-proxy admin key (MintAPIKey with scope admin).

docker run -d --name llm-proxy-admin -p 8080:8080 \
  -e PUBLIC_URL=https://admin.example.com \
  -e GOOGLE_CLIENT_ID=… -e GOOGLE_CLIENT_SECRET=… \
  -e ALLOWED_EMAILS='*@example.com' \
  -e SESSION_SECRET="$(openssl rand -base64 36)" \
  -e LLM_PROXY_ADDR=llm-proxy:9090 -e LLM_PROXY_ADMIN_KEY=llm_… \
  -e TOKENMETER_URL=http://light-tokenmeter:8080 \
  coyl/llm-proxy-admin:latest

examples/compose.yaml starts the whole family (llm-proxy, light-tokenmeter, and this console on one Postgres) with first-run steps in its header.

Just looking around on your machine? Skip Google entirely, on localhost only:

docker run --rm -p 8081:8080 -e PUBLIC_URL=http://localhost:8081 -e INSECURE_NO_AUTH=true \
  -e TOKENMETER_URL=http://host.docker.internal:8080 coyl/llm-proxy-admin:latest

INSECURE_NO_AUTH is refused unless PUBLIC_URL host is localhost, 127.0.0.1, or [::1].

Setting up Google sign-in

  1. In the Google Cloud console create an OAuth client ID of type Web application (configure the consent screen first; Internal works if everyone is in your Google Workspace, otherwise External).
  2. Under Authorized redirect URIs add PUBLIC_URL + /auth/callback, for example https://admin.example.com/auth/callback (and http://localhost:8080/auth/callback for local tests).
  3. Put the client id and secret into GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.

The console uses the authorization-code flow with PKCE, state, and nonce, and requires a verified e-mail. Only the openid email profile scopes are requested.

Who may sign in

ALLOWED_EMAILS is a comma- or space-separated list of patterns matched against the verified Google address, case-insensitively. * matches any run of characters within the part before or after the @, never across it.

Pattern Admits
alice@example.com exactly that address
*@example.com everyone at example.com (not x@sub.example.com)
*@*.example.com everyone on any subdomain of example.com
ops-*@example.com ops-eu@example.com, ops-us@example.com, …
*@* every verified Google account (the explicit “open to all”, logged at start)

Patterns need exactly one @; a bare * or example.com is rejected at startup so a typo can never open the door. An empty list admits nobody.

Running with one backend or both

The console shows only the pages whose backend you configured.

You set You get
TOKENMETER_URL Usage page. Nothing else.
LLM_PROXY_ADDR + LLM_PROXY_ADMIN_KEY Models, Rules, Keys, Nodes, Playground, Judge.
both Everything, plus estimated cost on the usage page (tokens × the prices on your models; estimates use standard in/out prices and do not account for peak or batch rates).

Configuration reference

Variable Default Description
PUBLIC_URL – Required. External base URL, e.g. https://admin.example.com.
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET – Required (unless INSECURE_NO_AUTH).
ALLOWED_EMAILS – Admin patterns. At least one of the two lists must be non-empty.
VIEWER_EMAILS empty Read-only patterns.
SESSION_SECRET random 32+ characters; signs the session cookie. Set it, or sessions end at every restart and cannot be shared between replicas.
SESSION_TTL 12h Session lifetime.
LLM_PROXY_ADDR empty host:port of llm-proxy’s gRPC endpoint.
LLM_PROXY_ADMIN_KEY – Key with the admin scope. Required with LLM_PROXY_ADDR.
LLM_PROXY_TLS false Use TLS to reach llm-proxy.
TOKENMETER_URL empty Base URL of light-tokenmeter’s HTTP port.
LISTEN_ADDR :8080 Listen address.
LOG_LEVEL info debug, info, warn, error.
INSECURE_NO_AUTH false Skip sign-in. Localhost PUBLIC_URL only.
OIDC_ISSUER Google Advanced: another OpenID Connect issuer that returns verified e-mails.

Deployment

A minimal Caddy configuration:

admin.example.com {
    reverse_proxy llm-proxy-admin:8080
}

What the pages do

Security model

Development

make test    # go test -race ./...
make dev     # run on :8080 without Google sign-in (set LLM_PROXY_* and/or TOKENMETER_URL)
make proto   # regenerate internal/gen from proto/ (needs buf)