SGNL Policy Snippet Reference

Introduction

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:

  • Principal - Defines the population of principals (e.g. users, services, robots) that a policy will apply to. It may look at an attribute or relationship of users in order to define a cohort, e.g. All Users in a Corporate Azure AD that have a department of ‘Engineering’.
  • Action - Defines the actions that SGNL receives from your Protected System at the Access Service. These might include simple actions such as “read” or “write”, or more complex actions such as “issue refund” or “createUser”.
  • Asset - Defines the resource(s) that need protecting within a specific Protected System. These may be individual customers, accounts, products, or something else. Asset-scoped snippets can increase the specificity of policies, e.g. Customer data for customers with more than 10,000 employees.
  • Condition - Defines the conditions with which to allow or deny. Condition snippets might look to ensure that a given principal has an appropriate business justification (e.g. through a ServiceNow Case assigned for a given customer), or might look to ensure the user is in the right location, on a trusted device.

Creating Policy Snippets

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,

  1. In the left side navigation in the SGNL Console, go to Snippets, and click Add Snippet like so:

    SGNL - Create Policy Snippet

  2. Add the Display Name, select the Scope, add an optional description, and click Save.

Creating Policy Snippet Versions

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:

SGNL - Create Policy Snippet Version

Common Fields

{
  "snippetId": "360E7BC5-9C00-4855-93CB-E74C2AA09C92",
  "description": "Description",
  "nodes": [{}],
  "relationships": [{}],
  "condition": {},
  "version": 1
}
Property NameProperty TypeDescription
snippetIdstringThe identifier for the Snippet you wish to create this Snippet Version within. The snippetId is already set to the ID of the snippet
descriptionstringA friendly description that describes this version of the Policy Snippet
nodesarray of objectsOptional field to describe the types of entities that will be described in your Policy Snippet Version. More information below
relationshipsarray of objectsOptional field to define relationships between nodes used to evaluate the policy. More information below
conditionobjectOptional field to constrain the search criteria of the nodes that should be evaluated. More information below
versionintegerThe version for this Snippet Version, must be greater than the latest existing Snippet Version

Nodes

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 NameProperty TypeDescription
entityIdstringThe 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
nodeNamestringAssign 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
queryFieldNamestring(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

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 NameProperty TypeDescription
relationshipNamestringDetermines 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.
fromNodeNamestringThe name of the node to start this evaluation from, with a name as declared in the nodes expression in this snippet
toNodeNamearray of objectsThe name of the node to terminate this evaluation, with a name as declared in the nodes expression in this snippet
transitivebooleanCan 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)
undirectedbooleanWhether a snippet evaluation should match in any direction, thereby ignoring the direction that is configured in the relationship

Condition

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.

  • Note: you can use any attribute on the entity, but because we’re creating policy, we should choose one that is unique and immutable
   "condition": {
       "predicate": {
           "lhs": {
               "attributeId": {{attributeId}},
               "nodeName": "group"
           },
           "op": "EqualTo",
           "rhs": {
               "string": "S-1-5-21-2562418665-3218585558-1813906818-1576"
           }
       }
   }
Property NameProperty TypeDescription
lhsobjectSpecifies the “left-hand-side” of the condition evaluation, or the thing that should be compared - this can be any of the comparators detailed below
opstringThe operator to use for the condition evaluation, supported operators include: Contains, EndsWith, EqualTo, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqualTo, RegexEqualTo, StartsWith
rhsobjectSpecifies 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
ComparatorDescription
queryFieldNameOne of the fields in the request to the access service (e.g. “queryFieldName”: “action” )
nodeName, attributeIdReference to a specific node declared in this snippet (from the nodes above) and an attribute on that node (e.g. "attributeId": {{attributeId}}, "nodeName": "group")
booleanWhether a specific value is true or false
dateEvaluates a date in the form of “YYYY-MM-DD” (e.g. "2022-10-18")
dateTimeEvaluates a date in the form of “YYYY-MM-DDThh:mm:ssTZD” (e.g. "2022-10-19T05:24:06+00:00")
integerEvaluates an integer (e.g. 12)
numberEvaluates a number (e.g. 12.32)
stringEvaluates 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 OperandDescription
andAll of the predicates need to be evaluated as true for this policy snippet to match
orAny of the predicates need to be evaluated as true for this policy snippet to match
notThese 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"
        }
      }    
    }
  }

Policy Snippet Version Samples

Principal Samples

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
}

Asset Samples

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
}

Condition Samples

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
}

Action Samples

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