Skip to main content

Input Controls

RBAC

rbac decides what an authenticated caller may ask the model to do, based on the roles in its verified identity. You can limit which tools each role may declare, how sensitive the requested data may be, and which roles may send health information.

These rules apply to model traffic. Access to organization resources, such as agents and secrets, is a separate system: IAM roles.

Roles come only from the verified identity of the application token. An X-User-Role: analyst header does not give the caller that role.

Configuration​

Save this as a test configuration, or add it to your configuration with the config-first workflow. Replace analyst with a role from your verified identities.

policy-config.yaml
pack:
  name: analyst-tool-access
  version: 1.0.0
  enabled: true
policies:
  chain:
    - rbac
policy:
  rbac:
    require_auth: true
    roles:
      analyst:
        allowed_tools:
          - search
          - summarize
        denied_tools:
          - delete_*

Verify the access rule​

The offline test runner has no verified identity, so test through a gateway. Use a test token whose identity has the analyst role, and declare tools in the model request:

RequestResult
Declares only searchPasses this rule
Declares delete_recordBlocked with rbac.tool_not_allowed
Declares export_dataBlocked, because no rule allows it
Has no verified identityRejected by authentication, or blocked with rbac.missing_identity

The control checks the tools that the request declares. It does not run them, so your application must still authorize tool execution.

rbac: {} is the smallest valid block. It requires a verified identity and blocks every tool from an identity with roles, because no allowed_tools rule exists. If rbac is in the chain without any policy.rbac block, every request is blocked with policy.rbac_configuration_required.

Fields​

FieldTypeDefaultDescription
require_authbooleantrueBlocks a request without a verified identity. The schema shows false, but the runtime uses true. Set it explicitly.
deny_if_missingstring[][]Headers that must have non-empty values. The schema shows ["X-User-ID"], but the runtime uses an empty list.
rolesobject{}Rules by role name. Names must match the roles in the verified identity.
roles.<role>.allowed_toolsstring[][]Tool name patterns the role can declare. * matches any sequence, including an empty one.
roles.<role>.denied_toolsstring[][]Tool name patterns the role cannot declare. A deny wins over an allow.
data_accessobject{}Data sensitivity limits by role name
data_access.<role>.max_sensitivitystringpublicHighest verdictan.data_sensitivity the role can request: public, internal, confidential, or restricted, in that order
minimum_necessary.enabledbooleanfalseBlocks health-identifier text from roles that are not in allowed_phi_roles
minimum_necessary.allowed_phi_rolesstring[][]Roles that may send health-identifier text

How it works​

  1. The control reads the verified identity and its roles from the request context.
  2. A missing deny_if_missing header, or a missing identity with require_auth: true, blocks the request with rbac.missing_identity.
  3. If roles is not empty and the identity has no role, the request is blocked with rbac.missing_role.
  4. The deny_if_missing headers X-User-ID, X-Org-ID, and X-User-Role may contain only ASCII letters, digits, -, _, and .. Anything else blocks with rbac.invalid_identity.
  5. For an identity with roles, the control reads each tool name from tools[].function.name or tools[].name.
  6. Each tool is checked against each role. A denied_tools match blocks it, and an allowed_tools match allows it. A tool that no role allows blocks the request with rbac.tool_not_allowed.
  7. If data_access has an entry for one of the roles, the control reads verdictan.data_sensitivity from the request. A missing or unknown value counts as public. If no role allows that level, the request is blocked with rbac.data_access_denied.
  8. If minimum_necessary.enabled is true, allowed_phi_roles is not empty, and the identity has none of those roles, the control runs the HIPAA identifier detector on the message text. A detection blocks with rbac.minimum_necessary.
  9. Otherwise, the request is allowed with rbac.allowed.

The decision details name the role, the roles list, and the tool, requested_sensitivity, max_sensitivity, or phi_detections value that caused a block.

Phase and verdicts​

ItemValue
Phaseinput
Request familiesChat Completions, Completions, Responses, Messages, Embeddings, Audio transcriptions, Moderation
Verdictsallow, block
Reason codesrbac.allowed, rbac.missing_identity, rbac.missing_role, rbac.invalid_identity, rbac.tool_not_allowed, rbac.data_access_denied, rbac.minimum_necessary, policy.rbac_configuration_required

A blocked request gets HTTP 400 with error code content_policy_violation and a verdictan.decision object in the body.

Limits and failure behavior​

  • Roles come only from the verified identity. Headers alone never create a verified identity, and require_auth: true blocks such a request.
  • deny_if_missing only checks that headers have values. It does not authenticate anyone.
  • The tool check runs when the identity has roles and the request has tools. Each tool must match an allowed_tools pattern of some role. With roles: {}, every request with tools from an identity with roles is blocked.
  • A role that the identity has but roles does not list allows no tool. List every role that uses tools.
  • The data sensitivity check runs only when data_access has an entry for one of the roles. A request without verdictan.data_sensitivity counts as public and passes every limit.
  • minimum_necessary uses the same HIPAA detector as PII Detector in healthcare_mode. It reads only messages[].content strings, not structured content parts.
  • require_auth: false lets a request without identity through only when roles is empty. With roles configured, such a request is blocked with rbac.missing_role.
  • The control stops at the first failed check. The details show only that check.

Next steps​