Skip to content

Commit fbb4437

Browse files
authored
Add JWT Authenticator commands to aks-preview (#9189)
1 parent 032b5e2 commit fbb4437

12 files changed

Lines changed: 3096 additions & 0 deletions

File tree

src/aks-preview/HISTORY.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ To release a new version, please select a new version number (usually plus 1 to
1212
Pending
1313
+++++++
1414
* Fix `--localdns-config` parameter to handle null values in JSON configuration files gracefully, preventing crashes when DNS override sections are null.
15+
* Add jwtauthenticator commands `az aks jwtauthenticator add/update/show/list/delete` to manage JWT authenticators for a managed cluster.
1516

1617
18.0.0b40
1718
+++++++

src/aks-preview/azext_aks_preview/_client_factory.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,7 @@ def get_keyvault_client(cli_ctx, subscription_id=None):
155155

156156
def cf_load_balancers(cli_ctx, *_):
157157
return get_container_service_client(cli_ctx).load_balancers
158+
159+
160+
def cf_jwt_authenticators(cli_ctx, *_):
161+
return get_container_service_client(cli_ctx).jwt_authenticators

src/aks-preview/azext_aks_preview/_format.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,3 +486,52 @@ def _get_extension_type_versions_table_row(result):
486486
return OrderedDict([
487487
('versions', result['properties']['version'])
488488
])
489+
490+
491+
def aks_jwtauthenticator_list_table_format(results):
492+
"""Format a list of JWT authenticators as summary results for display with "-o table". """
493+
return [_get_jwtauthenticator_table_row(result) for result in results]
494+
495+
496+
def aks_jwtauthenticator_show_table_format(result):
497+
"""Format a JWT authenticator as summary results for display with "-o table". """
498+
return _get_jwtauthenticator_table_row(result)
499+
500+
501+
def _get_jwtauthenticator_table_row(result):
502+
"""Extract information from a JWT authenticator for table display."""
503+
properties = result.get('properties', {})
504+
provisioningState = properties.get('provisioningState', '')
505+
issuer = properties.get('issuer', {})
506+
507+
issuer_url = issuer.get('url', '') if issuer else ''
508+
audiences = issuer.get('audiences', []) if issuer else []
509+
audience_list = ', '.join(audiences) if audiences else ''
510+
511+
claim_mappings = properties.get('claimMappings', {})
512+
has_claim_mappings = 'No'
513+
if claim_mappings:
514+
has_username = bool(claim_mappings.get('username'))
515+
has_groups = bool(claim_mappings.get('groups'))
516+
has_uid = bool(claim_mappings.get('uid'))
517+
has_extra = (claim_mappings.get('extra') and
518+
isinstance(claim_mappings['extra'], list) and
519+
len(claim_mappings['extra']) > 0)
520+
521+
if has_username or has_groups or has_uid or has_extra:
522+
has_claim_mappings = 'Yes'
523+
524+
claim_rules = properties.get('claimValidationRules', [])
525+
user_rules = properties.get('userValidationRules', [])
526+
has_claim_rules = 'Yes' if claim_rules else 'No'
527+
has_user_rules = 'Yes' if user_rules else 'No'
528+
529+
return OrderedDict([
530+
('name', result.get('name', '')),
531+
('provisioningState', provisioningState),
532+
('issuerUrl', issuer_url),
533+
('audiences', audience_list),
534+
('hasClaimMappings', has_claim_mappings),
535+
('hasClaimRules', has_claim_rules),
536+
('hasUserRules', has_user_rules),
537+
])

src/aks-preview/azext_aks_preview/_help.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4082,3 +4082,109 @@
40824082
type: string
40834083
short-summary: Name of the identity binding to show.
40844084
"""
4085+
4086+
helps['aks jwtauthenticator'] = """
4087+
type: group
4088+
short-summary: Commands to manage JWT authenticators in Azure Kubernetes Service.
4089+
long-summary: JWT authenticators enable external JWT token validation for Kubernetes authentication.
4090+
For more information, see https://aka.ms/aks-external-issuers-docs.
4091+
"""
4092+
4093+
helps['aks jwtauthenticator add'] = """
4094+
type: command
4095+
short-summary: Add a JWT authenticator to a managed cluster.
4096+
long-summary: Adds a new JWT authenticator configuration to the managed cluster for external JWT validation.
4097+
The configuration will be applied to the kube-apiserver to enable JWT token authentication.
4098+
parameters:
4099+
- name: --cluster-name
4100+
type: string
4101+
short-summary: Name of the managed cluster.
4102+
- name: --name -n
4103+
type: string
4104+
short-summary: Name of the JWT authenticator (must be unique within the cluster).
4105+
- name: --config-file
4106+
type: string
4107+
short-summary: Path to JSON file containing the JWT authenticator configuration.
4108+
long-summary: The JSON file should contain the properties schema for one JWT authenticator.
4109+
For details on how to configure the properties of a JWT authenticator, please refer to the Kubernetes documentation
4110+
at https://kubernetes.io/docs/reference/access-authn-authz/authentication/#using-authentication-configuration.
4111+
Please note that not all fields available in the Kubernetes documentation are supported by AKS.
4112+
For troubleshooting, please see https://aka.ms/aks-external-issuers-docs.
4113+
- name: --aks-custom-headers
4114+
type: string
4115+
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
4116+
examples:
4117+
- name: Add a JWT authenticator from a configuration file
4118+
text: az aks jwtauthenticator add -g MyResourceGroup --cluster-name MyCluster --name myjwt --config-file config.json
4119+
"""
4120+
4121+
helps['aks jwtauthenticator update'] = """
4122+
type: command
4123+
short-summary: Update a JWT authenticator in a managed cluster.
4124+
long-summary: Updates an existing JWT authenticator configuration. The entire configuration will be replaced
4125+
with the configuration from the provided file.
4126+
parameters:
4127+
- name: --cluster-name
4128+
type: string
4129+
short-summary: Name of the managed cluster.
4130+
- name: --name -n
4131+
type: string
4132+
short-summary: Name of the JWT authenticator to update.
4133+
- name: --config-file
4134+
type: string
4135+
short-summary: Path to JSON file containing the updated JWT authenticator configuration.
4136+
long-summary: The JSON file should contain the properties schema for one JWT authenticator.
4137+
For details on how to configure the properties of a JWT authenticator, please refer to the Kubernetes documentation
4138+
at https://kubernetes.io/docs/reference/access-authn-authz/authentication/#using-authentication-configuration.
4139+
Please note that not all fields available in the Kubernetes documentation are supported by AKS.
4140+
For troubleshooting, please see https://aka.ms/aks-external-issuers-docs.
4141+
- name: --aks-custom-headers
4142+
type: string
4143+
short-summary: Send custom headers. When specified, format should be Key1=Value1
4144+
examples:
4145+
- name: Update a JWT authenticator configuration
4146+
text: az aks jwtauthenticator update -g MyResourceGroup --cluster-name MyCluster --name myjwt --config-file updated-config.json
4147+
"""
4148+
4149+
helps['aks jwtauthenticator delete'] = """
4150+
type: command
4151+
short-summary: Delete a JWT authenticator from a managed cluster.
4152+
long-summary: Removes the JWT authenticator configuration from the managed cluster and updates the kube-apiserver.
4153+
parameters:
4154+
- name: --cluster-name
4155+
type: string
4156+
short-summary: Name of the managed cluster.
4157+
- name: --name -n
4158+
type: string
4159+
short-summary: Name of the JWT authenticator to delete.
4160+
examples:
4161+
- name: Delete a JWT authenticator
4162+
text: az aks jwtauthenticator delete -g MyResourceGroup --cluster-name MyCluster --name myjwt
4163+
"""
4164+
4165+
helps['aks jwtauthenticator list'] = """
4166+
type: command
4167+
short-summary: List all JWT authenticators in a managed cluster.
4168+
parameters:
4169+
- name: --cluster-name
4170+
type: string
4171+
short-summary: Name of the managed cluster.
4172+
examples:
4173+
- name: List all JWT authenticators in a cluster
4174+
text: az aks jwtauthenticator list -g MyResourceGroup --cluster-name MyCluster
4175+
"""
4176+
4177+
helps['aks jwtauthenticator show'] = """
4178+
type: command
4179+
short-summary: Show details of a JWT authenticator in a managed cluster.
4180+
parameters:
4181+
- name: --cluster-name
4182+
type: string
4183+
short-summary: Name of the managed cluster.
4184+
- name: --name -n
4185+
type: string
4186+
short-summary: Name of the JWT authenticator to show.
4187+
examples:
4188+
- name: Show a specific JWT authenticator configuration
4189+
text: az aks jwtauthenticator show -g MyResourceGroup --cluster-name MyCluster --name myjwt
4190+
"""

src/aks-preview/azext_aks_preview/_params.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2927,6 +2927,27 @@ def load_arguments(self, _):
29272927
action="store_true",
29282928
)
29292929

2930+
# JWT Authenticator commands
2931+
with self.argument_context("aks jwtauthenticator") as c:
2932+
c.argument("cluster_name", help="The cluster name.")
2933+
c.argument(
2934+
"aks_custom_headers",
2935+
help="Send custom headers. When specified, format should be Key1=Value1,Key2=Value2.",
2936+
)
2937+
2938+
for scope in ['aks jwtauthenticator add',
2939+
'aks jwtauthenticator update',
2940+
'aks jwtauthenticator delete',
2941+
'aks jwtauthenticator show']:
2942+
with self.argument_context(scope) as c:
2943+
c.argument('name', options_list=['--name', '-n'], required=True, help='Name of the JWT authenticator.')
2944+
2945+
for scope in ['aks jwtauthenticator add',
2946+
'aks jwtauthenticator update']:
2947+
with self.argument_context(scope) as c:
2948+
c.argument('config_file', options_list=['--config-file'], type=file_type, completer=FilesCompleter(),
2949+
help='Path to the JSON configuration file containing JWT authenticator properties.')
2950+
29302951

29312952
def _get_default_install_location(exe_name):
29322953
system = platform.system()

src/aks-preview/azext_aks_preview/commands.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
cf_operations,
1717
cf_load_balancers,
1818
cf_identity_bindings,
19+
cf_jwt_authenticators,
1920
)
2021

2122
from azext_aks_preview._format import (
@@ -46,6 +47,8 @@
4647
aks_extension_type_show_table_format,
4748
aks_extension_type_versions_list_table_format,
4849
aks_extension_type_version_show_table_format,
50+
aks_jwtauthenticator_list_table_format,
51+
aks_jwtauthenticator_show_table_format,
4952
)
5053

5154
from knack.log import get_logger
@@ -141,6 +144,12 @@ def load_command_table(self, _):
141144
client_factory=cf_mc_snapshots,
142145
)
143146

147+
jwt_authenticators_sdk = CliCommandType(
148+
operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks."
149+
"operations._jwt_authenticators_operations#JWTAuthenticatorsOperations.{}",
150+
client_factory=cf_jwt_authenticators,
151+
)
152+
144153
# AKS managed cluster commands
145154
with self.command_group(
146155
"aks",
@@ -517,3 +526,33 @@ def load_command_table(self, _):
517526
g.custom_command("delete", "aks_identity_binding_delete")
518527
g.custom_show_command("show", "aks_identity_binding_show")
519528
g.custom_command("list", "aks_identity_binding_list")
529+
530+
# AKS jwt authenticator commands
531+
with self.command_group(
532+
"aks jwtauthenticator", jwt_authenticators_sdk, client_factory=cf_jwt_authenticators,
533+
) as g:
534+
g.custom_command(
535+
"add",
536+
"aks_jwtauthenticator_add",
537+
supports_no_wait=True
538+
)
539+
g.custom_command(
540+
"update",
541+
"aks_jwtauthenticator_update",
542+
supports_no_wait=True
543+
)
544+
g.custom_command(
545+
"delete",
546+
"aks_jwtauthenticator_delete",
547+
supports_no_wait=True, confirmation=True
548+
)
549+
g.custom_command(
550+
"list",
551+
"aks_jwtauthenticator_list",
552+
table_transformer=aks_jwtauthenticator_list_table_format
553+
)
554+
g.custom_show_command(
555+
"show",
556+
"aks_jwtauthenticator_show",
557+
table_transformer=aks_jwtauthenticator_show_table_format
558+
)

src/aks-preview/azext_aks_preview/custom.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@
118118
from azext_aks_preview.machine import (
119119
add_machine,
120120
)
121+
from azext_aks_preview.jwtauthenticator import (
122+
aks_jwtauthenticator_add_internal,
123+
aks_jwtauthenticator_update_internal,
124+
)
121125
from azure.cli.command_modules.acs._helpers import (
122126
get_user_assigned_identity_by_resource_id
123127
)
@@ -4501,3 +4505,87 @@ def aks_bastion(cmd, client, resource_group_name, name, bastion=None, port=None,
45014505
aks_identity_binding_delete = aks_ib_cmd_delete
45024506
aks_identity_binding_show = aks_ib_cmd_show
45034507
aks_identity_binding_list = aks_ib_cmd_list
4508+
4509+
4510+
# JWT Authenticator commands
4511+
def aks_jwtauthenticator_add(
4512+
cmd,
4513+
client,
4514+
resource_group_name,
4515+
cluster_name,
4516+
name,
4517+
config_file,
4518+
aks_custom_headers=None,
4519+
no_wait=False
4520+
):
4521+
headers = get_aks_custom_headers(aks_custom_headers)
4522+
existingJWTAuthenticator = None
4523+
try:
4524+
existingJWTAuthenticator = client.get(resource_group_name, cluster_name, name, headers=headers)
4525+
except ResourceNotFoundError:
4526+
pass
4527+
4528+
if existingJWTAuthenticator:
4529+
raise ClientRequestError(
4530+
f"JWT Authenticator '{name}' already exists. Please use 'az aks jwtauthenticator update' to update it."
4531+
)
4532+
4533+
raw_parameters = locals()
4534+
return aks_jwtauthenticator_add_internal(
4535+
cmd,
4536+
client,
4537+
raw_parameters,
4538+
headers,
4539+
no_wait,
4540+
)
4541+
4542+
4543+
def aks_jwtauthenticator_update(
4544+
cmd,
4545+
client,
4546+
resource_group_name,
4547+
cluster_name,
4548+
name,
4549+
config_file,
4550+
aks_custom_headers=None,
4551+
no_wait=False
4552+
):
4553+
headers = get_aks_custom_headers(aks_custom_headers)
4554+
raw_parameters = locals()
4555+
return aks_jwtauthenticator_update_internal(
4556+
cmd,
4557+
client,
4558+
raw_parameters,
4559+
headers,
4560+
no_wait,
4561+
)
4562+
4563+
4564+
def aks_jwtauthenticator_delete(
4565+
cmd,
4566+
client,
4567+
resource_group_name,
4568+
cluster_name,
4569+
name,
4570+
aks_custom_headers=None,
4571+
no_wait=False
4572+
):
4573+
headers = get_aks_custom_headers(aks_custom_headers)
4574+
return sdk_no_wait(
4575+
no_wait,
4576+
client.begin_delete,
4577+
resource_group_name,
4578+
cluster_name,
4579+
name,
4580+
headers=headers,
4581+
)
4582+
4583+
4584+
def aks_jwtauthenticator_list(cmd, client, resource_group_name, cluster_name, aks_custom_headers=None):
4585+
headers = get_aks_custom_headers(aks_custom_headers)
4586+
return client.list_by_managed_cluster(resource_group_name, cluster_name, headers=headers)
4587+
4588+
4589+
def aks_jwtauthenticator_show(cmd, client, resource_group_name, cluster_name, name, aks_custom_headers=None):
4590+
headers = get_aks_custom_headers(aks_custom_headers)
4591+
return client.get(resource_group_name, cluster_name, name, headers=headers)

0 commit comments

Comments
 (0)