Dataverse Row Level Security – DEV Community


Row level security is one of the fundamental access requirements we need for more advanced databases.

Dataverse uses RBAC (Role-Based Access Control), where you don’t have a access hierarchy, but access permissions per table based on roles created. That way access can be configured to enable least privilege needed in all roles.

Security roles default to table level access, with roles allowing specific levels for:

  • Create
  • Read
  • Update
  • Delete
  • Share
  • Append
  • Append to

It also has the added option to enable field level security, so roles can have specific levels per fields (ie can edit all fields except one where they can only view, great for approvals). But what if you want to control access to specific rows based on their value. Good example could be sales for stores, where regional managers can only see sales from stores in their region. This is row level security, and generally the most difficult to use, as its working with dynamic data for access, not schema data like tables and fields.

row level security

Dataverse enables row level security using Business Units, with the added benefits that they are a node based, so have parents who can inherit their children’s access. But as I said, it’s not quite as easy as table and field level to set up, so I though I would write a blog about it 😎

  1. Enable Feature
  2. Create Business Unit
  3. Create Security Role for Business Unit
  4. Assign Role to Users/Team
  5. Set Record Business Unit



1. Enable Feature

Business Units need to be enable in each environment, as this requires an update to all Dataverse tables to add a Business Unit field to the schema. So it can take a few minutes to proper gate through environment when enabled and also forces a dependency on all down stream environments that you wish to deploy to to also have it enabled.

To turn on go to the PPAC (Power Platform Admin Center), select the environment, go to Settings/Product- Features – and then turn on ‘Record ownership across Business Units’.

environment setting

And that’s it.



2. Create Business Unit

Business Units are created in each environment (and sadly are not solution aware so can’t be deployed). Just like the feature flag, you go to PPAC, select the environment, Settings/Users+permissions – Business Units.

business units

You should see all current Business Units, and at the top the option to create a new one. Business units can be nested/hierarchical, so you can set any other Business Unit as your parent (else it will default to the entire environment Unit).

create unit

You can update/manage them here or in the Dynamics 365 app. The Dynamics app has the added benefits of being able to export/import your Business Units (that way you can copy to other environments).

dynamics 365

Call out, Business Units, like most things are just a Dataverse Table (businessunits), so with a flow/custom script, you could leverage an API and copy the Business Units directly between environments too.



3. Create Security Role for Business Unit

The security role will be for the table that uses the Business Units, I have done a full blog on Security Roles here for more information. But in this example Im creating a simple sales table with store, Region, Sales. And I want to give users access to stores in their Business Unit region.

sales table

The role needs all the access you want to the custom table, but set to Business Unit. Additionally you need permission to read and append to the Business Unit Table

custom table

business unit permission

Callout, you can also create a security role that is scoped to a Business Unit, so you can either have a role that uses the team/user to set business unit or a role that sets the business unit



4. Assign Role to Users

Although the Business Units show up as a Team they cannot have users added to them, so we need to create new teams.

business unit cant add members

When creating the team we can set the business unit we want it to use, this means all members of the team will have access to that business unit.

create team

We finally then give the team the custom security role we created.

team security role



5. Set Record Business Unit

Now we have the access setup but how do we link the Region to the Business Unit. The simple way is we have a one to one mapping, so we don’t have a Region any more, just the Business Unit and when the data is added we set the Region by setting the Business Unit.

business unit in form

The other way is to use Automated Low-Code Plugins, again I have gone into more detail about them before here.

So in this case the creating a row will trigger a plug-in that will set the Business Unit. To make it easier I have created a lookup table, in this case Regions, which creates a relationship between the Region and Business Unit. We need to make sure our Sales table uses the Region table as a Lookup and we make sure our Security Role has permission to read and append this table.

region table

This may seem unnecessary, and probably is, but it does allow you to split your Business Unit from Region, meaning you can add in more complex logic or re-use Business Units with different Regions etc.

Low-Code Plug-ins/Dataverse Functions state you should use Set() to update the record, as to stop infinite loops. But as this is still soooooooo buggy it doesn’t work, you get the following error: “This record cannot be copied. Instead, create an inline record using {…} notation to copy the individual fields desired.”
This error was documented 18 months ago and is still not fixed, so I’m not holding much hope for it to be fixed soon. Which means we can only run this on create, not modify. To modify we would have to trigger a flow.

The Low-Code Plug-in should look like this:

low-code plug-in

With({
    bu:NewRecord.Region.'Owning Business Unit',
    buRecord:NewRecord
},
Patch(Sales,buRecord,{'Owning Business Unit':bu})
)
Enter fullscreen mode

Exit fullscreen mode


And that’s it, we now have row level security, see what I mean that it isn’t as simple as field or table level.



Source link