47
47
from azure .cli .command_modules .acs ._params import regions_in_preview , regions_in_prod
48
48
from azure .cli .core .api import get_config_dir
49
49
from azure .cli .core .azclierror import (ResourceNotFoundError ,
50
- ArgumentUsageError ,
51
50
ClientRequestError ,
51
+ ArgumentUsageError ,
52
52
InvalidArgumentValueError ,
53
53
MutuallyExclusiveArgumentError ,
54
- ValidationError )
54
+ ValidationError ,
55
+ UnauthorizedError )
55
56
from azure .cli .core ._profile import Profile
56
57
from azure .cli .core .profiles import ResourceType
57
58
from azure .cli .core .commands .client_factory import get_mgmt_service_client , get_subscription_id
100
101
from ._consts import ADDONS
101
102
from ._consts import CONST_CANIPULL_IMAGE
102
103
from ._consts import CONST_PRIVATE_DNS_ZONE_SYSTEM
104
+ from ._consts import CONST_MANAGED_IDENTITY_OPERATOR_ROLE , CONST_MANAGED_IDENTITY_OPERATOR_ROLE_ID
103
105
104
106
logger = get_logger (__name__ )
105
107
@@ -784,10 +786,16 @@ def _generate_properties(api_version, orchestrator_type, orchestrator_version, m
784
786
return properties
785
787
786
788
787
- def _get_user_assigned_identity_client_id (cli_ctx , resource_id ):
788
- pattern = '/subscriptions/(.*?)/resourcegroups/(.*?)/providers/microsoft.managedidentity/userassignedidentities/(.*)' # pylint: disable=line-too-long
789
+ def _get_user_assigned_identity_resource_id_regular_expression ():
790
+ return re .compile (
791
+ r'/subscriptions/(.*?)/resourcegroups/(.*?)/providers/microsoft.managedidentity/userassignedidentities/(.*)' ,
792
+ flags = re .IGNORECASE )
793
+
794
+
795
+ def _get_user_assigned_identity (cli_ctx , resource_id ):
789
796
resource_id = resource_id .lower ()
790
- match = re .search (pattern , resource_id )
797
+ _re_user_assigned_identity_resource_id = _get_user_assigned_identity_resource_id_regular_expression ()
798
+ match = _re_user_assigned_identity_resource_id .search (resource_id )
791
799
if match :
792
800
subscription_id = match .group (1 )
793
801
resource_group_name = match .group (2 )
@@ -798,14 +806,21 @@ def _get_user_assigned_identity_client_id(cli_ctx, resource_id):
798
806
resource_name = identity_name )
799
807
except CloudError as ex :
800
808
if 'was not found' in ex .message :
801
- raise ResourceNotFoundError (
802
- "Identity {} not found." .format (resource_id ))
809
+ raise ResourceNotFoundError ("Identity {} not found." .format (resource_id ))
803
810
raise ClientRequestError (ex .message )
804
- return identity . client_id
811
+ return identity
805
812
raise InvalidArgumentValueError (
806
813
"Cannot parse identity name from provided resource id {}." .format (resource_id ))
807
814
808
815
816
+ def _get_user_assigned_identity_client_id (cli_ctx , resource_id ):
817
+ return _get_user_assigned_identity (cli_ctx , resource_id ).client_id
818
+
819
+
820
+ def _get_user_assigned_identity_object_id (cli_ctx , resource_id ):
821
+ return _get_user_assigned_identity (cli_ctx , resource_id ).principal_id
822
+
823
+
809
824
# pylint: disable=too-many-locals
810
825
def acs_create (cmd , client , resource_group_name , deployment_name , name , ssh_key_value , dns_name_prefix = None ,
811
826
location = None , admin_username = "azureuser" , api_version = None , master_profile = None ,
@@ -1958,6 +1973,7 @@ def aks_create(cmd, client, resource_group_name, name, ssh_key_value, # pylint:
1958
1973
appgw_watch_namespace = None ,
1959
1974
enable_sgxquotehelper = False ,
1960
1975
enable_encryption_at_host = False ,
1976
+ assign_kubelet_identity = None ,
1961
1977
enable_ultra_ssd = False ,
1962
1978
no_wait = False ,
1963
1979
yes = False ,
@@ -1992,6 +2008,9 @@ def aks_create(cmd, client, resource_group_name, name, ssh_key_value, # pylint:
1992
2008
ManagedClusterIdentity = cmd .get_models ('ManagedClusterIdentity' ,
1993
2009
resource_type = ResourceType .MGMT_CONTAINERSERVICE ,
1994
2010
operation_group = 'managed_clusters' )
2011
+ ManagedClusterPropertiesIdentityProfileValue = cmd .get_models ('ManagedClusterPropertiesIdentityProfileValue' ,
2012
+ resource_type = ResourceType .MGMT_CONTAINERSERVICE ,
2013
+ operation_group = 'managed_clusters' )
1995
2014
ManagedCluster = cmd .get_models ('ManagedCluster' ,
1996
2015
resource_type = ResourceType .MGMT_CONTAINERSERVICE ,
1997
2016
operation_group = 'managed_clusters' )
@@ -2291,6 +2310,25 @@ def aks_create(cmd, client, resource_group_name, name, ssh_key_value, # pylint:
2291
2310
user_assigned_identities = user_assigned_identity
2292
2311
)
2293
2312
2313
+ identity_profile = None
2314
+ if assign_kubelet_identity :
2315
+ if not assign_identity :
2316
+ # pylint: disable=line-too-long
2317
+ raise ArgumentUsageError ('--assign-kubelet-identity can only be specified when --assign-identity is specified' )
2318
+ kubelet_identity = _get_user_assigned_identity (cmd .cli_ctx , assign_kubelet_identity )
2319
+ identity_profile = {
2320
+ 'kubeletidentity' : ManagedClusterPropertiesIdentityProfileValue (
2321
+ resource_id = assign_kubelet_identity ,
2322
+ client_id = kubelet_identity .client_id ,
2323
+ object_id = kubelet_identity .principal_id
2324
+ )
2325
+ }
2326
+ cluster_identity_object_id = _get_user_assigned_identity_object_id (cmd .cli_ctx , assign_identity )
2327
+ # ensure the cluster identity has "Managed Identity Operator" role at the scope of kubelet identity
2328
+ _ensure_cluster_identity_permission_on_kubelet_identity (
2329
+ cmd .cli_ctx ,
2330
+ cluster_identity_object_id )
2331
+
2294
2332
mc = ManagedCluster (
2295
2333
location = location ,
2296
2334
tags = tags ,
@@ -2307,7 +2345,8 @@ def aks_create(cmd, client, resource_group_name, name, ssh_key_value, # pylint:
2307
2345
auto_scaler_profile = cluster_autoscaler_profile ,
2308
2346
api_server_access_profile = api_server_access_profile ,
2309
2347
identity = identity ,
2310
- disk_encryption_set_id = node_osdisk_diskencryptionset_id
2348
+ disk_encryption_set_id = node_osdisk_diskencryptionset_id ,
2349
+ identity_profile = identity_profile
2311
2350
)
2312
2351
2313
2352
use_custom_private_dns_zone = False
@@ -4694,3 +4733,23 @@ def _put_managed_cluster_ensuring_permission(
4694
4733
headers = headers )
4695
4734
4696
4735
return cluster
4736
+
4737
+
4738
+ def _ensure_cluster_identity_permission_on_kubelet_identity (cli_ctx , cluster_identity_object_id , scope ):
4739
+ factory = get_auth_management_client (cli_ctx , scope )
4740
+ assignments_client = factory .role_assignments
4741
+
4742
+ for i in assignments_client .list_for_scope (scope = scope , filter = 'atScope()' ):
4743
+ if i .scope .lower () != scope .lower ():
4744
+ continue
4745
+ if not i .role_definition_id .lower ().endswith (CONST_MANAGED_IDENTITY_OPERATOR_ROLE_ID ):
4746
+ continue
4747
+ if i .principal_id .lower () != cluster_identity_object_id .lower ():
4748
+ continue
4749
+ # already assigned
4750
+ return
4751
+
4752
+ if not _add_role_assignment (cli_ctx , CONST_MANAGED_IDENTITY_OPERATOR_ROLE , cluster_identity_object_id ,
4753
+ is_service_principal = False , scope = scope ):
4754
+ raise UnauthorizedError ('Could not grant Managed Identity Operator '
4755
+ 'permission to cluster identity at scope {}' .format (scope ))
0 commit comments