Skip to main content

OPA Authorization Policy


Overview

OPA Authorization Policy is an environment-level request authorization capability provided by CloudBase, built on top of the open-source policy engine Open Policy Agent (OPA) and the policy language Rego. By writing a piece of policy code in the CloudBase console, you can define unified access control rules for all HTTP API and HTTP Access Service requests in the entire environment.

CloudBase executes the policy on every incoming request, makes an "allow / deny" decision based on three categories of information — user identity, HTTP request, and environment context — and then forwards the request to the actual target resource.

User request

CloudBase

Build input (subject + request + cloudbase)

Evaluate OPA policy
├─ allow = true and deny = false → allow → access actual resource
└─ deny = true → reject, return 403 + reason

By default, CloudBase ships a platform default policy for HTTP API and HTTP Access Service, covering the default allow / deny rules for various resources under different identities. See Appendix A: Platform Default Policy for the detailed rules.

User policies can be layered on top of the platform default policy:

  • An allow defined in the user policy can open up requests denied by the platform default
  • A deny defined in the user policy can reject requests allowed by the platform default (deny takes precedence over allow)

By tuning the user policy, you can flexibly and granularly define authorization rules based on HTTP requests, user identity, accessed resources, or any combination of conditions, achieving highly customizable permission control. With OPA policies, you can implement requirements such as:

  • IP allowlist access control
  • Read/write permissions by user identity
  • Protection of admin backend APIs
  • Different rules per access entry point
  • ...

For complete examples, see Practical Cases.

Core Capabilities

CapabilityDescription
Multi-condition authorizationFlexibly combine multiple dimensions such as user identity, request features, and environment information to achieve fine-grained access control
Unified policy entryA single policy covers both HTTP API and HTTP Access Service (Cloud Function / CloudBase Run / Static Hosting, etc.) entry points, unifying public traffic governance
Traceable rejection reasonsWhen a request is denied, a human-readable reason can be returned to the caller for quick troubleshooting
Customize on top of platform defaultsThe platform has built-in default allow/deny rules for each resource type; you only need to write rules to override what you want, no need to start from scratch
Standard Rego syntaxBuilt on the OPA open-source policy engine, using the widely adopted Rego policy language with a low learning curve and rich community resources

Relationship with Other Security Capabilities

CloudBase provides multiple layers of security capabilities. The OPA Authorization Policy sits at the access control layer at the request entry, and works together with other capabilities to form a defense-in-depth system:

CapabilityScopeControl DimensionWhen to Use
OPA Authorization PolicyAll HTTP API and HTTP Access Service requests in the environmentUser + request + environment contextWhen you need complex condition combinations, request-level, programmable access control
Rate LimitingCloud Function, CloudBase RunQPS (resource dimension / client dimension)Anti-abuse, anti-overload
Static Hosting SecurityStatic Hosting resourcesReferer / IP / QPSStatic resource hotlink protection
Trusted OriginsClient SDK callsDomain allowlistRestrict the source of SDK calls
tip

The OPA Authorization Policy and the capabilities above can be enabled simultaneously — a request first passes through trusted-origin checks and OPA policy evaluation, and then enters subsequent stages such as rate limiting.

Quick Start

The following is a minimal usable policy:

package authz.user

# Default deny
default allow := false

# Allow administrators to access /v1/ paths
allow if {
input.subject.auth_type == "administrator"
startswith(input.request.path, "/v1/")
}

# Forbid unauthenticated users from issuing DELETE
deny contains "DELETE requires authentication" if {
input.request.method == "DELETE"
input.subject.auth_type == "unauthenticated"
}

The startswith in the example is a Rego built-in function. For the full syntax and built-in function list, see the Rego language reference and the Rego built-in function reference. For security reasons, CloudBase only enables a whitelisted subset of these. See Appendix B for commonly disabled functions.

The policy input input is constructed by CloudBase on every request. Its full structure is shown below; for detailed field definitions, see Policy Context:

{
"subject": {
"user_id": "c-user-123",
"auth_type": "administrator",
"groups": ["developer"]
},
"request": {
"method": "GET",
"raw_host": "env-xxx.api.tcloudbasegateway.com",
"host": "env-xxx.api.tcloudbasegateway.com",
"path": "/v1/functions/foo",
"query": {"page": "1"},
"client_ip": "10.1.2.3",
"header": {"X-Env-Id": ["env-xxx"]},
"header_map": {"X-Env-Id": "env-xxx"}
},
"cloudbase": {
"env_id": "env-xxx",
"region": "ap-shanghai",
"entrypoint_type": "tcbopenapi",
"resource_type": "functions"
}
}

Decision matrix at a glance:

denyallowFinal Result
trueanyDeny
falsetrueAllow
falsefalseDeny

Policy Context (input)

input is the only external data the policy can read. It always contains three top-level fields:

input.subject # Request subject (user)
input.request # Current HTTP request
input.cloudbase # CloudBase environment context

User Information (subject)

FieldTypeDescription
user_idstringC-end user ID; "" when not logged in
auth_typestringBuilt-in identity authentication type, see the table below; case-sensitive
groups[]stringUser roles associated with the request, corresponding to the groups field in the request JWT

All possible values of auth_type:

ValueMeaning
administratorAdministrator
internalInternal user
externalExternal user
anonymousAnonymously logged-in user
unauthenticatedNot logged in / no AccessToken
service_role(Only present in PostgreSQL environments) service_role, super privileges
anon(Only present in PostgreSQL environments) anonymous role
authenticated(Only present in PostgreSQL environments) authenticated role

Request Information (request)

FieldTypeDescription
methodstringHTTP method, normalized to uppercase
raw_hoststringOriginal Host header, not normalized
hoststringNormalized Host (port removed, lower-cased)
pathstringRequest path, URL encoding preserved
queryobject<string, string>URL query parameters; multi-value parameters joined by &
client_ipstringClient IP, may be "" / IPv4 / IPv6
headerobject<string, array<string>>Request headers, preserving multiple values
header_mapobject<string, string>Request headers

Difference between header and header_map:

headerheader_map
Value typearray<string>string
Read asinput.request.header["X-Foo"][0]input.request.header_map["X-Env-Id"]

Header keys must be in HTTP Canonical form (e.g. X-Env-Id, Content-Type); lower-cased or all-uppercased keys are not readable. Sensitive headers such as Authorization / Cookie have been stripped by CloudBase and cannot be accessed by the policy.

Environment Information (cloudbase)

FieldTypeDescription
env_idstringCurrent environment ID
regionstringRegion of the environment, e.g. "ap-shanghai"
entrypoint_typestringEntry point type, see below
resource_typestringResource type matched by the current request, see below

Possible values of entrypoint_type:

ValueMeaning
tcbopenapiHTTP API path, with domain {envid}.api.tcloudbasegateway.com
tcbgatewayHTTP Access Service / CloudBase Run / Static Hosting / Cloud Storage and other HTTP Access Services. Default domains include .app.tcloudbase.com / .service.tcloudbase.com (HTTP Access Service), .tcloudbaseapp.com (Static Hosting), .tcb.qcloud.la (Cloud Storage), .run.tcloudbase.com (CloudBase Run), etc.; also includes custom domains bound to the above paths

Possible values of resource_type:

ResourceIdentifierDescription
Cloud StoragestoragesObject storage operations
Cloud FunctionfunctionsCloud function invocation
CloudBase RuncloudrunCloudBase Run service access
Large ModelsaiAI large model access
AI AgentaibotAI agent service
Data ModelmodelData model management
Knowledge BaseknowledgeKnowledge base management
MySQL AccessrdbMySQL database access

Output: allow / deny

The policy must declare allow or deny (at least one) under package authz.user:

RuleTypeForm
allowbooldefault allow := false
allow if { ... }
denybool or set of stringdeny if { ... } or deny contains "rejection reason" if { ... }

deny supports two forms:

  • Boolean form deny if { ... } — block the request without returning a reason.
  • Set form deny contains "msg" if { ... } — block the request and surface the message to the end user as: Access denied by policy. Reason: msg.

The engine evaluates each rule independently, and ultimately decides whether to allow the request based on the combined results of allow and deny.


Notes on Writing Policies

  • Rego v1 is mandatory: there is no need to write import rego.v1; deprecated v0 syntax (such as allow { ... }) will be rejected on save.
  • The package must be exactly authz.user: any other package name will be rejected on save.
  • Policy size ≤ 2 KiB (including comments and blank lines).
  • No more than 20 non-default rules: each allow if {...}, deny if {...}, and deny contains "msg" if {...} counts as one; default declarations do not count.
  • deny reasons should not contain sensitive information: messages in the deny set are returned to the end user, so avoid concatenating internal userIDs, SQL, tokens, etc.
  • Strict mode: OPA strict mode is enabled when saving policies; unused imports and unused function parameters (other than wildcards) will be rejected.
  • Restricted built-in functions: this engine uses an allowlist; for commonly disabled functions, see Appendix B.
  • Requests not evaluated by the OPA policy: internal CloudBase platform requests and Integration Center callback requests are not evaluated by the policy.

Practical Cases

Read/Write Permissions by User Identity

package authz.user

default allow := false

# Unauthenticated users are read-only
allow if {
input.subject.auth_type == "unauthenticated"
input.request.method in {"GET", "HEAD", "OPTIONS"}
}

# Authenticated / anonymous C-end users can read and write
allow if {
input.subject.auth_type in {"internal", "external", "anonymous"}
input.request.method in {"GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH", "DELETE"}
}

# Administrators have no method restrictions
allow if input.subject.auth_type == "administrator"

Restrict Admin APIs to Administrators Only

package authz.user

default allow := false

# Non-admin APIs: allow all
allow if not startswith(input.request.path, "/admin/")

# Admin APIs: administrators only
allow if {
startswith(input.request.path, "/admin/")
input.subject.auth_type == "administrator"
}

IP Allowlist

package authz.user

default allow := false

office_cidrs := ["10.0.0.0/8", "192.168.0.0/16"]

allow if {
some cidr in office_cidrs
net.cidr_contains(cidr, input.request.client_ip)
}

Allow HTTP API Access Only

package authz.user

default allow := false

allow if input.cloudbase.entrypoint_type == "tcbopenapi"

deny contains "this env only accepts openapi traffic" if {
input.cloudbase.entrypoint_type == "tcbgateway"
}

Role-based Control via JWT groups

package authz.user

default allow := false

# ops group: no method restrictions
allow if "ops" in input.subject.groups

# dev group: all methods except DELETE
allow if {
"dev" in input.subject.groups
input.request.method != "DELETE"
}

Appendix A: Platform Default Policy

The platform default policy makes decisions along three dimensions: path, resource type, and identity. User policies are layered on top: the user's allow can open up requests denied by default, and the user's deny can reject requests allowed by default (deny takes precedence over allow). In the tables below, ✅ means allowed by default, ❌ means denied by default.

The following identities are allowed by default for all paths and all resources, and are not repeated in the tables below:

  • Not logged in (unauthenticated): you must add a deny in the user policy to block them
  • PostgreSQL environment identities: service_role, anon, authenticated
info

Resource types not listed in the tables below are allowed by default for all four identities: super-admin / internal user / external user / visitor.

HTTP API Default Policy

tip

The HTTP API path is identified by: entrypoint_type == "tcbopenapi"

Module (resource_type)Super-admin (administrator)Internal (internal)External (external)Visitor (anonymous)
CloudBase Run (cloudrun), Knowledge Base (knowledge)
Large Models (ai)

HTTP Access Service Default Policy

tip

The HTTP Access Service path is identified by: entrypoint_type == "tcbgateway"

Module (resource_type)Super-admin (administrator)Internal (internal)External (external)Visitor (anonymous)
Cloud Function (functions), Cloud Storage (storages), CloudBase Run (cloudrun)

Appendix B: Disabled Built-in Functions

This engine uses an allowlist for built-in functions. Commonly disabled functions are listed below; for functions not in the table, refer to the validation result returned on save.

CategoryDisabled Functions
Outbound networkhttp.send, net.lookup_ip_addr, providers.aws.sign_req
Timetime.*
Regexregex.*, re_match (use startswith / endswith / contains / glob.match instead)
JWT parsingio.jwt.*
Encoding / decodingbase64.*, base64url.*, hex.*, urlquery.*
YAMLyaml.* (use json.* instead)
Reflection / metadataopa.runtime, rego.metadata.*, rego.parse_module
Debuggingtrace, print
Resource consumptionwalk, net.cidr_expand, numbers.range, numbers.range_step, graph.*, graphql.*, strings.render_template
Certificates / keyscrypto.x509.*, crypto.parse_private_keys
Othersuuid.*, rand.intn, semver.*, units.*, json.patch, json.match_schema, json.verify_schema

Next Steps