Skip to content

Commit b100993

Browse files
committed
[AKS] az aks update: Add new parameter --kms-infrastructure-encryption to enable KMS infrastructure encryption on an existing cluster.
1 parent ac57da8 commit b100993

File tree

10 files changed

+1864
-1
lines changed

10 files changed

+1864
-1
lines changed

src/aks-preview/HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ To release a new version, please select a new version number (usually plus 1 to
1111

1212
Pending
1313
+++++++
14+
15+
18.0.0b44
16+
+++++++
1417
* Vendor new SDK and bump API version to 2025-08-02-preview.
1518
* Pre-deprecate `--enable-custom-ca-trust` and `--disable-custom-ca-trust` in `az aks create`, `az aks update` commands.
19+
* `az aks update`: Add new parameter `--kms-infrastructure-encryption` to enable KMS infrastructure encryption on an existing cluster.
1620

1721
18.0.0b43
1822
+++++++

src/aks-preview/azext_aks_preview/_help.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,10 @@
11101110
- name: --azure-keyvault-kms-key-vault-resource-id
11111111
type: string
11121112
short-summary: Resource ID of Azure Key Vault.
1113+
- name: --kms-infrastructure-encryption
1114+
type: string
1115+
short-summary: Enable encryption at rest of Kubernetes resource objects using service-managed keys.
1116+
long-summary: Enable infrastructure encryption for Kubernetes resource objects. This feature provides encryption at rest for cluster secrets and configuration using service-managed keys. For more information see https://aka.ms/aks/kubernetesResourceObjectEncryption.
11131117
- name: --enable-image-cleaner
11141118
type: bool
11151119
short-summary: Enable ImageCleaner Service.

src/aks-preview/azext_aks_preview/_params.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,11 @@ def load_arguments(self, _):
12641264
"azure_keyvault_kms_key_vault_resource_id",
12651265
validator=validate_azure_keyvault_kms_key_vault_resource_id,
12661266
)
1267+
c.argument(
1268+
"kms_infrastructure_encryption",
1269+
arg_type=get_enum_type(["Enabled", "Disabled"]),
1270+
is_preview=True,
1271+
)
12671272
c.argument("http_proxy_config")
12681273
c.argument(
12691274
"bootstrap_artifact_source",

src/aks-preview/azext_aks_preview/custom.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,7 @@ def aks_update(
865865
azure_keyvault_kms_key_id=None,
866866
azure_keyvault_kms_key_vault_network_access=None,
867867
azure_keyvault_kms_key_vault_resource_id=None,
868+
kms_infrastructure_encryption=None,
868869
http_proxy_config=None,
869870
disable_http_proxy=False,
870871
enable_http_proxy=False,

src/aks-preview/azext_aks_preview/managed_cluster_decorator.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5128,6 +5128,34 @@ def update_image_integrity(self, mc: ManagedCluster) -> ManagedCluster:
51285128

51295129
return mc
51305130

5131+
def update_kms_infrastructure_encryption(self, mc: ManagedCluster) -> ManagedCluster:
5132+
"""Update security profile KubernetesResourceObjectEncryptionProfile for the ManagedCluster object.
5133+
5134+
:return: the ManagedCluster object
5135+
"""
5136+
self._ensure_mc(mc)
5137+
5138+
kms_infrastructure_encryption = self.context.get_kms_infrastructure_encryption()
5139+
5140+
# no infrastructure encryption related changes
5141+
if not kms_infrastructure_encryption or kms_infrastructure_encryption == "Disabled":
5142+
return mc
5143+
5144+
if mc.security_profile is None:
5145+
mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member
5146+
5147+
# Set or update the kubernetes resource object encryption profile
5148+
if mc.security_profile.kubernetes_resource_object_encryption_profile is None:
5149+
mc.security_profile.kubernetes_resource_object_encryption_profile = (
5150+
self.models.KubernetesResourceObjectEncryptionProfile() # pylint: disable=no-member
5151+
)
5152+
5153+
# Set infrastructure encryption
5154+
# pylint: disable=line-too-long
5155+
mc.security_profile.kubernetes_resource_object_encryption_profile.infrastructure_encryption = kms_infrastructure_encryption
5156+
5157+
return mc
5158+
51315159
def update_storage_profile(self, mc: ManagedCluster) -> ManagedCluster:
51325160
"""Update storage profile for the ManagedCluster object.
51335161
@@ -5956,6 +5984,8 @@ def update_mc_profile_preview(self) -> ManagedCluster:
59565984
mc = self.update_image_cleaner(mc)
59575985
# update image integrity
59585986
mc = self.update_image_integrity(mc)
5987+
# update KMS infrastructure encryption
5988+
mc = self.update_kms_infrastructure_encryption(mc)
59595989
# update workload auto scaler profile
59605990
mc = self.update_workload_auto_scaler_profile(mc)
59615991
# update azure monitor metrics profile

src/aks-preview/azext_aks_preview/tests/latest/recordings/test_aks_update_with_kms_infrastructure_encryption.yaml

Lines changed: 1633 additions & 0 deletions
Large diffs are not rendered by default.

src/aks-preview/azext_aks_preview/tests/latest/test_aks_commands.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11991,6 +11991,69 @@ def test_aks_create_with_kms_infrastructure_encryption(
1199111991
],
1199211992
)
1199311993

11994+
@AllowLargeResponse()
11995+
@AKSCustomResourceGroupPreparer(
11996+
random_name_length=17,
11997+
name_prefix="clitest",
11998+
location="eastus2euap",
11999+
)
12000+
def test_aks_update_with_kms_infrastructure_encryption(
12001+
self, resource_group, resource_group_location
12002+
):
12003+
aks_name = self.create_random_name("cliakstest", 16)
12004+
k8s_version = self._get_version_in_range(location=resource_group_location, min_version="1.33.0", max_version="1.34.0")
12005+
self.kwargs.update(
12006+
{
12007+
"resource_group": resource_group,
12008+
"name": aks_name,
12009+
"ssh_key_value": self.generate_ssh_keys(),
12010+
"k8s_version": k8s_version,
12011+
}
12012+
)
12013+
12014+
# create cluster without infrastructure encryption
12015+
create_cmd = (
12016+
"aks create --resource-group={resource_group} --name={name} "
12017+
"--kubernetes-version={k8s_version} "
12018+
"--ssh-key-value={ssh_key_value} -o json"
12019+
)
12020+
self.cmd(
12021+
create_cmd,
12022+
checks=[
12023+
self.check("provisioningState", "Succeeded"),
12024+
self.not_exists("securityProfile.kubernetesResourceObjectEncryptionProfile"),
12025+
],
12026+
)
12027+
12028+
# update cluster to enable infrastructure encryption
12029+
update_cmd = (
12030+
"aks update --resource-group={resource_group} --name={name} "
12031+
"--kms-infrastructure-encryption Enabled "
12032+
"--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/KMSPMKPreview "
12033+
"-o json"
12034+
)
12035+
self.cmd(
12036+
update_cmd,
12037+
checks=[
12038+
self.check("provisioningState", "Succeeded"),
12039+
self.check(
12040+
"securityProfile.kubernetesResourceObjectEncryptionProfile.infrastructureEncryption",
12041+
"Enabled"
12042+
),
12043+
],
12044+
)
12045+
12046+
# delete
12047+
cmd = (
12048+
"aks delete --resource-group={resource_group} --name={name} --yes --no-wait"
12049+
)
12050+
self.cmd(
12051+
cmd,
12052+
checks=[
12053+
self.is_empty(),
12054+
],
12055+
)
12056+
1199412057
@AllowLargeResponse()
1199512058
@AKSCustomResourceGroupPreparer(
1199612059
random_name_length=17,

src/aks-preview/azext_aks_preview/tests/latest/test_managed_cluster_decorator.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7468,6 +7468,126 @@ def test_update_azure_keyvault_kms(self):
74687468
)
74697469
self.assertEqual(dec_mc_7, ground_truth_mc_7)
74707470

7471+
def test_update_kms_infrastructure_encryption(self):
7472+
# test no change when no parameter provided
7473+
dec_1 = AKSPreviewManagedClusterUpdateDecorator(
7474+
self.cmd,
7475+
self.client,
7476+
{},
7477+
CUSTOM_MGMT_AKS_PREVIEW,
7478+
)
7479+
mc_1 = self.models.ManagedCluster(location="test_location")
7480+
dec_1.context.attach_mc(mc_1)
7481+
dec_mc_1 = dec_1.update_kms_infrastructure_encryption(mc_1)
7482+
# no change expected
7483+
ground_truth_mc_1 = self.models.ManagedCluster(location="test_location")
7484+
self.assertEqual(dec_mc_1, ground_truth_mc_1)
7485+
7486+
# test no change when Disabled
7487+
dec_2 = AKSPreviewManagedClusterUpdateDecorator(
7488+
self.cmd,
7489+
self.client,
7490+
{
7491+
"kms_infrastructure_encryption": "Disabled",
7492+
},
7493+
CUSTOM_MGMT_AKS_PREVIEW,
7494+
)
7495+
mc_2 = self.models.ManagedCluster(location="test_location")
7496+
dec_2.context.attach_mc(mc_2)
7497+
dec_mc_2 = dec_2.update_kms_infrastructure_encryption(mc_2)
7498+
# no change expected
7499+
ground_truth_mc_2 = self.models.ManagedCluster(location="test_location")
7500+
self.assertEqual(dec_mc_2, ground_truth_mc_2)
7501+
7502+
# test with Enabled on new cluster
7503+
dec_3 = AKSPreviewManagedClusterUpdateDecorator(
7504+
self.cmd,
7505+
self.client,
7506+
{
7507+
"kms_infrastructure_encryption": "Enabled",
7508+
},
7509+
CUSTOM_MGMT_AKS_PREVIEW,
7510+
)
7511+
mc_3 = self.models.ManagedCluster(location="test_location")
7512+
dec_3.context.attach_mc(mc_3)
7513+
dec_mc_3 = dec_3.update_kms_infrastructure_encryption(mc_3)
7514+
7515+
# expected security profile with infrastructure encryption
7516+
ground_truth_kube_resource_encryption_profile_3 = self.models.KubernetesResourceObjectEncryptionProfile(
7517+
infrastructure_encryption="Enabled"
7518+
)
7519+
ground_truth_security_profile_3 = self.models.ManagedClusterSecurityProfile(
7520+
kubernetes_resource_object_encryption_profile=ground_truth_kube_resource_encryption_profile_3,
7521+
)
7522+
ground_truth_mc_3 = self.models.ManagedCluster(
7523+
location="test_location",
7524+
security_profile=ground_truth_security_profile_3,
7525+
)
7526+
self.assertEqual(dec_mc_3, ground_truth_mc_3)
7527+
7528+
# test with Enabled on cluster with existing security profile
7529+
dec_4 = AKSPreviewManagedClusterUpdateDecorator(
7530+
self.cmd,
7531+
self.client,
7532+
{
7533+
"kms_infrastructure_encryption": "Enabled",
7534+
},
7535+
CUSTOM_MGMT_AKS_PREVIEW,
7536+
)
7537+
existing_security_profile = self.models.ManagedClusterSecurityProfile()
7538+
mc_4 = self.models.ManagedCluster(
7539+
location="test_location",
7540+
security_profile=existing_security_profile,
7541+
)
7542+
dec_4.context.attach_mc(mc_4)
7543+
dec_mc_4 = dec_4.update_kms_infrastructure_encryption(mc_4)
7544+
7545+
# should add to existing security profile
7546+
ground_truth_kube_resource_encryption_profile_4 = self.models.KubernetesResourceObjectEncryptionProfile(
7547+
infrastructure_encryption="Enabled"
7548+
)
7549+
ground_truth_security_profile_4 = self.models.ManagedClusterSecurityProfile(
7550+
kubernetes_resource_object_encryption_profile=ground_truth_kube_resource_encryption_profile_4,
7551+
)
7552+
ground_truth_mc_4 = self.models.ManagedCluster(
7553+
location="test_location",
7554+
security_profile=ground_truth_security_profile_4,
7555+
)
7556+
self.assertEqual(dec_mc_4, ground_truth_mc_4)
7557+
7558+
# test with Enabled on cluster with existing kubernetes_resource_object_encryption_profile
7559+
dec_5 = AKSPreviewManagedClusterUpdateDecorator(
7560+
self.cmd,
7561+
self.client,
7562+
{
7563+
"kms_infrastructure_encryption": "Enabled",
7564+
},
7565+
CUSTOM_MGMT_AKS_PREVIEW,
7566+
)
7567+
existing_kube_encryption_profile = self.models.KubernetesResourceObjectEncryptionProfile()
7568+
existing_security_profile = self.models.ManagedClusterSecurityProfile(
7569+
kubernetes_resource_object_encryption_profile=existing_kube_encryption_profile,
7570+
)
7571+
mc_5 = self.models.ManagedCluster(
7572+
location="test_location",
7573+
security_profile=existing_security_profile,
7574+
)
7575+
dec_5.context.attach_mc(mc_5)
7576+
dec_mc_5 = dec_5.update_kms_infrastructure_encryption(mc_5)
7577+
7578+
# should update existing profile
7579+
ground_truth_kube_resource_encryption_profile_5 = self.models.KubernetesResourceObjectEncryptionProfile(
7580+
infrastructure_encryption="Enabled"
7581+
)
7582+
ground_truth_security_profile_5 = self.models.ManagedClusterSecurityProfile(
7583+
kubernetes_resource_object_encryption_profile=ground_truth_kube_resource_encryption_profile_5,
7584+
)
7585+
ground_truth_mc_5 = self.models.ManagedCluster(
7586+
location="test_location",
7587+
security_profile=ground_truth_security_profile_5,
7588+
)
7589+
self.assertEqual(dec_mc_5, ground_truth_mc_5)
7590+
74717591
def test_update_workload_auto_scaler_profile(self):
74727592
# Throws exception when incorrect mc object is passed.
74737593
dec_1 = AKSPreviewManagedClusterUpdateDecorator(

src/aks-preview/linter_exclusions.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ aks update:
143143
azure_keyvault_kms_key_vault_resource_id:
144144
rule_exclusions:
145145
- option_length_too_long
146+
kms_infrastructure_encryption:
147+
rule_exclusions:
148+
- option_length_too_long
146149
enable_workload_identity:
147150
rule_exclusions:
148151
- option_length_too_long

src/aks-preview/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from setuptools import find_packages, setup
1111

12-
VERSION = "18.0.0b43"
12+
VERSION = "18.0.0b44"
1313

1414
CLASSIFIERS = [
1515
"Development Status :: 4 - Beta",

0 commit comments

Comments
 (0)