-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Conversation
️✔️AzureCLI-FullTest
|
️✔️AzureCLI-BreakingChangeTest
|
AD |
Default permissions are created for the current user or service principal unless the `--no-self-perms` | ||
or `--enable-rbac-authorization` flag is specified. |
There was a problem hiding this comment.
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']: |
There was a problem hiding this comment.
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:
azure-cli/src/azure-cli-core/azure/cli/core/_profile.py
Lines 408 to 415 in b00483c
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 | |
}, |
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.') |
There was a problem hiding this comment.
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']) |
There was a problem hiding this comment.
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.
if len(accounts) > 1: | ||
logger.warning("Multiple service principals found with spn '%s'. " | ||
"You can avoid this by specifying object id.", spn) | ||
return None |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
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 |
There was a problem hiding this comment.
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
.
except CloudError: | ||
pass |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
#29878 caused merge conflict on |
bce9266
to
beaa4df
Compare
lab
and servicefabric
command modules to Microsoft Graphservicefabric
command module to Microsoft Graph
servicefabric
command module to Microsoft Graphservicefabric
command module to Microsoft Graph
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks!
Related command
az sf
Description
servicefabric
command module directly useazure-graphrbac
SDK to call AD Graph.This PR migrates
servicefabric
command module to call Microsoft Graph to address #22174.