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:

 

1. Consistent model to authorize access data in large number of services

 

2. Ability to dynamically apply data masking and row-filtering

 

3. Delegated access control administration

 

4. Ability to explicitly deny access

 

5. Use of wildcards in resource names in access policies

 

6. Role-based access control (RBAC)

 

7. Tag-based access control (TBAC), based on tags associated with resources

 

8. 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 each user's department:

 

/data/dept/${{USER.dept}}

 

Policy resource for database of each user's department:

 

db_${{USER.dept}}

 

Supported expressions

 

Variable/Function name

Description

Example values

GET_TAG_NAMES()

Names of tags associated with the resource, as a CSV (comma separated values) string

PII,FINANCE

GET_TAG_ATTR_NAMES()

Names of attributes in all tags associated with the resource, as a CSV string

piiType,sensitiveLevel

GET_TAG_ATTR(attrName)

Value of the given attribute in tags associated with the resource, as a CSV string

email

GET_UG_NAMES()

Names of groups the user belongs to, as a CSV string

managers,finance-admins

GET_UG_ATTR_NAMES()

Names of all attributes in groups the user belongs to, as a CSV string

attr1,attr2

GET_UG_ATTR(attrName)

Value of the given attribute in groups the user belongs to, as a CSV string

val1

GET_UR_NAMES()

Names of roles assigned to the user,  as a CSV string

analyst,dba

GET_USER_ATTR_NAMES()

Names of all attributes of the user, as a CSV string

allowedSensitiveLevel, allowedSources

GET_USER_ATTR(attrName)

Value of the given attribute associated with the user

10

HAS_TAG(tagName)

Is the given tag associated with the resource?

true

false

HAS_ANY_TAG

Is any tag associated with the resource?

true

false

HAS_NO_TAG

Are not tags associated with the resource?

true

false

HAS_USER_ATTR(attrName)

Does the user have the given attribute?

true

false

HAS_UG_ATTR(attrName)

Does any group associated with the user have the specified attribute?

true

false

HAS_TAG_ATTR(attrName)

Does any tag associated with the resource have the specified attribute?

true

false

IS_IN_GROUP(groupName)

Does the user belong to the specified group?

true

false

IS_IN_ROLE(roleName)

Is the user assigned to the specified role?

true

false

IS_IN_ANY_GROUP

Does the user belong to any group?

true

false

IS_IN_ANY_ROLE

Is any role assigned to the user?

true

false

IS_NOT_IN_ANY_GROUP

Does the user belong to no group?

true

false

IS_NOT_IN_ANY_ROLE

Is the user associated with no roles?

true

false

REQ

Request details, as a map

{

 "accessType":  "select",

 "clientIPAddress": "10.120.27.49",

 "clusterType": "etl",

 "clusterName": "etl-e1",

 "accessType":  "select",

 "user":        "scott",

 "userGroups":  [ "g1" ],

 "userRoles":   [ "r1" ],

}

RES

Resource details, as a map

{

  "database":   "db1",

  "table":      "tbl1",

  "Column":     "col1",

  "_ownerUser": "jane"

}

TAG

Current tag, as a map.

This is 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

{

 "SENSITIVE": {

  "_type", "SENSITIVE",

  "level": 10

 },

 "PII": {

  "_type",   "PII",

  "piiType": "email"

 }

}

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" ]

USER

Name of the user

"scott"

 

Most functions listed in the table 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')