def encrypt_vmss( cmd, resource_group_name, vmss_name, # pylint: disable=too-many-locals, too-many-statements disk_encryption_keyvault, key_encryption_keyvault=None, key_encryption_key=None, key_encryption_algorithm='RSA-OAEP', volume_type=None, force=False): from msrestazure.tools import parse_resource_id # pylint: disable=no-member UpgradeMode, VirtualMachineScaleSetExtension, VirtualMachineScaleSetExtensionProfile = cmd.get_models( 'UpgradeMode', 'VirtualMachineScaleSetExtension', 'VirtualMachineScaleSetExtensionProfile') compute_client = _compute_client_factory(cmd.cli_ctx) vmss = compute_client.virtual_machine_scale_sets.get( resource_group_name, vmss_name) is_linux = _is_linux_os(vmss.virtual_machine_profile) extension = vm_extension_info['Linux' if is_linux else 'Windows'] # 1. First validate arguments volume_type = _handles_default_volume_type_for_vmss_encryption( is_linux, volume_type, force) # encryption is not supported on all linux distros, but service never tells you # so let us verify at the client side if is_linux: image_reference = getattr(vmss.virtual_machine_profile.storage_profile, 'image_reference', None) if image_reference: result, message = _check_encrypt_is_supported( image_reference, volume_type) if not result: logger.warning(message) # retrieve keyvault details disk_encryption_keyvault_url = get_key_vault_base_url( cmd.cli_ctx, (parse_resource_id(disk_encryption_keyvault))['name']) # disk encryption key itself can be further protected, so let us verify if key_encryption_key: key_encryption_keyvault = key_encryption_keyvault or disk_encryption_keyvault if '://' not in key_encryption_key: # appears a key name key_encryption_key = _get_keyvault_key_url( cmd.cli_ctx, (parse_resource_id(key_encryption_keyvault))['name'], key_encryption_key) # to avoid bad server errors, ensure the vault has the right configurations _verify_keyvault_good_for_encryption(cmd.cli_ctx, disk_encryption_keyvault, key_encryption_keyvault, vmss, force) # 2. we are ready to provision/update the disk encryption extensions public_config = { 'KeyVaultURL': disk_encryption_keyvault_url, 'KeyEncryptionKeyURL': key_encryption_key or '', "KeyVaultResourceId": disk_encryption_keyvault, "KekVaultResourceId": key_encryption_keyvault if key_encryption_key else '', 'KeyEncryptionAlgorithm': key_encryption_algorithm if key_encryption_key else '', 'VolumeType': volume_type, 'EncryptionOperation': 'EnableEncryption' } ext = VirtualMachineScaleSetExtension( name=extension['name'], publisher=extension['publisher'], type=extension['name'], type_handler_version=extension['version'], settings=public_config, auto_upgrade_minor_version=True, force_update_tag=uuid.uuid4()) if not vmss.virtual_machine_profile.extension_profile: vmss.virtual_machine_profile.extension_profile = VirtualMachineScaleSetExtensionProfile( extensions=[]) vmss.virtual_machine_profile.extension_profile.extensions.append(ext) poller = compute_client.virtual_machine_scale_sets.create_or_update( resource_group_name, vmss_name, vmss) LongRunningOperation(cmd.cli_ctx)(poller) _show_post_action_message(resource_group_name, vmss.name, vmss.upgrade_policy.mode == UpgradeMode.manual, True)
def encrypt_vm( cmd, resource_group_name, vm_name, # pylint: disable=too-many-locals, too-many-statements disk_encryption_keyvault, aad_client_id=None, aad_client_secret=None, aad_client_cert_thumbprint=None, key_encryption_keyvault=None, key_encryption_key=None, key_encryption_algorithm='RSA-OAEP', volume_type=None, encrypt_format_all=False): from msrestazure.tools import parse_resource_id from knack.util import CLIError # pylint: disable=no-member compute_client = _compute_client_factory(cmd.cli_ctx) vm = compute_client.virtual_machines.get(resource_group_name, vm_name) is_linux = _is_linux_os(vm) backup_encryption_settings = vm.storage_profile.os_disk.encryption_settings vm_encrypted = backup_encryption_settings.enabled if backup_encryption_settings else False _, has_old_ade = _detect_ade_status(vm) use_new_ade = not aad_client_id and not has_old_ade extension = vm_extension_info['Linux' if is_linux else 'Windows'] if not use_new_ade and not aad_client_id: raise CLIError('Please provide --aad-client-id') # 1. First validate arguments if not use_new_ade and not aad_client_cert_thumbprint and not aad_client_secret: raise CLIError( 'Please provide either --aad-client-cert-thumbprint or --aad-client-secret' ) if volume_type is None: if not is_linux: volume_type = _ALL_VOLUME_TYPE elif vm.storage_profile.data_disks: raise CLIError('VM has data disks, please supply --volume-type') else: volume_type = 'OS' # encryption is not supported on all linux distros, but service never tells you # so let us verify at the client side if is_linux: image_reference = getattr(vm.storage_profile, 'image_reference', None) if image_reference: result, message = _check_encrypt_is_supported( image_reference, volume_type) if not result: logger.warning(message) # sequence_version should be unique sequence_version = uuid.uuid4() # retrieve keyvault details disk_encryption_keyvault_url = get_key_vault_base_url( cmd.cli_ctx, (parse_resource_id(disk_encryption_keyvault))['name']) # disk encryption key itself can be further protected, so let us verify if key_encryption_key: key_encryption_keyvault = key_encryption_keyvault or disk_encryption_keyvault if '://' not in key_encryption_key: # appears a key name key_encryption_key = _get_keyvault_key_url( cmd.cli_ctx, (parse_resource_id(key_encryption_keyvault))['name'], key_encryption_key) # 2. we are ready to provision/update the disk encryption extensions # The following logic was mostly ported from xplat-cli public_config = { 'KeyVaultURL': disk_encryption_keyvault_url, 'VolumeType': volume_type, 'EncryptionOperation': 'EnableEncryption' if not encrypt_format_all else 'EnableEncryptionFormatAll', 'KeyEncryptionKeyURL': key_encryption_key, 'KeyEncryptionAlgorithm': key_encryption_algorithm, 'SequenceVersion': sequence_version, } if use_new_ade: public_config.update({ "KeyVaultResourceId": disk_encryption_keyvault, "KekVaultResourceId": key_encryption_keyvault if key_encryption_key else '', }) else: public_config.update({ 'AADClientID': aad_client_id, 'AADClientCertThumbprint': aad_client_cert_thumbprint, }) ade_legacy_private_config = { 'AADClientSecret': aad_client_secret if is_linux else (aad_client_secret or '') } VirtualMachineExtension, DiskEncryptionSettings, KeyVaultSecretReference, KeyVaultKeyReference, SubResource = \ cmd.get_models('VirtualMachineExtension', 'DiskEncryptionSettings', 'KeyVaultSecretReference', 'KeyVaultKeyReference', 'SubResource') ext = VirtualMachineExtension( location=vm.location, # pylint: disable=no-member publisher=extension['publisher'], virtual_machine_extension_type=extension['name'], protected_settings=None if use_new_ade else ade_legacy_private_config, type_handler_version=extension['version'] if use_new_ade else extension['legacy_version'], settings=public_config, auto_upgrade_minor_version=True) poller = compute_client.virtual_machine_extensions.create_or_update( resource_group_name, vm_name, extension['name'], ext) poller.result() # verify the extension was ok extension_result = compute_client.virtual_machine_extensions.get( resource_group_name, vm_name, extension['name'], 'instanceView') if extension_result.provisioning_state != 'Succeeded': raise CLIError( 'Extension needed for disk encryption was not provisioned correctly' ) if not use_new_ade: if not (extension_result.instance_view.statuses and extension_result.instance_view.statuses[0].message): raise CLIError( 'Could not find url pointing to the secret for disk encryption' ) # 3. update VM's storage profile with the secrets status_url = extension_result.instance_view.statuses[0].message vm = compute_client.virtual_machines.get(resource_group_name, vm_name) secret_ref = KeyVaultSecretReference( secret_url=status_url, source_vault=SubResource(id=disk_encryption_keyvault)) key_encryption_key_obj = None if key_encryption_key: key_encryption_key_obj = KeyVaultKeyReference( key_url=key_encryption_key, source_vault=SubResource(id=key_encryption_keyvault)) disk_encryption_settings = DiskEncryptionSettings( disk_encryption_key=secret_ref, key_encryption_key=key_encryption_key_obj, enabled=True) if vm_encrypted: # stop the vm before update if the vm is already encrypted logger.warning( "Deallocating the VM before updating encryption settings...") compute_client.virtual_machines.deallocate(resource_group_name, vm_name).result() vm = compute_client.virtual_machines.get(resource_group_name, vm_name) vm.storage_profile.os_disk.encryption_settings = disk_encryption_settings set_vm(cmd, vm) if vm_encrypted: # and start after the update logger.warning("Restarting the VM after the update...") compute_client.virtual_machines.start(resource_group_name, vm_name).result() if is_linux and volume_type != _DATA_VOLUME_TYPE: old_ade_msg = "If you see 'VMRestartPending', please restart the VM, and the encryption will finish shortly" logger.warning( "The encryption request was accepted. Please use 'show' command to monitor " "the progress. %s", "" if use_new_ade else old_ade_msg)
def _get_keyvault_key_url(cli_ctx, keyvault_name, key_name): client = create_keyvault_data_plane_client(cli_ctx) result = client.get_key(get_key_vault_base_url(cli_ctx, keyvault_name), key_name, '') return result.key.kid # pylint: disable=no-member
def encrypt_vmss(cmd, resource_group_name, vmss_name, # pylint: disable=too-many-locals, too-many-statements disk_encryption_keyvault, key_encryption_keyvault=None, key_encryption_key=None, key_encryption_algorithm='RSA-OAEP', volume_type=None, force=False): from msrestazure.tools import parse_resource_id # pylint: disable=no-member UpgradeMode, VirtualMachineScaleSetExtension, VirtualMachineScaleSetExtensionProfile = cmd.get_models( 'UpgradeMode', 'VirtualMachineScaleSetExtension', 'VirtualMachineScaleSetExtensionProfile') compute_client = _compute_client_factory(cmd.cli_ctx) vmss = compute_client.virtual_machine_scale_sets.get(resource_group_name, vmss_name) is_linux = _is_linux_os(vmss.virtual_machine_profile) extension = vm_extension_info['Linux' if is_linux else 'Windows'] # 1. First validate arguments volume_type = _handles_default_volume_type_for_vmss_encryption(is_linux, volume_type, force) # retrieve keyvault details disk_encryption_keyvault_url = get_key_vault_base_url(cmd.cli_ctx, (parse_resource_id(disk_encryption_keyvault))['name']) # disk encryption key itself can be further protected, so let us verify if key_encryption_key: key_encryption_keyvault = key_encryption_keyvault or disk_encryption_keyvault # to avoid bad server errors, ensure the vault has the right configurations _verify_keyvault_good_for_encryption(cmd.cli_ctx, disk_encryption_keyvault, key_encryption_keyvault, vmss, force) # if key name and not key url, get url. if key_encryption_key and '://' not in key_encryption_key: key_encryption_key = _get_keyvault_key_url( cmd.cli_ctx, (parse_resource_id(key_encryption_keyvault))['name'], key_encryption_key) # 2. we are ready to provision/update the disk encryption extensions public_config = { 'KeyVaultURL': disk_encryption_keyvault_url, 'KeyEncryptionKeyURL': key_encryption_key or '', "KeyVaultResourceId": disk_encryption_keyvault, "KekVaultResourceId": key_encryption_keyvault if key_encryption_key else '', 'KeyEncryptionAlgorithm': key_encryption_algorithm if key_encryption_key else '', 'VolumeType': volume_type, 'EncryptionOperation': 'EnableEncryption' } ext = VirtualMachineScaleSetExtension(name=extension['name'], publisher=extension['publisher'], type=extension['name'], type_handler_version=extension['version'], settings=public_config, auto_upgrade_minor_version=True, force_update_tag=uuid.uuid4()) exts = [ext] # remove any old ade extensions set by this command and add the new one. vmss_ext_profile = vmss.virtual_machine_profile.extension_profile if vmss_ext_profile and vmss_ext_profile.extensions: exts.extend(old_ext for old_ext in vmss.virtual_machine_profile.extension_profile.extensions if old_ext.type != ext.type or old_ext.name != ext.name) vmss.virtual_machine_profile.extension_profile = VirtualMachineScaleSetExtensionProfile(extensions=exts) poller = compute_client.virtual_machine_scale_sets.create_or_update(resource_group_name, vmss_name, vmss) LongRunningOperation(cmd.cli_ctx)(poller) _show_post_action_message(resource_group_name, vmss.name, vmss.upgrade_policy.mode == UpgradeMode.manual, True)
def encrypt_vm(cmd, resource_group_name, vm_name, # pylint: disable=too-many-locals, too-many-statements disk_encryption_keyvault, aad_client_id=None, aad_client_secret=None, aad_client_cert_thumbprint=None, key_encryption_keyvault=None, key_encryption_key=None, key_encryption_algorithm='RSA-OAEP', volume_type=None, encrypt_format_all=False): from msrestazure.tools import parse_resource_id from knack.util import CLIError # pylint: disable=no-member compute_client = _compute_client_factory(cmd.cli_ctx) vm = compute_client.virtual_machines.get(resource_group_name, vm_name) is_linux = _is_linux_os(vm) backup_encryption_settings = vm.storage_profile.os_disk.encryption_settings vm_encrypted = backup_encryption_settings.enabled if backup_encryption_settings else False _, has_old_ade = _detect_ade_status(vm) use_new_ade = not aad_client_id and not has_old_ade extension = vm_extension_info['Linux' if is_linux else 'Windows'] if not use_new_ade and not aad_client_id: raise CLIError('Please provide --aad-client-id') # 1. First validate arguments if not use_new_ade and not aad_client_cert_thumbprint and not aad_client_secret: raise CLIError('Please provide either --aad-client-cert-thumbprint or --aad-client-secret') if volume_type is None: if not is_linux: volume_type = _ALL_VOLUME_TYPE elif vm.storage_profile.data_disks: raise CLIError('VM has data disks, please supply --volume-type') else: volume_type = 'OS' # encryption is not supported on all linux distros, but service never tells you # so let us verify at the client side if is_linux: image_reference = getattr(vm.storage_profile, 'image_reference', None) if image_reference: result, message = _check_encrypt_is_supported(image_reference, volume_type) if not result: logger.warning(message) # sequence_version should be unique sequence_version = uuid.uuid4() # retrieve keyvault details disk_encryption_keyvault_url = get_key_vault_base_url( cmd.cli_ctx, (parse_resource_id(disk_encryption_keyvault))['name']) # disk encryption key itself can be further protected, so let us verify if key_encryption_key: key_encryption_keyvault = key_encryption_keyvault or disk_encryption_keyvault if '://' not in key_encryption_key: # appears a key name key_encryption_key = _get_keyvault_key_url( cmd.cli_ctx, (parse_resource_id(key_encryption_keyvault))['name'], key_encryption_key) # 2. we are ready to provision/update the disk encryption extensions # The following logic was mostly ported from xplat-cli public_config = { 'KeyVaultURL': disk_encryption_keyvault_url, 'VolumeType': volume_type, 'EncryptionOperation': 'EnableEncryption' if not encrypt_format_all else 'EnableEncryptionFormatAll', 'KeyEncryptionKeyURL': key_encryption_key, 'KeyEncryptionAlgorithm': key_encryption_algorithm, 'SequenceVersion': sequence_version, } if use_new_ade: public_config.update({ "KeyVaultResourceId": disk_encryption_keyvault, "KekVaultResourceId": key_encryption_keyvault if key_encryption_key else '', }) else: public_config.update({ 'AADClientID': aad_client_id, 'AADClientCertThumbprint': aad_client_cert_thumbprint, }) ade_legacy_private_config = { 'AADClientSecret': aad_client_secret if is_linux else (aad_client_secret or '') } VirtualMachineExtension, DiskEncryptionSettings, KeyVaultSecretReference, KeyVaultKeyReference, SubResource = \ cmd.get_models('VirtualMachineExtension', 'DiskEncryptionSettings', 'KeyVaultSecretReference', 'KeyVaultKeyReference', 'SubResource') ext = VirtualMachineExtension( location=vm.location, # pylint: disable=no-member publisher=extension['publisher'], virtual_machine_extension_type=extension['name'], protected_settings=None if use_new_ade else ade_legacy_private_config, type_handler_version=extension['version'] if use_new_ade else extension['legacy_version'], settings=public_config, auto_upgrade_minor_version=True) poller = compute_client.virtual_machine_extensions.create_or_update( resource_group_name, vm_name, extension['name'], ext) poller.result() # verify the extension was ok extension_result = compute_client.virtual_machine_extensions.get( resource_group_name, vm_name, extension['name'], 'instanceView') if extension_result.provisioning_state != 'Succeeded': raise CLIError('Extension needed for disk encryption was not provisioned correctly') if not use_new_ade: if not (extension_result.instance_view.statuses and extension_result.instance_view.statuses[0].message): raise CLIError('Could not find url pointing to the secret for disk encryption') # 3. update VM's storage profile with the secrets status_url = extension_result.instance_view.statuses[0].message vm = compute_client.virtual_machines.get(resource_group_name, vm_name) secret_ref = KeyVaultSecretReference(secret_url=status_url, source_vault=SubResource(id=disk_encryption_keyvault)) key_encryption_key_obj = None if key_encryption_key: key_encryption_key_obj = KeyVaultKeyReference(key_url=key_encryption_key, source_vault=SubResource(id=key_encryption_keyvault)) disk_encryption_settings = DiskEncryptionSettings(disk_encryption_key=secret_ref, key_encryption_key=key_encryption_key_obj, enabled=True) if vm_encrypted: # stop the vm before update if the vm is already encrypted logger.warning("Deallocating the VM before updating encryption settings...") compute_client.virtual_machines.deallocate(resource_group_name, vm_name).result() vm = compute_client.virtual_machines.get(resource_group_name, vm_name) vm.storage_profile.os_disk.encryption_settings = disk_encryption_settings set_vm(cmd, vm) if vm_encrypted: # and start after the update logger.warning("Restarting the VM after the update...") compute_client.virtual_machines.start(resource_group_name, vm_name).result() if is_linux and volume_type != _DATA_VOLUME_TYPE: old_ade_msg = "If you see 'VMRestartPending', please restart the VM, and the encryption will finish shortly" logger.warning("The encryption request was accepted. Please use 'show' command to monitor " "the progress. %s", "" if use_new_ade else old_ade_msg)
def encrypt_vmss(cmd, resource_group_name, vmss_name, # pylint: disable=too-many-locals, too-many-statements disk_encryption_keyvault, key_encryption_keyvault=None, key_encryption_key=None, key_encryption_algorithm='RSA-OAEP', volume_type=None, force=False): from msrestazure.tools import parse_resource_id # pylint: disable=no-member UpgradeMode, VirtualMachineScaleSetExtension, VirtualMachineScaleSetExtensionProfile = cmd.get_models( 'UpgradeMode', 'VirtualMachineScaleSetExtension', 'VirtualMachineScaleSetExtensionProfile') compute_client = _compute_client_factory(cmd.cli_ctx) vmss = compute_client.virtual_machine_scale_sets.get(resource_group_name, vmss_name) is_linux = _is_linux_os(vmss.virtual_machine_profile) extension = vm_extension_info['Linux' if is_linux else 'Windows'] # 1. First validate arguments volume_type = _handles_default_volume_type_for_vmss_encryption(is_linux, volume_type, force) # encryption is not supported on all linux distros, but service never tells you # so let us verify at the client side if is_linux: image_reference = getattr(vmss.virtual_machine_profile.storage_profile, 'image_reference', None) if image_reference: result, message = _check_encrypt_is_supported(image_reference, volume_type) if not result: logger.warning(message) # retrieve keyvault details disk_encryption_keyvault_url = get_key_vault_base_url(cmd.cli_ctx, (parse_resource_id(disk_encryption_keyvault))['name']) # disk encryption key itself can be further protected, so let us verify if key_encryption_key: key_encryption_keyvault = key_encryption_keyvault or disk_encryption_keyvault if '://' not in key_encryption_key: # appears a key name key_encryption_key = _get_keyvault_key_url( cmd.cli_ctx, (parse_resource_id(key_encryption_keyvault))['name'], key_encryption_key) # to avoid bad server errors, ensure the vault has the right configurations _verify_keyvault_good_for_encryption(cmd.cli_ctx, disk_encryption_keyvault, key_encryption_keyvault, vmss, force) # 2. we are ready to provision/update the disk encryption extensions public_config = { 'KeyVaultURL': disk_encryption_keyvault_url, 'KeyEncryptionKeyURL': key_encryption_key or '', "KeyVaultResourceId": disk_encryption_keyvault, "KekVaultResourceId": key_encryption_keyvault if key_encryption_key else '', 'KeyEncryptionAlgorithm': key_encryption_algorithm if key_encryption_key else '', 'VolumeType': volume_type, 'EncryptionOperation': 'EnableEncryption' } ext = VirtualMachineScaleSetExtension(name=extension['name'], publisher=extension['publisher'], type=extension['name'], type_handler_version=extension['version'], settings=public_config, auto_upgrade_minor_version=True, force_update_tag=uuid.uuid4()) if not vmss.virtual_machine_profile.extension_profile: vmss.virtual_machine_profile.extension_profile = VirtualMachineScaleSetExtensionProfile(extensions=[]) vmss.virtual_machine_profile.extension_profile.extensions.append(ext) poller = compute_client.virtual_machine_scale_sets.create_or_update(resource_group_name, vmss_name, vmss) LongRunningOperation(cmd.cli_ctx)(poller) _show_post_action_message(resource_group_name, vmss.name, vmss.upgrade_policy.mode == UpgradeMode.manual, True)
def _get_keyvault_key_url(cli_ctx, keyvault_name, key_name): client = create_keyvault_data_plane_client(cli_ctx) result = client.get_key(get_key_vault_base_url(cli_ctx, keyvault_name), key_name, '') return result.key.kid # pylint: disable=no-member