4 minute read

Within our company, we have a sponsorship subscription we use for developing / testing purposes. As we heavily use this subscription, we often come into problems with access rights depending on the type of resource group.

In a larger environment, we would solve this by creating multiple subscriptions, but as we do not have multiple sponsorship subscriptions, we came up with another idea.

We categorize resource groups by using tags and came up with the idea to set up access rights on the resource groups based on the tags that are supplied on newly created resource groups. To get this operational, a colleague and I thought out a new custom policy that he created that I am sharing with the community.

For this policy, we use the policy effect 'deployIfnotexists'. By using this effect, we have the option to execute a deployment when a new resource group is created by using the below policy rule.

            "if": {
                "allOf": [
                    {
                        "field": "type",
                        "equals": "Microsoft.Resources/subscriptions/resourceGroups"
                    },
                    {
                        "field": "[concat('tags[', parameters('tagName'), ']')]",
                        "equals": "[parameters('tagValue')]"
                    }
                ]
            }

This rule checks if the type of the resource is a resource group and if it contains a tag with a specific value. The tag and its value it needs to check up on are specified when assigning the policy to a specific scope.

The 'then' of the rule will then execute a deployment, which is just a general RBAC deployment via ARM.

"then": {
                "effect": "deployIfNotExists",
                "details": {
                    "EvaluationDelay": "AfterProvisioningSuccess",
                    "roleDefinitionIds": [
                        "/providers/microsoft.authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
                    ],
                    "type": "Microsoft.Authorization/roleAssignments",
                    "existenceCondition": {
                        "allOf": [
                            {
                                "field": "Microsoft.Authorization/roleAssignments/roleDefinitionId",
                                "equals": "[concat('/subscriptions/',subscription().subscriptionId ,parameters('roleId'))]"
                            },
                            {
                                "field": "Microsoft.Authorization/roleAssignments/principalId",
                                "equals": "[parameters('principalId')]"
                            }
                        ]
                    },
                    "deployment": {
                        "properties": {
                            "mode": "incremental",
                            "parameters": {
                                "principalType": {
                                    "value": "[parameters('principalType')]"
                                },
                                "principalId": {
                                    "value": "[parameters('principalId')]"
                                },
                                "roleId": {
                                    "value": "[parameters('roleId')]"
                                }
                            },
                            "template": {
                                "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                                "contentVersion": "1.0.0.0",
                                "parameters": {
                                    "principalType": {
                                        "type": "string"
                                    },
                                    "principalId": {
                                        "type": "string"
                                    },
                                    "roleId": {
                                        "type": "string"
                                    }
                                },
                                "variables": {},
                                "resources": [
                                    {
                                        "name": "[guid(resourceGroup().id, deployment().name)]",
                                        "type": "Microsoft.Authorization/roleAssignments",
                                        "apiVersion": "2020-10-01-preview",
                                        "properties": {
                                            "principalId": "[parameters('principalId')]",
                                            "roleDefinitionId": "[parameters('roleId')]",
                                            "principalType": "[parameters('principalType')]"
                                        }
                                    }
                                ],
                                "outputs": {
                                    "policy": {
                                        "type": "string",
                                        "value": "[concat('Added RBAC Rights')]"
                                    }
                                }
                            }
                        }
                    }
                }
            }

On the 'deployifnotexists', there is also an 'EvaluationDelay' specified. This specifies when the existence of the related resources should be evaluated. The delay is only used for evaluations that are a result of a create or update resource request. So the evaluation is done after the provisioning is succeeded.

The complete policy definitions then look like this.

{
    "properties": {
        "displayName": "Add access rights based on tags",
        "policyType": "Custom",
        "mode": "All",
        "description": "Policy to add access rights based on tags added to a resource group",
        "metadata": {
            "version": "1.0.0",
            "category": "Custom"
        },
        "parameters": {
            "tagName": {
                "type": "String",
                "metadata": {
                    "displayName": "Tag Name",
                    "description": "The Tag name to audit against (i.e. Environment CostCenter etc.)"
                },
                "defaultValue": "Environment"
            },
            "tagValue": {
                "type": "String",
                "metadata": {
                    "displayName": "Tag Value",
                    "description": "Value of the tag to audit against (i.e. Prod/UAT/TEST 12345 etc.)"
                }
            },
            "roleId": {
                "type": "string",
                "metadata": {
                    "displayName": "roleId",
                    "description": "roleId",
                    "strongType": "Microsoft.Authorization/roleDefinitions"
                }
            },
            "principalId": {
                "type": "string",
                "metadata": {
                    "displayName": "principalId",
                    "description": "principalId"
                }
            },
            "principalType": {
                "type": "string",
                "metadata": {
                    "displayName": "principalType",
                    "description": "principalType"
                },
                "allowedValues": [
                    "Device",
                    "ForeignGroup",
                    "Group",
                    "ServicePrincipal",
                    "User"
                ]
            }
        },
        "policyRule": {
            "if": {
                "allOf": [
                    {
                        "field": "type",
                        "equals": "Microsoft.Resources/subscriptions/resourceGroups"
                    },
                    {
                        "field": "[concat('tags[', parameters('tagName'), ']')]",
                        "equals": "[parameters('tagValue')]"
                    }
                ]
            },
            "then": {
                "effect": "deployIfNotExists",
                "details": {
                    "EvaluationDelay": "AfterProvisioningSuccess",
                    "roleDefinitionIds": [
                        "/providers/microsoft.authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
                    ],
                    "type": "Microsoft.Authorization/roleAssignments",
                    "existenceCondition": {
                        "allOf": [
                            {
                                "field": "Microsoft.Authorization/roleAssignments/roleDefinitionId",
                                "equals": "[concat('/subscriptions/',subscription().subscriptionId ,parameters('roleId'))]"
                            },
                            {
                                "field": "Microsoft.Authorization/roleAssignments/principalId",
                                "equals": "[parameters('principalId')]"
                            }
                        ]
                    },
                    "deployment": {
                        "properties": {
                            "mode": "incremental",
                            "parameters": {
                                "principalType": {
                                    "value": "[parameters('principalType')]"
                                },
                                "principalId": {
                                    "value": "[parameters('principalId')]"
                                },
                                "roleId": {
                                    "value": "[parameters('roleId')]"
                                }
                            },
                            "template": {
                                "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                                "contentVersion": "1.0.0.0",
                                "parameters": {
                                    "principalType": {
                                        "type": "string"
                                    },
                                    "principalId": {
                                        "type": "string"
                                    },
                                    "roleId": {
                                        "type": "string"
                                    }
                                },
                                "variables": {},
                                "resources": [
                                    {
                                        "name": "[guid(resourceGroup().id, deployment().name)]",
                                        "type": "Microsoft.Authorization/roleAssignments",
                                        "apiVersion": "2020-10-01-preview",
                                        "properties": {
                                            "principalId": "[parameters('principalId')]",
                                            "roleDefinitionId": "[parameters('roleId')]",
                                            "principalType": "[parameters('principalType')]"
                                        }
                                    }
                                ],
                                "outputs": {
                                    "policy": {
                                        "type": "string",
                                        "value": "[concat('Added RBAC Rights')]"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

GitHub

Check out GitHub for the script files and the policy also supplied in Bicep:

https://github.com/maikvandergaag/msft-azureplatform/tree/main/policies/add_access