Skip to content

Commit

Permalink
[AKS]Support associating an existing user assigned identity for MSI c…
Browse files Browse the repository at this point in the history
…luster (#2015)

* Support associating an existing user assigned identity for MSI cluster

* Fix style

* Fix typo
  • Loading branch information
norshtein authored Jul 17, 2020
1 parent dc0091e commit 06c2e3e
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/aks-preview/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Release History
===============
0.4.57
+++++
* Support "--assign-identity" for specifying an existing user assigned identity for control plane's usage in MSI clusters.

0.4.56
+++++
* Support "--enable-aad" for "az aks update" to update an existing RBAC-enabled non-AAD cluster to the new AKS-managed AAD experience
Expand Down
10 changes: 10 additions & 0 deletions src/aks-preview/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,14 @@ az aks create \
-g MyResourceGroup \
-n MyManagedCluster \
--enable-managed-identity
```

#### Create aks cluster whose cluster resource group will be managed by a user assigned managed identity (instead of a service principal)
*Examples:*
```
az aks create \
-g MyResourceGroup \
-n MyManagedCluster \
--enable-managed-identity \
--assign-identity <EXISTING_USER_ASSIGNED_IDENTITY_RESOURCE_ID>
```
5 changes: 4 additions & 1 deletion src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,10 @@
short-summary: Enable VMSS node public IP.
- name: --enable-managed-identity
type: bool
short-summary: (PREVIEW) Using a system assigned managed identity to manage cluster resource group.
short-summary: (PREVIEW) Using managed identity to manage cluster resource group.
- name: --assign-identity
type: string
short-summary: (PREVIEW) Specify an existing user assigned identity to manage cluster resource group.
- name: --api-server-authorized-ip-ranges
type: string
short-summary: Comma seperated list of authorized apiserver IP ranges. Set to 0.0.0.0/32 to restrict apiserver traffic to node pools.
Expand Down
3 changes: 2 additions & 1 deletion src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
validate_load_balancer_outbound_ips, validate_load_balancer_outbound_ip_prefixes,
validate_taints, validate_priority, validate_eviction_policy, validate_spot_max_price, validate_acr, validate_user,
validate_load_balancer_outbound_ports, validate_load_balancer_idle_timeout, validate_nodepool_tags,
validate_nodepool_labels, validate_vnet_subnet_id, validate_max_surge)
validate_nodepool_labels, validate_vnet_subnet_id, validate_max_surge, validate_assign_identity)
from ._consts import CONST_OUTBOUND_TYPE_LOAD_BALANCER, \
CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING, CONST_SCALE_SET_PRIORITY_REGULAR, CONST_SCALE_SET_PRIORITY_SPOT, \
CONST_SPOT_EVICTION_POLICY_DELETE, CONST_SPOT_EVICTION_POLICY_DEALLOCATE, \
Expand Down Expand Up @@ -102,6 +102,7 @@ def load_arguments(self, _):
c.argument('aks_custom_headers')
c.argument('enable_private_cluster', action='store_true')
c.argument('enable_managed_identity', action='store_true')
c.argument('assign_identity', type=str, validator=validate_assign_identity)

with self.argument_context('aks update') as c:
c.argument('enable_cluster_autoscaler', options_list=["--enable-cluster-autoscaler", "-e"], action='store_true')
Expand Down
9 changes: 9 additions & 0 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,12 @@ def validate_max_surge(namespace):
raise CLIError("--max-surge must be positive")
except ValueError:
raise CLIError("--max-surge should be an int or percentage")


def validate_assign_identity(namespace):
if namespace.assign_identity is not None:
if namespace.assign_identity == '':
return
from msrestazure.tools import is_valid_resource_id
if not is_valid_resource_id(namespace.assign_identity):
raise CLIError("--assign-identity is not a valid Azure resource ID.")
16 changes: 14 additions & 2 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
ContainerServiceStorageProfileTypes,
ManagedClusterIdentity,
ManagedClusterAPIServerAccessProfile,
ManagedClusterSKU)
ManagedClusterSKU,
ManagedClusterIdentityUserAssignedIdentitiesValue)
from ._client_factory import cf_resource_groups
from ._client_factory import get_auth_management_client
from ._client_factory import get_graph_rbac_management_client
Expand Down Expand Up @@ -811,6 +812,7 @@ def aks_create(cmd, # pylint: disable=too-many-locals,too-many-statements,to
enable_aad=False,
enable_azure_rbac=False,
aad_admin_group_object_ids=None,
assign_identity=None,
no_wait=False):
if not no_ssh_key:
try:
Expand Down Expand Up @@ -1011,10 +1013,20 @@ def aks_create(cmd, # pylint: disable=too-many-locals,too-many-statements,to
api_server_access_profile = _populate_api_server_access_profile(api_server_authorized_ip_ranges)

identity = None
if enable_managed_identity:
if not enable_managed_identity and assign_identity:
raise CLIError('--assign-identity can only be specified when --enable-managed-identity is specified')
if enable_managed_identity and not assign_identity:
identity = ManagedClusterIdentity(
type="SystemAssigned"
)
elif enable_managed_identity and assign_identity:
user_assigned_identity = {
assign_identity: ManagedClusterIdentityUserAssignedIdentitiesValue()
}
identity = ManagedClusterIdentity(
type="UserAssigned",
user_assigned_identities=user_assigned_identity
)

enable_rbac = True
if disable_rbac:
Expand Down
31 changes: 31 additions & 0 deletions src/aks-preview/azext_aks_preview/tests/latest/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,34 @@ def test_throws_on_negative(self):
with self.assertRaises(CLIError) as cm:
validators.validate_max_surge(MaxSurgeNamespace("-3"))
self.assertTrue('positive' in str(cm.exception), msg=str(cm.exception))


class AssignIdentityNamespace:
def __init__(self, assign_identity):
self.assign_identity = assign_identity


class TestAssignIdentity(unittest.TestCase):
def test_invalid_identity_id(self):
invalid_identity_id = "dummy identity id"
namespace = AssignIdentityNamespace(invalid_identity_id)
err = ("--assign-identity is not a valid Azure resource ID.")

with self.assertRaises(CLIError) as cm:
validators.validate_assign_identity(namespace)
self.assertEqual(str(cm.exception), err)

def test_valid_identity_id(self):
valid_identity_id = "/subscriptions/testid/resourceGroups/MockedResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/mockIdentityID"
namespace = AssignIdentityNamespace(valid_identity_id)
validators.validate_assign_identity(namespace)

def test_none_identity_id(self):
none_identity_id = None
namespace = AssignIdentityNamespace(none_identity_id)
validators.validate_assign_identity(namespace)

def test_empty_identity_id(self):
empty_identity_id = ""
namespace = AssignIdentityNamespace(empty_identity_id)
validators.validate_assign_identity(namespace)
2 changes: 1 addition & 1 deletion src/aks-preview/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from codecs import open as open1
from setuptools import setup, find_packages

VERSION = "0.4.56"
VERSION = "0.4.57"
CLASSIFIERS = [
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
Expand Down

0 comments on commit 06c2e3e

Please sign in to comment.