The key-application service
Note
Part of the upcoming 0.2 line. The service sources are in services/access/ on the
main branch. The procedure below describes the intended deployment; the service’s
README and its example configuration list the exact setting names and are
authoritative where they differ.
The key-application service receives applications for model keys from the website, lets
the kLLM team review them in the administration console, and delivers the key files of the
granted catalog models to approved applicants (Model keys). It is a small
Python application (FastAPI served by uvicorn) with a SQLite database. It is separate from
the kllm package and is not needed to use kLLM. In production it is served under
https://kllm.agentnetwork.org.cn/api, with the administration console at
https://kllm.agentnetwork.org.cn/admin/ and the application form at
https://kllm.agentnetwork.org.cn/apply.
Interfaces
Endpoint |
Purpose |
|---|---|
|
List the catalog models that applicants may request, for the application form. |
|
Submit an application: name, email address, organization, role, country, intended use, the catalog models applied for and agreement to the terms. A hidden field rejects automated submissions, sizes are limited and submissions are rate-limited per client address and per email address. |
|
Confirm the email address of an application through the one-time link sent to it. |
|
Report that the service is running, for health checks. |
|
The one-time delivery page of an approved applicant, and the download of the archive of granted model keys from it. |
Administration endpoints |
List, filter and view applications; approve with a grant of catalog models, reject or request more information; add notes; issue, reissue or revoke key delivery; view the audit log; export CSV. They require an administrator session and are used through the administration console. |
Security properties
Administrator sessions use a cookie marked
HttpOnly,SecureandSameSite=Strict, and every state-changing request carries a CSRF token header. Passwords are hashed with scrypt; a second factor (TOTP) can be enabled per account.Key delivery. Model key files are read from a directory configured on the server, one file per catalog model, when a delivery link is issued (to check that they exist) and when it is used. They are never stored in the database and never sent by email. An approved applicant receives an email with a one-time, expiring download link to an archive that holds the key files of the granted models.
Audit. Every administrator action is recorded in an audit log.
Origins. Cross-origin requests are accepted only from the configured website origin, and responses carry strict security headers.
Retention. Rejected and stale applications are deleted or anonymized after a configured period.
The service holds personal data. The website’s privacy page describes what the form collects and how long it is kept; keep it consistent with the retention setting.
Configuration
The service is configured through environment variables, normally kept in an .env file
next to the Compose file. services/access/.env.example lists every variable with its
default; services/access/README.md describes them in full. Variables ending in _FILE
read a secret from a file and take precedence over the plain variable. The main settings:
Variable |
Purpose |
|---|---|
|
Required, at least 32 characters. Keys the hashes of client addresses and email addresses. |
|
The external HTTPS address under which the reverse proxy exposes the service’s
|
|
The address of the public website, whose origin is the only origin allowed to call
the public form endpoints, and the page that verification links redirect to
(default |
|
The origins of the administration console (default: the origin of
|
|
The SQLite database file. Place it on a persistent volume. |
|
The addresses whose forwarding headers are trusted, that is, the reverse proxy. |
|
The directory of model key files, one per catalog model, named after the catalog
model: |
|
Optional. The passphrase of the issued key files, shown on the delivery page and never in email. When it is unset, the delivery page states that the kLLM team provides the passphrase separately. |
|
The catalog models that applicants may request: a catalog file in the format of
|
|
The mail backend ( |
|
How long a verification link and a key download link stay valid (defaults 48 and 72 hours). |
|
Administrator sessions: the |
|
Rate limits per client address and per email address, and the sign-in lockout. |
|
Whether expired records are anonymized or deleted, the retention periods per record state (defaults: unverified 14 days, rejected 90, inactive with information requested 180, approved 730, audit entries 730) and how often retention runs. |
Outgoing mail
Production mail is sent from hi@anet0.com, a Tencent Exmail mailbox. Exmail accepts
authenticated SMTP with implicit TLS on port 465:
ACCESS_MAIL_BACKEND=smtp
ACCESS_SMTP_HOST=smtp.exmail.qq.com
ACCESS_SMTP_SECURITY=ssl
ACCESS_SMTP_PORT=465
ACCESS_SMTP_USERNAME=hi@anet0.com
ACCESS_SMTP_PASSWORD_FILE=/run/secrets/smtp_password
ACCESS_MAIL_FROM=kLLM <hi@anet0.com>
ACCESS_MAIL_REPLY_TO=hi@anet0.com
Credentials. The user name is the full mailbox address. Keep the password out of
.envand the repository: put it in a file readable by the service only and name the file inACCESS_SMTP_PASSWORD_FILE. Where the mailbox requires a client-specific password for SMTP clients, generate one in the Exmail web console and use it here instead of the sign-in password.Sender. Exmail sends only for the authenticated mailbox, so the address in
ACCESS_MAIL_FROMmust behi@anet0.com. Information requests are answered by email;ACCESS_MAIL_REPLY_TOdirects replies to the monitored mailbox.Check.
python -m access checkvalidates the configuration, andpython -m access mail-test --to ADDRESSsends a test message with the mail settings. During development,ACCESS_MAIL_BACKEND=consolewrites messages, including their links, to the log instead; never use it in production.
Deployment
The service ships with a Dockerfile and a Compose file. A typical deployment runs one
container behind a TLS-terminating reverse proxy on a host operated by the kLLM team.
Prepare the host. Create a directory for the database on persistent storage, and a key directory that only the service’s container can read. Issue the key file of each catalog model into it with
tools/catalog/issue_key.pyon the machine that holds the master key (Issuing model keys); the master key itself never goes to this host.Configure. Copy
services/access/.env.exampleto.env, set the variables listed above, and keep the file readable by the operator only. It contains the SMTP credentials.Start the service. From
services/access:$ docker compose up -d --build
The service listens on a local port for the reverse proxy; do not publish that port to other hosts.
Configure the reverse proxy. Terminate TLS for the service’s public address and forward requests to the local port. Make sure the service sees the client address, because per-address rate limits otherwise apply to the proxy’s own address. Serve the administration console from the same site (The kLLM website). Every route of the service is under
/api, so a single proxy location that passes the path through unchanged covers it; Production deployment gives the production layout.Check health.
$ curl -s https://kllm.agentnetwork.org.cn/api/health
Point the website at the service. When the website is served from the same origin as the service, as in production, build it with
VITE_ACCESS_APIunset; otherwise set it to the service’s public address (The kLLM website).
Issuing model keys
The key of each catalog model is derived from the catalog’s master key, which the kLLM team keeps offline (Keys). On the machine that holds the master key, write the key file of each catalog model with a passphrase for the issued files, then copy the files to the service’s key directory:
$ python tools/catalog/issue_key.py Qwen3-8B-kllm --master master.key -o keys/Qwen3-8B-kllm.key
issue_key.py reads the master key’s passphrase from KLLM_PASSPHRASE or the terminal,
and the passphrase of the new file from KLLM_NEW_PASSPHRASE or the terminal. Only the
derived model key goes into the file. Use the same passphrase for every issued file when it
is shown on the delivery page through ACCESS_KEY_PASSPHRASE. The service reads the
public fingerprint of each file without the passphrase. python -m access keys and the
console’s settings summary list, for every catalog model, whether its key file is present
and its fingerprint:
$ docker compose exec access python -m access keys
Administrator accounts
Administrator accounts are created on the host, not through the web interface:
$ docker compose exec access python -m access admin create --email reviewer@example.org --totp
The command asks for the password and, with --totp, enrols a second factor
interactively. python -m access admin --help lists the other account actions (list,
set-password, disable, enable, totp-enable, totp-disable). Create one account per person, so that
the audit log identifies who acted, and enable the second factor for every account.
Reviewing applications
A new application appears in the console’s queue once its email address is confirmed.
Review the stated intended use and the catalog models applied for. Approve with a grant of one or more catalog models, reject, or request more information; add notes for other reviewers. A grant can be narrower than the request, and it can be changed later; every change is recorded in the audit log.
For an approved application, issue key delivery. The applicant receives an email with the one-time download link. The delivery page explains what a model key is, a key shared by every applicant approved for that model that is not a confidentiality boundary, and offers one archive with the key file of each granted model and instructions (
kllm key import qwen3-8b-kllm Qwen3-8B-kllm.key, thenkllm runwith the model).The console shows whether the link has been used or has expired. Issue a new link if needed, or revoke an unused one.
The console also shows the number of applications per day and the approval rate.
Operations
Backups. Back up the SQLite database file regularly while the service is idle, or with the
sqlite3.backupcommand. The key directory is not part of the backup; the key files can be issued again from the master key at any time.Updates. Rebuild and restart the container with
docker compose up -d --build.Logs. The container logs record requests and errors. They are not the audit log, which is kept in the database and shown in the console.
New catalog models. When a catalog model is added, issue its key file into the key directory and add the model to
ACCESS_CATALOG_FILEorACCESS_CATALOG_MODELSso that applicants can request it.Key rotation. When the key version of a catalog model is raised, issue the new key file into the key directory under the same name. Future deliveries carry the new key; copies of the model downloaded earlier still need the earlier key.
Upgrades from the community key.
ACCESS_KEY_FILEandACCESS_KEY_FILENAMEare no longer accepted; the service refuses to start while either is set. Replace them withACCESS_KEY_DIR.
See also
Model keys for what a model key is and is not.
The catalog of official sealed models for the catalog models and their keys.
The kLLM website for the public site and the administration console.