Let only your customers call it
Alice, the platform engineer, puts the model qwen-chat on eks-prod behind a JWT policy from your identity provider; for a quick test, API keys that AstroPulse keeps for you. Bob, a developer at your customer, then gets an answer with his token, and a request without one is refused.
Before you start
eks-prod(your cluster's name) hasgateway,cert-managerandmodel-serving;apps.example.com(a domain you own) is verified.external-dnsis optional: without it, create the DNS record by hand.- JWT (production): your issuer and JWKS address, reachable from the cluster.
1. Alice creates the policy: API keys or JWT
Path: Integrations > Access Policies
- Identity provider (OIDC): name, Issuer (exactly the
issin your tokens), JWKS URI (optional: found from the issuer), Audiences (theaudyour tokens carry for this model) and Required claims (for examplesub). A token passes when its signature verifies with a key from the JWKS, itsissequals the issuer exactly, itsaudcontains one of the audiences, it is unexpired and every required claim holds. Select Test a token on the policy row, or runastroctl access-policy test <policy> --token-file t.jwt, which returnsaccepted,reasonandmessageas the endpoint would judge it. A workload on a Kubernetes cluster can use its own service-account token: the EKS example. - Or, for a quick test, API keys: Policy name
inference-callers(a name for your access policy), Create. AstroPulse holds the keys, so there is no Secret to create. - API keys only: on the policy row select Keys, then Create key. Enter a Label naming who the key is for, such as
first-caller, and an optional expiry. Copy the value. The endpoint readsNot workinguntil the first key exists. - Or from a terminal:
astroctl access-policy key create inference-callers --label first-caller. It prints thekeyonce;astroctl access-policy key list inference-callersshows ID, label, created and expiry, never a value.
Hand it to the caller when you create it. AstroPulse never lists a key's value again.
2. Alice attaches it to the model
Path: Workloads > Models > qwen-chat > Update > Access (qwen-chat is your model deployment's name)
- Serve on
apps.example.com(your domain). - Who may call it: your policy. Exposure is refused without one.
- Review, then apply.
On a model already served, as in the picture, the hostname is fixed and only Who may call it changes. The line under it reads Callers present JWT, or Callers present API keys for a test policy.
3. Alice gives Bob a credential
Path: Workloads > Models > qwen-chat > Overview
- JWT: your identity provider issues Bob's token. API keys: Alice made Bob's key in step 1.
- Wait for the endpoint to change from
Not ready yettoReady for callers. The pill can also readOpen to anyone,Not workingorClosed to callers. The line under Try it then startsCallers must send an API key from access policy <name>.or, for an identity provider,Callers must send a token that access policy <name> accepts.
4. Alice calls it the way Bob will
Path: Workloads > Models > qwen-chat > Call it from code
- Set
ASTROPULSE_API_KEYto a service-account key from Settings, Service Accounts, then run the code with Bob's credential.
from astropulse import Client
ap = Client() # reads ASTROPULSE_API_KEY
application = ap.applications.get_application("qwen-chat")
print(application.data.model.external_endpoint)
from openai import OpenAI
client = OpenAI(base_url=application.data.model.external_endpoint,
api_key="<key or JWT the policy accepts>")
client.chat.completions.create(
model="<model-name>", # the name shown in Call it from code
messages=[{"role": "user", "content": "Hello"}],
)
The same call with curl; both send the credential as Authorization: Bearer <credential>; a policy with apiKeys.header: x-api-key takes x-api-key: <your-key> instead.
ENDPOINT=$(astroctl app endpoint get qwen-chat -o json | jq -r .url) # https://<hostname>/v1
curl -s "$ENDPOINT/chat/completions" \
-H "Authorization: Bearer <your-key-or-token>" \
-H "Content-Type: application/json" \
-d '{"model": "<model-name>", "messages": [{"role": "user", "content": "Hello"}]}'
A call without a credential, or with a wrong, revoked or expired one, is refused with 401. A token for another audience, or a valid token that lacks a required claim, is refused with 403. For what each refusal means and what to do next, see When a call is refused.
To check without code, select Try it in the Models list or on the model's Overview and paste a key or token the policy accepts; the page keeps it until you reload or leave. Try it is off until the endpoint is serving, and off for an embeddings model, because a chat gets 404 from one.
5. Alice rotates a credential
Path: Integrations > Access Policies
- JWT: rotate the signing key in your identity provider; AstroPulse reads its JWKS.
- API keys: on the policy row select Keys, then Revoke beside the caller's key and type its label to confirm. It stops on every model that uses the policy within a minute, not instantly, with no restart.
The confirmation names them (qwen-chat will refuse every caller until a new key is created.) and asks you to type the policy name instead of the label; expired keys do not count. astroctl access-policy key revoke prints the same warning and asks for the policy name. A revoke is never blocked, so a leaked key can always be cut off at once.
6. Alice closes the endpoint
Path: Workloads > Models > qwen-chat > Overview > Endpoint
- Select Close endpoint and confirm in Close this endpoint?. To open it again, select Reopen endpoint.
Nova reads the model's endpoint and answers. Create policies and keys in the console or with astroctl.
The Anyone option (no authentication) lets anyone who finds the URL run inference on your GPUs. It needs an org Owner and is audited. In production, use JWT with audiences and required claims set.
Clean up
Delete the model first, because a policy that an application references cannot be deleted. Then under Integrations > Access Policies select Delete on the policy, type its name, and confirm with Delete policy. For the full order, see Clean up.