Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ To release a new version, please select a new version number (usually plus 1 to

Pending
+++++++
* Vendor new SDK and bump API version to 2025-08-02-preview.
* Pre-deprecate `--enable-custom-ca-trust` and `--disable-custom-ca-trust` in `az aks create`, `az aks update` commands.
* `az aks update`: Add new parameter `--kms-infrastructure-encryption` to enable KMS infrastructure encryption on an existing cluster.

18.0.0b44
+++++++
* Vendor new SDK and bump API version to 2025-08-02-preview.
* Pre-deprecate `--enable-custom-ca-trust` and `--disable-custom-ca-trust` in `az aks create`, `az aks update` commands.
* Hide `--enable-managed-system-pool` parameter for `az aks create` for now, as the feature is not ready yet.

18.0.0b43
Expand Down
4 changes: 4 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,10 @@
- name: --azure-keyvault-kms-key-vault-resource-id
type: string
short-summary: Resource ID of Azure Key Vault.
- name: --kms-infrastructure-encryption
type: string
short-summary: Enable encryption at rest of Kubernetes resource objects using service-managed keys.
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.
- name: --enable-image-cleaner
type: bool
short-summary: Enable ImageCleaner Service.
Expand Down
5 changes: 5 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,11 @@ def load_arguments(self, _):
"azure_keyvault_kms_key_vault_resource_id",
validator=validate_azure_keyvault_kms_key_vault_resource_id,
)
c.argument(
"kms_infrastructure_encryption",
arg_type=get_enum_type(["Enabled", "Disabled"]),
is_preview=True,
)
c.argument("http_proxy_config")
c.argument(
"bootstrap_artifact_source",
Expand Down
1 change: 1 addition & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,7 @@ def aks_update(
azure_keyvault_kms_key_id=None,
azure_keyvault_kms_key_vault_network_access=None,
azure_keyvault_kms_key_vault_resource_id=None,
kms_infrastructure_encryption=None,
http_proxy_config=None,
disable_http_proxy=False,
enable_http_proxy=False,
Expand Down
30 changes: 30 additions & 0 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5128,6 +5128,34 @@ def update_image_integrity(self, mc: ManagedCluster) -> ManagedCluster:

return mc

def update_kms_infrastructure_encryption(self, mc: ManagedCluster) -> ManagedCluster:
"""Update security profile KubernetesResourceObjectEncryptionProfile for the ManagedCluster object.

:return: the ManagedCluster object
"""
self._ensure_mc(mc)

kms_infrastructure_encryption = self.context.get_kms_infrastructure_encryption()

# no infrastructure encryption related changes
if not kms_infrastructure_encryption or kms_infrastructure_encryption == "Disabled":
return mc

if mc.security_profile is None:
mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member

# Set or update the kubernetes resource object encryption profile
if mc.security_profile.kubernetes_resource_object_encryption_profile is None:
mc.security_profile.kubernetes_resource_object_encryption_profile = (
self.models.KubernetesResourceObjectEncryptionProfile() # pylint: disable=no-member
)

# Set infrastructure encryption
# pylint: disable=line-too-long
mc.security_profile.kubernetes_resource_object_encryption_profile.infrastructure_encryption = kms_infrastructure_encryption

return mc

def update_storage_profile(self, mc: ManagedCluster) -> ManagedCluster:
"""Update storage profile for the ManagedCluster object.

Expand Down Expand Up @@ -5956,6 +5984,8 @@ def update_mc_profile_preview(self) -> ManagedCluster:
mc = self.update_image_cleaner(mc)
# update image integrity
mc = self.update_image_integrity(mc)
# update KMS infrastructure encryption
mc = self.update_kms_infrastructure_encryption(mc)
# update workload auto scaler profile
mc = self.update_workload_auto_scaler_profile(mc)
# update azure monitor metrics profile
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -11991,6 +11991,69 @@ def test_aks_create_with_kms_infrastructure_encryption(
],
)

@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17,
name_prefix="clitest",
location="eastus2euap",
)
def test_aks_update_with_kms_infrastructure_encryption(
Comment thread
FumingZhang marked this conversation as resolved.
self, resource_group, resource_group_location
):
aks_name = self.create_random_name("cliakstest", 16)
k8s_version = self._get_version_in_range(location=resource_group_location, min_version="1.33.0", max_version="1.34.0")
self.kwargs.update(
{
"resource_group": resource_group,
"name": aks_name,
"ssh_key_value": self.generate_ssh_keys(),
"k8s_version": k8s_version,
}
)

# create cluster without infrastructure encryption
create_cmd = (
"aks create --resource-group={resource_group} --name={name} "
"--kubernetes-version={k8s_version} "
"--ssh-key-value={ssh_key_value} -o json"
)
self.cmd(
create_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.not_exists("securityProfile.kubernetesResourceObjectEncryptionProfile"),
],
)

# update cluster to enable infrastructure encryption
update_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--kms-infrastructure-encryption Enabled "
"--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/KMSPMKPreview "
"-o json"
)
self.cmd(
update_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check(
"securityProfile.kubernetesResourceObjectEncryptionProfile.infrastructureEncryption",
"Enabled"
),
],
)

# delete
cmd = (
"aks delete --resource-group={resource_group} --name={name} --yes --no-wait"
)
self.cmd(
cmd,
checks=[
self.is_empty(),
],
)

@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7468,6 +7468,126 @@ def test_update_azure_keyvault_kms(self):
)
self.assertEqual(dec_mc_7, ground_truth_mc_7)

def test_update_kms_infrastructure_encryption(self):
# test no change when no parameter provided
dec_1 = AKSPreviewManagedClusterUpdateDecorator(
self.cmd,
self.client,
{},
CUSTOM_MGMT_AKS_PREVIEW,
)
mc_1 = self.models.ManagedCluster(location="test_location")
dec_1.context.attach_mc(mc_1)
dec_mc_1 = dec_1.update_kms_infrastructure_encryption(mc_1)
# no change expected
ground_truth_mc_1 = self.models.ManagedCluster(location="test_location")
self.assertEqual(dec_mc_1, ground_truth_mc_1)

# test no change when Disabled
dec_2 = AKSPreviewManagedClusterUpdateDecorator(
self.cmd,
self.client,
{
"kms_infrastructure_encryption": "Disabled",
},
CUSTOM_MGMT_AKS_PREVIEW,
)
mc_2 = self.models.ManagedCluster(location="test_location")
dec_2.context.attach_mc(mc_2)
dec_mc_2 = dec_2.update_kms_infrastructure_encryption(mc_2)
# no change expected
ground_truth_mc_2 = self.models.ManagedCluster(location="test_location")
self.assertEqual(dec_mc_2, ground_truth_mc_2)

# test with Enabled on new cluster
dec_3 = AKSPreviewManagedClusterUpdateDecorator(
self.cmd,
self.client,
{
"kms_infrastructure_encryption": "Enabled",
},
CUSTOM_MGMT_AKS_PREVIEW,
)
mc_3 = self.models.ManagedCluster(location="test_location")
dec_3.context.attach_mc(mc_3)
dec_mc_3 = dec_3.update_kms_infrastructure_encryption(mc_3)

# expected security profile with infrastructure encryption
ground_truth_kube_resource_encryption_profile_3 = self.models.KubernetesResourceObjectEncryptionProfile(
infrastructure_encryption="Enabled"
)
ground_truth_security_profile_3 = self.models.ManagedClusterSecurityProfile(
kubernetes_resource_object_encryption_profile=ground_truth_kube_resource_encryption_profile_3,
)
ground_truth_mc_3 = self.models.ManagedCluster(
location="test_location",
security_profile=ground_truth_security_profile_3,
)
self.assertEqual(dec_mc_3, ground_truth_mc_3)

# test with Enabled on cluster with existing security profile
dec_4 = AKSPreviewManagedClusterUpdateDecorator(
self.cmd,
self.client,
{
"kms_infrastructure_encryption": "Enabled",
},
CUSTOM_MGMT_AKS_PREVIEW,
)
existing_security_profile = self.models.ManagedClusterSecurityProfile()
mc_4 = self.models.ManagedCluster(
location="test_location",
security_profile=existing_security_profile,
)
dec_4.context.attach_mc(mc_4)
dec_mc_4 = dec_4.update_kms_infrastructure_encryption(mc_4)

# should add to existing security profile
ground_truth_kube_resource_encryption_profile_4 = self.models.KubernetesResourceObjectEncryptionProfile(
infrastructure_encryption="Enabled"
)
ground_truth_security_profile_4 = self.models.ManagedClusterSecurityProfile(
kubernetes_resource_object_encryption_profile=ground_truth_kube_resource_encryption_profile_4,
)
ground_truth_mc_4 = self.models.ManagedCluster(
location="test_location",
security_profile=ground_truth_security_profile_4,
)
self.assertEqual(dec_mc_4, ground_truth_mc_4)

# test with Enabled on cluster with existing kubernetes_resource_object_encryption_profile
dec_5 = AKSPreviewManagedClusterUpdateDecorator(
self.cmd,
self.client,
{
"kms_infrastructure_encryption": "Enabled",
},
CUSTOM_MGMT_AKS_PREVIEW,
)
existing_kube_encryption_profile = self.models.KubernetesResourceObjectEncryptionProfile()
existing_security_profile = self.models.ManagedClusterSecurityProfile(
kubernetes_resource_object_encryption_profile=existing_kube_encryption_profile,
)
mc_5 = self.models.ManagedCluster(
location="test_location",
security_profile=existing_security_profile,
)
dec_5.context.attach_mc(mc_5)
dec_mc_5 = dec_5.update_kms_infrastructure_encryption(mc_5)

# should update existing profile
ground_truth_kube_resource_encryption_profile_5 = self.models.KubernetesResourceObjectEncryptionProfile(
infrastructure_encryption="Enabled"
)
ground_truth_security_profile_5 = self.models.ManagedClusterSecurityProfile(
kubernetes_resource_object_encryption_profile=ground_truth_kube_resource_encryption_profile_5,
)
ground_truth_mc_5 = self.models.ManagedCluster(
location="test_location",
security_profile=ground_truth_security_profile_5,
)
self.assertEqual(dec_mc_5, ground_truth_mc_5)

def test_update_workload_auto_scaler_profile(self):
# Throws exception when incorrect mc object is passed.
dec_1 = AKSPreviewManagedClusterUpdateDecorator(
Expand Down
3 changes: 3 additions & 0 deletions src/aks-preview/linter_exclusions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ aks update:
azure_keyvault_kms_key_vault_resource_id:
rule_exclusions:
- option_length_too_long
kms_infrastructure_encryption:
rule_exclusions:
- option_length_too_long
enable_workload_identity:
rule_exclusions:
- option_length_too_long
Expand Down
Loading