Skip to main content

Snowflake Documentation

Role-Based Access Control (RBAC) configuration examples

This topic provides examples of RBAC configurations set in different scenarios using properties and user tagging scripts.

Example 1

You want to provide or maintain a map of functional Ids and associated user groups, so the user with groups associated with some functional IDs can access app data with a username equal to the functional ID.

Case

Group G1 is mapped to functional IDs U1 and U2, so users belonging to G1 can access the data with usernames U1 or U2.

Create one role for each function ID, assign the groups applicable and apply the filter.

com.unraveldata.rbac.roles role1,role2,...
com.unraveldata.rbac.role.role1.groups G1,..
com.unraveldata.rbac.role.role1.views clusters.resources,clusters.chargeback,clusters.workload,jobs
com.unraveldata.rbac.role.role1.data.field.userName <functionId>,$user
  • Create a role with fids tag using properties:

    com.unraveldata.rbac.roles=fid
    com.unraveldata.rbac.role.fid.groups=group1,group2,group3,..
    com.unraveldata.rbac.role.fid.data.field.userName=$tags.fids
  • User tagging script

    • Input file: functional_ids_groups.csv

      Input file content:

      Functional Ids;Groups
      ala;ux-rg-bd-scealadlbiro-dev
      bda;ux-rg-bd-bigdataadmins
      user6;dummy-groups06,dummy-group12
      user7;dummy-group12
      
    • Script file content:

      const path = require('path');
      const fs = require('fs');
      
      const inputFileName = 'functional_ids_groups.csv';
      
      const inputFilePath = path.join(__dirname, inputFileName);
      
      function union(arr1, arr2) {
        const arr = [];
        const obj = {};
      
        for (let i = 0; i < arr1.length; i += 1) {
          arr.push(arr1[i]);
          obj[arr1[i]] = true;
        }
      
        for (let i = 0; i < arr2.length; i += 1) {
          if (!obj[arr2[i]]) {
            arr.push(arr2[i]);
          }
        }
      
        return arr;
      }
      
      function getGroupsFunctionalIdsMap() {
        let fd;
        const groupsFIdsMap = {};
      
        try {
          fd = fs.openSync(inputFilePath, 'r');
        } catch (err) {
          console.error('RBAC : could not open functional_ids_groups.csv file; file path =', inputFilePath);
          console.error(err);
          return {};
        }
      
        try {
          const txt = fs.readFileSync(fd, 'utf-8');
      
          if (typeof txt === 'string' && txt.length > 0) {
            const lines = txt.trim().split(/\r?\n/);
      
            for (let i = 1; i < lines.length; i += 1) {
              const line = lines[i];
              const fIdsGroups = line.split(';');
              const fIds = fIdsGroups[0].split(',');
              const groups = fIdsGroups[1].split(',');
              const formattedFIds = [];
              const formattedGroups = [];
      
              for (let j = 0; j < fIds.length; j += 1) {
                const formattedFId = fIds[j].trim();
      
                if (formattedFId) {
                  formattedFIds.push(formattedFId);
                }
              }
      
              for (let j = 0; j < groups.length; j += 1) {
                const formattedGroup = groups[j].trim().toLowerCase();
      
                if (formattedGroup) {
                  formattedGroups.push(formattedGroup);
                }
              }
      
              for (let j = 0; j < formattedGroups.length; j += 1) {
                const formattedGroup = formattedGroups[j];
      
                if (groupsFIdsMap[formattedGroup]) {
                  groupsFIdsMap[formattedGroup] = union(groupsFIdsMap[formattedGroup], formattedFIds);
                } else {
                  groupsFIdsMap[formattedGroup] = formattedFIds;
                }
              }
            }
          }
      
          return groupsFIdsMap;
        } catch (err) {
          console.error('RBAC : could not create Groups Functional IDS Map.');
          console.error(err);
          return {};
        } finally {
          fs.closeSync(fd);
        }
      }
      
      const groupsFIdsMap = getGroupsFunctionalIdsMap();
      
      console.log('RBAC : Groups & Functional IDS Map -', JSON.stringify(groupsFIdsMap));
      
      function getTags(username, userGroups) {
        const tags = {};
      
        if (
          Object.keys(groupsFIdsMap).length === 0
          || !Array.isArray(userGroups)
          || userGroups.length === 0
        ) {
          return tags;
        }
      
        let fIds = [];
      
        for (let i = 0; i < userGroups.length; i += 1) {
          const userGroup = userGroups[i].toLowerCase();
          const fId = groupsFIdsMap[userGroup];
      
          if (fId && fId.length > 0) {
            fIds = union(fIds, fId);
          }
        }
      
        if (fIds.length > 0) {
          tags.fids = fIds;
        }
      
        return tags;
      }
      
      module.exports = getTags;
      
Example 2

You want the users to access only a specific Workspace or Cluster.

Case
  • user1 belonging to group GRP_A can only view data for all clusters in workspace DBWkps1.

  • user2 belonging to groups GRP_B can only view the data in clusters Cluster1 and Cluster2.

  • user3 belonging to group GRP_C can only view data in all clusters in workspace DBWkps2 and only Cluster3, Cluster4 in another workspace.

##roles list
com.unraveldata.rbac.roles=role1, cluster_1_2, workspace1, workspace_cluster

##workspace1 role config
com.unraveldata.rbac.role.workspace1.users= user1    ##Optional
com.unraveldata.rbac.role.workspace1.groups=GRP_A
com.unraveldata.rbac.role.workspace1.views=clusters.resources,  clusters.chargeback, compute,  jobs  ##Set which tabs should be seen by the user in UI
com.unraveldata.rbac.role.workspace1.data.user.filter=false   ##Set to true if the user should also see apps that they run.
com.unraveldata.rbac.role.workspace1.data.tags.filter=true      ##Set to true if the user should also see apps with matching user tags.
com.unraveldata.rbac.role.workspace1.data.field.queue=DBWkps1   ##Only app data with ‘queue = DBWkps1’ is shown to user.

##cluster_1_2 role config
com.unraveldata.rbac.role.cluster_1_2.users= user2    ##Optional
com.unraveldata.rbac.role.cluster_1_2.groups=GRP_B
com.unraveldata.rbac.role.cluster_1_2.views=clusters.resources,  clusters.chargeback, compute,  jobs  ##Set which tabs should be seen by the user in UI
com.unraveldata.rbac.role.cluster_1_2.data.user.filter=false   ##Set to true if the user should also see  apps run by him
com.unraveldata.rbac.role.cluster_1_2.data.tags.filter=true      ##Set to true if the user should also see  apps with matching user tags
com.unraveldata.rbac.role.cluster_1_2.data.field.clusterUid=cluster1, cluster2  ##Only app data with “ clusterUid == cluster1 || cluster2 “ is shown to user

##workspace_cluster role config
com.unraveldata.rbac.role.workspace_cluster.users= user3    ##Optional
com.unraveldata.rbac.role.workspace_cluster.groups=GRP_C
com.unraveldata.rbac.role.workspace_cluster.views=clusters.resources,  clusters.chargeback, compute,  jobs  ##Set which tabs should be seen by the user in UI
com.unraveldata.rbac.role.workspace_cluster.data.user.filter=false   ##Set to true if the user should also see  apps run by him
com.unraveldata.rbac.role.workspace_cluster.data.tags.filter=true      ##Set to true if the user should also see  apps with matching user tags
com.unraveldata.rbac.role.workspace_cluster.data.field.clusterUid=cluster3, cluster4  ##Only app data with “ clusterUid == cluster3 || cluster4 “ is shown to user
com.unraveldata.rbac.role.workspace_cluster.data.field.queue=‘DBWkps2’   ##Only app data with “ queue == DBWkps2“ is shown to user
  • Create a role with rbac_clusters and rbac_workspaces tag:

    com.unraveldata.rbac.roles=cw
    com.unraveldata.rbac.role.cw.groups=group1,group2,group3,..
    com.unraveldata.rbac.role.cw.data.field.clusterUid=$tags.rbac_clusters
    com.unraveldata.rbac.role.cw.data.field.queue=$tags.rbac_workspaces
  • User tagging script

    • Input file: clusters-workspaces_groups.csv

      Input file content:

      Clusters;Workspaces;Groups 
      ala;;ux-rg-bd-scealadlbiro-dev
      bda;;ux-rg-bd-bigdataadmins
      db467450-0523-4919-81c3-1f18f6937246;;dummy-group12,dummy-group10
      ;root.users.user6,root.users.user7;dummy-group12
      
    • Script file content:

      const fs = require('fs');
      const path = require('path');
      
      const CWGroupsCSVPath = path.join(__dirname, 'clusters-workspaces_groups.csv');
      
      function union(arr1, arr2) {
        const arr = [];
        const obj = {};
      
         for (let i = 0; i < arr1.length; i += 1) {
          arr.push(arr1[i]);
          obj[arr1[i]] = true;
       }
       
        for (let i = 0; i < arr2.length; i += 1) {
          if (!obj[arr2[i]]) {
            arr.push(arr2[i]);
          }
        }
      
        return arr;
      }
      
      const groupsClustersMap = {};
      const groupsWorkspacesMap = {};
      
      function getGroupsCWMap() {
        let fd;
      
        try {
          fd = fs.openSync(CWGroupsCSVPath, 'r');
        } catch (err) {
          console.error(
            'RBAC : could not open rbac_queues_groups.csv file; file path 
      =',
            CWGroupsCSVPath
          );
          console.error(err);
          return {};
        }
      
        try {
          const txt = fs.readFileSync(fd, 'utf-8');
      
          if (typeof txt === 'string' && txt.length > 0) {
            const lines = txt.trim().split(/\r?\n/);
      
            for (let i = 1; i < lines.length; i += 1) {
              const line = lines[i];
              const cwGroups = line.split(';');
              const clusters = cwGroups[0].split(',');
              const workspaces = cwGroups[1].split(',');
              const groups = cwGroups[2].split(',');
              const formattedClusters = [];
              const formattedWorkspaces = [];
              const formattedGroups = [];
      
              for (let j = 0; j < clusters.length; j += 1) {
                const formattedCluster = clusters[j].trim().toLowerCase();
      
                if (formattedCluster) {
                  formattedClusters.push(formattedCluster);
                }
              }
      
              for (let j = 0; j < workspaces.length; j += 1) {
                const formattedWorkspace = workspaces[j].trim().toLowerCase();
      
                if (formattedWorkspace) {
                  formattedWorkspaces.push(formattedWorkspace);
                }
              }
      
              for (let j = 0; j < groups.length; j += 1) {
                const formattedGroup = groups[j].trim().toLowerCase();
      
                if (formattedGroup) {
                  formattedGroups.push(formattedGroup);
                }
              }
      
              for (let j = 0; j < formattedGroups.length; j += 1) {
                const formattedGroup = formattedGroups[j];
                if (groupsClustersMap[formattedGroup]) {
                  groupsClustersMap[formattedGroup] = union(
                    groupsClustersMap[formattedGroup],
                    formattedClusters
                  );
                } else {
                  groupsClustersMap[formattedGroup] = formattedClusters;
                }
      
                if (groupsWorkspacesMap[formattedGroup]) {
                  groupsWorkspacesMap[formattedGroup] = union(
                    groupsWorkspacesMap[formattedGroup],
                    formattedWorkspaces
                  );
                } else {
                  groupsWorkspacesMap[formattedGroup] = formattedWorkspaces;
                }
              }
            }
          }
      
          return groupsCWMap;
        } catch (err) {
          console.error('RBAC : could not create Groups Queues Map.');
          console.error(err);
          return {};
        } finally {
          fs.closeSync(fd);
        }
      }
      
      getGroupsCWMap();
      
      console.log('RBAC : Groups Clusters Map -', JSON.stringify(groupsClustersMap));
      console.log('RBAC : Groups Workspaces Map -', JSON.stringify(groupsWorkspacesMap));
      
      function getTags(username, userGroups) {
        const tags = {};
      
        if (
          ( 
            Object.keys(groupsWorkspacesMap).length === 0
            && Object.keys(groupsClustersMap).length === 0
          )
          || !Array.isArray(userGroups)
          || userGroups.length === 0
        ) {
          return tags;
       }
        let rbac_workspaces = [];
        let rbac_clusters = [];
      
        for (let i = 0; i < userGroups.length; i += 1) {
          const userGroup = userGroups[i].toLowerCase();
          const workspaces = groupsWorkspacesMap[userGroup];
          const clusters = groupsClustersMap[userGroup];
      
          if (workspaces && workspaces.length > 0) {
            rbac_workspaces = union(rbac_workspaces, workspaces);
          }
      
          if (clusters && clusters.length > 0) {
            rbac_clusters = union(rbac_clusters, clusters);
          }
        }
      
        if (rbac_clusters.length > 0) {
          tags.rbac_clusters = rbac_clusters;
        }
      
        if (rbac_workspaces.length > 0) {
          tags.rbac_workspaces = rbac_workspaces;
        }
      
        return tags;
      }
      
      module.exports = getTags;
      
      
Example 3

You have a map of queues to groups, where users of a group can access the data with queues belonging to the possible queues of the respective group.

com.unraveldata.rbac.roles=role1, role2,..
com.unraveldata.rbac.role.role1.users= user1    ##Optional
com.unraveldata.rbac.role.role1.groups=G1
com.unraveldata.rbac.role.role1.views=clusters.resources,  clusters.chargeback, compute,  jobs     ##Set the tabs that must be seen by the user on the UI.
com.unraveldata.rbac.role.role1.data.user.filter=false   ##Set to true if the user should also see apps run by them.
com.unraveldata.rbac.role.role1.data.tags.filter=true    ##Set to true if the user should also see apps with matching user tags.
com.unraveldata.rbac.role.role1.data.field.queue=Q1, Q2   ##Only app data with ‘queue = Q1 || Q2 “ is shown to user.
  • Create a role with rbac_queue tag:

    com.unraveldata.rbac.roles=rq
    com.unraveldata.rbac.role.rq.groups=group1,group2,group3,..
    com.unraveldata.rbac.role.rq.data.field.queue=$tags.rbac_queue
  • User tagging script

    • Input file: rbac_queues_groups.csv

      Input file content:

      Queue Names;Group Name
      ala;ux-rg-bd-scealadlbiro-dev
      bda;ux-rg-bd-bigdataadmins
      root.users.user6;dummy-groups06,dummy-group12
      root.users.user7;dummy-group12
      
    • Script file content:

      const fs = require('fs');
      const path = require('path');
      
      const CSV_FILE_NAME = 'rbac_queues_groups.csv';
      const CSV_FILE_PATH = path.join(__dirname, CSV_FILE_NAME);
      
      function union(arr1, arr2) {
        const arr = [];
        const obj = {};
      
         for (let i = 0; i < arr1.length; i += 1) {
          arr.push(arr1[i]);
          obj[arr1[i]] = true;
       }
       
        for (let i = 0; i < arr2.length; i += 1) {
          if (!obj[arr2[i]]) {
            arr.push(arr2[i]);
          }
        }
      
        return arr;
      }
      
      function getGroupsQueuesMap() {
        let fd;
        const groupsQueuesMap = {};
      
       try {
         fd = fs.openSync(CSV_FILE_PATH, 'r');
       } catch (err) {
          console.error(
            'RBAC : could not open rbac_queues_groups.csv file; file path =',
            CSV_FILE_PATH
          );
          console.error(err);
          return {};
        }
      
        try {
          const txt = fs.readFileSync(fd, 'utf-8');
      
          if (typeof txt === 'string' && txt.length > 0) {
            const lines = txt.trim().split(/\r?\n/);
      
            for (let i = 1; i < lines.length; i += 1) {
              const line = lines[i];
              const queuesGroups = line.split(';');
              const queues = queuesGroups[0].split(',');
              const groups = queuesGroups[1].split(',');
              const formattedQueues = [];
              const formattedGroups = [];
      
              for (let j = 0; j < queues.length; j += 1) {
                const formattedQueue = queues[j].trim().toLowerCase();
      
                if (formattedQueue) {
                  formattedQueues.push(formattedQueue);
                }
              }
      
              for (let j = 0; j < groups.length; j += 1) {
                const formattedGroup = groups[j].trim().toLowerCase();
      
                if (formattedGroup) {
                  formattedGroups.push(formattedGroup);
                }
              }
      
              for (let j = 0; j < formattedGroups.length; j += 1) {
                const formattedGroup = formattedGroups[j];
      
                if (groupsQueuesMap[formattedGroup]) {
                  groupsQueuesMap[formattedGroup] = union(
                    groupsQueuesMap[formattedGroup],
                    formattedQueues
                  );
                } else {
                  groupsQueuesMap[formattedGroup] = formattedQueues;
                }
              }
            }
          }
      
          return groupsQueuesMap;
        } catch (err) {
          console.error('RBAC : could not create Groups Queues Map.');
          console.error(err);
          return {};
        } finally {
          fs.closeSync(fd);
        }
      }
      
      const groupsQueuesMap = getGroupsQueuesMap();
      
      console.log('RBAC : Groups Queues Map -', JSON.stringify(groupsQueuesMap));
      
      function getTags(username, userGroups) {
        const tags = {};
      
        if (
          Object.keys(groupsFIdsMap).length === 0
          || !Array.isArray(userGroups)
          || userGroups.length === 0
        ) {
          return tags;
        }
        let rbac_queue = [];
      
        for (let i = 0; i < userGroups.length; i += 1) {
          const userGroup = userGroups[i].toLowerCase();
          const queues = groupsQueuesMap[userGroup];
      
          if (queues && queues.length > 0) {
            rbac_queue = union(rbac_queue, queues);
          }
       }
      
        if (rbac_queue.length > 0) {
          tags.rbac_queue = rbac_queue;
        }
      
        return tags;
      }
      
      module.exports = getTags;