Give callers API keys
Give each caller of a model its own API key. AstroPulse keeps the keys in its vault, shows each value once, and lets you rotate or revoke one at any time without a redeploy. For your own services, prefer tokens from your issuer. The example: policy partner-keys, model qwen-chat, caller partner-a.
Before you start
- A model on a verified domain, on a cluster with the Gateway add-on. See Access policies.
- An organization owner creates the policy. An owner or admin creates and revokes keys; for anyone else Keys is disabled.
In the console
-
Open Integrations > Access Policies and select API keys.
-
In New API-key policy, enter the Policy name
partner-keysand select Create. "AstroPulse holds the keys for this policy. Create them after saving; each key is shown once."Open zoom view -
On the policy's row, select Keys. Keys for partner-keys opens: "No keys yet. Models using this policy refuse every caller until you create one."
-
Enter a Label that says who the key is for, such as
partner-a, optionally a date under Expires (optional), and select Create key.Open zoom view -
Copy the key: "Copy this key now. You will not see it again." Hand it to the caller then.
-
Attach the policy to the model under Who may call it on the Access step of Deploy model. See Access policies.
You should see
The key is listed in Keys for partner-keys with its label, "Created" date and "Never expires" or its expiry. On the model's Overview, the Endpoint section reads Ready: "Callers must send an API key from access policy partner-keys."
How keys reach the endpoint
A policy with no keys yet serves nothing: an endpoint using it reports Error and its route is withdrawn. A new key reaches every model on the policy within about a minute, with no redeploy or reopen, and the endpoint then opens by itself. If it reads Pending after that, its message says what it still waits for, such as DNS or a certificate.
AstroPulse keeps a policy's keys once, in its vault, and places them once on each cluster that runs a model using the policy, whatever the number of models. A revoked or expired key stops working on every one of them within a minute, with no restart. Every create and revoke is audited without its value. A policy holds at most 32 keys at a time.
Rotate a key
- Create a new key for the same caller, for example
partner-a-2. - Hand it over and let the caller switch to it.
- Revoke the old key.
Revoke a key
In Keys for partner-keys, select Revoke beside the key and type its label to confirm in Revoke key: "Every model using partner-keys stops accepting this key within a minute. This cannot be undone."
Revoking a policy's last unexpired key takes every open endpoint on it offline. The confirmation then names them, for example "This is the last API key of access policy partner-keys. qwen-chat will refuse every caller until a new key is created.", and asks you to type the policy name instead. A revoke is never blocked, so a leaked key can always be cut off at once.
Call a model with an API key
The caller sends the key in the header the policy names (apiKeys.header):
apiKeys.header | The caller sends |
|---|---|
Authorization (the default) | Authorization: Bearer <your-key> |
x-api-key | x-api-key: <your-key>, with no Bearer prefix |
The model's Overview shows the same under Call it from code.
ENDPOINT=$(astroctl app endpoint get qwen-chat -o json | jq -r .url) # https://<hostname>/v1
AP_KEY='<your-key>'
curl -s "$ENDPOINT/models" -H "Authorization: Bearer $AP_KEY"
curl -s "$ENDPOINT/chat/completions" \
-H "Authorization: Bearer $AP_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "<model-name>", "messages": [{"role": "user", "content": "Hello"}]}'
The openai Python package sends api_key as Authorization: Bearer <key>, which a policy with the default header expects:
from openai import OpenAI
client = OpenAI(
base_url="https://<hostname>/v1", # the endpoint's url
api_key="<your-key>", # read it from a secret store, never commit it
)
reply = client.chat.completions.create(
model="<model-name>", # an id from GET /v1/models
messages=[{"role": "user", "content": "Hello"}],
)
print(reply.choices[0].message.content)
Your own Secret (last resort)
Use this only if managed keys and tokens cannot work for you. Set secretRef instead of managed: the policy then reads an Opaque Secret you create and rotate in the model's namespace, and AstroPulse issues, lists and revokes nothing. Each entry is one caller: the entry name identifies the client, and the value is a raw key of at least 16 characters, with no Bearer prefix.
apiVersion: platform.astropulse.io/v1
kind: AccessPolicy
metadata:
name: partner-own-keys
spec:
apiKeys:
secretRef:
name: partner-caller-keys
The namespace is the application's own, which AstroPulse generates. Read it after the model is deployed with astroctl app get <app> -o json | jq -r .targetNamespace, or on the model's Overview. Create the Secret there, then attach the policy. The gateway picks up a changed entry within seconds. A kubectl apply of a manifest without a key merges, so the key stays: remove one with kubectl edit or kubectl patch.
Other ways in
- Nova: ask it, for example "create a key for partner-a on partner-keys".
- SDK and API: the same operations, in the API reference.
With astroctl
apiVersion: platform.astropulse.io/v1
kind: AccessPolicy
metadata:
name: partner-keys
spec:
apiKeys:
managed: true # AstroPulse keeps the keys
header: Authorization # or x-api-key
astroctl access-policy apply -f partner-keys.yaml
astroctl access-policy key create partner-keys --label partner-a
astroctl access-policy key create partner-keys --label partner-b --expires-at 2027-01-01T00:00:00Z
astroctl access-policy key list partner-keys # ID, LABEL, CREATED, EXPIRES; never a value
astroctl access-policy key revoke partner-keys <key-id> # asks you to type the key ID; -y in scripts
key create prints "Store this key now: AstroPulse does not show it again. A new key works within about 10 seconds." and then the key once. In a script, write it to a file only you can read, and never echo it into a log:
umask 077
astroctl access-policy key create partner-keys --label partner-a -o json > partner-a.json
With -y, revoking the last key still prints the warning. Every flag: astroctl access-policy key.
Settings
The policy's own fields are on Access policies. A key has:
labelRequiredWho the key is for. Listed with the key; never the value.
expiresAtWhen the key stops working. The console sets the end of the chosen day.
2027-01-01T00:00:00Z.If it's refused
--label).secretRef).managed: true.A caller's call refused with 401: API key refused walks through the header, the key, its expiry and the policy.
Next
- Access policies: attach the policy, check the endpoint, close it.
- Let your services call with tokens
- Serve a model