Outcome
By the end of this lesson, you will be able to design AI access using the two first-class capabilities, explain why one is Admin-only to mutate and the other is not, and apply provider scoping as a third policy segment.
| Tier | Architect |
| JTBD | ”Let teams manage their own AI keys without letting them connect provider credentials.” |
| Personas | Security/Compliance · Engineering Leader |
| Prerequisites | M3.10.L3 · M3.1 (RBAC) |
| Time | 9 minutes |
| Bloom verb | Design (Create), Explain (Understand), Apply (Apply) |
1. Concept
AI access runs through the same permission system as everything else.
There is no separate path for it. The AI capabilities sit in the role matrix and the policy table alongside resource and schedule, and are enforced in the same place.
TWO FIRST-CLASS CAPABILITIES
AI VIRTUAL KEY virtual-key:{view,create,update,delete} AI MODEL ai-model:{view,create,update,delete}
PLUS AI cost/usage reads stay on ai-usage:viewThe split, and the rule behind it
The two capabilities have different default role assignments, and the rule that decides it is one you already know from M3.1:
Connecting a credential is Admin.
AI VIRTUAL KEY A budget-bounded consumption artifact over models that are ALREADY connected. It accepts no provider secret.
So, like resource / schedule / dashboard: EDITOR GETS FULL CRUD.
AI MODEL A provider CREDENTIAL-CONNECTION surface. It accepts a provider API key or free-form params, and it can mint Bedrock STS credentials off a connected AWS account.
So, like cloud-account / integrations: ADMIN-ONLY TO MUTATE. EDITOR IS VIEW-ONLY.
VIEWER view-only on all AIADMIN full CRUD on bothThat asymmetry is the whole design, and it lands exactly where you would predict if you had internalised M3.1: the thing that touches a credential is Admin, and the thing that spends within already-connected capacity is not.
Two gating details worth knowing
ROTATION GATES ON UPDATE, NOT CREATE. POST /ai/keys/{id}/rotations is authorised by virtual-key:update rather than the POST-default create.
WHY: rotation REVOKES the old key. It destroys something. A create-only role must not be able to destroy a key by rotating it.
ai-model:update GATES A ROUTE THE UI DOES NOT USE YET. It authorises the dedicated deployment-edit endpoint, available to API clients. The frontend has no model-edit UI today, so editing in the app still rides ai-model:create.The rotation detail is a good example of a verb being chosen by consequence rather than by HTTP method. A POST that destroys is an update.
Provider scoping: the third segment
Provider scoping generalises the resource-type scoping you met on resource:view:ec2.
virtual-key:<verb>:<provider>ai-model:<verb>:<provider>
e.g. virtual-key:create:bedrock
A SCOPED ROLE can view, create, edit and delete onlythat provider's keys, and manage only that provider'smodels.
A BROAD GRANT means all providers, exactly asresource:view means all resource types. Backwardcompatible.The Scope dropdown in the role matrix is fed the org’s connected providers, so it offers real options rather than a fixed list.
Where scoping is enforced, and the one exception
This is the subtle part, and it follows from where the data lives.
THE MODEL ALLOW-LIST IS IN THE REQUEST BODY, NOT THE URL.
So the GATEWAY grants the capability, and CONFIGENFORCES THE PROVIDER NARROWING on the body or entity:
create checks the NEW models' providers update/delete/ check the TARGET key rotate list HIDES keys outside the caller's providersTHE ONE EXCEPTION: THE MODEL LIST IS A SHARED READ.
ai-model:view scope is a NO-OP on the list. Providerscope narrows model create and delete, NOT view.So a Bedrock-scoped role sees every registered model and can only manage Bedrock ones. That is deliberate: the model list is reference data, and hiding models a caller cannot manage would make it impossible to understand what the org offers.
The create-key picker is separately filtered to the caller’s allowed providers, as defense in depth: the enforcement is in Config, and the UI does not offer choices that would be rejected.
Designing with it
TYPICAL SHAPES
A DEDICATED MODEL MANAGER ai-model:{view,create,update,delete} plus virtual-key:view Someone who curates what the org offers without managing team spend.
A PROVIDER-SCOPED KEY MANAGER virtual-key:{view,create,update,delete}:bedrock A team lead who manages their own Bedrock keys and cannot touch anyone else's provider.
A COST READER ai-usage:view only FinOps, reporting on AI spend, managing nothing.The third one is worth noting: AI cost reads are a separate capability from both key and model management, so someone can report on AI spend without any ability to change it.
2. Demo
Designing AI access for a four-team org:
THE REQUIREMENT - platform team curates which models exist - each product team manages its own keys - FinOps reports on spend, changes nothing - nobody outside platform connects a provider
DESIGN
platform-lead ADMIN Needs to connect providers, which is a credential connection. Only role that can.
platform-engineer custom: ai-model:{view,create,update,delete} virtual-key:view ai-usage:view Curates the model catalogue. Cannot connect a provider (that is a cloud-account/integration action at Admin), cannot manage team keys.
product-team-lead x4 EDITOR Editor already carries full CRUD on AI Virtual Key, because a key is a consumption artifact over already-connected models. Editor is VIEW-ONLY on AI Model, so a team lead cannot register a model and quietly introduce a new provider credential. NO CUSTOM ROLE NEEDED. This is the case the default split was designed for.
finops-analyst custom: ai-usage:view plus their existing cost policies Reports on AI spend by provider, model, tier and team. Manages nothing.
THE ONE CUSTOM SCOPED ROLE A contractor team working only on a Bedrock-based feature:
virtual-key:{view,create,update,delete}:bedrock
They manage their own Bedrock keys and cannot see or touch keys for other providers: the list hides them.
They CAN see the whole model list, because ai-model:view scope is a no-op on the list. That is intentional: reference data.
WHAT THE DESIGN AVOIDED The first draft gave every product-team lead a custom role. Reading the default split showed that Editor already did exactly what was wanted, and four custom roles were deleted before they were created.3. Hands-on (6 min)
1. In the role matrix, find the two AI capabilities. Confirm the defaults: Editor on AI Virtual Key: full CRUD / view-only Editor on AI Model: full CRUD / view-only
2. Explain the asymmetry in one line, using the rule from M3.1: ______________________________________________
3. Check the Scope dropdown for a provider-scoped role. Which providers does it offer? ______________________________________________ (It is fed your CONNECTED providers.)
4. Create a provider-scoped test role. Confirm: can it see other providers' KEYS? Y / N can it see other providers' MODELS? Y / N (Expected: no, and yes.)
5. Identify who in your org needs ai-usage:view WITHOUT any management capability: ______________________________________________4. Knowledge check
Q1
Why does Editor get full CRUD on AI Virtual Key but only view on AI Model?
A. Because models are more expensive to change
B. Because model registration requires a migration
C. Because the split follows the “connecting a credential is Admin” rule
D. Because virtual keys are personal, whereas the models are org-wide
Show answer
Correct: C. A virtual key is a budget-bounded consumption artifact over already-connected models and accepts no provider secret, like resource or schedule. AI Model registration is a credential-connection surface that accepts a provider API key and can mint Bedrock STS credentials, like cloud-account or integrations. D is wrong twice: virtual keys are org-visible rather than personal (L3), and both are org-wide. The credential rule is the one that predicts this and every similar split in the product.
Q2
Rotating a virtual key is a POST, but it is gated on virtual-key:update rather than create. Why?
A. Because rotation modifies an existing record
B. Because rotation revokes the old key: it destroys something
C. Because create is reserved for the initial provisioning
D. Because the rotation endpoint is nested under the key id
Show answer
Correct: B. A create-only role must not be able to destroy a key by rotating it, so the verb is chosen by consequence rather than by HTTP method. A is technically true and misses the point: the reason to care is the destructive half. This is a useful pattern to recognise generally, since a POST that destroys is an update.
Q3
A role scoped to ai-model:view:bedrock opens the model list. It sees:
A. Only Bedrock models
B. No models, since the scope does not match the list route
C. Bedrock models plus any model on a key they own
D. Every registered model
Show answer
Correct: D. The model list is a shared read and ai-model:view scope is a no-op on it: provider scope narrows model create and delete, not view, because the list is reference data and hiding models a caller cannot manage would make the org’s offering impossible to understand. Contrast with the virtual-key list, which does hide keys outside the caller’s providers. Keys are things you manage and models are things you reference, and the scoping follows that difference.
5. Apply
Check whether the default Editor split already does what you want before writing a custom role. In most orgs it does: team leads managing their own keys and unable to register models is exactly the shape the defaults were designed for.
Reserve provider scoping for the genuine case of a team that should be confined to one provider, and remember that it narrows key visibility and model management but not the model list.
Related lessons
- L4: Routing and spend reporting
- L3: Virtual keys and budgets
- T3.M3.1.L2: System roles
- T3.M3.1.L3: Custom roles
Glossary terms touched
virtual-key policy · ai-model policy · Provider scoping · ai-usage:view