Accessing Power Automate is controlled by security roles, with the 3 main ones being System Admin, Maker and Basic User. This though is only for Dataverse enabled environments (non just have System Admin and Maker).
So I wanted to look at how secure Power Automate actually is, and I suspected the biggest exposure is the Basic User role. Microsoft states that:
So as you can see, it is required to use an app in an environment (though not always the case, it should be), and it is pushed as good practice to.
https://www.matthewdevaney.com
This means a lot of people will have this role and in production environments too.
As a comparison what actual rights does Basic User have:
Basic User
CRUD (Create Read Update Delete) access to records that you create on selected tables. Organisation view rights on some system tables.
Maker
CRUD access to records that you create on selected tables (just more), and selected api's
And now lets dive into what this actually means:
Scenarios
- Non Dataverse Environment Access Shared Flow
- Dataverse Environment Access Shared Flow
- Dataverse Environment Create Flow
- App calls Flow
- Read Variables
Additional
- Learnings
- How to Protect your Environments
Couple of call outs before we dive in:
One important thing to understand, security should be at the back end, not just the front end. Presuming that everyone will only access the way you expect is just ridiculous. Its like putting up a gate but no fence, the only people who would follow the rules are the polite ones, the ones you worry about would just walk around it.
Another key is PoLP (The principle of least privilege), this principle is one of the foundations to good security. It states that you should only have access to something if you need it and at the level you need, nothing more, nothing less. This can add administrative overhead (more roles, less bucketing), but if you don't follow it its the equivalent of giving everyone a 'master key' because its easy then giving them just the keys they need.
Lastly you really should be using Dataverse enabled environment, it is the future for the platform (and is required for solutions). It still allows build flows out side of solutions (like the non Dataverse environments), unless you set 'Create new canvas apps and cloud flows in Dataverse solutions' in the environment options. Then any flow or app created outside are still solution aware, just in a shared solution (normally the Common Data Service Default Solution).
Non Dataverse Environment Access Shared Flow
As you may have noticed there is no Basic User role in non Dataverse environments, what does that mean, well it kind of means everyone is a Basic User.
In this scenario the user does not have maker role, but another user with maker role shares their flow with them. They can't see it in the standard UI, but if the url to the environment is shared, guess what, they can see it, edit and run it.
If outside of Dataverse I can access flows shared with me, even if you have no role, you don't need maker role to edit, only create
Dataverse Environment Access Shared Flow
In Dataverse environments it is similar, you just need Basic User role (except if the flow is made outside of a solution, in this case it is treated the same as a flow in a non Dataverse Environment).
If a Dataverse flow (solution aware), I can access flows shared with me if I have Basic User, you don't need maker role to edit
Dataverse Environment Create Flow
What about creating a Dataverse flow in an environment with only Basic User, the role gives me CRUD rights for certain tables, is the workflow table one of those tables, well yes it is.
Through the UI I can't create a flow, even though I have the permission:
But guess what, through the api I can:
As a Basic User I have full CRUD rights to the workflows table, it is only the maker UI that stops me creating a flow
It even appears in the UI where I can treat it like a shared flow, editing it, turning it on and off.
Well kind of, the good news from security side is the above example worked with no connections, what about with connections. So it turns out those selected tables do not include connection references.
So even though I can create connections in the environment (this is what happens when we use Power Apps in an environment, and can be done if you have the environment url), I can't create connection references (or even read them).
But, lets say I did have maker access before, I created a connection reference, now after dropping to Basic User, I still can't access the connect reference, but I don't need to. The flow runs without checking owners permission to access the connection reference, so now I can create flows through the api as long as I reference one of my connection references. Note even if the connection reference is shared with you, you still cant use it, this is because you don't have rights to the connection within the connection reference.
Above shows access error due to missing permissions but it is still running
Connection References are the only blocker to Basic Users creating flows.
But wait a second, we already know about differences between solution aware and non solution flows, the latter does not have connection references. So what happens if we send a flow which uses legacy connections (no connection references):
"connectionReferences": {
"shared_sharepointonline": {
"connectionName": "shared-sharepointonl-594ec2f7-b783-4358-8a34-901d2cf18e0e",
"source": "Embedded",
"id": "/providers/Microsoft.PowerApps/apis/shared_sharepointonline",
"tier": "NotSpecified"
}
},
instead of
"connectionReferences": {
"shared_sharepointonline": {
"runtimeSource": "embedded",
"connection": {
"connectionReferenceLogicalName": "crb89_sharedsharepointonline_684e9"
},
"api": {
"name": "shared_sharepointonline"
}
}
}
Yep, that works!!!
It creates a non connection reference connection.
If you can create legacy connections then you can create a flow with just Basic User
App calls Flow
I looked into if you could see any flows that you have access through a app (so the app calls the flow). Good news on this front, for both Solution aware and non solution apps/flows, you cant see the flow or logs. This is the same for both on behalf and owner connections.
Although you have permission to call the flow but you have no ability to see the flow or its logs, let alone edit it
Read Environment Variables
Variables are stored in 2 tables, Definition (name and type) and Value (the actual value in the variable). Checking the permissions for the tables shows that Basic User has full read access.
Good news they can't edit them, but it does mean we can see every environment variable in the environment.
Environment variables are public to all Basic Users
App shared
I know this is Power Automate but as a bonus what about Power Apps? With flows the flow owner could share the flow and the new maker can make changes without the right license. What about with apps. Well if you share edit access they can open and edit the app, but good news, they cant save any changes.
But that's only non solution apps, solution aware apps are even better, you cant even open it.
Even if shared ownership you cant save edits to Power Apps without maker permissions
Learnings
Because the Basic security role gives the ability to CRUD your own records it means that its only the UI that is stopping you. The maker role gives access to additional tables that are generally needed, but there are workarounds to work out of just the workflows table. I understand that the Basic Role may require read access to the workflow table (Instant Cloud Flows), but whey give them create rights? This does not feel like PoLP (The principle of least privilege).
And if you really want to give edit rights (to turn flows on off etc), then there should be column level security on the clientdata field (where the flow definition is stored).
Additionally it feels like we need a 'shared with' with permission, so that we can block records being shared with the user (The 'share' permission allows you to share, 'shared with' allows you to receive that share).
The connection reference table is our one key to stopping a Basic User creating a flow in an unapproved environment, but unfortunately you can use legacy connections within Dataverse (bypassing that key).
We know Environment Variables are public, do not store anything confidential in there (that could have impact on email address/contact numbers stored for notifications).
And finally apps are done right, you have the minimum permissions needed and thats for both the app and connected flows.
How to Protect your Environments
So what can we do to protect our enviroments. Well the good news is this is limited to creating/editing flows only. Data can't be accessed unless explicit sharing, and they still need a Basic User role (except in those legacy environments). But it still allows bypassing controls, so you should:
- Switch to Dataverse environments, at least that forces everyone to require a Basic User license
- Purge all of a users data when they lose access (especially connection references)
- Train developers not to share flows (use repository process instead)
- Secure developer environments with a security group where possible
- Don't give out Basic Security Role without consideration
- Use 'Block unmanaged customizations' in Test/Prod so no one can edit (managed is not enough as you can bypass it with solution layers)
And the basics:
- Don't give developers access to prod, use service accounts/spn's
- Monitor your flows, check for unapproved flow owners
And what about Microsoft, well they could:
- Remove Create rights for Basic User from workflows table
- Add column level security to clientdata field
- Get Create new canvas apps and cloud flows in Dataverse solutions out of preview and into GA
- Add controls on sharing
Top comments (1)
Thank you for the thorough explanation...Specially the fence analogy