Skip to main content

Service accounts

A service account is a directory identity for a workload instead of a person. An agent, job, or service running in Kubernetes calls the AI Gateway and the Connector Gateway as its service account by presenting the projected ServiceAccount token Kubernetes gives its pod. There's no key to issue, store, or rotate. The account has its own groups, model set grants, and budget, and its spend is attributed to it.

Use a service account when a Kubernetes workload should act independently of any user. Use a virtual API key when a script or CI job should act as a person: the key carries its owner's access and budget, and the client stores it.

How a workload is recognized​

A workload's token signs it in when three conditions hold:

  • A trusted issuer tells Stacklok Enterprise which cluster's tokens to accept: the cluster's issuer URL, where its public signing keys are, and the audience workloads request their token for.
  • A binding maps the workload's Kubernetes ServiceAccount, by namespace and name and optionally its UID, to one service account.
  • The service account is Active.

After sign-in, the account's model access and budgets decide which models it can call, and its groups decide which connectors it reaches, as they do for a user. See What an account can reach.

Prerequisites​

  • Each gateway the workload calls, set up for workloads. For the AI Gateway, a cluster administrator completes Accept service account workloads once per installation. The Connector Gateway accepts workloads by default when it connects to the Enterprise Manager over TLS.
  • The platform admin grant, which covers directory administration.
  • The Kubernetes ServiceAccount the workload runs as. Stacklok Enterprise doesn't create it. Note its namespace and name.

In the console, select Administration under Experience in the account menu, then open Service Accounts.

Trust the cluster's issuer​

Each cluster whose workloads call the gateways needs one trusted issuer. You can also add an issuer from the Bindings step when you create an account.

  1. Open the Trusted issuers tab and select Add issuer.

  2. Choose where the issuer is:

    • This cluster trusts the cluster that runs Stacklok Enterprise. Gateways read its keys from the Kubernetes API, so choose it only when every gateway runs in this cluster. For Issuer URL, enter the issuer this command prints, which on managed clusters such as Amazon EKS is a public URL:

      kubectl get --raw /.well-known/openid-configuration | jq -r .issuer
    • Another issuer trusts any other cluster. Enter its public Issuer URL, then give its public keys as a JWKS URL or with Upload JWKS.

  3. Enter an Audience that only Stacklok Enterprise accepts, such as stacklok-enterprise-platform. Workloads request their token for this audience, so share it with the teams that deploy them.

  4. Select Add issuer.

Both gateways pick up a new or changed issuer on their next poll of the directory, every 30 seconds by default.

The default Signing algorithms, under Advanced, accept RS256. Change them only when the cluster signs its tokens with another type of key.

Disabling an issuer stops its workloads from signing in and keeps their bindings, so enabling it again lets them back in. You can delete an issuer only when no binding uses it.

Create a service account​

On the Accounts tab, select New service account. The wizard walks through five steps, and every step after Details can be skipped and completed later from the account's tabs.

  1. Details: enter a Name and a description that says which workload uses the account.

  2. Connectors: add the account to groups, or create one, and choose each group's connectors. The account gets everything a group confers: its connectors, budget pool, and model set grants. A change to a group's connectors applies to every member of the group. The list leaves out groups managed through SCIM and connectors that can't serve a service account.

  3. Model Sets: grant model sets directly, and optionally set a Budget amount and period. The All Users model set and the organization default budget never apply to a service account. A workload that calls the AI Gateway therefore needs model set grants and a budget from this step or from its groups, unless the gateway turns those controls off, as described in What an account can reach. A workload that only calls connectors needs neither.

  4. Bindings: choose the Issuer URL, then enter the Namespace and ServiceAccount name of the workload's ServiceAccount. To pin the binding to that exact ServiceAccount, also enter its UID:

    kubectl get serviceaccount <SERVICE_ACCOUNT_NAME> -n <NAMESPACE> \
    -o jsonpath='{.metadata.uid}'
  5. Review: check the summary and select Create and activate service account.

Without a binding, the button reads Create service account and the account is created Suspended. A service account authenticates only while it's Active, and activating it requires at least one binding to an enabled issuer. Add a binding on the account's Bindings tab, then select Activate in the alert on its page.

Once the account is active, the team that deploys the workload configures it as described in Call the AI Gateway from Kubernetes workloads and Call the Connector Gateway from Kubernetes workloads. One token serves both gateways.

Choose between a pinned and a name-only binding​

A name-only binding matches any ServiceAccount with its namespace and name. That includes a ServiceAccount deleted and created again under the same name, and one created by anyone who can create ServiceAccounts in that namespace, which the built-in Kubernetes edit role allows. Pin the UID when the account's grants and budget are worth more than what the cluster already grants that ServiceAccount name.

A pinned binding still admits every pod that runs as its ServiceAccount, and anyone who can create pods in the namespace, which the edit role also allows, can run a pod as that ServiceAccount and get its token. For an account with sensitive grants, also restrict who can create pods in that namespace.

A pinned binding takes precedence over a name-only binding for its UID. When another account already reaches the same ServiceAccount by name, the console asks you to confirm with Reassign. The new account takes over the ServiceAccount with that UID, and the other account keeps its name-only binding for any other ServiceAccount with that name, such as one created again later.

To change a binding, remove it from the account's Bindings tab and add a new one. Each change applies on the workload's next request.

Revoke a workload's access​

To stop a workload at once, suspend its account from the account's actions menu. The gateways refuse the workload's next request, and requests already admitted finish.

Removing the account's binding also stops the workload, unless another account has a name-only binding for the same ServiceAccount, as after a Reassign. That account then takes the workload over on its next request, so remove its binding too, or suspend the account instead.

A token already issued keeps working until it expires, up to 60 minutes, even after you delete the Kubernetes ServiceAccount, because the gateways verify tokens by their signature. With a name-only binding, a ServiceAccount created again under the same name is the account again.

An account that loses its last binding, or whose issuers are all disabled, stays Active but its workloads are refused. Its page shows Active, but its workloads can't authenticate with a link to fix it.

Deleting a service account is permanent. It removes the account's bindings, group memberships, and model set grants, and deletes its own budget. The account is kept with the status Deleted, so its past spend remains attributed to it. The Accounts tab shows deleted accounts when you filter Status by Deleted.

What an account can reach​

A trusted issuer accepts tokens from every namespace in its cluster, and the gateways refuse any workload without an active, bound account.

An account reaches a connector only through a group the connector is granted to, and only when the connector uses None, Bearer token, or Header injection authentication. The other authentication types act as the calling person, and a service account has no person behind it. An account has no connections to make, so the gateway serves it every connector it reaches. The account's Connectors tab lists the connectors granted to its groups and the group each one comes through, marks the ones it can't use as Not available to service accounts, and lets you change its groups and their connectors. Connectors governed by a Cedar policy aren't listed there. A connector's Activity tab shows the account's tool calls under its name, with a Service account badge.

The AI Gateway's model access and budget settings decide which models the account can call:

Model access (modelAccess.enabled)Budgets (budgets.endpoint)An active, bound account can call
OnSetThe models its grants cover, within budget
OnEmptyThe models its grants cover, unmetered
OffSetAny model, within budget
OffEmptyAny model, unmetered

A gateway with an empty budgets.endpoint renders only with budgets.acknowledgeUnmetered: true, and model access then needs its own modelAccess.endpoint, which otherwise defaults to the budget endpoint. Users get the same treatment, so a gateway with neither model access nor budgets admits every bound workload as freely as every signed-in user. See Control model access and Budgets and pricing.

Next steps​

Troubleshooting​

Activate is unavailable

The account has no binding, or every issuer its bindings use is disabled. Add a binding on the account's Bindings tab, or enable an issuer on the Trusted issuers tab.

A workload is refused with 401 or 403

See Handle errors for the AI Gateway or the Connector Gateway for what each response means and where to find the reason.