Skip to content

Conversation

@jiasli
Copy link
Member

@jiasli jiasli commented Dec 5, 2024

Related command
az role assignment list
az role assignment delete

Description
Close #30436
Fix #20349, #30428, #30672

With more encouragement on managed identity and more strict permission/access control, supporting --assignee-object-id to bypass Graph query is a necessary feature for role assignment’s management experience.

Similar to #5273 which added --assignee-object-id to az role assignment create to bypass Graph query, this PR adds --assignee-object-id to az role assignment list/delete.

Testing Guide

az role assignment list --assignee
az role assignment list --assignee-object-id
az role assignment delete --assignee
az role assignment delete --assignee-object-id

History Notes

[Role] az role assignment list/delete: Add --assignee-object-id argument. Use this argument instead of --assignee to bypass Microsoft Graph query

@azure-client-tools-bot-prd
Copy link

azure-client-tools-bot-prd bot commented Dec 5, 2024

️✔️AzureCLI-FullTest
️✔️acr
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️acs
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️advisor
️✔️latest
️✔️3.12
️✔️3.9
️✔️ams
️✔️latest
️✔️3.12
️✔️3.9
️✔️apim
️✔️latest
️✔️3.12
️✔️3.9
️✔️appconfig
️✔️latest
️✔️3.12
️✔️3.9
️✔️appservice
️✔️latest
️✔️3.12
️✔️3.9
️✔️aro
️✔️latest
️✔️3.12
️✔️3.9
️✔️backup
️✔️latest
️✔️3.12
️✔️3.9
️✔️batch
️✔️latest
️✔️3.12
️✔️3.9
️✔️batchai
️✔️latest
️✔️3.12
️✔️3.9
️✔️billing
️✔️latest
️✔️3.12
️✔️3.9
️✔️botservice
️✔️latest
️✔️3.12
️✔️3.9
️✔️cdn
️✔️latest
️✔️3.12
️✔️3.9
️✔️cloud
️✔️latest
️✔️3.12
️✔️3.9
️✔️cognitiveservices
️✔️latest
️✔️3.12
️✔️3.9
️✔️compute_recommender
️✔️latest
️✔️3.12
️✔️3.9
️✔️computefleet
️✔️latest
️✔️3.12
️✔️3.9
️✔️config
️✔️latest
️✔️3.12
️✔️3.9
️✔️configure
️✔️latest
️✔️3.12
️✔️3.9
️✔️consumption
️✔️latest
️✔️3.12
️✔️3.9
️✔️container
️✔️latest
️✔️3.12
️✔️3.9
️✔️containerapp
️✔️latest
️✔️3.12
️✔️3.9
️✔️core
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️cosmosdb
️✔️latest
️✔️3.12
️✔️3.9
️✔️databoxedge
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️dls
️✔️latest
️✔️3.12
️✔️3.9
️✔️dms
️✔️latest
️✔️3.12
️✔️3.9
️✔️eventgrid
️✔️latest
️✔️3.12
️✔️3.9
️✔️eventhubs
️✔️latest
️✔️3.12
️✔️3.9
️✔️feedback
️✔️latest
️✔️3.12
️✔️3.9
️✔️find
️✔️latest
️✔️3.12
️✔️3.9
️✔️hdinsight
️✔️latest
️✔️3.12
️✔️3.9
️✔️identity
️✔️latest
️✔️3.12
️✔️3.9
️✔️iot
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️keyvault
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️lab
️✔️latest
️✔️3.12
️✔️3.9
️✔️managedservices
️✔️latest
️✔️3.12
️✔️3.9
️✔️maps
️✔️latest
️✔️3.12
️✔️3.9
️✔️marketplaceordering
️✔️latest
️✔️3.12
️✔️3.9
️✔️monitor
️✔️latest
️✔️3.12
️✔️3.9
️✔️mysql
️✔️latest
️✔️3.12
️✔️3.9
️✔️netappfiles
️✔️latest
️✔️3.12
️✔️3.9
️✔️network
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️policyinsights
️✔️latest
️✔️3.12
️✔️3.9
️✔️privatedns
️✔️latest
️✔️3.12
️✔️3.9
️✔️profile
️✔️latest
️✔️3.12
️✔️3.9
️✔️rdbms
️✔️latest
️✔️3.12
️✔️3.9
️✔️redis
️✔️latest
️✔️3.12
️✔️3.9
️✔️relay
️✔️latest
️✔️3.12
️✔️3.9
️✔️resource
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️role
️✔️latest
️✔️3.12
️✔️3.9
️✔️search
️✔️latest
️✔️3.12
️✔️3.9
️✔️security
️✔️latest
️✔️3.12
️✔️3.9
️✔️servicebus
️✔️latest
️✔️3.12
️✔️3.9
️✔️serviceconnector
️✔️latest
️✔️3.12
️✔️3.9
️✔️servicefabric
️✔️latest
️✔️3.12
️✔️3.9
️✔️signalr
️✔️latest
️✔️3.12
️✔️3.9
️✔️sql
️✔️latest
️✔️3.12
️✔️3.9
️✔️sqlvm
️✔️latest
️✔️3.12
️✔️3.9
️✔️storage
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️synapse
️✔️latest
️✔️3.12
️✔️3.9
️✔️telemetry
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️util
️✔️latest
️✔️3.12
️✔️3.9
️✔️vm
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9

@azure-client-tools-bot-prd
Copy link

azure-client-tools-bot-prd bot commented Dec 5, 2024

⚠️AzureCLI-BreakingChangeTest
⚠️role
rule cmd_name rule_message suggest_message
⚠️ 1006 - ParaAdd role assignment delete cmd role assignment delete added parameter assignee_object_id
⚠️ 1006 - ParaAdd role assignment list cmd role assignment list added parameter assignee_object_id

@yonzhan
Copy link
Collaborator

yonzhan commented Dec 5, 2024

Thank you for your contribution! We will review the pull request and get back to you soon.

@github-actions
Copy link

github-actions bot commented Dec 5, 2024

⚠️Your changes in this PR will be released on Jan 14, 2025 due to CCOA (extend to Jan 6, 2025)

@jiasli
Copy link
Member Author

jiasli commented Dec 5, 2024

In az role assignment list, --assignee is also used to back fill classic administrators:

if include_classic_administrators:
results += _backfill_assignments_for_co_admins(cmd.cli_ctx, authorization_client, assignee)

Classic administrator support should be dropped: #29470

@jiasli
Copy link
Member Author

jiasli commented Dec 5, 2024

In az role assignment list, even if --assignee-object-id is provided, this command still queries Graph for the assignee information:

if principal_ids:
try:
principals = _get_object_stubs(graph_client, principal_ids)

I feel this behavior should be skipped if --assignee-object-id is provided, or we can introduce another argument such as --no-graph-query.

Update: #30693 added --fill-principal-name to bypass Graph query.

Comment on lines +243 to +246
if assignee_object_id and include_classic_administrators:
raise CLIError('Usage error: --assignee-object-id cannot be used with --include-classic-administrators. '
'Use --assignee instead.')
Copy link
Member Author

@jiasli jiasli Mar 27, 2025

Choose a reason for hiding this comment

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

Classic admin assignments use email_address (UPN), instead of principal ID:

co_admins = [x for x in co_admins if assignee == x.email_address.lower()]

When --assignee-object-id is provided, it is necessary to convert object ID to UPN:

if is_guid(assignee):
try:
result = _get_object_stubs(graph_client, [assignee])
if not result:
return []
assignee = _get_displayable_name(result[0]).lower()
except ValueError:
pass

This will trigger Graph call which is against the initial purpose.

Moreover, as --include-classic-administrator will be removed soon (#29470). Updating the legacy code is worthless.

@jiasli jiasli reopened this Mar 28, 2025
@jiasli jiasli changed the title [Role] az role assignment list/delete: Support --assignee-object-id [Role] az role assignment list/delete: Add --assignee-object-id to bypass Graph query Mar 28, 2025
Comment on lines -239 to -242
'''
:param include_groups: include extra assignments to the groups of which the user is a
member(transitively).
'''
Copy link
Member Author

Choose a reason for hiding this comment

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

include_groups should be declared in _params.py, not here. #602 (comment)

@jiasli jiasli changed the title [Role] az role assignment list/delete: Add --assignee-object-id to bypass Graph query [Role] az role assignment list/delete: Add --assignee-object-id Apr 3, 2025
self.not_exists("[0].principalName")
])
# Manually verify the recording file that no HTTP request to https://graph.microsoft.com is made
self.cmd('role assignment delete --scope {rg_id} --assignee-object-id {uami_object_id}')
Copy link
Member Author

@jiasli jiasli Apr 3, 2025

Choose a reason for hiding this comment

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

az role assignment delete doesn't support --all, so it can only query role assignments via

if scope:
f = 'atScope()' # atScope() excludes role assignments at subscopes
if assignee_object_id and include_groups:
f = f + " and assignedTo('{}')".format(assignee_object_id)
assignments = list(assignments_client.list_for_scope(scope=scope, filter=f))

This still makes the recording big. #31179 will solve this.

Comment on lines +728 to +729
self.cmd('role assignment list --all --assignee-object-id {uami_object_id} '
'--fill-role-definition-name false --fill-principal-name false',
Copy link
Member Author

@jiasli jiasli Apr 3, 2025

Choose a reason for hiding this comment

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

Using --all --assignee-object-id reduces az role assignment list's recording file size (#31152 (comment)).

@jiasli jiasli marked this pull request as ready for review April 3, 2025 08:43
@jiasli jiasli requested review from bebound and evelyn-ys as code owners April 3, 2025 08:43
@jiasli jiasli force-pushed the assignee_object_id branch 2 times, most recently from bbfb909 to 933506c Compare April 3, 2025 10:43
@jiasli jiasli force-pushed the assignee_object_id branch from 933506c to 56123d6 Compare April 7, 2025 07:22
except Exception as ex: # pylint: disable=broad-except
if _error_caused_by_role_assignment_exists(ex): # for idempotent
return list_role_assignments(cmd, assignee=assignee, role=role, scope=scope)[0]
return list_role_assignments(cmd, assignee_object_id=object_id, role=role, scope=scope)[0]
Copy link
Member Author

@jiasli jiasli Apr 8, 2025

Choose a reason for hiding this comment

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

Using object_id instead of assignee saves one Graph query for az role assignment create.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Auto-Assign Auto assign by bot RBAC az role

Projects

None yet

4 participants