@@ -11946,7 +11946,7 @@ def test_aks_disable_azurekeyvaultkms(
1194611946 name_prefix="clitest",
1194711947 location="eastus2euap",
1194811948 )
11949- def test_aks_create_with_kms_infrastructure_encryption (
11949+ def test_aks_create_with_kms_pmk (
1195011950 self, resource_group, resource_group_location
1195111951 ):
1195211952 aks_name = self.create_random_name("cliakstest", 16)
@@ -11991,6 +11991,290 @@ def test_aks_create_with_kms_infrastructure_encryption(
1199111991 ],
1199211992 )
1199311993
11994+ @live_only()
11995+ @AllowLargeResponse()
11996+ @AKSCustomResourceGroupPreparer(
11997+ random_name_length=17,
11998+ name_prefix="clitest",
11999+ location="eastus2euap",
12000+ )
12001+ def test_aks_create_with_kms_pmk_and_cmk(
12002+ self, resource_group, resource_group_location
12003+ ):
12004+ """Test PMK-enabled cluster creation with versionless key ID"""
12005+ aks_name = self.create_random_name("cliakstest", 16)
12006+ kv_name = self.create_random_name("cliakstestkv", 16)
12007+ identity_name = self.create_random_name("cliakstestidentity", 24)
12008+ k8s_version = self._get_version_in_range(location=resource_group_location, min_version="1.33.0", max_version="1.34.0")
12009+ self.kwargs.update(
12010+ {
12011+ "resource_group": resource_group,
12012+ "name": aks_name,
12013+ "kv_name": kv_name,
12014+ "identity_name": identity_name,
12015+ "ssh_key_value": self.generate_ssh_keys(),
12016+ "k8s_version": k8s_version,
12017+ }
12018+ )
12019+
12020+ # create user-assigned identity
12021+ identity_id = self._get_user_assigned_identity(resource_group)
12022+ identity_object_id = self._get_principal_id_of_user_assigned_identity(identity_id)
12023+ assert identity_id is not None
12024+ assert identity_object_id is not None
12025+ self.kwargs.update(
12026+ {
12027+ "identity_id": identity_id,
12028+ "identity_object_id": identity_object_id,
12029+ }
12030+ )
12031+
12032+ # create key vault and key
12033+ create_keyvault = (
12034+ "keyvault create --resource-group={resource_group} --name={kv_name} --enable-rbac-authorization=false --no-self-perms -o json"
12035+ )
12036+ self.cmd(
12037+ create_keyvault,
12038+ checks=[self.check("properties.provisioningState", "Succeeded")],
12039+ )
12040+
12041+ # set access policy for test identity
12042+ test_identity_object_id = self._get_test_identity_object_id()
12043+ test_identity_access_policy = 'keyvault set-policy --resource-group={resource_group} --name={kv_name} ' \
12044+ '--key-permissions all --object-id ' + test_identity_object_id
12045+ self.cmd(test_identity_access_policy, checks=[
12046+ self.check('properties.provisioningState', 'Succeeded')
12047+ ])
12048+
12049+ # create key and extract versionless key ID
12050+ create_key = "keyvault key create -n kms --vault-name {kv_name} -o json"
12051+ key = self.cmd(
12052+ create_key, checks=[self.check("attributes.enabled", True)]
12053+ ).get_output_in_json()
12054+ key_id_versioned = key["key"]["kid"]
12055+ # Extract versionless key ID (remove version part)
12056+ # Format: https://{vault}.vault.azure.net/keys/{name}/{version}
12057+ # We want: https://{vault}.vault.azure.net/keys/{name}
12058+ key_id_parts = key_id_versioned.rsplit('/', 1)
12059+ key_id_versionless = key_id_parts[0]
12060+
12061+ assert key_id_versionless is not None
12062+ self.kwargs.update(
12063+ {
12064+ "key_id": key_id_versionless,
12065+ }
12066+ )
12067+
12068+ # Get key vault resource ID
12069+ kv_resource_id = self.cmd(
12070+ "keyvault show --resource-group={resource_group} --name={kv_name} --query id -o tsv"
12071+ ).output.strip()
12072+ self.kwargs.update(
12073+ {
12074+ "kv_resource_id": kv_resource_id,
12075+ }
12076+ )
12077+
12078+ # assign access policy
12079+ set_policy = (
12080+ "keyvault set-policy --resource-group={resource_group} --name={kv_name} "
12081+ "--object-id {identity_object_id} --key-permissions encrypt decrypt -o json"
12082+ )
12083+ self.cmd(
12084+ set_policy, checks=[self.check("properties.provisioningState", "Succeeded")]
12085+ )
12086+
12087+ # create cluster with PMK enabled and versionless key ID
12088+ create_cmd = (
12089+ "aks create --resource-group={resource_group} --name={name} "
12090+ "--assign-identity {identity_id} "
12091+ "--enable-azure-keyvault-kms --azure-keyvault-kms-key-id={key_id} "
12092+ "--azure-keyvault-kms-key-vault-resource-id={kv_resource_id} "
12093+ "--kms-infrastructure-encryption=Enabled "
12094+ "--kubernetes-version={k8s_version} "
12095+ "--ssh-key-value={ssh_key_value} "
12096+ "--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/KMSPMKPreview "
12097+ "-o json"
12098+ )
12099+ self.cmd(
12100+ create_cmd,
12101+ checks=[
12102+ self.check("provisioningState", "Succeeded"),
12103+ self.check("securityProfile.azureKeyVaultKms.enabled", True),
12104+ self.check("securityProfile.azureKeyVaultKms.keyId", key_id_versionless),
12105+ self.check("securityProfile.azureKeyVaultKms.keyVaultResourceId", kv_resource_id),
12106+ self.check(
12107+ "securityProfile.kubernetesResourceObjectEncryptionProfile.infrastructureEncryption",
12108+ "Enabled"
12109+ ),
12110+ ],
12111+ )
12112+
12113+ # delete
12114+ cmd = (
12115+ "aks delete --resource-group={resource_group} --name={name} --yes --no-wait"
12116+ )
12117+ self.cmd(
12118+ cmd,
12119+ checks=[
12120+ self.is_empty(),
12121+ ],
12122+ )
12123+
12124+ @live_only()
12125+ @AllowLargeResponse()
12126+ @AKSCustomResourceGroupPreparer(
12127+ random_name_length=17,
12128+ name_prefix="clitest",
12129+ location="centraluseuap",
12130+ )
12131+ def test_aks_update_with_pmk_enabled_key_rotation(
12132+ self, resource_group, resource_group_location
12133+ ):
12134+ """Test PMK-enabled cluster key rotation with versionless key ID"""
12135+ aks_name = self.create_random_name("cliakstest", 16)
12136+ kv_name = self.create_random_name("cliakstestkv", 16)
12137+ identity_name = self.create_random_name("cliakstestidentity", 24)
12138+ k8s_version = self._get_version_in_range(location=resource_group_location, min_version="1.33.0", max_version="1.34.0")
12139+ self.kwargs.update(
12140+ {
12141+ "resource_group": resource_group,
12142+ "name": aks_name,
12143+ "kv_name": kv_name,
12144+ "identity_name": identity_name,
12145+ "ssh_key_value": self.generate_ssh_keys(),
12146+ "k8s_version": k8s_version,
12147+ }
12148+ )
12149+
12150+ # create user-assigned identity
12151+ identity_id = self._get_user_assigned_identity(resource_group)
12152+ identity_object_id = self._get_principal_id_of_user_assigned_identity(identity_id)
12153+ assert identity_id is not None
12154+ assert identity_object_id is not None
12155+ self.kwargs.update(
12156+ {
12157+ "identity_id": identity_id,
12158+ "identity_object_id": identity_object_id,
12159+ }
12160+ )
12161+
12162+ # create key vault and first key
12163+ create_keyvault = (
12164+ "keyvault create --resource-group={resource_group} --name={kv_name} --enable-rbac-authorization=false --no-self-perms -o json"
12165+ )
12166+ self.cmd(
12167+ create_keyvault,
12168+ checks=[self.check("properties.provisioningState", "Succeeded")],
12169+ )
12170+
12171+ # set access policy for test identity
12172+ test_identity_object_id = self._get_test_identity_object_id()
12173+ test_identity_access_policy = 'keyvault set-policy --resource-group={resource_group} --name={kv_name} ' \
12174+ '--key-permissions all --object-id ' + test_identity_object_id
12175+ self.cmd(test_identity_access_policy, checks=[
12176+ self.check('properties.provisioningState', 'Succeeded')
12177+ ])
12178+
12179+ # create first key
12180+ create_key = "keyvault key create -n kms --vault-name {kv_name} -o json"
12181+ key = self.cmd(
12182+ create_key, checks=[self.check("attributes.enabled", True)]
12183+ ).get_output_in_json()
12184+ key_id_versioned_0 = key["key"]["kid"]
12185+ key_id_versionless = key_id_versioned_0.rsplit('/', 1)[0]
12186+
12187+ assert key_id_versionless is not None
12188+ self.kwargs.update(
12189+ {
12190+ "key_id": key_id_versionless,
12191+ }
12192+ )
12193+
12194+ # Get key vault resource ID
12195+ kv_resource_id = self.cmd(
12196+ "keyvault show --resource-group={resource_group} --name={kv_name} --query id -o tsv"
12197+ ).output.strip()
12198+ self.kwargs.update(
12199+ {
12200+ "kv_resource_id": kv_resource_id,
12201+ }
12202+ )
12203+
12204+ # assign access policy
12205+ set_policy = (
12206+ "keyvault set-policy --resource-group={resource_group} --name={kv_name} "
12207+ "--object-id {identity_object_id} --key-permissions encrypt decrypt -o json"
12208+ )
12209+ self.cmd(
12210+ set_policy, checks=[self.check("properties.provisioningState", "Succeeded")]
12211+ )
12212+
12213+ # create cluster with PMK enabled
12214+ create_cmd = (
12215+ "aks create --resource-group={resource_group} --name={name} "
12216+ "--assign-identity {identity_id} "
12217+ "--enable-azure-keyvault-kms --azure-keyvault-kms-key-id={key_id} "
12218+ "--azure-keyvault-kms-key-vault-network-access=Public "
12219+ "--azure-keyvault-kms-key-vault-resource-id={kv_resource_id} "
12220+ "--kms-infrastructure-encryption=Enabled "
12221+ "--kubernetes-version={k8s_version} "
12222+ "--ssh-key-value={ssh_key_value} "
12223+ "--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/KMSPMKPreview "
12224+ "-o json"
12225+ )
12226+ self.cmd(
12227+ create_cmd,
12228+ checks=[
12229+ self.check("provisioningState", "Succeeded"),
12230+ self.check("securityProfile.azureKeyVaultKms.enabled", True),
12231+ self.check("securityProfile.azureKeyVaultKms.keyId", key_id_versionless),
12232+ self.check(
12233+ "securityProfile.kubernetesResourceObjectEncryptionProfile.infrastructureEncryption",
12234+ "Enabled"
12235+ ),
12236+ ],
12237+ )
12238+
12239+ # Create a new version of the same key (simulating key rotation)
12240+ # With versionless key ID, the cluster should automatically use the new version
12241+ key_new_version = self.cmd(
12242+ create_key, checks=[self.check("attributes.enabled", True)]
12243+ ).get_output_in_json()
12244+ key_id_versioned_1 = key_new_version["key"]["kid"]
12245+
12246+ # The versionless key ID stays the same
12247+ assert key_id_versionless == key_id_versioned_1.rsplit('/', 1)[0]
12248+
12249+ # Update cluster - with PMK and versionless key, no key ID change is needed for rotation
12250+ # The cluster will automatically pick up the new key version
12251+ update_cmd = (
12252+ "aks update --resource-group={resource_group} --name={name} "
12253+ "--enable-azure-keyvault-kms --azure-keyvault-kms-key-id={key_id} "
12254+ "--azure-keyvault-kms-key-vault-network-access=Public "
12255+ "--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/KMSPMKPreview "
12256+ "-o json"
12257+ )
12258+ self.cmd(
12259+ update_cmd,
12260+ checks=[
12261+ self.check("provisioningState", "Succeeded"),
12262+ self.check("securityProfile.azureKeyVaultKms.enabled", True),
12263+ self.check("securityProfile.azureKeyVaultKms.keyId", key_id_versionless),
12264+ ],
12265+ )
12266+
12267+ # delete
12268+ cmd = (
12269+ "aks delete --resource-group={resource_group} --name={name} --yes --no-wait"
12270+ )
12271+ self.cmd(
12272+ cmd,
12273+ checks=[
12274+ self.is_empty(),
12275+ ],
12276+ )
12277+
1199412278 @AllowLargeResponse()
1199512279 @AKSCustomResourceGroupPreparer(
1199612280 random_name_length=17,
0 commit comments