Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{Service Fabric} Migrate servicefabric command module to Microsoft Graph #28105

Merged
merged 1 commit into from
Sep 12, 2024

Conversation

jiasli
Copy link
Member

@jiasli jiasli commented Dec 28, 2023

Related command
az sf

Description
servicefabric command module directly use azure-graphrbac SDK to call AD Graph.

This PR migrates servicefabric command module to call Microsoft Graph to address #22174.

Copy link

azure-client-tools-bot-prd bot commented Dec 28, 2023

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

Copy link

azure-client-tools-bot-prd bot commented Dec 28, 2023

️✔️AzureCLI-BreakingChangeTest
️✔️Non Breaking Changes

@yonzhan
Copy link
Collaborator

yonzhan commented Dec 28, 2023

AD

Comment on lines 242 to 243
Default permissions are created for the current user or service principal unless the `--no-self-perms`
or `--enable-rbac-authorization` flag is specified.
Copy link
Member Author

Choose a reason for hiding this comment

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

This changes the original cumbersome expression (#12074 (comment)).

if not subscription:
return None

if subscription['user']:
Copy link
Member Author

@jiasli jiasli Dec 28, 2023

Choose a reason for hiding this comment

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

It is not possible for a subscription to have no user field, as _USER_ENTITY(user) will always be set during creation:

subscription_dict = {
_SUBSCRIPTION_ID: s.id.rpartition('/')[2],
_SUBSCRIPTION_NAME: s.display_name,
_STATE: s.state,
_USER_ENTITY: {
_USER_NAME: user,
_USER_TYPE: _SERVICE_PRINCIPAL if is_service_principal else _USER
},

Comment on lines -342 to -350
if subscription['user']:
if subscription['user']['type'] == 'user':
return _get_object_id_by_upn(graph_client, subscription['user']['name'])
if subscription['user']['type'] == 'servicePrincipal':
return _get_object_id_by_spn(graph_client, subscription['user']['name'])
logger.warning("Unknown user type '%s'", subscription['user']['type'])
else:
logger.warning('Current credentials are not from a user or service principal. '
'Azure Key Vault does not work with certificate credentials.')
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 guess certificate credential is a remnant of the very old implementation for RDFE.

return _get_object_id_by_upn(graph_client, subscription['user']['name'])
if subscription['user']['type'] == 'servicePrincipal':
return _get_object_id_by_spn(graph_client, subscription['user']['name'])
logger.warning("Unknown user type '%s'", subscription['user']['type'])
Copy link
Member Author

Choose a reason for hiding this comment

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

user and servicePrincipal are the only possible values for user.type:

_USER_TYPE: _SERVICE_PRINCIPAL if is_service_principal else _USER

Unless the user deliberately corrupt azureProfile.json, this warning can never be hit.

Comment on lines -319 to -322
if len(accounts) > 1:
logger.warning("Multiple service principals found with spn '%s'. "
"You can avoid this by specifying object id.", spn)
return None
Copy link
Member Author

Choose a reason for hiding this comment

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

It is not possible for multiple service principals to have the same spn, so this check will never be hit. azure.cli.command_modules.role.custom._resolve_object_id_and_type has such logic:

# 2+ matches should never happen, so we only check 'no match' here

accounts = list(graph_client.service_principal_list(
filter="servicePrincipalNames/any(c:c eq '{}')".format(spn)))
if not accounts:
logger.warning("Unable to find user with spn '%s'", spn)
Copy link
Member Author

Choose a reason for hiding this comment

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

spn stands for Service Principal Name. A user object never has spn property.

@virtualjack
Copy link

If az-cli isn't being updated to remove EOL libraries, I guess it means that it is effectively unsupported.

from msrestazure.azure_exceptions import CloudError
try:
current_user = graph_client.signed_in_user.get()
if current_user and current_user.object_id: # pylint:disable=no-member
Copy link
Member Author

Choose a reason for hiding this comment

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

A user object can never have no object_id.

Comment on lines 541 to 545
except CloudError:
pass
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 guess this line tries to silence the exception. However, L125 relies on the exception. The code is buggy.

return None


def _get_object_id(graph_client, spn=None, upn=None):
Copy link
Member Author

@jiasli jiasli Sep 3, 2024

Choose a reason for hiding this comment

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

There is no need for _get_object_id to support subscription argument. _get_object_id_from_subscription can be directly called by get_current_identity_object_id.

# Before
keyvault/servicefabric/lab -> _get_object_id -> [subscription] _get_object_id_from_subscription
                                             -> [spn] _get_object_id_by_spn
                                             -> [upn] _get_object_id_by_upn

# After
keyvault -> get_object_id -> _get_object_id -> [spn] _get_object_id_by_spn
                                            -> [upn] _get_object_id_by_upn

keyvault/servicefabric/lab -> get_current_identity_object_id -> [subscription] _get_object_id_from_subscription

Copy link
Member Author

Choose a reason for hiding this comment

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

There is no test named test_node_type.

Copy link
Member Author

Choose a reason for hiding this comment

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

test_add_secondary_node_type_add_remove_node was changed to live only by #25735.

except GraphError:
from azure.cli.core._profile import Profile
profile = Profile(cli_ctx)
subscription = profile.get_subscription(subscription=cli_ctx.data.get('subscription_id', None))
Copy link
Member

Choose a reason for hiding this comment

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

Can we add a subscription parameter for get_current_identity_object_id to avoid calling profile.get_subscription() twice? Keyvault/Servicefabric has already got subscription before calling get_current_identity_object_id.

Copy link
Member Author

@jiasli jiasli Sep 4, 2024

Choose a reason for hiding this comment

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

The first attempt of get_current_identity_object_id() is to call _get_current_user_object_id(), it will use the current login context. Supporting a custom subscription parameter may cause inconsistency with _get_current_user_object_id().

Actually, I think even this line shouldn't pass subscription=cli_ctx.data.get('subscription_id', None) as this may cause inconsistency with _get_current_user_object_id(). This may result in using the current login context to look up the object ID of another identity.

We clearly documented this in the help message:

If you want to assign the default permission, you have to change the default subscription with az account set first, instead of using --subscription.

Copy link
Member

Choose a reason for hiding this comment

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

Not sure if this will break cross-tenant support (Not sure if it still works). I will do manual test this afternoon

except GraphError:
from azure.cli.core._profile import Profile
profile = Profile(cli_ctx)
subscription = profile.get_subscription()
Copy link
Member

Choose a reason for hiding this comment

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

It surprised me that even we removed subscription=cmd.cli_ctx.data.get('subscription_id', None), it still used the value passed by --subscription
image

Copy link
Member

Choose a reason for hiding this comment

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

Then I have no concerns. Cross-tenant is still supported

Copy link
Member

@evelyn-ys evelyn-ys Sep 4, 2024

Choose a reason for hiding this comment

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

Oh wait... It's created in --subscription because it's calling _get_current_user_object_id(), not _get_object_id_from_subscription().

It's difficult to prepare a cross-tenant sp account for test

Copy link
Member

Choose a reason for hiding this comment

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

I finally understand that graph call is tenant level. There's no meaning to care about cross-sub level support in keyvault creation as it's always a mess.

No concerns, just go ahead

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 provided a comprehensive analysis on this issue at #29837

evelyn-ys
evelyn-ys previously approved these changes Sep 4, 2024
evelyn-ys
evelyn-ys previously approved these changes Sep 5, 2024
@jiasli
Copy link
Member Author

jiasli commented Sep 11, 2024

#29878 caused merge conflict on src/azure-cli/azure/cli/command_modules/lab/validators.py.

@jiasli jiasli changed the title {AD} Migrate lab and servicefabric command modules to Microsoft Graph {AD} Migrate servicefabric command module to Microsoft Graph Sep 11, 2024
@jiasli jiasli changed the title {AD} Migrate servicefabric command module to Microsoft Graph {Service Fabric} Migrate servicefabric command module to Microsoft Graph Sep 11, 2024
Comment on lines +244 to +245
Copy link
Contributor

@zhoxing-ms zhoxing-ms Sep 11, 2024

Choose a reason for hiding this comment

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

Just a little question: could we just leave a blank line in the middle? Is there any reason for leaving two blank lines?

Copy link
Member Author

Choose a reason for hiding this comment

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

Since > is used, 2 blank lines will be rendered as 1 blank line:

> az keyvault create -h

Command
    az keyvault create : Create a Vault or HSM.
        RBAC authorization is enabled by default. If `--enable-rbac-authorization` is manually
        specified to `false` and `--no-self-perms` flag is not specified, default permissions are
        created for the current user or service principal.

        If you want to assign the default permission, you have to change the default subscription
        with `az account set` first, instead of using `--subscription`.

If we only put 1 blank line here, these paragraphs will not be separated:

> az keyvault create -h

Command
    az keyvault create : Create a Vault or HSM.
        RBAC authorization is enabled by default. If `--enable-rbac-authorization` is manually
        specified to `false` and `--no-self-perms` flag is not specified, default permissions are
        created for the current user or service principal.
        If you want to assign the default permission, you have to change the default subscription
        with `az account set` first, instead of using `--subscription`.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it, thanks!

@jiasli jiasli merged commit 3ae89ed into Azure:dev Sep 12, 2024
61 checks passed
@jiasli jiasli deleted the module-graph branch September 12, 2024 09:16
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 Service Fabric az sf
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants