Back to Checks
azure

Custom role has permission to administer resource locks

iam_custom_role_has_permissions_to_administer_resource_locks
Service: iamSeverity: medium
OfficialBuilt-inVerified
Categories:identity-access
Resource Type:microsoft.authorization/roledefinitions

Azure custom RBAC roles include the Microsoft.Authorization/locks/* action, indicating permission to administer management locks at subscription, resource group, or resource scope.

Risk

Absent a scoped custom role for Microsoft.Authorization/locks/*, lock control falls to broad roles (e.g., Owner), weakening least privilege. Locks can be disabled or altered, enabling unauthorized changes or deletion, harming integrity and availability, and reducing separation of duties and accountability.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler azure --checks iam_custom_role_has_permissions_to_administer_resource_locks

Recommendation

Define a least-privilege custom role restricted to Microsoft.Authorization/locks/* and assign it to a tightly controlled group at minimal scope. Apply separation of duties, use just-in-time elevation, audit lock changes, and avoid broad roles or pipeline identities managing locks. Layer with defense-in-depth controls.

Remediation

CLI

az role definition create --role-definition '{"Name":"<role_name>","Description":"Custom role to administer resource locks","IsCustom":true,"Actions":["Microsoft.Authorization/locks/*"],"NotActions":[],"AssignableScopes":["/subscriptions/<subscription_id>"]}'

Terraform

# Custom role with permission to administer resource locks
resource "azurerm_role_definition" "<example_resource_name>" {
  name  = "<example_resource_name>"
  scope = "/subscriptions/<example_resource_id>"

  permissions {
    actions = [
      "Microsoft.Authorization/locks/*" # CRITICAL: adds lock admin permission to pass the check
    ]
  }

  assignable_scopes = ["/subscriptions/<example_resource_id>"]
}

NativeIaC

// Custom role that can administer resource locks
targetScope = 'subscription'

resource roleDef 'Microsoft.Authorization/roleDefinitions@2022-04-01' = {
  name: guid(subscription().id, '<role_name>') // CRITICAL: use GUID for role definition name
  properties: {
    roleName: '<role_name>'
    description: 'Custom role to administer resource locks'
    permissions: [
      {
        actions: [
          'Microsoft.Authorization/locks/*' // CRITICAL: grants lock administration to pass the check
        ]
        notActions: []
      }
    ]
    assignableScopes: [ subscription().id ]
  }
}

Other

1In the Azure portal, go to the target scope (Subscription or Resource group) and open Access control (IAM)
2Click Roles, find your custom role, and select Edit
3Go to Permissions > Add permissions
4Search for "Microsoft.Authorization/locks" and select Microsoft.Authorization/locks/*
5Click Add, then Review + save > Save

Check Code

from re import search

from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.iam.iam_client import iam_client


class iam_custom_role_has_permissions_to_administer_resource_locks(Check):
    def execute(self) -> Check_Report_Azure:
        findings = []
        for subscription, roles in iam_client.custom_roles.items():
            subscription_name = iam_client.subscriptions.get(subscription, subscription)
            exits_role_with_permission_over_locks = False

            for custom_role in roles.values():
                if exits_role_with_permission_over_locks:
                    break
                report = Check_Report_Azure(
                    metadata=self.metadata(), resource=custom_role
                )
                report.subscription = subscription
                report.status = "FAIL"
                report.status_extended = f"Role {custom_role.name} from subscription {subscription_name} ({subscription}) has no permission to administer resource locks."

                for permission_item in custom_role.permissions:
                    if exits_role_with_permission_over_locks:
                        break
                    for action in permission_item.actions:
                        if search("^Microsoft.Authorization/locks/.*", action):
                            report.status = "PASS"
                            report.status_extended = f"Role {custom_role.name} from subscription {subscription_name} ({subscription}) has permission to administer resource locks."
                            exits_role_with_permission_over_locks = True
                            break
                findings.append(report)
        return findings