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 integration 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 Integration. 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. APIs are available to create and manage Policy Snippets.

In order to create a Policy Snippet, you must specify:

{
  "displayName": "Name",
  "description": "Description",
  "scope": "PRINCIPAL",
  "type": "STATE_MATCH",
  "tenantId": "360E7BC5-9C00-4855-93CB-E74C2AA09C92"
}

A new Policy Snippet that will be Principal scoped

Property NameDescription
displayNameThe display name you want to give to this snippet, this will appear during policy creation and management
descriptionThe description for this snippet, this will appear during policy creation and management
scopeValue should be one of PRINCIPAL, ACTION, ASSET, or CONDITIONAL depending on the scope of the snippet you are creating
typeValue should be STATE_MATCH - in the future, type will aid in the classification of snippets
tenantIdThe tenantId for the tenant in your SGNL client that you are managing

Creating Policy Snippet Versions

In order to use a Policy Snippet, at least one Policy Snippet Version must be available. Policy Snippet Versions are created via the SGNL APIs.

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.

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, this is available via the Snippet APIs
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, see below
relationshipsarray of objectsOptional field to define relationships between nodes used to evaluate the policy, see below
conditionobjectOptional field to constrain the search criteria of the nodes that should be evaluated, see 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 data sources 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, use Nodes 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, you do not need to define Nodes if your snippet evaluates whether a principal from any Data Source 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 Corporate Azure AD Tenant.

 "nodes": [
   {
     "nodeName": "user",
     "entityId": "{{aadUserEntityId}}",
     "queryFieldName": "principalId"
   },
   {
     "nodeName": "group",
     "entityId": "{{aadGroupEntityId}}"
   }
   ],
Property NameProperty TypeDescription
datasourceIdstringThe data source identifier for the datasource that contains the entity you’re reference in the snippet version, this identifier is available from the data sources API as ‘Id’, e.g. 1a82af25-291c-4eee-9d86-27d1a829c109
entityIdstringThe entity identifier for the entity in your data source (e.g. Azure AD User) that you are referencing in the snippet version, this identifier is available from the entities API as ‘Id’, 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 datasource (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": "GROUP",
     "fromNodeName": "user",
     "toNodeName": "group",
     "transitive": false
   }
 ],
Property NameProperty TypeDescription
relationshipNamestringDetermines the type of relationship to traverse, this can be one of the well-defined relationships that SGNL creates within a datasource, the join attribute used for entities of the same type across data sources, or a custom relationship type, see below for further detail
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)
Relationship NameDescription
MAPPED_TOCreated by a SGNL Administrator expressing Join Rules between entities of the same type across different data sources. MAPPED_TO relationships are automatically created when Join Rules are specified through the SGNL Console User Interface during Data Source configuration; they do not need to be specified again via Policy Snippet Versions. As an example, a Join Rule representing a MAPPED_TO relationship can be used to connect users in ServiceNow and users in AzureAD based on matching email addresses
GROUPCreated by the SGNL Platform between entities (commonly users and/or groups) and groups. As an example, a GROUP relationship would commonly exist between 2 or more entities in a single data source (e.g. Azure AD), and commonly have a high cardinality of transitive relationships
MANAGERCreated by the SGNL Platform between two user entities based on reporting hierarchy. As an example, a MANAGER relationship would exist between 2 or more entities in a single data source (e.g. Azure AD) based on manager relationships. Manager relationships are commonly transitive
ASSIGNED_TOCreated by the SGNL Platform between user entities and cases/tickets. As an example, an ASSIGNED_TO relationship would commonly exist between a single user and 1 or more case/ticket entities in ITSM solutions (e.g. ServiceNow, Zendesk, JIRA). It is common for a single user to have many ASSIGNED_TO relationships
ACCOUNTCreated by the SGNL Platform between case/ticket entities and Customers/Accounts. As an example, an ACCOUNT relationship would commonly exist between a single case/ticket and a single customer/account in the ITSM solution.
CustomCreated by a SGNL Admin between an entity and another entity, based on a common join attribute and given a custom relationship name. Custom relationships are available to be created via the Relationships API.

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.

 "condition": {
      "and": [
          {
              "predicate": {
              "lhs": {
                  "attributeId": "employeeType",
                  "nodeName": "aadUser"
              },
              "op": "EqualTo",
              "rhs": {
                  "string": "FTE"
                   }
               }
          },
          {
              "predicate": {
              "lhs": {
                  "attributeId": "employeeId",
                  "nodeName": "aadUser"
              },
              "op": "RegexEqualTo",
              "rhs": {
                  "string": ".*"
                   }
               }
          }
      ]
  }
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

Policy Snippet Version Samples

Principal Samples

Evaluate whether a principal is a direct member of an Azure AD Group

{
  "nodes": [
    {
      "nodeName": "user",
      "entityId": "{{aadUserEntityId}}",
      "queryFieldName": "principalId"
    },
    {
      "nodeName": "group",
      "entityId": "{{aadGroupEntityId}}"
    }
  ],
  "relationships": [
    {
      "relationshipName": "GROUP",
      "fromNodeName": "user",
      "toNodeName": "group",
      "transitive": false
    }
  ],
  "condition": {
    "predicate": {
      "lhs": {
        "attributeId": {{attributeId}},
        "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",
      "datasourceId": "{{oktaDatasourceId}}",
      "entityId": "{{oktaUserEntityId}}",
      "queryFieldName": "principalId"
    }
  ],
  "condition": {
    "or": [
      {
        "predicate": {
          "lhs": {
            "attributeId": "profile__title",
            "nodeName": "oktaUser"
          },
          "op": "EqualTo",
          "rhs": {
            "string": "admin"
          }
        }
      },
      {
        "predicate": {
          "lhs": {
            "attributeId": "profile__title",
            "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",
      "datasourceId": "{{sfdcDatasourceId}}",
      "entityId": "{{sfdcAccountEntityId}}",
      "nodeName": "account"
    }
  ],
  "condition": {
    "predicate": {
      "lhs": {
        "attributeId": "Type",
        "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": [
    {
      "datasourceId": "{{snowDatasourceId}}",
      "entityId": "{{snowUserEntityId}}",
      "nodeName": "snowUser",
      "queryFieldName": "principalId"
    },
    {
      "datasourceId": "{{snowDatasourceId}}",
      "entityId": "{{snowCaseEntityId}}",
      "nodeName": "snowCase"
    },
    {
      "datasourceId": "{{snowDatasourceId}}",
      "entityId": "{{snowAccountEntityId}}",
      "nodeName": "snowAccount",
      "queryFieldName": "assetId"
    }
  ],
  "relationships": [
    {
      "relationshipName": "ASSIGNED_TO",
      "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
}

Determine whether the calling principal is the manager of a ServiceNow Group

{
  "nodes": [
    {
      "datasourceId": "{{snowDatasourceId}}",
      "entityId": "{{snowUserEntityId}}",
      "nodeName": "snowUser",
      "queryFieldName": "principalId"
    },
    {
      "datasourceId": "{{snowDatasourceId}}",
      "entityId": "{{snowGroupEntityId}}",
      "nodeName": "snowGroup"
    }
  ],
  "relationships": [
    {
      "relationshipName": "MANAGER",
      "fromNodeName": "snowGroup",
      "toNodeName": "snowUser"
    }
  ],
  "description": "Group Manager",
  "snippetId": "{{snippetId}}",
  "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}}"
}