Grant access to models
Aperture denies model requests that do not match a grant. However, the configuration shipped with a new Aperture gateway grants all users access to all models. Allow network access to Aperture through your tailnet, then narrow or replace the default grant to control which models each user or group can use.
For more information on how Aperture uses Tailscale identity for authentication and access control, refer to How Aperture works. For the model behind grants, including deny-by-default access and precedence, refer to how Aperture grants work.
Prerequisites
Before you begin, you need:
- An Aperture gateway with at least one configured provider.
- Admin access to the Aperture admin dashboard.
- Access to the Tailscale admin console.
Step 1: Allow network access to the Aperture gateway
Your tailnet access control rules must allow users to reach the Aperture gateway before they can access models.
- Sign in to the Tailscale admin console.
- Go to the Access controls page.
- Confirm that your access control rules allow users to connect to the Aperture gateway.
The following tailnet policy file example permits all users in group:ai-users to connect to the Aperture gateway with the hostname ai:
{
"groups": {
"group:ai-users": [
"dave@example.com",
"alice@example.com"
]
},
"hosts": {
"ai": "<aperture-ip-address>"
},
"grants": [
{
"src": ["group:ai-users"],
"dst": ["ai"],
"ip": ["tcp:80", "tcp:443", "icmp:*"]
}
]
}
Replace <aperture-ip-address> with the Tailscale IP address of your Aperture gateway.
You can also use Tailscale tags to manage access to the Aperture gateway. Assign a tag (for example, tag:ai) to the Aperture gateway and use it as the dst in your grant rule. For how the Aperture gateway is referenced in grants defined in the tailnet policy file, refer to Grants versus tailnet policy file grants.
Step 2: Configure grants to control model access
After users can reach the Aperture gateway, configure grants to define which models they can access. You can define these grants in the Aperture configuration or in the tailnet policy file. Aperture combines matching grants from both sources.
Open the Aperture admin dashboard and go to Administration > Grants.
At /admin/settings/grants, use the visual grant editor, or edit the same grants as JSON at /admin/settings/config, on the Administration > Configuration page.
To change the configuration programmatically, refer to the grants configuration reference.
The following example grants all users standard user access and lets them use all Anthropic models:
{
"grants": [
{
"src": ["*"],
"app": {
"tailscale.com/cap/aperture": [
{ "role": "user" },
{ "models": "anthropic/**" }
]
}
}
]
}
To restrict access, replace "*" with individual login names (for example, "alice@example.com"), Tailscale or SCIM groups (for example, "group:ai-users"), or tags (for example, "tag:ci"). Use a tag to grant access to non-user devices such as CI runners or services. Group matching requires visible groups enabled for the Aperture gateway.
The following example grants members of group:ai-users access to all Anthropic models:
{
"grants": [
{
"src": ["group:ai-users"],
"app": {
"tailscale.com/cap/aperture": [
{ "role": "user" },
{ "models": "anthropic/**" }
]
}
}
]
}
The grant examples on this page use Aperture configuration syntax, where the dst field is not required because the destination is the Aperture device itself. If you define grants in the tailnet policy file instead, you must include a dst key specifying the Aperture device (for example, "dst": ["tag:aperture"]). Omitting dst in a tailnet policy file grant causes the grant to silently have no effect. For a full comparison and conversion steps, refer to Aperture grants vs. tailnet policy file grants.
Each capability entry under tailscale.com/cap/aperture has these fields:
role: Set to"user"for standard API access or"admin"for administrative access. Theadminrole grants access to the admin dashboard. Portal access is available by default and is controlled separately withenable_portal.models: Optional. A glob pattern that specifies which models the user can access, inprovider/modelformat. For example,"anthropic/**"matches all Anthropic models, and"**"matches all models from all providers. An entry with nomodelsfield is floating. It applies regardless of model, and it grants no model access on its own.enable_portal: Optional. Portal access is available by default. Set it tofalseto opt matched non-admin users out, ortrueto override a broader opt-out. Admins always retain portal access. The legacyenable_chat_uifield has the same effect.connectors: Optional. An array of FQN globs that grant access to MCP tools, resources, and HTTP connector proxies. Because Aperture is deny-by-default, users have no connector access until an entry matches. Refer to grant MCP tool access for details.
Model pattern examples
The following examples show how to use patterns to grant access to specific models:
| Pattern | Matches |
|---|---|
"**" | All models from all providers |
"anthropic/**" | All Anthropic models |
"openai/gpt-5.5" | Exactly openai/gpt-5.5 |
"*/claude-sonnet*" | Any claude-sonnet* model from any single provider |
Grant access to tagged devices
Use a grant to give a CI runner or another tagged device access to models without giving access to every user. Find the device on the Machines page of the admin console and note its tags. Then choose a src value for the grant:
- To match any device carrying one tag, use
"src": ["tag:ci-runner"]. A device with additional tags still matches this grant. - To match only devices with an exact set of tags, use the synthetic login name for that tag set. To build it, sort the tags alphabetically and join them with commas, with no spaces. For example, a device with
tag:prodandtag:apihas the synthetic login nametag:api,tag:prod, so use"src": ["tag:api,tag:prod"]. This value matches every device with the same tag set, not one specific device. If the device's tags change, update the grant.
Add a role and a matching models capability, as shown in the earlier examples. Use "src": ["*"] only to give model access to everyone who can reach the gateway, including tagged devices. Do not use it to discover a device's tags.
Verify access
After configuring grants, verify that users can access the expected models.
-
Connect a test device to your tailnet.
-
Send a request to Aperture with
curlor any HTTP client. Use a model ID that matches a configured provider and yourmodelsgrant. Specify either the bare model name, for example,claude-sonnet-5-5, or the fullprovider/modelform:curl -s http://<aperture-hostname>/v1/messages \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-5-5", "max_tokens": 25, "messages": [{"role": "user", "content": "respond with: hello"}] }' -
Confirm that the request returns a successful response, which means the grant is working.
If the request fails, use the status code to identify the cause:
- HTTP 403: The user has no
rolegrant. Add a{ "role": "user" }entry. - HTTP 404: The user has a role, but no
modelsgrant matches the requested model, or the model is not configured on any provider. Check themodelspattern and confirm the model ID matches a configured provider.
Refer to Troubleshooting Aperture for help diagnosing access issues.
Next steps
- Grant access to connectors to control which MCP tools, resources, and HTTP APIs users can access.
- Set per-user spending limits to manage costs.
- Set up the chat UI to let users talk to models directly from their browser.
- Set up LLM clients to connect through Aperture.