Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{AKS} support disabling Azure KeyVault KMS #5087

Merged
merged 1 commit into from
Jul 25, 2022
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
2 changes: 2 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ To release a new version, please select a new version number (usually plus 1 to
Pending
+++++++

* Support disabling Azure KeyVault KMS.

0.5.91
++++++

Expand Down
3 changes: 3 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,9 @@
- name: --enable-azure-keyvault-kms
type: bool
short-summary: Enable Azure KeyVault Key Management Service.
- name: --disable-azure-keyvault-kms
type: bool
short-summary: Disable Azure KeyVault Key Management Service.
- name: --azure-keyvault-kms-key-id
type: string
short-summary: Identifier of Azure Key Vault key.
Expand Down
1 change: 1 addition & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ def load_arguments(self, _):
c.argument('enable_workload_identity', arg_type=get_three_state_flag())
c.argument('enable_oidc_issuer', action='store_true', is_preview=True)
c.argument('enable_azure_keyvault_kms', action='store_true', is_preview=True)
c.argument('disable_azure_keyvault_kms', action='store_true', is_preview=True)
c.argument('azure_keyvault_kms_key_id', validator=validate_azure_keyvault_kms_key_id, is_preview=True)
c.argument('azure_keyvault_kms_key_vault_network_access', arg_type=get_enum_type(keyvault_network_access_types), is_preview=True)
c.argument('azure_keyvault_kms_key_vault_resource_id', validator=validate_azure_keyvault_kms_key_vault_resource_id, is_preview=True)
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 @@ -766,6 +766,7 @@ def aks_update(
enable_workload_identity=None,
enable_oidc_issuer=False,
enable_azure_keyvault_kms=False,
disable_azure_keyvault_kms=False,
azure_keyvault_kms_key_id=None,
azure_keyvault_kms_key_vault_network_access=None,
azure_keyvault_kms_key_vault_resource_id=None,
Expand Down
43 changes: 43 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 @@ -680,6 +680,37 @@ def get_enable_azure_keyvault_kms(self) -> bool:
"""
return self._get_enable_azure_keyvault_kms(enable_validation=True)

def _get_disable_azure_keyvault_kms(self, enable_validation: bool = False) -> bool:
"""Internal function to obtain the value of disable_azure_keyvault_kms.

This function supports the option of enable_validation. When enabled, if both enable_azure_keyvault_kms and disable_azure_keyvault_kms are
specified, raise a MutuallyExclusiveArgumentError.

:return: bool
"""
# Read the original value passed by the command.
disable_azure_keyvault_kms = self.raw_param.get("disable_azure_keyvault_kms")

# This option is not supported in create mode, hence we do not read the property value from the `mc` object.
# This parameter does not need dynamic completion.
if enable_validation:
if disable_azure_keyvault_kms and self._get_enable_azure_keyvault_kms(enable_validation=False):
raise MutuallyExclusiveArgumentError(
"Cannot specify --enable-azure-keyvault-kms and --disable-azure-keyvault-kms at the same time."
)

return disable_azure_keyvault_kms

def get_disable_azure_keyvault_kms(self) -> bool:
"""Obtain the value of disable_azure_keyvault_kms.

This function will verify the parameter by default. If both enable_azure_keyvault_kms and disable_azure_keyvault_kms are specified, raise a
MutuallyExclusiveArgumentError.

:return: bool
"""
return self._get_disable_azure_keyvault_kms(enable_validation=True)

def _get_azure_keyvault_kms_key_id(self, enable_validation: bool = False) -> Union[str, None]:
"""Internal function to obtain the value of azure_keyvault_kms_key_id according to the context.

Expand Down Expand Up @@ -1964,6 +1995,18 @@ def update_azure_keyvault_kms(self, mc: ManagedCluster) -> ManagedCluster:
self.context.get_azure_keyvault_kms_key_vault_resource_id()
)

if self.context.get_disable_azure_keyvault_kms():
# get kms profile
if mc.security_profile is None:
mc.security_profile = self.models.ManagedClusterSecurityProfile()
azure_key_vault_kms_profile = mc.security_profile.azure_key_vault_kms
if azure_key_vault_kms_profile is None:
azure_key_vault_kms_profile = self.models.AzureKeyVaultKms()
mc.security_profile.azure_key_vault_kms = azure_key_vault_kms_profile

# set enabled to False
azure_key_vault_kms_profile.enabled = False

return mc

def update_storage_profile(self, mc: ManagedCluster) -> ManagedCluster:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4291,6 +4291,80 @@ def test_aks_update_with_azurekeyvaultkms_private_key_vault(self, resource_group
self.is_empty(),
])

@live_only()
@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(random_name_length=17, name_prefix='clitest', location='centraluseuap')
def test_aks_disable_azurekeyvaultkms(self, resource_group, resource_group_location):
aks_name = self.create_random_name('cliakstest', 16)
kv_name = self.create_random_name('cliakstestkv', 16)
identity_name = self.create_random_name('cliakstestidentity', 24)
self.kwargs.update({
'resource_group': resource_group,
'name': aks_name,
"kv_name": kv_name,
"identity_name": identity_name,
'ssh_key_value': self.generate_ssh_keys()
})

# create user-assigned identity
create_identity = 'identity create --resource-group={resource_group} --name={identity_name} -o json'
identity = self.cmd(create_identity).get_output_in_json()
identity_id = identity['id']
identity_object_id = identity['principalId']
assert identity_id is not None
assert identity_object_id is not None
self.kwargs.update({
'identity_id': identity_id,
'identity_object_id': identity_object_id,
})

# create key vault and key
create_keyvault = 'keyvault create --resource-group={resource_group} --name={kv_name} -o json'
kv = self.cmd(create_keyvault, checks=[
self.check('properties.provisioningState', 'Succeeded')
]).get_output_in_json()

create_key = 'keyvault key create -n kms --vault-name {kv_name} -o json'
key = self.cmd(create_key, checks=[
self.check('attributes.enabled', True)
]).get_output_in_json()
key_id = key['key']['kid']
assert key_id is not None
self.kwargs.update({
'key_id': key_id,
})

# assign access policy
set_policy = 'keyvault set-policy --resource-group={resource_group} --name={kv_name} ' \
'--object-id {identity_object_id} --key-permissions encrypt decrypt -o json'
policy = self.cmd(set_policy, checks=[
self.check('properties.provisioningState', 'Succeeded')
]).get_output_in_json()

create_cmd = 'aks create --resource-group={resource_group} --name={name} ' \
'--assign-identity {identity_id} ' \
'--enable-azure-keyvault-kms --azure-keyvault-kms-key-id={key_id} --aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/AzureKeyVaultKmsPreview ' \
'--ssh-key-value={ssh_key_value} -o json'
self.cmd(create_cmd, checks=[
self.check('provisioningState', 'Succeeded'),
self.check('securityProfile.azureKeyVaultKms.enabled', True),
self.check('securityProfile.azureKeyVaultKms.keyId', key_id)
])

update_cmd = 'aks update --resource-group={resource_group} --name={name} ' \
'--disable-azure-keyvault-kms --aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/AzureKeyVaultKmsPreview ' \
'-o json'
self.cmd(update_cmd, checks=[
self.check('provisioningState', 'Succeeded'),
self.check('securityProfile.azureKeyVaultKms.enabled', False),
bingosummer marked this conversation as resolved.
Show resolved Hide resolved
])

# 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, name_prefix='clitest', location='westcentralus', preserve_default_location=True)
def test_aks_create_and_update_with_csi_drivers_extensibility(self, resource_group, resource_group_location):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,53 @@ def test_get_enable_azure_keyvault_kms(self):
with self.assertRaises(RequiredArgumentMissingError):
ctx_5.get_enable_azure_keyvault_kms()

def test_get_disable_azure_keyvault_kms(self):
ctx_0 = AKSPreviewManagedClusterContext(
self.cmd,
AKSManagedClusterParamDict({}),
self.models,
decorator_mode=DecoratorMode.UPDATE,
)
self.assertIsNone(ctx_0.get_enable_azure_keyvault_kms())

ctx_1 = AKSPreviewManagedClusterContext(
self.cmd,
AKSManagedClusterParamDict(
{
"disable_azure_keyvault_kms": True,
}
),
self.models,
decorator_mode=DecoratorMode.UPDATE,
)
self.assertEqual(ctx_1.get_disable_azure_keyvault_kms(), True)

ctx_2 = AKSPreviewManagedClusterContext(
self.cmd,
AKSManagedClusterParamDict(
{
"disable_azure_keyvault_kms": False,
}
),
self.models,
decorator_mode=DecoratorMode.UPDATE,
)
self.assertEqual(ctx_2.get_disable_azure_keyvault_kms(), False)

ctx_3 = AKSPreviewManagedClusterContext(
self.cmd,
AKSManagedClusterParamDict(
{
"enable_azure_keyvault_kms": True,
"disable_azure_keyvault_kms": True,
}
),
self.models,
decorator_mode=DecoratorMode.UPDATE,
)
with self.assertRaises(MutuallyExclusiveArgumentError):
ctx_3.get_disable_azure_keyvault_kms()

def test_get_azure_keyvault_kms_key_id(self):
ctx_0 = AKSPreviewManagedClusterContext(
self.cmd,
Expand Down Expand Up @@ -3959,6 +4006,67 @@ def test_update_azure_keyvault_kms(self):
)
self.assertEqual(dec_mc_4, ground_truth_mc_4)

dec_5 = AKSPreviewManagedClusterUpdateDecorator(
self.cmd,
self.client,
{
"disable_azure_keyvault_kms": True,
},
CUSTOM_MGMT_AKS_PREVIEW,
)
azure_keyvault_kms_profile_5 = self.models.AzureKeyVaultKms(
enabled=True,
key_id=key_id_1,
key_vault_network_access="Public",
)
security_profile_5 = self.models.ManagedClusterSecurityProfile(
azure_key_vault_kms=azure_keyvault_kms_profile_5,
)
mc_5 = self.models.ManagedCluster(
location="test_location",
security_profile=security_profile_5,
)
dec_5.context.attach_mc(mc_5)
dec_mc_5 = dec_5.update_azure_keyvault_kms(mc_5)

ground_truth_azure_keyvault_kms_profile_5 = self.models.AzureKeyVaultKms(
enabled=False,
key_id=key_id_1,
key_vault_network_access="Public",
)
ground_truth_security_profile_5 = self.models.ManagedClusterSecurityProfile(
azure_key_vault_kms=ground_truth_azure_keyvault_kms_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)

dec_6 = AKSPreviewManagedClusterUpdateDecorator(
self.cmd,
self.client,
{
"disable_azure_keyvault_kms": True,
},
CUSTOM_MGMT_AKS_PREVIEW,
)
mc_6 = self.models.ManagedCluster(
location="test_location",
)
dec_6.context.attach_mc(mc_6)
dec_mc_6 = dec_6.update_azure_keyvault_kms(mc_6)

ground_truth_azure_keyvault_kms_profile_6 = self.models.AzureKeyVaultKms()
ground_truth_azure_keyvault_kms_profile_6.enabled=False
ground_truth_security_profile_6 = self.models.ManagedClusterSecurityProfile()
ground_truth_security_profile_6.azure_key_vault_kms=ground_truth_azure_keyvault_kms_profile_6
ground_truth_mc_6 = self.models.ManagedCluster(
location="test_location",
security_profile=ground_truth_security_profile_6,
)
self.assertEqual(dec_mc_6, ground_truth_mc_6)


def test_update_storage_profile(self):
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 @@ -48,6 +48,9 @@ aks update:
enable_azure_keyvault_kms:
rule_exclusions:
- option_length_too_long
disable_azure_keyvault_kms:
rule_exclusions:
- option_length_too_long
azure_keyvault_kms_key_id:
rule_exclusions:
- option_length_too_long
Expand Down