Skip to content
This page is a translation of the authoritative Chinese source and may lag behind.View the original

Access control design

Access control answers "who can call what". The gateway combines three layers of control points: access keys (identity) → key groups (model/LB authorization) → Header ACL (request header rules).

Three control points

LayerGovernsConfigured at
Access keyCaller identityConsole → Access Keys
Key groupModel reachability + LB reachabilityConsole → Key Groups (models + load_balancers)
Header ACLMatch by request header to allow/denyConsole → Header ACL rules

Allowlist mode (default deny + single allow)

The regex engine does not support lookahead, so "allow only if the value does not contain X" cannot be written as a single regex. When you need default-deny and only allow specific requests, orchestrate the other way:

  1. Set default_action to deny (default deny).
  2. Use a "if contains X then allow" rule to allow matching items.
  3. Or split into multiple rules covering each allow condition.

This "allowlist + explicit allow" is safer than a denylist — new unknown requests are denied by default. For a config example, see the allowlist mode in Configure Header ACL.

Scope and priority

Header ACL rules have three scopes: global → key group → access key. Matching is first-match-wins, with the more specific scope taking priority. See Header ACL rule fields for the fields.

Expressiveness limits and rule orchestration

Regex does not support lookahead / backreferences

The regex engine is a linear-time, ReDoS-resistant implementation, so it does not support lookahead ((?=...) / (?!...)) or backreferences (\1). The trade-off is that negation conditions like "allow only if the value does not contain X" cannot be expressed as a single regex — use the allowlist mode above instead (default deny + explicit allow).

Rules that fail to load (syntax errors, etc.) are skipped and logged as a warning, while the remaining rules still take effect — so test rules before deploying, and don't rely on a single possibly-failing-to-load rule for a critical allow.

Key groups: two independent dimensions

A key group's models and load_balancers are two independent lists:

  • models: ["*"] (all models) does not carry LB permission.
  • load_balancers: ["*"] does not carry ordinary model permission either.
  • The two dimensions must be checked separately.

And an LB is an authorization unit — once an LB is allowed, keys in that group can reach every entry of that LB, without being validated against models one by one. For strict isolation, don't use LBs; see Multi-tenant isolation.

Behavior when rules fail

  • Rule syntax error: ignored at load time, logged as a warning, other rules take effect.
  • Regex no match: follows default_action.
  • Multiple scopes: first-match-wins, more specific scope takes priority.

FAQ

Q: Can a key group's models use an alias? No. It only matches the canonical name (name field), aliases are not resolved. See "Model aliases and hidden names" in Upstream and model fields.

Q: How do I authorize a hide_name model? Write its canonical name (not the alias) in the key group's models. hide_name=true only affects whether clients can access it by canonical name; authorization still uses the canonical name. See Upstream and model fields.

Q: How do I rate-limit per tenant? Each tenant has its own access key, and rate limits are counted per key. In multi-instance, configure Redis so rate limits are shared across instances. See Multi-tenant isolation.

Next: Multi-tenant isolation for isolation; Header ACL rule fields for fields; Configure Header ACL for examples.