Policy Snippets and Policy Snippet Versions are critical components in Policy composition. This reference will discuss the scope of policy snippets and importantly, the semantics to be used when creating policy snippet versions that can be used in policies.
Policy Snippets have different scopes, these include:
Policy Snippets are objects in SGNL that group Policy Snippet Versions. Policy Snippets are able to be created and partially updated after creation, however Policy Snippets are not able to be deleted once created.
In order to create a Policy Snippet,
In the left side navigation in the SGNL Console, go to Snippets, and click Add Snippet like so:
Add the Display Name, select the Scope, add an optional description, and click Save.
In order to use a Policy Snippet, it must have at least one Policy Snippet Versions. Snippet Versions leverage SGNL’s Graph Directory for fast, efficient, and simplified evaluation. In order to create Policy Snippet Versions against entities in the graph, SGNL makes use of Nodes, Relationships, and Conditions to pattern match in the graph.
To create a Snippet Version, click on the Policy Snippet you just created, and click on Create New Version. You should see a page like so:
{
"snippetId": "360E7BC5-9C00-4855-93CB-E74C2AA09C92",
"description": "Description",
"nodes": [{}],
"relationships": [{}],
"condition": {},
"version": 1
}
Property Name | Property Type | Description |
---|---|---|
snippetId | string | The identifier for the Snippet you wish to create this Snippet Version within. The snippetId is already set to the ID of the snippet |
description | string | A friendly description that describes this version of the Policy Snippet |
nodes | array of objects | Optional field to describe the types of entities that will be described in your Policy Snippet Version. More information below |
relationships | array of objects | Optional field to define relationships between nodes used to evaluate the policy. More information below |
condition | object | Optional field to constrain the search criteria of the nodes that should be evaluated. More information below |
version | integer | The version for this Snippet Version, must be greater than the latest existing Snippet Version |
Nodes describe the types of entities that will be described in your Policy Snippet Version. They directly reference entities that are synchronized from the various Systems of Record and entities you have configured inside of SGNL.
It is useful to define Nodes when your Policy Snippet Version refers to specific entities as part of the snippet evaluation. For instance, if your Policy Snippet Version evaluates whether an Okta User is from the Engineering Department, create a Node to specify the Okta User node. You can then use the attributeId
from the Okta User node you’ve defined to specify a Condition that evaluates whether the user’s profile__department attribute is EqualTo
Engineering.
However, Nodes are optional; you do not need to define Nodes if your snippet evaluates whether a principal from any System of Record has privileged access to secure assets following your organizational naming convention (i.e. principalId
starts with “privileged-user”).
For example, you might want to use Nodes to reference user entities and group entities in the Policy Snippet Version you are creating from your Okta Tenant.
"nodes": [
{
"nodeName": "user",
"entityId": "{{oktaUserEntityId}}",
"queryFieldName": "principalId"
},
{
"nodeName": "group",
"entityId": "{{oktaGroupEntityId}}"
}
],
Property Name | Property Type | Description |
---|---|---|
entityId | string | The entity identifier for the entity in your System of Record (e.g. Okta User) that you are referencing in the snippet version, e.g. c4194907-ec87-4018-9a82-b84c73b3eb56 |
nodeName | string | Assign the node you are referencing a name, so that you can refer to it in other parts of the policy snippet version, when defining relationships or conditions |
queryFieldName | string | (Optional) This is the field name of a property in the access request, that you might want to use as an operand against one of the nodes (i.e. does the principalId in the access request relate to this node) |
Relationships reference the nodes you’ve expressed in the ’nodes’ expression of your Snippet Version in order to define which edges in the graph (the relationships) to traverse in order to evaluate policy.
It is useful to define Relationships when your Policy Snippet Version makes snippet evaluation decisions based on relationships between nodes. For instance, if your Policy Snippet Version evaluates whether an Okta User is a Manager of another Okta User, use Relationships to assess whether the principal requesting access has that relationship.
However, you do not need to define Relationships if your snippet version does not draw upon one of the well-defined relationships that SGNL creates within a System of Record (see table on Relationship Names below for further detail) or a custom relationship that you have defined.
For example, you might want to use Relationships to take the user and group entities you referenced in the ‘nodes’ section of your Snippet Version to evaluate if the calling principal is a direct or indirect member of a group.
"relationships": [
{
"relationshipName": "{{Name of the relationship}}",
"fromNodeName": "user",
"toNodeName": "group",
"transitive": false
}
],
Property Name | Property Type | Description |
---|---|---|
relationshipName | string | Determines the relationship to traverse, this can be one of the well-defined relationships that SGNL creates within a System of Record, the join attribute used for entities of the same type across Systems of Record, or a custom relationship type. |
fromNodeName | string | The name of the node to start this evaluation from, with a name as declared in the nodes expression in this snippet |
toNodeName | array of objects | The name of the node to terminate this evaluation, with a name as declared in the nodes expression in this snippet |
transitive | boolean | Can multiple relationships of this type be traversed to determine whether this snippet matches (e.g. direct member of a group, or indirect via nesting; direct report to a manager or an indirect report via reporting structure) |
undirected | boolean | Whether a snippet evaluation should match in any direction, thereby ignoring the direction that is configured in the relationship |
Conditions constrain the search criteria of the nodes that should be evaluated as part of the snippet evaluation and of the evaluation of the policy.
Conditions are extremely flexible, but we’ll start with a simple example. Say you want to ensure that a Principal Snippet Version should only be evaluated for users in a certain group, you would specify Node and Relationship fields as we have above, and in the conditions - you would specify a constraint that the group had to have a specific identifier to be matched.
"condition": {
"predicate": {
"lhs": {
"attributeId": {{attributeId}},
"nodeName": "group"
},
"op": "EqualTo",
"rhs": {
"string": "S-1-5-21-2562418665-3218585558-1813906818-1576"
}
}
}
Property Name | Property Type | Description |
---|---|---|
lhs | object | Specifies the “left-hand-side” of the condition evaluation, or the thing that should be compared - this can be any of the comparators detailed below |
op | string | The operator to use for the condition evaluation, supported operators include: Contains, EndsWith, EqualTo, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqualTo, RegexEqualTo, StartsWith |
rhs | object | Specifies the “right-hand-side” of the condition evaluation, or the thing that should be compared to - this can be any of the comparators detailed below |
Comparator | Description |
---|---|
queryFieldName | One of the fields in the request to the access service (e.g. “queryFieldName”: “action” ) |
nodeName, attributeId | Reference to a specific node declared in this snippet (from the nodes above) and an attribute on that node (e.g. "attributeId": {{attributeId}}, "nodeName": "group") |
boolean | Whether a specific value is true or false |
date | Evaluates a date in the form of “YYYY-MM-DD” (e.g. "2022-10-18") |
dateTime | Evaluates a date in the form of “YYYY-MM-DDThh:mm:ssTZD” (e.g. "2022-10-19T05:24:06+00:00") |
integer | Evaluates an integer (e.g. 12) |
number | Evaluates a number (e.g. 12.32) |
string | Evaluates a string (e.g. "S-1-5-21-2562418665-3218585558-1813906818-1576") |
Thus far, we’ve looked only at Conditions that contain a single predicate, but conditions can support multiple predicates that can be evaluated together using additional operands.
Predicate Operand | Description |
---|---|
and | All of the predicates need to be evaluated as true for this policy snippet to match |
or | Any of the predicates need to be evaluated as true for this policy snippet to match |
not | These predicates cannot be evaluated as true for this policy snippet to match |
Example using and
The following condition evaluates to True
if the principal is in the Engineering department and the Country of Residence is USA. The attributeIds
are the UUIDs identifying each of the attributes being evaluated.
"condition": {
"and": [
{
"predicate": {
"lhs": {
"attributeId": "{{profile__department (UUID of the profile__department attribute in the Okta SoR)}}",
"nodeName": "oktaUser"
},
"op": "EqualTo",
"rhs": {
"string": "Engineering"
}
}
},
{
"predicate": {
"lhs": {
"attributeId": "{{profile__countryCode (UUID of the profile__countryCode attribute in the Okta SoR)}}",
"nodeName": "oktaUser"
},
"op": "RegexEqualTo",
"rhs": {
"string": "USA"
}
}
}
]
}
Example using or
The following condition evaluates to True
if the principal is in the Engineering department OR the Support department. The attributeIds
are the UUIDs identifying each of the attributes being evaluated.
"condition": {
"or": [
{
"predicate": {
"lhs": {
"attributeId": "{{profile__department (UUID of the profile__department attribute in the Okta SoR)}}",
"nodeName": "oktaUser"
},
"op": "EqualTo",
"rhs": {
"string": "Engineering"
}
}
},
{
"predicate": {
"lhs": {
"attributeId": "{{profile__department (UUID of the profile__department attribute in the Okta SoR)}}",
"nodeName": "oktaUser"
},
"op": "EqualTo",
"rhs": {
"string": "Support"
}
}
}
]
}
Example using not
The following condition evaluates to True
if the asset (Jira Issue) is not in Resolved status. The attributeIds
are the UUIDs identifying each of the attributes being evaluated.
"condition": {
"not": {
"predicate": {
"lhs": {
"attributeId": "{{status (UUID of the Jira Issue's status attribute in the Jira SoR)}}",
"nodeName": "jiraIssue"
},
"op": "EqualTo",
"rhs": {
"string": "Resolved"
}
}
}
}
Evaluate whether a principal is a direct member of an Azure AD Group
{
"nodes": [
{
"nodeName": "user",
"entityId": "{{aadUserEntityId (UUID of the User Entity in the Azure AD SoR)}}",
"queryFieldName": "principalId"
},
{
"nodeName": "group",
"entityId": "{{aadGroupEntityId (UUID of the Group Entity in the Azure AD SoR)}}"
}
],
"relationships": [
{
"relationshipName": "Group",
"fromNodeName": "user",
"toNodeName": "group",
"transitive": false
}
],
"condition": {
"predicate": {
"lhs": {
"attributeId": "{{jobTitle (UUID of the jobTitle attribute in the Azure AD SoR)}}",
"nodeName": "group"
},
"op": "EqualTo",
"rhs": {
"string": "S-1-5-21-2562418665-3218585558-1813906818-1576"
}
}
},
"description": "Belongs to our AAD Employee Group",
"snippetId": "{{snippetId}}",
"version": 1
}
Evaluate whether a principal has a title of Admin or Developer as provided by Okta
{
"nodes": [
{
"nodeName": "oktaUser",
"entityId": "{{oktaUserEntityId (UUID of the User Entity in the Okta SoR)}}",
"queryFieldName": "principalId"
}
],
"condition": {
"or": [
{
"predicate": {
"lhs": {
"attributeId": "{{profile__title (UUID of the profile__title attribute in the Okta User Entity)}}",
"nodeName": "oktaUser"
},
"op": "EqualTo",
"rhs": {
"string": "admin"
}
}
},
{
"predicate": {
"lhs": {
"attributeId": "{{profile__title (UUID of the profile__title attribute in the Okta User Entity)}}",
"nodeName": "oktaUser"
},
"op": "EqualTo",
"rhs": {
"string": "developer"
}
}
}
]
},
"description": "User is an Admin or a Developer",
"snippetId": "{{snippetId}}",
"version": 1
}
Determine whether the asset attempting to be accessed is a Customer Salesforce Account
{
"nodes": [
{
"queryFieldName": "assetId",
"entityId": "{{sfdcAccountEntityId (UUID of the Account Entity in the Salesforce SoR)}}",
"nodeName": "account"
}
],
"condition": {
"predicate": {
"lhs": {
"attributeId": "{{Type (UUID of the Type attribute in the Salesforce Account Entity)}}",
"nodeName": "account"
},
"op": "EqualTo",
"rhs": {
"string": "Customer"
}
}
},
"description": "Salesforce Customer Accounts",
"snippetId": "{{snippetId}}",
"version": 1
}
Determine whether the asset attempting to be accessed is one of the sensitive infrastructure assets, following our organizational naming convention
{
"condition": {
"predicate": {
"lhs": {
"queryFieldName": "assetId"
},
"op": "StartsWith",
"rhs": {
"string": "customer-prod-"
}
}
},
"description": "Production Assets owned by a Customer",
"snippetId": "{{snippetId}}",
"version": 1
}
Determine whether the calling principal is the assignee on an active case that belongs to the customer they are requesting access for
{
"nodes": [
{
"entityId": "{{snowUserEntityId (UUID of the User Entity in ServiceNow SoR)}}",
"nodeName": "snowUser",
"queryFieldName": "principalId"
},
{
"entityId": "{{snowCaseEntityId (UUID of the Case Entity in the ServiceNow SoR)}}",
"nodeName": "snowCase"
},
{
"entityId": "{{snowAccountEntityId (UUID of the Account Entity in the ServiceNow SoR)}}",
"nodeName": "snowAccount",
"queryFieldName": "assetId"
}
],
"relationships": [
{
"relationshipName": "AssignedTo",
"fromNodeName": "snowCase",
"toNodeName": "snowUser"
},
{
"relationshipName": "Account", //
"fromNodeName": "snowCase",
"toNodeName": "snowAccount"
}
],
"condition": {
"predicate": {
"lhs": {
"attributeId": "active",
"nodeName": "snowCase"
},
"op": "EqualTo",
"rhs": {
"boolean": true
}
}
},
"description": "User is assigned active case for the customer",
"snippetId": "{{snippetId}}",
"version": 1
}
AssignedTo is the name of the relationship created between a ServiceNow User and a ServiceNow Case Entity when the case is assigned to the user in ServiceNow SoR. Account is the name of the relationship created between a ServiceNow Case and a ServiceNow Account Entity when the case belongs to the account in ServiceNow SoR
Determine whether the calling principal is the manager of a ServiceNow Group
{
"nodes": [
{
"entityId": "{{snowUserEntityId (UUID of the User Entity in ServiceNow SoR)}}",
"nodeName": "snowUser",
"queryFieldName": "principalId"
},
{
"entityId": "{{snowGroupEntityId (UUID of the Group Entity in ServiceNow SoR)}}",
"nodeName": "snowGroup"
}
],
"relationships": [
{
"relationshipName": "Manager",
"fromNodeName": "snowGroup",
"toNodeName": "snowUser"
}
],
"description": "Group Manager",
"snippetId": "{{snippetId}}",
"version": 1
}
Determine whether the calling principal is coming from the United States (note: for more details on Location or Temporal Snippets, see our Advanced Snippet Reference)
{
"condition": {
"predicate": {
"lhs": {
"queryFieldName": "principal.ipAddress.location.country"
},
"op": "EqualTo",
"rhs": {
"string": "US"
}
}
},
"description": "User is physically located in the United States",
"version": 1
}
Determine whether the request is being made during the hours of 9am-5pm, Monday to Friday in US Pacfic Time (note: for more details on Location or Time-based Snippets, see our Advanced Snippet Reference)
{
"condition": {
"and": [
{
"predicate": {
"lhs": {
"expr": {
"lhs": {
"expr": {
"lhs": {
"queryFieldName": "time.now"
},
"op": "ToTimezone",
"rhs": {
"string": "America/Los_Angeles"
}
}
},
"op": "GetField",
"rhs": {
"string": "Hour"
}
}
},
"op": "GreaterThanOrEqualTo",
"rhs": {
"integer": 9
}
}
},
{
"predicate": {
"lhs": {
"expr": {
"lhs": {
"expr": {
"lhs": {
"queryFieldName": "time.now"
},
"op": "ToTimezone",
"rhs": {
"string": "America/Los_Angeles"
}
}
},
"op": "GetField",
"rhs": {
"string": "Hour"
}
}
},
"op": "LessThanOrEqualTo",
"rhs": {
"integer": 17
}
}
},
{
"predicate": {
"lhs": {
"expr": {
"lhs": {
"expr": {
"lhs": {
"queryFieldName": "time.now"
},
"op": "ToTimezone",
"rhs": {
"string": "America/Los_Angeles"
}
}
},
"op": "GetField",
"rhs": {
"string": "DayOfWeek"
}
}
},
"op": "LessThanOrEqualTo",
"rhs": {
"integer": 5
}
}
}
]
},
"description": "During US PST Business Hours - Monday to Friday",
"version": 1
}
Evaluate whether a principal can perform a login action
{
"condition": {
"predicate": {
"lhs": {
"queryFieldName": "action"
},
"op": "EqualTo",
"rhs": {
"string": "login"
}
}
},
"version": 1,
"description": "Perform a Login Action",
"snippetId": "{{snippetId}}"
}
Evaluate whether a principal can perform a read action
{
"condition": {
"predicate": {
"lhs": {
"queryFieldName": "action"
},
"op": "EqualTo",
"rhs": {
"string": "read"
}
}
},
"version": 1,
"description": "Perform a Read Action",
"snippetId": "{{snippetId}}"
}