Apache Ranger - Dynamic Expressions¶
Madhan Neethiraj, Apache Ranger committer · Dec 12, 2023
Introduction¶
Apache Ranger policy model offers a rich set of features that help security administrators handle various access and governance requirements with ease. These features include:
- Consistent model to authorize access data in large number of services
- Ability to dynamically apply data masking and row-filtering
- Delegated access control administration
- Ability to explicitly deny access
- Use of wildcards in resource names in access policies
- Role-based access control (RBAC)
- Tag-based access control (TBAC), based on tags associated with resources
- Attribute-based access control (ABAC), based on attributes of users, groups and tags
In addition to above, Apache Ranger policies can use various attributes available in the access context to authorize the access - attributes including resource owner, time of access, tags associated with the accessed resource, attributes of user/groups/tags, groups/roles the user belongs to. This document explores use cases that can leverage such attributes in policies using dynamic expressions.
Dynamic expressions¶
Apache Ranger policy engine evaluates dynamic expressions specified in policies using the script engine included in the JVM, in a sandboxed environment. Dynamic expressions can be used in Apache Ranger policies in following contexts:
Policy conditions¶
Expressions can used in policy conditions to decide whether to evaluate the policy or a policy-item. These
expressions should evaluate to a boolean value i.e., true or false. Examples:
Condition for highly sensitive data (level >= 10)
TAG.sensitiveLevel >= 10
Condition to check if the user has appropriate level of clearance to access sensitive data
USER.allowedSensitiveLevel >= TAG.sensitiveLevel
Condition to check if the user belongs to group finance and is in role analyst
IS_IN_GROUP('finance') AND IS_IN_ROLE('analyst')
Row filters¶
Expressions can be used to set up row-filters with dynamic values. To distinguish expressions from the rest
of the row-filter text, they should be enclosed within delimiters ${{ and }}. Examples:
Row-filter expression to restrict users to access only rows belonging to their department:
dept_code == ${{USER.department}}
Row-filter expression to restrict users to access only rows from data sources specified in user attribute named allowedSources:
data_source in (${{USER.allowedSources}})
Resource names¶
Use of expressions in resource names can help reduce the number of policies, which in turn makes it easier to manage policies. Examples:
Policy resource for home directory of the user:
/home/${{REQ.user}}
Policy resource for directory of user's department:
/data/dept/${{USER.dept}}
Policy resource for database of user's department:
db_${{USER.dept}}
Supported expressions¶
Expressions fall into three groups: functions that return a value, tests that return true or false, and
context objects that you can navigate with dot notation.
Value functions¶
Each function returns a string. Functions that can produce several values return them as a CSV (comma separated values) string.
| Function | Returns | Example |
|---|---|---|
GET_TAG_NAMES() |
Names of tags associated with the resource | PII,FINANCE |
GET_TAG_ATTR_NAMES() |
Names of attributes in all tags associated with the resource | piiType,sensitiveLevel |
GET_TAG_ATTR(attrName) |
Value of the given attribute in tags associated with the resource | email |
GET_UG_NAMES() |
Names of groups the user belongs to | managers,finance-admins |
GET_UG_ATTR_NAMES() |
Names of all attributes in groups the user belongs to | attr1,attr2 |
GET_UG_ATTR(attrName) |
Value of the given attribute in groups the user belongs to | val1 |
GET_UR_NAMES() |
Names of roles assigned to the user | analyst,dba |
GET_USER_ATTR_NAMES() |
Names of all attributes of the user | allowedSensitiveLevel,allowedSources |
GET_USER_ATTR(attrName) |
Value of the given attribute associated with the user | 10 |
Boolean tests¶
Each test evaluates to true or false.
| Test | Question it answers |
|---|---|
HAS_TAG(tagName) |
Is the given tag associated with the resource? |
HAS_ANY_TAG |
Is any tag associated with the resource? |
HAS_NO_TAG |
Are no tags associated with the resource? |
HAS_TAG_ATTR(attrName) |
Does any tag associated with the resource have the specified attribute? |
HAS_USER_ATTR(attrName) |
Does the user have the given attribute? |
HAS_UG_ATTR(attrName) |
Does any group associated with the user have the specified attribute? |
IS_IN_GROUP(groupName) |
Does the user belong to the specified group? |
IS_IN_ROLE(roleName) |
Is the user assigned to the specified role? |
IS_IN_ANY_GROUP |
Does the user belong to any group? |
IS_IN_ANY_ROLE |
Is any role assigned to the user? |
IS_NOT_IN_ANY_GROUP |
Does the user belong to no group? |
IS_NOT_IN_ANY_ROLE |
Is the user associated with no roles? |
Context objects¶
Context objects expose the request, the resource, the user and the tags as maps and lists. Access their members with
dot notation, for example USER.allowedSensitiveLevel or TAG.sensitiveLevel.
REQ-
Request details, as a map.
{ "accessType": "select", "clientIPAddress": "10.120.27.49", "clusterType": "etl", "clusterName": "etl-e1", "user": "scott", "userGroups": [ "g1" ], "userRoles": [ "r1" ] } RES-
Resource details, as a map.
{ "database": "db1", "table": "tbl1", "column": "col1", "_ownerUser": "jane" } USER-
Current user, as a map of the user name and the user's attributes.
{ "_name": "scott", "allowedSensitiveLevel": 10 } UGNAMES-
Names of groups the user belongs to, as a list.
[ "g1" ] URNAMES-
Names of roles the user is assigned to, as a list.
[ "r1" ] TAG-
Current tag, as a map. Available only in tag-based policies.
{ "_type": "SENSITIVE", "sensitiveLevel": 10 } TAGNAMES-
Names of tags associated with the resource, as a list.
[ "PII", "SENSITIVE" ] TAGS-
All tags associated with the resource, as a map keyed by tag name.
{ "SENSITIVE": { "_type": "SENSITIVE", "level": 10 }, "PII": { "_type": "PII", "piiType": "email" } }
Most functions listed above take optional parameters, to make it easier to handle use cases that require special handling.
Default value¶
A function call can include a default value as an optional parameter, which will be returned when there is no value available. For example, consider the following expression:
USER.allowedSensitiveLevel >= TAG.sensitiveLevel
When the user doesn't have an attribute named allowedSensitiveLevel, the expression will always evaluate to
false since USER.allowedSensitiveLevel would evaluate to null. To handle such cases, consider the following
alternate expression which would use 0 as the value instead of null:
GET_USER_ATTR('allowedSensitiveLevel', 0) >= TAG.sensitiveLevel
Here is another example of using default value in function calls:
dept_code in (${{GET_UG_ATTR('deptCode', -1)}})
Separator¶
Functions that return a CSV string, like GET_TAG_NAMES(), can include following optional parameters:
- optional #1. default value: value to return when no value is available
- optional #2. separator: string to use as the separator between values
Here is an example of using optional parameters:
GET_TAG_NAMES('', '|') == 'tag1|tag2|tag3'
Quotes¶
Each function that returns a CSV string has another version with _Q appended to the function name; this version surrounds each value within quotes. For example, consider the following row-filter expression:
location_state IN (${{GET_UG_ATTR_Q('state')}})
The expression can evaluate to the following, if the user belongs to groups having an attribute named state:
location_state IN ('CA','OR','WA')
Related documentation
Dynamic expressions are documented in Policy conditions and Attribute-based access control.