Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/azure-cli/azure/cli/command_modules/role/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,11 +793,19 @@
type: command
short-summary: List role assignments.
long-summary: >-
By default, only assignments scoped to subscription will be displayed.
To view assignments scoped by resource or group, use `--all`.
By default, the scope is the current subscription. Specifying the scope with `--scope` is recommended.


By default, only role assignments exactly at the scope are included, not including role assignments at
parent scopes or sub-scopes. For example, when `--scope` is a subscription, role assignments at management
groups or resource groups are not included.
To include role assignments at parent scopes, use `--include-inherited`.
To include role assignments at parent scopes and sub-scopes, use `--at-scope false`.
examples:
- name: List role assignments at the subscription scope.
- name: List role assignments exactly at the subscription scope.
text: az role assignment list --scope /subscriptions/00000000-0000-0000-0000-000000000000
- name: List role assignments at the subscription scope, including parent scopes and sub-scopes.
text: az role assignment list --scope /subscriptions/00000000-0000-0000-0000-000000000000 --at-scope false
- name: List role assignments at the subscription scope, without filling roleDefinitionName property.
text: az role assignment list --scope /subscriptions/00000000-0000-0000-0000-000000000000 --fill-role-definition-name false
- name: List role assignments with "Reader" role at the subscription scope.
Expand Down
13 changes: 11 additions & 2 deletions src/azure-cli/azure/cli/command_modules/role/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,12 @@ def load_arguments(self, _):

with self.argument_context('role assignment') as c:
c.argument('role', help='role name or id', completer=get_role_definition_name_completion_list)
c.argument('show_all', options_list=['--all'], action='store_true', help='show all assignments under the current subscription')
c.argument('include_inherited', action='store_true', help='include assignments applied on parent scopes')
c.argument('show_all', options_list=['--all'], action='store_true',
deprecate_info=c.deprecate(target='--all'),
help="Show all assignments under the current subscription. This argument is deprecated. "
"Use '--at-scope false' instead.")
c.argument('include_inherited', action='store_true',
help='Include role assignments at parent scopes. This argument only takes effect when --at-scope is true.')
c.argument('can_delegate', action='store_true', help='when set, the assignee will be able to create further role assignments to the same role')
c.argument('assignee', help='represent a user, group, or service principal. supported format: object id, user sign-in name, or service principal name')
c.argument('assignee_object_id',
Expand All @@ -345,6 +349,11 @@ def load_arguments(self, _):
c.argument('condition_version', is_preview=True, min_api='2020-04-01-preview', help='Version of the condition syntax. If --condition is specified without --condition-version, default to 2.0.')
c.argument('assignment_name', name_arg_type,
help='A GUID for the role assignment. It must be unique and different for each role assignment. If omitted, a new GUID is generated.')
c.argument('at_scope', arg_type=get_three_state_flag(),
help='If true, only assignments exactly at the scope are included, not including role assignments '
'at parent scopes or sub-scopes. Specify --include-inherited to include assignments at '
'parent scopes. '
'If false, assignments on parent scopes and sub-scopes are included.')

with self.argument_context('role assignment list') as c:
c.argument('fill_principal_name', arg_type=get_three_state_flag(),
Expand Down
24 changes: 17 additions & 7 deletions src/azure-cli/azure/cli/command_modules/role/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ def _create_role_assignment(cli_ctx, role, assignee, resource_group_name=None, s
def list_role_assignments(cmd, # pylint: disable=too-many-locals, too-many-branches
assignee=None, assignee_object_id=None,
role=None,
resource_group_name=None, scope=None,
scope=None, at_scope=True,
resource_group_name=None,
include_inherited=False,
show_all=False, include_groups=False,
fill_role_definition_name=True, fill_principal_name=True):
Expand All @@ -251,7 +252,8 @@ def list_role_assignments(cmd, # pylint: disable=too-many-locals, too-many-bran
assignee_object_id = _resolve_object_id(cmd.cli_ctx, assignee, fallback_to_object_id=True)
assignments = _search_role_assignments(assignments_client, definitions_client,
scope, assignee_object_id, role,
include_inherited, include_groups)
include_inherited, include_groups,
at_scope=at_scope)

results = todict(assignments) if assignments else []

Expand Down Expand Up @@ -499,7 +501,7 @@ def delete_role_assignments(cmd, ids=None,
assignee_object_id = _resolve_object_id(cmd.cli_ctx, assignee, fallback_to_object_id=True)
assignments = _search_role_assignments(assignments_client, definitions_client,
scope, assignee_object_id, role, include_inherited,
include_groups=False)
include_groups=False, at_scope=True)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am hesitating on whether --at-scope should be exposed by az role assignment delete, as setting --at-scope false will include subscope assignments, causing accidental deletion.


if assignments:
for a in assignments:
Expand All @@ -509,14 +511,20 @@ def delete_role_assignments(cmd, ids=None,


def _search_role_assignments(assignments_client, definitions_client,
scope, assignee_object_id, role, include_inherited, include_groups):
scope, assignee_object_id, role, include_inherited, include_groups,
at_scope=None):
# https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-list-rest
# "atScope()" and "principalId eq '{value}'" query cannot be used together (API limitation).
# always use "scope" if provided, so we can get assignments beyond subscription e.g. management groups
if scope:
f = 'atScope()' # atScope() excludes role assignments at subscopes
filters = []
if at_scope:
filters.append('atScope()') # atScope() excludes role assignments at subscopes
if assignee_object_id and not include_groups and not at_scope:
filters.append("principalId eq '{}'".format(assignee_object_id))
Comment on lines +523 to +524
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now with the ability to turn off atScope(), principalId eq '{}' filter can be used with scope, fixing #14302 (comment).

if assignee_object_id and include_groups:
f = f + " and assignedTo('{}')".format(assignee_object_id)
filters.append("assignedTo('{}')".format(assignee_object_id))
f = ' and '.join(filters) if filters else None
assignments = list(assignments_client.list_for_scope(scope=scope, filter=f))
elif assignee_object_id:
if include_groups:
Expand All @@ -529,8 +537,10 @@ def _search_role_assignments(assignments_client, definitions_client,

if assignments:
assignments = [ra for ra in assignments if (
# If no scope, list all assignments
# If no scope (--all), list all assignments
not scope or
# If --at-scope false, list all assignments
not at_scope or
# If scope is provided with include_inherited, list assignments at and above the scope.
# Note that assignments below the scope are already excluded by atScope()
include_inherited or
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
interactions:
- request:
body: '{"location": "westus"}'
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
CommandName:
- identity create
Connection:
- keep-alive
Content-Length:
- '22'
Content-Type:
- application/json
ParameterSetName:
- -g -n --location
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.12.10 (Windows-11-10.0.26100-SP0)
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001/providers/Microsoft.ManagedIdentity/userAssignedIdentities/clitest000002?api-version=2023-01-31
response:
body:
string: '{"location":"westus","tags":{},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_role_assign000001/providers/Microsoft.ManagedIdentity/userAssignedIdentities/clitest000002","name":"clitest000002","type":"Microsoft.ManagedIdentity/userAssignedIdentities","properties":{"tenantId":"54826b22-38d6-4fb2-bad9-b7b93a3e9c5a","principalId":"88c53162-584e-4c98-984b-62149c2e9bca","clientId":"8cc2fab2-7cc6-4863-aae8-9ee986d5a5ac"}}'
headers:
cache-control:
- no-cache
content-length:
- '449'
content-type:
- application/json; charset=utf-8
date:
- Mon, 14 Apr 2025 08:54:23 GMT
expires:
- '-1'
location:
- /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_role_assign000001/providers/Microsoft.ManagedIdentity/userAssignedIdentities/clitest000002
pragma:
- no-cache
strict-transport-security:
- max-age=31536000; includeSubDomains
x-cache:
- CONFIG_NOCACHE
x-content-type-options:
- nosniff
x-ms-operation-identifier:
- tenantId=54826b22-38d6-4fb2-bad9-b7b93a3e9c5a,objectId=0d504196-1423-4569-9a6e-15149656f0ee/japanwest/90ea6275-c25c-4d73-ba0a-55e6fbe522bb
x-ms-ratelimit-remaining-subscription-global-writes:
- '2999'
x-ms-ratelimit-remaining-subscription-writes:
- '199'
x-msedge-ref:
- 'Ref A: 4359A8C8A1DE4A538CC6C54BFB82E1A0 Ref B: TYO201100114011 Ref C: 2025-04-14T08:54:21Z'
status:
code: 201
message: Created
- request:
body: '{"properties": {"roleDefinitionId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7",
"principalId": "88c53162-584e-4c98-984b-62149c2e9bca", "principalType": "ServicePrincipal"}}'
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
CommandName:
- role assignment create
Connection:
- keep-alive
Content-Length:
- '270'
Content-Type:
- application/json
ParameterSetName:
- --assignee-object-id --assignee-principal-type --role --scope
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.12.10 (Windows-11-10.0.26100-SP0)
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001/providers/Microsoft.Authorization/roleAssignments/88888888-0000-0000-0000-000000000001?api-version=2022-04-01
response:
body:
string: '{"properties":{"roleDefinitionId":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7","principalId":"88c53162-584e-4c98-984b-62149c2e9bca","principalType":"ServicePrincipal","scope":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001","condition":null,"conditionVersion":null,"createdOn":"2025-04-14T08:54:25.8958593Z","updatedOn":"2025-04-14T08:54:26.7153899Z","createdBy":null,"updatedBy":"0d504196-1423-4569-9a6e-15149656f0ee","delegatedManagedIdentityResourceId":null,"description":null},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001/providers/Microsoft.Authorization/roleAssignments/88888888-0000-0000-0000-000000000001","type":"Microsoft.Authorization/roleAssignments","name":"88888888-0000-0000-0000-000000000001"}'
headers:
cache-control:
- no-cache
content-length:
- '897'
content-type:
- application/json; charset=utf-8
date:
- Mon, 14 Apr 2025 08:54:30 GMT
expires:
- '-1'
pragma:
- no-cache
strict-transport-security:
- max-age=31536000; includeSubDomains
x-cache:
- CONFIG_NOCACHE
x-content-type-options:
- nosniff
x-ms-operation-identifier:
- tenantId=54826b22-38d6-4fb2-bad9-b7b93a3e9c5a,objectId=0d504196-1423-4569-9a6e-15149656f0ee/japaneast/5aef1660-efc8-4259-ada4-ff3377587bdb
x-ms-ratelimit-remaining-subscription-global-writes:
- '2999'
x-ms-ratelimit-remaining-subscription-writes:
- '199'
x-msedge-ref:
- 'Ref A: 06485B5DC8264B9C917E7D0942EDE412 Ref B: TYO201151002025 Ref C: 2025-04-14T08:54:25Z'
status:
code: 201
message: Created
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
CommandName:
- role assignment list
Connection:
- keep-alive
ParameterSetName:
- --scope --at-scope --assignee-object-id --fill-role-definition-name --fill-principal-name
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.12.10 (Windows-11-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?$filter=principalId%20eq%20'88c53162-584e-4c98-984b-62149c2e9bca'&api-version=2022-04-01
response:
body:
string: '{"value":[{"properties":{"roleDefinitionId":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7","principalId":"88c53162-584e-4c98-984b-62149c2e9bca","principalType":"ServicePrincipal","scope":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001","condition":null,"conditionVersion":null,"createdOn":"2025-04-14T08:54:26.7153899Z","updatedOn":"2025-04-14T08:54:26.7153899Z","createdBy":"0d504196-1423-4569-9a6e-15149656f0ee","updatedBy":"0d504196-1423-4569-9a6e-15149656f0ee","delegatedManagedIdentityResourceId":null,"description":null},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001/providers/Microsoft.Authorization/roleAssignments/88888888-0000-0000-0000-000000000001","type":"Microsoft.Authorization/roleAssignments","name":"88888888-0000-0000-0000-000000000001"}]}'
headers:
cache-control:
- no-cache
content-length:
- '943'
content-type:
- application/json; charset=utf-8
date:
- Mon, 14 Apr 2025 08:54:31 GMT
expires:
- '-1'
pragma:
- no-cache
strict-transport-security:
- max-age=31536000; includeSubDomains
x-cache:
- CONFIG_NOCACHE
x-content-type-options:
- nosniff
x-ms-operation-identifier:
- tenantId=54826b22-38d6-4fb2-bad9-b7b93a3e9c5a,objectId=0d504196-1423-4569-9a6e-15149656f0ee/japaneast/4f3785c6-7da5-4a37-9e9a-37b877a366e0
x-ms-ratelimit-remaining-subscription-global-reads:
- '3749'
x-msedge-ref:
- 'Ref A: F01D790831084190BDA2FD89661CF517 Ref B: TYO201151001054 Ref C: 2025-04-14T08:54:31Z'
status:
code: 200
message: OK
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
CommandName:
- role assignment list
Connection:
- keep-alive
ParameterSetName:
- --scope --at-scope --assignee-object-id --fill-role-definition-name --fill-principal-name
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.12.10 (Windows-11-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001/providers/Microsoft.Authorization/roleAssignments?$filter=principalId%20eq%20'88c53162-584e-4c98-984b-62149c2e9bca'&api-version=2022-04-01
response:
body:
string: '{"value":[{"properties":{"roleDefinitionId":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7","principalId":"88c53162-584e-4c98-984b-62149c2e9bca","principalType":"ServicePrincipal","scope":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001","condition":null,"conditionVersion":null,"createdOn":"2025-04-14T08:54:26.7153899Z","updatedOn":"2025-04-14T08:54:26.7153899Z","createdBy":"0d504196-1423-4569-9a6e-15149656f0ee","updatedBy":"0d504196-1423-4569-9a6e-15149656f0ee","delegatedManagedIdentityResourceId":null,"description":null},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_role_assign000001/providers/Microsoft.Authorization/roleAssignments/88888888-0000-0000-0000-000000000001","type":"Microsoft.Authorization/roleAssignments","name":"88888888-0000-0000-0000-000000000001"}]}'
headers:
cache-control:
- no-cache
content-length:
- '943'
content-type:
- application/json; charset=utf-8
date:
- Mon, 14 Apr 2025 08:54:31 GMT
expires:
- '-1'
pragma:
- no-cache
strict-transport-security:
- max-age=31536000; includeSubDomains
x-cache:
- CONFIG_NOCACHE
x-content-type-options:
- nosniff
x-ms-operation-identifier:
- tenantId=54826b22-38d6-4fb2-bad9-b7b93a3e9c5a,objectId=0d504196-1423-4569-9a6e-15149656f0ee/japaneast/b891f240-fe35-43fb-a8ef-cd9597db7f7e
x-ms-ratelimit-remaining-subscription-global-reads:
- '3749'
x-msedge-ref:
- 'Ref A: 0DD953D8592F4F9796E6678A325D0EAB Ref B: TYO201151002025 Ref C: 2025-04-14T08:54:32Z'
status:
code: 200
message: OK
version: 1
Loading
Loading