Skip to content

Commit

Permalink
{Keyvault} az keyvault security-domain: Migrate security domain to …
Browse files Browse the repository at this point in the history
…use track2 SDK (#30252)

* add dependency

* track2 migration for security-domain init-recovery/upload/download/wait

* rerun tests

* vendored sdk

* line-too-long
  • Loading branch information
evelyn-ys authored Nov 11, 2024
1 parent 4ac17d6 commit 7506f6a
Show file tree
Hide file tree
Showing 72 changed files with 11,871 additions and 8,995 deletions.
9 changes: 3 additions & 6 deletions src/azure-cli-core/azure/cli/core/profiles/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ class ResourceType(Enum): # pylint: disable=too-few-public-methods
DATA_KEYVAULT_CERTIFICATES = ('azure.keyvault.certificates', 'CertificateClient')
DATA_KEYVAULT_KEYS = ('azure.keyvault.keys', 'KeyClient')
DATA_KEYVAULT_SECRETS = ('azure.keyvault.secrets', 'SecretClient')
DATA_KEYVAULT = ('azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_t1', 'KeyVaultClient')
DATA_KEYVAULT_SECURITY_DOMAIN = ('azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_securitydomain',
'SecurityDomainClient')
DATA_KEYVAULT_ADMINISTRATION_BACKUP = ('azure.keyvault.administration', 'KeyVaultBackupClient')
DATA_KEYVAULT_ADMINISTRATION_ACCESS_CONTROL = ('azure.keyvault.administration', 'KeyVaultAccessControlClient')
DATA_KEYVAULT_ADMINISTRATION_SETTING = ('azure.keyvault.administration', 'KeyVaultSettingsClient')
Expand Down Expand Up @@ -207,8 +208,8 @@ def default_api_version(self):
ResourceType.DATA_KEYVAULT_CERTIFICATES: None,
ResourceType.DATA_KEYVAULT_KEYS: None,
ResourceType.DATA_KEYVAULT_SECRETS: None,
ResourceType.DATA_KEYVAULT_SECURITY_DOMAIN: None,
ResourceType.DATA_KEYVAULT_ADMINISTRATION_SETTING: None,
ResourceType.DATA_KEYVAULT: '7.0',
ResourceType.DATA_KEYVAULT_ADMINISTRATION_BACKUP: '7.5-preview.1',
ResourceType.DATA_KEYVAULT_ADMINISTRATION_ACCESS_CONTROL: '7.4',
ResourceType.DATA_STORAGE: '2018-11-09',
Expand Down Expand Up @@ -299,7 +300,6 @@ def default_api_version(self):
ResourceType.DATA_KEYVAULT_CERTIFICATES: None,
ResourceType.DATA_KEYVAULT_KEYS: None,
ResourceType.DATA_KEYVAULT_SECRETS: None,
ResourceType.DATA_KEYVAULT: '2016-10-01',
ResourceType.DATA_STORAGE: '2018-11-09',
ResourceType.DATA_STORAGE_BLOB: '2019-07-07',
ResourceType.DATA_STORAGE_FILEDATALAKE: '2019-07-07',
Expand Down Expand Up @@ -346,7 +346,6 @@ def default_api_version(self):
ResourceType.DATA_KEYVAULT_CERTIFICATES: None,
ResourceType.DATA_KEYVAULT_KEYS: None,
ResourceType.DATA_KEYVAULT_SECRETS: None,
ResourceType.DATA_KEYVAULT: '2016-10-01',
ResourceType.DATA_STORAGE: '2017-11-09',
ResourceType.DATA_STORAGE_BLOB: '2017-11-09',
ResourceType.DATA_STORAGE_FILEDATALAKE: '2017-11-09',
Expand Down Expand Up @@ -385,7 +384,6 @@ def default_api_version(self):
ResourceType.DATA_KEYVAULT_CERTIFICATES: None,
ResourceType.DATA_KEYVAULT_KEYS: None,
ResourceType.DATA_KEYVAULT_SECRETS: None,
ResourceType.DATA_KEYVAULT: '2016-10-01',
ResourceType.DATA_STORAGE: '2017-04-17',
ResourceType.DATA_STORAGE_BLOB: '2017-04-17',
ResourceType.DATA_STORAGE_FILEDATALAKE: '2017-04-17',
Expand Down Expand Up @@ -416,7 +414,6 @@ def default_api_version(self):
ResourceType.DATA_KEYVAULT_CERTIFICATES: None,
ResourceType.DATA_KEYVAULT_KEYS: None,
ResourceType.DATA_KEYVAULT_SECRETS: None,
ResourceType.DATA_KEYVAULT: '2016-10-01',
ResourceType.DATA_STORAGE: '2015-04-05',
ResourceType.DATA_STORAGE_BLOB: '2015-04-05',
ResourceType.DATA_STORAGE_FILEDATALAKE: '2015-04-05',
Expand Down
8 changes: 0 additions & 8 deletions src/azure-cli-core/azure/cli/core/tests/test_api_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,14 +263,6 @@ def test_get_versioned_sdk_path_date(self):
"azure.mgmt.storage.v2020_10_10"
)

def test_get_versioned_sdk_path_semver(self):
test_profile = {'latest': {ResourceType.DATA_KEYVAULT: '7.0'}}
with mock.patch('azure.cli.core.profiles._shared.AZURE_API_PROFILES', test_profile):
self.assertEqual(
get_versioned_sdk_path('latest', ResourceType.DATA_KEYVAULT),
"azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_t1.v7_0"
)


if __name__ == '__main__':
unittest.main()
68 changes: 35 additions & 33 deletions src/azure-cli/azure/cli/command_modules/keyvault/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from azure.cli.core.azclierror import RequiredArgumentMissingError
from azure.cli.core.commands import CliCommandType
from azure.cli.core.commands.client_factory import prepare_client_kwargs_track2
from azure.cli.core.profiles import get_api_version, ResourceType
from azure.cli.core._profile import Profile

Expand Down Expand Up @@ -39,9 +40,6 @@ class Clients(str, Enum):
KEYVAULT_TEMPLATE_STRINGS = {
ResourceType.MGMT_KEYVAULT:
'azure.mgmt.keyvault{api_version}.{module_name}#{class_name}{obj_name}',
ResourceType.DATA_KEYVAULT:
'azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_t1{api_version}.'
'key_vault_client#{class_name}{obj_name}',
ResourceType.DATA_KEYVAULT_ADMINISTRATION_BACKUP:
'azure.keyvault.administration._backup_client#KeyVaultBackupClient{obj_name}',
ResourceType.DATA_KEYVAULT_ADMINISTRATION_ACCESS_CONTROL:
Expand All @@ -54,6 +52,9 @@ class Clients(str, Enum):
'azure.keyvault.keys._client#KeyClient{obj_name}',
ResourceType.DATA_KEYVAULT_SECRETS:
'azure.keyvault.secrets._client#SecretClient{obj_name}',
ResourceType.DATA_KEYVAULT_SECURITY_DOMAIN:
'azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_securitydomain.'
'_patch#SecurityDomainClient{obj_name}',
}


Expand All @@ -67,6 +68,7 @@ def get_operations_tmpl(resource_type, client_name):
ResourceType.DATA_KEYVAULT_CERTIFICATES,
ResourceType.DATA_KEYVAULT_KEYS,
ResourceType.DATA_KEYVAULT_SECRETS,
ResourceType.DATA_KEYVAULT_SECURITY_DOMAIN,
ResourceType.DATA_KEYVAULT_ADMINISTRATION_SETTING]:
return KEYVAULT_TEMPLATE_STRINGS[resource_type].format(obj_name='.{}')

Expand All @@ -84,6 +86,7 @@ def get_docs_tmpl(cli_ctx, resource_type, client_name, module_name='operations')
ResourceType.DATA_KEYVAULT_CERTIFICATES,
ResourceType.DATA_KEYVAULT_KEYS,
ResourceType.DATA_KEYVAULT_SECRETS,
ResourceType.DATA_KEYVAULT_SECURITY_DOMAIN,
ResourceType.DATA_KEYVAULT_ADMINISTRATION_SETTING]:
return KEYVAULT_TEMPLATE_STRINGS[resource_type].format(obj_name='.{}')

Expand All @@ -108,8 +111,6 @@ def get_docs_tmpl(cli_ctx, resource_type, client_name, module_name='operations')
def get_client_factory(resource_type, client_name=''):
if is_mgmt_plane(resource_type):
return keyvault_mgmt_client_factory(resource_type, client_name)
if resource_type == ResourceType.DATA_KEYVAULT:
return keyvault_private_data_plane_factory_v7_2_preview
if resource_type == ResourceType.DATA_KEYVAULT_ADMINISTRATION_BACKUP:
return data_plane_azure_keyvault_administration_backup_client
if resource_type == ResourceType.DATA_KEYVAULT_ADMINISTRATION_ACCESS_CONTROL:
Expand All @@ -122,6 +123,8 @@ def get_client_factory(resource_type, client_name=''):
return data_plane_azure_keyvault_key_client
if resource_type == ResourceType.DATA_KEYVAULT_SECRETS:
return data_plane_azure_keyvault_secret_client
if resource_type == ResourceType.DATA_KEYVAULT_SECURITY_DOMAIN:
return data_plane_azure_keyvault_security_domain_client
raise CLIError('Unsupported resource type: {}'.format(resource_type))


Expand Down Expand Up @@ -165,29 +168,6 @@ def _keyvault_mgmt_client_factory(cli_ctx, _):
return _keyvault_mgmt_client_factory


def keyvault_private_data_plane_factory_v7_2_preview(cli_ctx, _):
from azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_t1 import (
KeyVaultAuthentication, KeyVaultClient)
from azure.cli.core.util import should_disable_connection_verify

def get_token(server, resource, scope): # pylint: disable=unused-argument
return Profile(cli_ctx=cli_ctx).get_raw_token(resource=resource,
subscription=cli_ctx.data.get('subscription_id'))[0]

client = KeyVaultClient(KeyVaultAuthentication(get_token), api_version='7.2')

# HACK, work around the fact that KeyVault library does't take confiuration object on constructor
# which could be used to turn off the verifiaction. Remove this once we migrate to new data plane library
# pylint: disable=protected-access
if hasattr(client, '_client') and hasattr(client._client, 'config'):
verify = not should_disable_connection_verify()
client._client.config.connection.verify = verify
else:
logger.info('Could not find the configuration object to turn off the verification if needed')

return client


def data_plane_azure_keyvault_administration_backup_client(cli_ctx, command_args):
from azure.keyvault.administration import KeyVaultBackupClient

Expand All @@ -202,8 +182,10 @@ def data_plane_azure_keyvault_administration_access_control_client(cli_ctx, comm

vault_url, credential, version = _prepare_data_plane_azure_keyvault_client(
cli_ctx, command_args, ResourceType.DATA_KEYVAULT_ADMINISTRATION_ACCESS_CONTROL)
client_kwargs = prepare_client_kwargs_track2(cli_ctx)
client_kwargs.pop('http_logging_policy')
return KeyVaultAccessControlClient(
vault_url=vault_url, credential=credential, api_version=version, verify_challenge_resource=False)
vault_url=vault_url, credential=credential, api_version=version, **client_kwargs)


def data_plane_azure_keyvault_administration_setting_client(cli_ctx, command_args):
Expand All @@ -214,8 +196,10 @@ def data_plane_azure_keyvault_administration_setting_client(cli_ctx, command_arg
command_args.pop('hsm_name', None)
command_args.pop('vault_base_url', None)
command_args.pop('identifier', None)
client_kwargs = prepare_client_kwargs_track2(cli_ctx)
client_kwargs.pop('http_logging_policy')
return KeyVaultSettingsClient(
vault_url=vault_url, credential=credential, api_version='7.4', verify_challenge_resource=False)
vault_url=vault_url, credential=credential, api_version='7.4', **client_kwargs)


def data_plane_azure_keyvault_certificate_client(cli_ctx, command_args):
Expand All @@ -227,8 +211,10 @@ def data_plane_azure_keyvault_certificate_client(cli_ctx, command_args):
command_args.pop('vault_base_url', None)
command_args.pop('identifier', None)
api_version = '7.4' if not is_azure_stack_profile(cmd=None, cli_ctx=cli_ctx) else '2016-10-01'
client_kwargs = prepare_client_kwargs_track2(cli_ctx)
client_kwargs.pop('http_logging_policy')
return CertificateClient(
vault_url=vault_url, credential=credential, api_version=api_version or version, verify_challenge_resource=False)
vault_url=vault_url, credential=credential, api_version=api_version or version, **client_kwargs)


def data_plane_azure_keyvault_key_client(cli_ctx, command_args):
Expand All @@ -240,8 +226,10 @@ def data_plane_azure_keyvault_key_client(cli_ctx, command_args):
command_args.pop('vault_base_url', None)
command_args.pop('identifier', None)
api_version = '7.5-preview.1' if not is_azure_stack_profile(cmd=None, cli_ctx=cli_ctx) else '2016-10-01'
client_kwargs = prepare_client_kwargs_track2(cli_ctx)
client_kwargs.pop('http_logging_policy')
return KeyClient(
vault_url=vault_url, credential=credential, api_version=api_version or version, verify_challenge_resource=False)
vault_url=vault_url, credential=credential, api_version=api_version or version, **client_kwargs)


def data_plane_azure_keyvault_secret_client(cli_ctx, command_args):
Expand All @@ -253,8 +241,22 @@ def data_plane_azure_keyvault_secret_client(cli_ctx, command_args):
command_args.pop('vault_base_url', None)
command_args.pop('identifier', None)
api_version = '7.4' if not is_azure_stack_profile(cmd=None, cli_ctx=cli_ctx) else '2016-10-01'
client_kwargs = prepare_client_kwargs_track2(cli_ctx)
client_kwargs.pop('http_logging_policy')
return SecretClient(
vault_url=vault_url, credential=credential, api_version=api_version or version, verify_challenge_resource=False)
vault_url=vault_url, credential=credential, api_version=api_version or version, **client_kwargs)


def data_plane_azure_keyvault_security_domain_client(cli_ctx, command_args):
from azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_securitydomain import SecurityDomainClient
vault_url, credential, _ = _prepare_data_plane_azure_keyvault_client(
cli_ctx, command_args, ResourceType.DATA_KEYVAULT_SECURITY_DOMAIN)
command_args.pop('hsm_name', None)
command_args.pop('vault_base_url', None)
command_args.pop('identifier', None)
client_kwargs = prepare_client_kwargs_track2(cli_ctx)
client_kwargs.pop('http_logging_policy')
return SecurityDomainClient(vault_url=vault_url, credential=credential, **client_kwargs)


def _prepare_data_plane_azure_keyvault_client(cli_ctx, command_args, resource_type):
Expand Down
12 changes: 3 additions & 9 deletions src/azure-cli/azure/cli/command_modules/keyvault/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,10 +564,10 @@ class CLISecurityDomainOperation(str, Enum):
# endregion

# region keyvault security-domain
for scope in ['init-recovery', 'download', 'upload']:
for scope in ['init-recovery', 'download', 'upload', 'wait']:
with self.argument_context('keyvault security-domain {}'.format(scope), arg_group='HSM Id') as c:
c.argument('hsm_name', hsm_url_type, required=False,
help='Name of the HSM. Can be omitted if --id is specified.')
c.extra('hsm_name', hsm_url_type, required=False,
help='Name of the HSM. Can be omitted if --id is specified.')
c.extra('identifier', options_list=['--id'], validator=validate_vault_or_hsm, help='Full URI of the HSM.')
c.ignore('vault_base_url')

Expand Down Expand Up @@ -605,14 +605,8 @@ class CLISecurityDomainOperation(str, Enum):
'for recovery.')

with self.argument_context('keyvault security-domain wait') as c:
c.argument('hsm_name', hsm_url_type, help='Name of the HSM. Can be omitted if --id is specified.',
required=False)
c.argument('identifier', options_list=['--id'], validator=validate_vault_or_hsm, help='Full URI of the HSM.')
c.argument('resource_group_name', options_list=['--resource-group', '-g'],
help='Proceed only if HSM belongs to the specified resource group.')
c.argument('target_operation', arg_type=get_enum_type(CLISecurityDomainOperation),
help='Target operation that needs waiting.')
c.ignore('vault_base_url')
# endregion

# region keyvault backup/restore
Expand Down
10 changes: 10 additions & 0 deletions src/azure-cli/azure/cli/command_modules/keyvault/_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,3 +474,13 @@ def transform_certificate_issuer_admin_list(result, **command_args):
} for contact in admin_contacts]
return ret
return result


def transform_security_domain_output(result, **command_args):
if not result or isinstance(result, dict):
return result
ret = {
'status': getattr(result, 'status', None),
'statusDetails': getattr(result, 'status_details', None)
}
return ret
16 changes: 9 additions & 7 deletions src/azure-cli/azure/cli/command_modules/keyvault/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
get_client, get_client_factory, Clients, is_azure_stack_profile)

from azure.cli.command_modules.keyvault._transformers import (
filter_out_managed_resources,
filter_out_managed_resources, transform_security_domain_output,
multi_transformers, transform_key_decryption_output, keep_max_results, transform_key_list_output,
transform_key_output, transform_key_encryption_output, transform_key_random_output,
transform_secret_list, transform_deleted_secret_list, transform_secret_set,
Expand Down Expand Up @@ -53,12 +53,12 @@ def load_command_table(self, _):
if not is_azure_stack_profile(self):
mgmt_hsms_entity = get_client(self.cli_ctx, ResourceType.MGMT_KEYVAULT, Clients.managed_hsms)
mgmt_hsms_regions_entity = get_client(self.cli_ctx, ResourceType.MGMT_KEYVAULT, Clients.mhsm_regions)
private_data_entity = get_client(self.cli_ctx, ResourceType.DATA_KEYVAULT, Clients.private_7_2)
data_security_domain_entity = get_client(self.cli_ctx, ResourceType.DATA_KEYVAULT_SECURITY_DOMAIN)
data_backup_entity = get_client(self.cli_ctx, ResourceType.DATA_KEYVAULT_ADMINISTRATION_BACKUP)
data_access_control_entity = get_client(self.cli_ctx, ResourceType.DATA_KEYVAULT_ADMINISTRATION_ACCESS_CONTROL)
data_setting_entity = get_client(self.cli_ctx, ResourceType.DATA_KEYVAULT_ADMINISTRATION_SETTING)
else:
mgmt_hsms_entity = mgmt_hsms_regions_entity = private_data_entity = data_backup_entity = \
mgmt_hsms_entity = mgmt_hsms_regions_entity = data_security_domain_entity = data_backup_entity = \
data_access_control_entity = data_setting_entity = None

kv_vaults_custom = CliCommandType(
Expand Down Expand Up @@ -142,12 +142,14 @@ def load_command_table(self, _):
with self.command_group('keyvault restore', data_backup_entity.command_type) as g:
g.keyvault_custom('start', 'full_restore')

with self.command_group('keyvault security-domain', private_data_entity.command_type) as g:
with self.command_group('keyvault security-domain', data_security_domain_entity.command_type) as g:
g.keyvault_custom('init-recovery', 'security_domain_init_recovery')
g.keyvault_custom('restore-blob', 'security_domain_restore_blob')
g.keyvault_custom('upload', 'security_domain_upload', supports_no_wait=True)
g.keyvault_custom('download', 'security_domain_download', supports_no_wait=True)
g.keyvault_custom('wait', '_wait_security_domain_operation')
g.keyvault_custom('upload', 'security_domain_upload', supports_no_wait=True,
transform=transform_security_domain_output)
g.keyvault_custom('download', 'security_domain_download', supports_no_wait=True,
transform=transform_security_domain_output)
g.keyvault_custom('wait', '_wait_security_domain_operation', transform=transform_security_domain_output)

with self.command_group('keyvault key', data_key_entity.command_type) as g:
g.keyvault_custom('create', 'create_key', transform=transform_key_output, validator=validate_key_create)
Expand Down
Loading

0 comments on commit 7506f6a

Please sign in to comment.