diff --git a/src/azure-cli/azure/cli/command_modules/vm/_params.py b/src/azure-cli/azure/cli/command_modules/vm/_params.py index af85483e075..ffc67bd161c 100644 --- a/src/azure-cli/azure/cli/command_modules/vm/_params.py +++ b/src/azure-cli/azure/cli/command_modules/vm/_params.py @@ -318,6 +318,10 @@ def load_arguments(self, _): help="enable/disable disk write accelerator. Use singular value 'true/false' to apply across, or specify individual disks, e.g.'os=true 1=true 2=true' for os disk and data disks with lun of 1 & 2") c.argument('disk_caching', nargs='*', help="Use singular value to apply across, or specify individual disks, e.g. 'os=ReadWrite 0=None 1=ReadOnly' should enable update os disk and 2 data disks") c.argument('ultra_ssd_enabled', ultra_ssd_enabled_type) + c.argument('enable_secure_boot', arg_type=get_three_state_flag(), min_api='2020-12-01', + help='Enable secure boot.') + c.argument('enable_vtpm', arg_type=get_three_state_flag(), min_api='2020-12-01', + help='Enable vTPM.') with self.argument_context('vm create') as c: c.argument('name', name_arg_type, validator=_resource_not_exists(self.cli_ctx, 'Microsoft.Compute/virtualMachines')) @@ -349,6 +353,12 @@ def load_arguments(self, _): help='Specify the scale set logical fault domain into which the virtual machine will be created. By default, the virtual machine will be automatically assigned to a fault domain that best maintains balance across available fault domains. This is applicable only if the virtualMachineScaleSet property of this virtual machine is set. The virtual machine scale set that is referenced, must have platform fault domain count. This property cannot be updated once the virtual machine is created. Fault domain assignment can be viewed in the virtual machine instance view') c.argument('count', type=int, is_preview=True, help='Number of virtual machines to create. Value range is [2, 250], inclusive. Don\'t specify this parameter if you want to create a normal single VM. The VMs are created in parallel. The output of this command is an array of VMs instead of one single VM. Each VM has its own public IP, NIC. VNET and NSG are shared. It is recommended that no existing public IP, NIC, VNET and NSG are in resource group. When --count is specified, --attach-data-disks, --attach-os-disk, --boot-diagnostics-storage, --computer-name, --host, --host-group, --nics, --os-disk-name, --private-ip-address, --public-ip-address, --public-ip-address-dns-name, --storage-account, --storage-container-name, --subnet, --use-unmanaged-disk, --vnet-name are not allowed.') + c.argument('security_type', arg_type=get_enum_type(['TrustedLaunch']), min_api='2020-12-01', + help='Specify if the VM is Trusted Launch enabled. See https://docs.microsoft.com/azure/virtual-machines/trusted-launch.') + c.argument('enable_secure_boot', arg_type=get_three_state_flag(), min_api='2020-12-01', + help='Enable secure boot. It is part of trusted launch.') + c.argument('enable_vtpm', arg_type=get_three_state_flag(), min_api='2020-12-01', + help='Enable vTPM. It is part of trusted launch.') with self.argument_context('vm create', arg_group='Storage') as c: c.argument('attach_os_disk', help='Attach an existing OS disk to the VM. Can use the name or ID of a managed disk or the URI to an unmanaged disk VHD.') diff --git a/src/azure-cli/azure/cli/command_modules/vm/_template_builder.py b/src/azure-cli/azure/cli/command_modules/vm/_template_builder.py index 356f3f7331d..1b39cf0ccbb 100644 --- a/src/azure-cli/azure/cli/command_modules/vm/_template_builder.py +++ b/src/azure-cli/azure/cli/command_modules/vm/_template_builder.py @@ -278,7 +278,8 @@ def build_vm_resource( # pylint: disable=too-many-locals, too-many-statements computer_name=None, dedicated_host=None, priority=None, max_price=None, eviction_policy=None, enable_agent=None, vmss=None, os_disk_encryption_set=None, data_disk_encryption_sets=None, specialized=None, encryption_at_host=None, dedicated_host_group=None, enable_auto_update=None, patch_mode=None, - enable_hotpatching=None, platform_fault_domain=None, count=None): + enable_hotpatching=None, platform_fault_domain=None, security_type=None, enable_secure_boot=None, + enable_vtpm=None, count=None): os_caching = disk_info['os'].get('caching') @@ -501,8 +502,19 @@ def _build_storage_profile(): if max_price is not None: vm_properties['billingProfile'] = {'maxPrice': max_price} + vm_properties['securityProfile'] = {} + if encryption_at_host is not None: - vm_properties['securityProfile'] = {'encryptionAtHost': encryption_at_host} + vm_properties['securityProfile']['encryptionAtHost'] = encryption_at_host + + if security_type is not None: + vm_properties['securityProfile']['securityType'] = security_type + + if enable_secure_boot is not None or enable_vtpm is not None: + vm_properties['securityProfile']['uefiSettings'] = { + 'secureBootEnabled': enable_secure_boot, + 'vTpmEnabled': enable_vtpm + } if platform_fault_domain is not None: vm_properties['platformFaultDomain'] = platform_fault_domain diff --git a/src/azure-cli/azure/cli/command_modules/vm/custom.py b/src/azure-cli/azure/cli/command_modules/vm/custom.py index 9bb090b3a36..b48b59cf5cd 100644 --- a/src/azure-cli/azure/cli/command_modules/vm/custom.py +++ b/src/azure-cli/azure/cli/command_modules/vm/custom.py @@ -722,7 +722,8 @@ def create_vm(cmd, vm_name, resource_group_name, image=None, size='Standard_DS1_ priority=None, max_price=None, eviction_policy=None, enable_agent=None, workspace=None, vmss=None, os_disk_encryption_set=None, data_disk_encryption_sets=None, specialized=None, encryption_at_host=None, enable_auto_update=None, patch_mode=None, ssh_key_name=None, - enable_hotpatching=None, platform_fault_domain=None, count=None): + enable_hotpatching=None, platform_fault_domain=None, security_type=None, enable_secure_boot=None, + enable_vtpm=None, count=None): from azure.cli.core.commands.client_factory import get_subscription_id from azure.cli.core.util import random_string, hash_string from azure.cli.core.commands.arm import ArmTemplateBuilder @@ -915,7 +916,8 @@ def create_vm(cmd, vm_name, resource_group_name, image=None, size='Standard_DS1_ data_disk_encryption_sets=data_disk_encryption_sets, specialized=specialized, encryption_at_host=encryption_at_host, dedicated_host_group=dedicated_host_group, enable_auto_update=enable_auto_update, patch_mode=patch_mode, enable_hotpatching=enable_hotpatching, - platform_fault_domain=platform_fault_domain, count=count) + platform_fault_domain=platform_fault_domain, security_type=security_type, enable_secure_boot=enable_secure_boot, + enable_vtpm=enable_vtpm, count=count) vm_resource['dependsOn'] = vm_dependencies @@ -1313,7 +1315,8 @@ def show_vm(cmd, resource_group_name, vm_name, show_details=False): def update_vm(cmd, resource_group_name, vm_name, os_disk=None, disk_caching=None, write_accelerator=None, license_type=None, no_wait=False, ultra_ssd_enabled=None, - priority=None, max_price=None, proximity_placement_group=None, workspace=None, **kwargs): + priority=None, max_price=None, proximity_placement_group=None, workspace=None, enable_secure_boot=None, + enable_vtpm=None, **kwargs): from msrestazure.tools import parse_resource_id, resource_id, is_valid_resource_id from ._vm_utils import update_write_accelerator_settings, update_disk_caching vm = kwargs['parameters'] @@ -1357,6 +1360,12 @@ def update_vm(cmd, resource_group_name, vm_name, os_disk=None, disk_caching=None if proximity_placement_group is not None: vm.proximity_placement_group = {'id': proximity_placement_group} + if enable_secure_boot is not None or enable_vtpm is not None: + vm.security_profile = {'uefiSettings': { + 'secureBootEnabled': enable_secure_boot, + 'vTpmEnabled': enable_vtpm + }} + if workspace is not None: workspace_id = _prepare_workspace(cmd, resource_group_name, workspace) workspace_name = parse_resource_id(workspace_id)['name'] diff --git a/src/azure-cli/azure/cli/command_modules/vm/tests/latest/test_vm_commands.py b/src/azure-cli/azure/cli/command_modules/vm/tests/latest/test_vm_commands.py index cad0ca3fd76..e416aafb936 100644 --- a/src/azure-cli/azure/cli/command_modules/vm/tests/latest/test_vm_commands.py +++ b/src/azure-cli/azure/cli/command_modules/vm/tests/latest/test_vm_commands.py @@ -5072,6 +5072,29 @@ def test_vm_ssh_key(self, resource_group): self.cmd('sshkey show -g {rg} -n k3') +class VMTrustedLaunchScenarioTest(ScenarioTest): + @unittest.skip('Not supported') + @ResourceGroupPreparer(name_prefix='cli_test_vm_trusted_launch_', location='southcentralus') + def test_vm_trusted_launch(self, resource_group): + self.cmd('vm create -g {rg} -n vm --image Win2019Datacenter --security-type TrustedLaunch --enable-secure-boot true --enable-vtpm true --admin-username azureuser --admin-password testPassword0 --nsg-rule None') + self.cmd('vm show -g {rg} -n vm', checks=[ + self.check('securityProfile.securityType', 'TrustedLaunch'), + self.check('securityProfile.UefiSettings.secureBootEnabled', True), + self.check('securityProfile.UefiSettings.vTpmEnabled', True) + ]) + + @unittest.skip('Not supported') + @ResourceGroupPreparer(name_prefix='cli_test_vm_trusted_launch_update_', location='southcentralus') + def test_vm_trusted_launch_update(self, resource_group): + self.cmd('vm create -g {rg} -n vm --image Win2019Datacenter --security-type TrustedLaunch --admin-username azureuser --admin-password testPassword0 --nsg-rule None') + self.cmd('vm update -g {rg} -n vm --enable-secure-boot true --enable-vtpm true') + self.cmd('vm show -g {rg} -n vm', checks=[ + self.check('securityProfile.securityType', 'TrustedLaunch'), + self.check('securityProfile.UefiSettings.secureBootEnabled', True), + self.check('securityProfile.UefiSettings.vTpmEnabled', True) + ]) + + class VMCreateCountScenarioTest(ScenarioTest): @ResourceGroupPreparer(name_prefix='cli_test_vm_create_count_') def test_vm_create_count(self, resource_group):