Document updated on Dec 12, 2022
Security Policies language and syntax
The policies language and syntax look nearly identical to C++, Go, Java, and Typescript and is based on Google’s CEL built-in functions and advanced macros. If you have existing validation using the CEL Component, you can also port them as policies.
The policy language is used in CEL Validation, Security Policies, and in the Tiered Rate Limit.
Basic syntax
Data types
The supported data types are:
uint(unsigned integer)int(integer)double(Number, float)string(string)bool(boolean)null_typebytes(on JSON mapping a string of base64-encoded bytes)map(Object. e.g.,{})list(Array. e.g.,[])duration(e.g.,1h1mfor 1 hour and 1 minute)timestamp(e.g.,timestamp(now)returns in RFC3339 format including timezone2023-01-01T10:00:20.021-05:00).dynthe union of all other types.
In addition, you can cast some types using their type name as a function, for instance: int("23") or double("21.3").
Logic and arithmetic operators
The logic operators are:
!(not)==(equal)!=(unequal)&&(and)||(or)_?_:_(ternary)<,<=,>=,>(ordering)
The arithmetic operators are:
%(mod)*(multiplication)+(sum and concatenation)-(subtract)/(divide)
Accessing maps
A map (also could be named object) is traversed with the dot operator ., or using the syntax ['field']. For instance, the map {"foo": {"bar": 1}} can be accessed as foo.bar and foo['bar] equivalently. The second method is necessary when keys use characters like - that can be interpreted as operators. E.g., req_headers['X-Forwarded-For'].
If you want to test if a specific field exists in a map use has('field').
Functions and macros
For the complete list of supported functions and macros see:
Data variables
The following data variables are available inside CEL and security policies. They are only available if you are in a request, response, or validating a token accordingly:
- Use a
req_type variable to access request data. - Use a
resp_type variable to access response data. - Use the
JWTvariable to access the payload of the JWT (available onendpointcontext only if the namespaceauth/validatoris correctly configured).
When instead of working with security policies, you work with a Tiered Rate Limit policy using the qos/ratelimit/tiered namespace, the only variable you can access is:
value, which contains the string value that matched the ratelimit tier.
For example:
A policy value.matches('[a-zA-Z]+') will make sure that the rate limit tier is a word of one or more letters using a regular expression.
Variables for requests
You can use the following variables inside policies:
req_method: Returns the method of this endpoint, e.g.:GETreq_path: The path used to access this endpoint, e.g.:/fooreq_params: An object with all the placeholder{parameters}declared in the endpoint.First letter capitalizedAll
req_paramscapitalize the first letter.E.g., an
"endpoint": "/users/{id_user}"will set a variablereq_params.Id_usercontaining the value of the parameter passed in the request. When you use the sequential proxy you also have underreq_params.RespX_fieldthe response of a previous backend call (whereXis the sequence number andfieldthe object you want to retrieve.req_headers: A map with all the headers received in its canonical form (converts the first letter and any letter following a hyphen to upper case; the rest are converted to lowercase. For example, the canonical key foraccept-encodingisAccept-Encoding). The value of the map is an array, as you can have a header declared multiple times (e.g., multiple cookies withSet-Cookie). For example, you can access headers like this:req_headers['X-Forwarded-For'].Do not forgetinput_headers!Thereq_headersvariable won’t contain any headers that are not declared in theinput_headersof the endpoint.req_querystring: An Object with all the query strings that the user passed to the endpoint (not anything you wrote on the backendurl_pattern). Remember that no query strings pass unless they are in theinput_query_stringslist. Notice that query strings, unlikereq_params, are NOT capitalized. Thereq_querystring.foowill also return an array as a query string can contain multiple values (e.g.,?foo[]=1&foo[]=2). Most of the times you might wantreq_querystring.foo[0].Do not forgetinput_query_strings!Thereq_querystringvariable won’t contain any query strings that are not declared in theinput_query_stringsof the endpoint.now: An object containing the current timestamp, e.g.,timestamp(now).getDayOfWeek()
Variables for responses
You can use the following variables inside the policies:
resp_completed: Boolean whether all the data has been successfully retrieved. When you use multiple backends, this information makes sense in theendpointcontext.resp_metadata_status: Returns an integer with the status code. Only available when usingno-opencoding.resp_metadata_headers: Returns a map with all the headers of the response. Only available when usingno-opencoding.resp_data: An object with all the data captured in the response. Using the dot notation, you can access its fields, e.g.:resp_data.user_id. If you use thegroupoperator in the backend, then you need to add it to access the object, e.g.,resp_data.mygroup.user_id. Not available when usingno-op.now: An object containing the current timestamp
Variables for the JWT rejecter
You can also use CEL expressions during the JWT token validation. Use the JWT variable to access its metadata in an endpoint context. The namespace auth/validator must be correctly configured. For instance:
has(JWT.user_id) && has(JWT.enabled_days) && (timestamp(now).getDayOfWeek() in JWT.enabled_days)
This example checks that the JWT token contains the metadata user_id and
enabled_days with the macro has(), and then checks that today’s weekday is within one of the allowed days to see the endpoint.
