Skip to main content

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​

  1. Open Integrations > Access Policies and select API keys.

  2. In New API-key policy, enter the Policy name partner-keys and select Create. "AstroPulse holds the keys for this policy. Create them after saving; each key is shown once."

    Open zoom view

    The New API-key policy form with a policy name, above the policy list

    The New API-key policy form with a policy name, above the policy listThe New API-key policy form with a policy name, above the policy list
  3. 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."

  4. 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

    Keys for a policy: an existing key with Revoke, and the Label and Expires fields with Create key

    Keys for a policy: an existing key with Revoke, and the Label and Expires fields with Create keyKeys for a policy: an existing key with Revoke, and the Label and Expires fields with Create key
  5. Copy the key: "Copy this key now. You will not see it again." Hand it to the caller then.

  6. 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."

Open zoom view

A model's Endpoint section reading Ready, with callers required to send an API key from its access policy

A model's Endpoint section reading Ready, with callers required to send an API key from its access policyA model's Endpoint section reading Ready, with callers required to send an API key from its access policy

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​

  1. Create a new key for the same caller, for example partner-a-2.
  2. Hand it over and let the caller switch to it.
  3. 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."

Open zoom view

The Revoke key confirmation, asking to type the key's label

The Revoke key confirmation, asking to type the key's labelThe Revoke key confirmation, asking to type the key's label

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.headerThe caller sends
Authorization (the default)Authorization: Bearer <your-key>
x-api-keyx-api-key: <your-key>, with no Bearer prefix

The model's Overview shows the same under Call it from code.

Open zoom view

Call it from code on a model's Overview: find the endpoint with the SDK, then call it with an OpenAI client and a key

Call it from code on a model's Overview: find the endpoint with the SDK, then call it with an OpenAI client and a keyCall it from code on a model's Overview: find the endpoint with the SDK, then call it with an OpenAI client and a key
Terminal
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:

Python
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.

partner-own-keys.yaml
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​

partner-keys.yaml
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
Terminal
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:

Terminal
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:

LabellabelRequired

Who the key is for. Listed with the key; never the value.

Accepts
1 to 63 printable characters.
Expires (optional)expiresAt

When the key stops working. The console sets the end of the chosen day.

Accepts
An RFC 3339 time in the future, such as 2027-01-01T00:00:00Z.
Default
Never expires.

If it's refused​

"a label naming who the key is for is required"
Cause
The key was created without a label.
Fix
Enter a Label (--label).
"an access policy holds at most 32 API keys; revoke one first"
Cause
The policy already holds 32 keys.
Fix
Revoke a key you no longer hand out, then create the new one.
"Access policy partner-own-keys does not keep its API keys in AstroPulse. Apply it with apiKeys.managed: true to create keys here."
Cause
The policy uses your own Secret (secretRef).
Fix
Manage the Secret yourself, or apply the policy with managed: true.

A caller's call refused with 401: API key refused walks through the header, the key, its expiry and the policy.

Next​