I’m exploring options for securing some Azure resources within a subscription from tampering, even by subscription owners.
The intent is to standardize our subscriptions which are used by other teams for their engineering. We’ve considered giving teams custom RBAC roles similar to Owner and Contributor, but slightly reduced–however we’ve found this approach to be high friction and not to cover 100% of our scenarios. In some cases excluding a permission is fine–in others we need to grant them those permissions but restrict them from being used on our resources.
Our preferred design is to create a resource group of a known-name in each standardized subscription, place the resources users aren’t allowed to modify or delete in the group, and explore options to prevent subscription owners from tampering with that RG or its resources.
So far we’ve explored most options we’re aware of:
- excluding the action/permission isn’t an option as the users need those actions/permissions to manage other resources of the same type (i.e. denying users the ability create/modify/delete resource groups isn’t viable)
- defining an Azure Resource Policy to either deny all operations on the RG (which doesn’t appear to function)
- defining an Azure Resource Policy to require our standard resources — this still does nothing to prevent deletion
- Blueprints (in Preview) to create a locked (with some kind of lock other than a Resource Lock?!?) RG and apply deny assignments
Other options begin to get "sloppy". They leave gaps, or create significant complexity. Such as…
- Relying on Policy to report (and possibly redeploy) when required resources were destroyed
- These resources are security and compliance related–Policy can eventually detect their absence, but the gap between deletion and detection leads to these subscriptions being potentially tainted
- Denying our users the resource lock permissions, so we can exclusively lock our RG and they are unable to unlock it
- When the RG is unlocked there is no protection — so we would need to coordinate unlocking it, applying updates, relocking it, and re-verifying that nothing else snuck in while it was unlocked
- Give our teams a single RG per subscription and only grant them permissions at the RG level
- This may have merit if RGs could be nested — and perhaps is one of the few viable options, but taking away Resouce Group management from Azure engineers feels wrong and would likely lead to RGs being ‘bloated’ with multiple deployments as well as
- Blueprints may be an option, but raise similar questions around coordinating the unlocking and relocking of resources
- And, Terraform is our IaC platform — Blueprints are in some ways another layer of IaC, so while we may get this to work it will require some analysis to use Blueprint for just the minimum to create protections and Terraform to continue to do the bulk of the work
2
Answers
After learning more about Azure Policy I'm gaining the understanding that it's not capable of setting policies to prevent deletion. It can define conventions for creating or updating resources, it can create resources if they are absent, but it doesn't trigger during deletion and so resources required by Policy cannot be protected by Policy.
Overall this seems somewhat counter-intuitive--as delete operations are a
/write
permission just like create and update.So overall I don't believe Policy is actually a permissions component. It lacks any context of who is performing an action and instead effectively is good for saying "if you do X it needs to meet criteria Y". And not saying "your subscription is required to comply with X".
This is surprising--does Azure not have any way of setting resource-level permissions at the Subscription level or above?
After communicating with our Azure contacts this is a known limitation. Presently there is currently no way to retract permissions once granted. I.e. if you grant a user the ability manage resource groups you can not deny them those permissions to a specific instance.
There are some half-baked abilities in AWS Blueprint, which can deploy a Resource Group with an RBAC Deny Assignment (only available via Blueprints). When assigning the Blueprint the "lock" is actually an RBAC Deny — not a Resource Lock (confusing?).
Hoever they explicitly block that permission from being inherited. So while the resource group itself is "ReadOnly" nothing within it is. Using ARM templates deployed via Blueprints may support this — but in our case that would involve rewritting months of work.
Hopefully Microsoft will add Deny Assignments directly to RBAC. They have the API and ability but are keeping it hidden/locked at the moment.