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 Gateway 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 Gateway, 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 Gateway (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 Gateway 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

Configuring OPA Policies in the Console

The CloudBase console wraps the OPA policy configuration process, so you don't need to touch the underlying configuration directly — just complete the setup with visual operations. The console provides Form Mode and Syntax Mode:

ModeUse CaseDescription
Form ModeAllowing access to a specific resource — the most common scenarioConfigure entries one by one via form dropdowns, no coding required
Syntax ModeComplex scenarios that forms cannot express, such as combined control of custom domains, request paths, HTTP methods, etc.Switch to the syntax view and write Rego policies directly

Accessing the Entry

  1. Log in to the CloudBase console and enter your target environment.
  2. In the left menu, find Authorization Policy (path example: Environment → Authorization Policy).
  3. Click New Policy to open the configuration page.

Console entry

Form Mode (Recommended)

For common needs such as "allowing access to a certain resource", we recommend Form Mode. You can complete the configuration with dropdowns, no code required:

  1. On the configuration page, select Form Mode.
  2. Use the dropdown to select the resource type to allow access to (e.g. Cloud Function, Cloud Storage, CloudBase Run, etc.).
  3. Select the roles / user identities allowed to access.
  4. Click Save to complete the configuration.

Form mode 1

Form mode 2

Form Mode covers most "allow access by resource and role" scenarios. We recommend using Form Mode first, and only switch to Syntax Mode when the requirement goes beyond what forms can express.

Syntax Mode

When you need fine-grained combined control based on request paths, HTTP methods, or custom domains, forms cannot express it, so you need to switch to Syntax Mode and write Rego policies directly:

  1. On the configuration page, switch to the syntax view.
  2. Paste / write the Rego policy in the editor (see Policy Context (input) and Output: allow / deny for the full syntax).
  3. Click Save; validation runs on save (mandatory Rego v1, package must be authz.user, size and rule-count limits, etc. — see Notes on Writing Policies).

Syntax mode

Effect and Validation

  • The policy takes effect immediately after saving — no restart or redeployment needed.
  • The policy covers all HTTP API and HTTP Access Service requests in the current environment.
  • Validation runs on save; invalid policies (e.g. Rego v0 syntax, non-compliant package name) are rejected with a reason.
Note

The platform ships a built-in default policy for HTTP API and HTTP Access Service. The rules you configure in the console are adjustments on top of it. See Appendix A: Platform Default Policy for details.


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 (in the table below, both allow / deny refer to rules in the user policy):

User denyUser allowPlatform default policyFinal result
HitanyanyDeny (deny has the highest priority)
Not hittrueanyAllow
Not hitfalse / undefinedAllowAllow (a false user allow does not constitute a denial)
Not hitfalse / undefinedDenyDeny

The platform default policy's allow / deny rules can be found in Appendix A: Platform Default Policy.


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 Gateway / CloudBase Run / Static Hosting / Cloud Storage and other HTTP access services. Default domains include .app.tcloudbase.com / .service.tcloudbase.com (HTTP Gateway), .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
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.
caution

allow can only open up requests denied by the platform default policy — it cannot tighten access: default allow := false will not block any requests. To restrict access (IP allowlist, path control, HTTP method restrictions, etc.), you must write deny.

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

Requirement: unauthenticated users are read-only; logged-in C-end users can read and write but cannot delete.

Since the platform allows unauthenticated requests by default, restrictions such as "read-only" must be expressed through deny:

package authz.user

write_methods := {"POST", "PUT", "PATCH", "DELETE"}

# Tighten: unauthenticated users cannot perform write operations
deny contains "unauthenticated user cannot perform write operations" if {
input.subject.auth_type == "unauthenticated"
input.request.method in write_methods
}

# Tighten: logged-in C-end users cannot delete
deny contains "regular user cannot perform delete operations" if {
input.subject.auth_type in {"internal", "external", "anonymous"}
input.request.method == "DELETE"
}

# Open up: visitors (anonymous login) are denied by the platform by default under the
# HTTP Access Service path; here we allow their read operations
allow if {
input.subject.auth_type == "anonymous"
input.request.method in {"GET", "HEAD", "OPTIONS"}
}

Restrict Admin APIs to Administrators Only

Requirement: only administrators can access interfaces under the /admin/ path.

The platform default policy is not aware of request paths, so path-level control must use deny:

package authz.user

# Tighten: non-administrators accessing /admin/ are always rejected
deny contains "admin endpoints require administrator identity" if {
startswith(input.request.path, "/admin/")
input.subject.auth_type != "administrator"
}

IP Allowlist

Requirement: only office-network IPs are allowed; all other sources are rejected.

package authz.user

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

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

# Tighten: sources not in the allowlist are always rejected
deny contains "access source is not in the ip allowlist" if {
input.request.client_ip != ""
not in_office
}

Role-based Control via JWT groups

Requirement: only the ops and dev groups are allowed, and the dev group cannot delete.

package authz.user

allowed_groups := {"ops", "dev"}

has_allowed_group if {
some g in input.subject.groups
g in allowed_groups
}

# Tighten: requests not in any allowed role are always rejected
# (the groups of an unauthenticated request is empty, so it is also rejected)
deny contains "user group is not authorized in this env" if not has_allowed_group

# Tighten: the dev group cannot delete
deny contains "dev group cannot perform delete operations" 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 Gateway Default Policy

tip

The HTTP Gateway 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