Custom role has permission to administer resource locks
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 Cloudprowler azure --checks iam_custom_role_has_permissions_to_administer_resource_locksRecommendation
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
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