Skip to content

Commit dd351b1

Browse files
authored
[AKS] az aks identity-binding: Add command group to manage identity bindings (trust domain) for a managed cluster (#33558)
1 parent e7d544e commit dd351b1

7 files changed

Lines changed: 261 additions & 1 deletion

File tree

src/azure-cli/azure/cli/command_modules/acs/_client_factory.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ def cf_managed_namespaces(cli_ctx, *_):
3939
return get_container_service_client(cli_ctx).managed_namespaces
4040

4141

42+
def cf_identity_bindings(cli_ctx, *_):
43+
return get_container_service_client(cli_ctx).identity_bindings
44+
45+
4246
def cf_agent_pools(cli_ctx, *_):
4347
return get_container_service_client(cli_ctx).agent_pools
4448

src/azure-cli/azure/cli/command_modules/acs/_help.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2832,6 +2832,71 @@
28322832
short-summary: Specify the role binding name.
28332833
"""
28342834

2835+
helps["aks identity-binding"] = """
2836+
type: group
2837+
short-summary: Commands to manage identity bindings in Azure Kubernetes Service.
2838+
"""
2839+
2840+
helps["aks identity-binding list"] = """
2841+
type: command
2842+
short-summary: List all identity bindings under a managed Kubernetes cluster.
2843+
parameters:
2844+
- name: --cluster-name
2845+
type: string
2846+
short-summary: Name of the managed Kubernetes cluster.
2847+
examples:
2848+
- name: List all identity bindings in a managed cluster
2849+
text: az aks identity-binding list -g myResourceGroup --cluster-name myCluster
2850+
"""
2851+
2852+
helps["aks identity-binding show"] = """
2853+
type: command
2854+
short-summary: Show details of a specific identity binding in a managed Kubernetes cluster.
2855+
parameters:
2856+
- name: --cluster-name
2857+
type: string
2858+
short-summary: Name of the managed Kubernetes cluster.
2859+
- name: --name -n
2860+
type: string
2861+
short-summary: Name of the identity binding to show.
2862+
examples:
2863+
- name: Show details of an identity binding
2864+
text: az aks identity-binding show -g myResourceGroup --cluster-name myCluster -n myIdentityBinding
2865+
"""
2866+
2867+
helps["aks identity-binding create"] = """
2868+
type: command
2869+
short-summary: Create a new identity binding in a managed Kubernetes cluster.
2870+
parameters:
2871+
- name: --cluster-name
2872+
type: string
2873+
short-summary: Name of the managed Kubernetes cluster.
2874+
- name: --name -n
2875+
type: string
2876+
short-summary: Name of the identity binding to create.
2877+
- name: --managed-identity-resource-id
2878+
type: string
2879+
short-summary: The resource ID of the managed identity to use.
2880+
examples:
2881+
- name: Create a new identity binding
2882+
text: az aks identity-binding create -g myResourceGroup --cluster-name myCluster -n myIdentityBinding --managed-identity-resource-id /subscriptions/0000/resourceGroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity
2883+
"""
2884+
2885+
helps["aks identity-binding delete"] = """
2886+
type: command
2887+
short-summary: Delete a specific identity binding in a managed Kubernetes cluster.
2888+
parameters:
2889+
- name: --cluster-name
2890+
type: string
2891+
short-summary: Name of the managed Kubernetes cluster.
2892+
- name: --name -n
2893+
type: string
2894+
short-summary: Name of the identity binding to delete.
2895+
examples:
2896+
- name: Delete an identity binding
2897+
text: az aks identity-binding delete -g myResourceGroup --cluster-name myCluster -n myIdentityBinding
2898+
"""
2899+
28352900
helps["aks mesh"] = """
28362901
type: group
28372902
short-summary: Commands to manage Azure Service Mesh.

src/azure-cli/azure/cli/command_modules/acs/_params.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,6 +1287,21 @@ def load_arguments(self, _):
12871287
with self.argument_context('aks trustedaccess rolebinding update') as c:
12881288
c.argument('roles', help='comma-separated roles: Microsoft.Demo/samples/reader,Microsoft.Demo/samples/writer,...')
12891289

1290+
with self.argument_context('aks identity-binding') as c:
1291+
c.argument('cluster_name', help='Name of the managed cluster.')
1292+
1293+
for scope in ['aks identity-binding show', 'aks identity-binding create', 'aks identity-binding delete']:
1294+
with self.argument_context(scope) as c:
1295+
c.argument('name', options_list=['--name', '-n'], required=True,
1296+
help='Name of the identity binding.')
1297+
1298+
with self.argument_context('aks identity-binding create') as c:
1299+
c.argument(
1300+
'managed_identity_resource_id',
1301+
options_list=['--managed-identity-resource-id'],
1302+
help='The resource ID of the managed identity to use.',
1303+
)
1304+
12901305
with self.argument_context('aks mesh enable-ingress-gateway') as c:
12911306
c.argument('ingress_gateway_type',
12921307
arg_type=get_enum_type(ingress_gateway_types))

src/azure-cli/azure/cli/command_modules/acs/commands.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
cf_snapshots,
1212
cf_trustedaccess_role,
1313
cf_trustedaccess_role_binding,
14-
cf_machines
14+
cf_machines,
15+
cf_identity_bindings
1516
)
1617
from azure.cli.command_modules.acs._format import (
1718
aks_agentpool_list_table_format,
@@ -100,6 +101,14 @@ def load_command_table(self, _):
100101
client_factory=cf_trustedaccess_role_binding
101102
)
102103

104+
identity_bindings_sdk = CliCommandType(
105+
operations_tmpl='azure.mgmt.containerservice.operations.'
106+
'_operations#IdentityBindingsOperations.{}',
107+
operation_group='identity_bindings',
108+
resource_type=ResourceType.MGMT_CONTAINERSERVICE,
109+
client_factory=cf_identity_bindings
110+
)
111+
103112
# AKS commands
104113
with self.command_group('aks', managed_clusters_sdk,
105114
client_factory=cf_managed_clusters) as g:
@@ -266,6 +275,13 @@ def load_command_table(self, _):
266275
g.custom_command(
267276
'delete', 'aks_trustedaccess_role_binding_delete', confirmation=True)
268277

278+
# AKS identity binding commands
279+
with self.command_group('aks identity-binding', identity_bindings_sdk, client_factory=cf_identity_bindings) as g:
280+
g.custom_command('create', 'aks_identity_binding_create', supports_no_wait=True)
281+
g.custom_command('delete', 'aks_identity_binding_delete', supports_no_wait=True, confirmation=True)
282+
g.custom_show_command('show', 'aks_identity_binding_show')
283+
g.custom_command('list', 'aks_identity_binding_list')
284+
269285
# AKS mesh commands
270286
with self.command_group('aks mesh', managed_clusters_sdk, client_factory=cf_managed_clusters) as g:
271287
g.custom_command(

src/azure-cli/azure/cli/command_modules/acs/custom.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3802,6 +3802,50 @@ def aks_trustedaccess_role_binding_delete(cmd, client, resource_group_name, clus
38023802
return client.begin_delete(resource_group_name, cluster_name, role_binding_name)
38033803

38043804

3805+
def aks_identity_binding_create(cmd, client, resource_group_name, cluster_name, name,
3806+
managed_identity_resource_id, no_wait=False):
3807+
IdentityBinding, IdentityBindingProperties, IdentityBindingManagedIdentityProfile = cmd.get_models(
3808+
"IdentityBinding",
3809+
"IdentityBindingProperties",
3810+
"IdentityBindingManagedIdentityProfile",
3811+
resource_type=ResourceType.MGMT_CONTAINERSERVICE,
3812+
operation_group="identity_bindings",
3813+
)
3814+
instance = IdentityBinding(
3815+
properties=IdentityBindingProperties(
3816+
managed_identity=IdentityBindingManagedIdentityProfile(
3817+
resource_id=managed_identity_resource_id,
3818+
)
3819+
)
3820+
)
3821+
return sdk_no_wait(
3822+
no_wait,
3823+
client.begin_create_or_update,
3824+
resource_group_name,
3825+
cluster_name,
3826+
name,
3827+
instance,
3828+
)
3829+
3830+
3831+
def aks_identity_binding_delete(cmd, client, resource_group_name, cluster_name, name, no_wait=False): # pylint: disable=unused-argument
3832+
return sdk_no_wait(
3833+
no_wait,
3834+
client.begin_delete,
3835+
resource_group_name,
3836+
cluster_name,
3837+
name,
3838+
)
3839+
3840+
3841+
def aks_identity_binding_show(cmd, client, resource_group_name, cluster_name, name): # pylint: disable=unused-argument
3842+
return client.get(resource_group_name, cluster_name, name)
3843+
3844+
3845+
def aks_identity_binding_list(cmd, client, resource_group_name, cluster_name): # pylint: disable=unused-argument
3846+
return client.list_by_managed_cluster(resource_group_name, cluster_name)
3847+
3848+
38053849
def aks_mesh_enable(
38063850
cmd,
38073851
client,

src/azure-cli/azure/cli/command_modules/acs/linter_exclusions.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,4 +286,9 @@ aks mesh enable:
286286
proxy_redirection_mechanism:
287287
rule_exclusions:
288288
- option_length_too_long
289+
aks identity-binding create:
290+
parameters:
291+
managed_identity_resource_id:
292+
rule_exclusions:
293+
- option_length_too_long
289294
...
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
7+
from azure.cli.testsdk import ScenarioTest, live_only
8+
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
9+
10+
from azure.cli.command_modules.acs.tests.latest.recording_processors import KeyReplacer
11+
from azure.cli.command_modules.acs.tests.latest.custom_preparers import (
12+
AKSCustomResourceGroupPreparer,
13+
)
14+
15+
16+
class IdentityBindingTestCases(ScenarioTest):
17+
18+
def __init__(self, method_name):
19+
super(IdentityBindingTestCases, self).__init__(
20+
method_name,
21+
recording_processors=[KeyReplacer()],
22+
)
23+
24+
@AllowLargeResponse()
25+
@live_only()
26+
@AKSCustomResourceGroupPreparer(
27+
random_name_length=17,
28+
name_prefix="clitest",
29+
location="eastus2",
30+
)
31+
def test_identity_binding_usages(self, resource_group, resource_group_location):
32+
aks_name = self.create_random_name("cliakstest", 16)
33+
identity_name = self.create_random_name("cli", 16)
34+
identity_binding_name = self.create_random_name("cliib", 16)
35+
self.kwargs.update(
36+
{
37+
"resource_group": resource_group,
38+
"aks_name": aks_name,
39+
"identity_name": identity_name,
40+
"identity_binding_name": identity_binding_name,
41+
"location": resource_group_location,
42+
}
43+
)
44+
45+
create_aks_cmd = ("aks create --resource-group={resource_group} --name={aks_name} "
46+
"--location={location} --no-ssh-key -o json")
47+
self.cmd(create_aks_cmd, checks=[
48+
self.check("provisioningState", "Succeeded")])
49+
50+
list_identity_binding_cmd = ("aks identity-binding list --resource-group {resource_group} "
51+
"--cluster-name {aks_name} -o json")
52+
self.cmd(
53+
list_identity_binding_cmd,
54+
checks=[
55+
self.check("length(@)", 0)
56+
]
57+
)
58+
59+
create_identity_cmd = ("identity create --resource-group {resource_group} --name {identity_name} "
60+
"--location {location} -o json")
61+
identity = self.cmd(create_identity_cmd).get_output_in_json()
62+
identity_resource_id = identity["id"]
63+
identity_client_id = identity["clientId"]
64+
identity_tenant_id = identity["tenantId"]
65+
66+
identity_binding_checks = [
67+
self.check("properties.provisioningState", "Succeeded"),
68+
self.check(
69+
"properties.managedIdentity.resourceId",
70+
identity_resource_id
71+
),
72+
self.check(
73+
"properties.managedIdentity.clientId",
74+
identity_client_id
75+
),
76+
self.check(
77+
"properties.managedIdentity.tenantId",
78+
identity_tenant_id
79+
),
80+
self.check(
81+
f"ends_with(properties.oidcIssuer.oidcIssuerUrl, '/{identity_tenant_id}/{identity_client_id}')",
82+
True,
83+
),
84+
]
85+
86+
create_identity_binding_cmd = ("aks identity-binding create --resource-group {resource_group} --cluster-name {aks_name} "
87+
"-n {identity_binding_name} -o json"
88+
f" --managed-identity-resource-id {identity_resource_id}")
89+
self.cmd(create_identity_binding_cmd, checks=identity_binding_checks)
90+
91+
self.cmd(
92+
list_identity_binding_cmd,
93+
checks=[
94+
self.check("length(@)", 1)
95+
]
96+
)
97+
98+
show_identity_binding_cmd = ("aks identity-binding show --resource-group {resource_group} --cluster-name {aks_name} "
99+
"-n {identity_binding_name} -o json")
100+
self.cmd(show_identity_binding_cmd, checks=identity_binding_checks)
101+
102+
delete_identity_binding_cmd = ("aks identity-binding delete --resource-group {resource_group} --cluster-name {aks_name} "
103+
"-n {identity_binding_name} --yes -o json")
104+
self.cmd(delete_identity_binding_cmd)
105+
106+
self.cmd(
107+
list_identity_binding_cmd,
108+
checks=[
109+
self.check("length(@)", 0)
110+
]
111+
)

0 commit comments

Comments
 (0)