Skip to content

Commit a0057a0

Browse files
authored
[Compute] az vm/vmss create: Install guest attestation extension and turn on system MSI by default when Trusted Launch configuration is met (#22048)
1 parent ce055fd commit a0057a0

File tree

7 files changed

+16204
-114
lines changed

7 files changed

+16204
-114
lines changed

src/azure-cli/azure/cli/command_modules/vm/_params.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,7 @@ def load_arguments(self, _):
944944
c.ignore('aux_subscriptions')
945945
c.argument('edge_zone', edge_zone_type)
946946
c.argument('accept_term', action='store_true', help="Accept the license agreement and privacy statement.")
947+
c.argument('disable_integrity_monitoring', action='store_true', min_api='2020-12-01', help='Disable the default behavior of installing guest attestation extension and enabling System Assigned Identity for Trusted Launch enabled VMs and VMSS.')
947948

948949
with self.argument_context(scope, arg_group='Authentication') as c:
949950
c.argument('generate_ssh_keys', action='store_true', help='Generate SSH public and private key files if missing. The keys will be stored in the ~/.ssh directory')

src/azure-cli/azure/cli/command_modules/vm/_validators.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,22 @@ def _validate_vm_vmss_msi(cmd, namespace, is_identity_assign=False):
12841284
elif namespace.identity_scope or namespace.identity_role:
12851285
raise ArgumentUsageError('usage error: --assign-identity [--scope SCOPE] [--role ROLE]')
12861286

1287+
if not is_identity_assign:
1288+
_enable_msi_for_trusted_launch(namespace)
1289+
1290+
1291+
def _enable_msi_for_trusted_launch(namespace):
1292+
# Enable system assigned msi by default when Trusted Launch configuration is met
1293+
is_trusted_launch = namespace.security_type and namespace.security_type.lower() == 'trustedlaunch' \
1294+
and namespace.enable_vtpm and namespace.enable_secure_boot
1295+
if is_trusted_launch and not namespace.disable_integrity_monitoring:
1296+
from ._vm_utils import MSI_LOCAL_ID
1297+
logger.info('The MSI is enabled by default when Trusted Launch configuration is met')
1298+
if namespace.assign_identity is None:
1299+
namespace.assign_identity = [MSI_LOCAL_ID]
1300+
elif '[system]' not in namespace.assign_identity:
1301+
namespace.assign_identity.append(MSI_LOCAL_ID)
1302+
12871303

12881304
def _validate_vm_vmss_set_applications(cmd, namespace): # pylint: disable=unused-argument
12891305
if namespace.application_configuration_overrides and \

src/azure-cli/azure/cli/command_modules/vm/custom.py

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ def capture_vm(cmd, resource_group_name, vm_name, vhd_name_prefix,
764764
print(json.dumps(output, indent=2)) # pylint: disable=no-member
765765

766766

767-
# pylint: disable=too-many-locals, unused-argument, too-many-statements, too-many-branches
767+
# pylint: disable=too-many-locals, unused-argument, too-many-statements, too-many-branches, broad-except
768768
def create_vm(cmd, vm_name, resource_group_name, image=None, size='Standard_DS1_v2', location=None, tags=None,
769769
no_wait=False, authentication_type=None, admin_password=None, computer_name=None,
770770
admin_username=None, ssh_dest_key_path=None, ssh_key_value=None, generate_ssh_keys=False,
@@ -789,7 +789,7 @@ def create_vm(cmd, vm_name, resource_group_name, image=None, size='Standard_DS1_
789789
enable_hotpatching=None, platform_fault_domain=None, security_type=None, enable_secure_boot=None,
790790
enable_vtpm=None, count=None, edge_zone=None, nic_delete_option=None, os_disk_delete_option=None,
791791
data_disk_delete_option=None, user_data=None, capacity_reservation_group=None, enable_hibernation=None,
792-
v_cpus_available=None, v_cpus_per_core=None, accept_term=None):
792+
v_cpus_available=None, v_cpus_per_core=None, accept_term=None, disable_integrity_monitoring=False):
793793

794794
from azure.cli.core.commands.client_factory import get_subscription_id
795795
from azure.cli.core.util import random_string, hash_string
@@ -1074,6 +1074,33 @@ def create_vm(cmd, vm_name, resource_group_name, image=None, size='Standard_DS1_
10741074
return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, deployment_name, deployment)
10751075
LongRunningOperation(cmd.cli_ctx)(client.begin_create_or_update(resource_group_name, deployment_name, deployment))
10761076

1077+
# Guest Attestation Extension and enable System Assigned MSI by default
1078+
is_trusted_launch = security_type and security_type.lower() == 'trustedlaunch' and\
1079+
enable_vtpm and enable_secure_boot
1080+
if is_trusted_launch and not disable_integrity_monitoring:
1081+
vm = get_vm(cmd, resource_group_name, vm_name, 'instanceView')
1082+
client = _compute_client_factory(cmd.cli_ctx)
1083+
if vm.storage_profile.os_disk.os_type == 'Linux':
1084+
publisher = 'Microsoft.Azure.Security.LinuxAttestation'
1085+
if vm.storage_profile.os_disk.os_type == 'Windows':
1086+
publisher = 'Microsoft.Azure.Security.WindowsAttestation'
1087+
version = _normalize_extension_version(cmd.cli_ctx, publisher, 'GuestAttestation', None, vm.location)
1088+
VirtualMachineExtension = cmd.get_models('VirtualMachineExtension')
1089+
ext = VirtualMachineExtension(location=vm.location,
1090+
publisher=publisher,
1091+
type_properties_type='GuestAttestation',
1092+
protected_settings=None,
1093+
type_handler_version=version,
1094+
settings=None,
1095+
auto_upgrade_minor_version=True,
1096+
enable_automatic_upgrade=None)
1097+
try:
1098+
LongRunningOperation(cmd.cli_ctx)(client.virtual_machine_extensions.begin_create_or_update(
1099+
resource_group_name, vm_name, 'GuestAttestation', ext))
1100+
logger.info('Guest Attestation Extension has been successfully installed by default '
1101+
'when Trusted Launch configuration is met')
1102+
except Exception as e:
1103+
logger.error('Failed to install Guest Attestation Extension for Trusted Launch. %s', e)
10771104
if count:
10781105
vm_names = [vm_name + str(i) for i in range(count)]
10791106
else:
@@ -2847,7 +2874,7 @@ def create_vmss(cmd, vmss_name, resource_group_name, image=None,
28472874
user_data=None, network_api_version=None, enable_spot_restore=None, spot_restore_timeout=None,
28482875
capacity_reservation_group=None, enable_auto_update=None, patch_mode=None, enable_agent=None,
28492876
security_type=None, enable_secure_boot=None, enable_vtpm=None, automatic_repairs_action=None,
2850-
v_cpus_available=None, v_cpus_per_core=None, accept_term=None):
2877+
v_cpus_available=None, v_cpus_per_core=None, accept_term=None, disable_integrity_monitoring=False):
28512878

28522879
from azure.cli.core.commands.client_factory import get_subscription_id
28532880
from azure.cli.core.util import random_string, hash_string
@@ -3179,6 +3206,40 @@ def _get_public_ip_address_allocation(value, sku):
31793206
deployment_result['vmss']['identity'] = _construct_identity_info(identity_scope, identity_role,
31803207
vmss_info.identity.principal_id,
31813208
vmss_info.identity.user_assigned_identities)
3209+
# Guest Attestation Extension and enable System Assigned MSI by default
3210+
is_trusted_launch = security_type and security_type.lower() == 'trustedlaunch' and\
3211+
enable_vtpm and enable_secure_boot
3212+
if is_trusted_launch and not disable_integrity_monitoring:
3213+
client = _compute_client_factory(cmd.cli_ctx)
3214+
vmss = client.virtual_machine_scale_sets.get(resource_group_name, vmss_name)
3215+
vmss.virtual_machine_profile.storage_profile.image_reference = None
3216+
VirtualMachineScaleSetExtension, VirtualMachineScaleSetExtensionProfile = cmd.get_models(
3217+
'VirtualMachineScaleSetExtension', 'VirtualMachineScaleSetExtensionProfile')
3218+
if vmss.virtual_machine_profile.storage_profile.os_disk.os_type == 'Linux':
3219+
publisher = 'Microsoft.Azure.Security.LinuxAttestation'
3220+
if vmss.virtual_machine_profile.storage_profile.os_disk.os_type == 'Windows':
3221+
publisher = 'Microsoft.Azure.Security.WindowsAttestation'
3222+
version = _normalize_extension_version(cmd.cli_ctx, publisher, 'GuestAttestation', None, vmss.location)
3223+
ext = VirtualMachineScaleSetExtension(name='GuestAttestation',
3224+
publisher=publisher,
3225+
type_properties_type='GuestAttestation',
3226+
protected_settings=None,
3227+
type_handler_version=version,
3228+
settings=None,
3229+
auto_upgrade_minor_version=True,
3230+
provision_after_extensions=None,
3231+
enable_automatic_upgrade=None)
3232+
if not vmss.virtual_machine_profile.extension_profile:
3233+
vmss.virtual_machine_profile.extension_profile = VirtualMachineScaleSetExtensionProfile(extensions=[])
3234+
vmss.virtual_machine_profile.extension_profile.extensions.append(ext)
3235+
try:
3236+
LongRunningOperation(cmd.cli_ctx)(client.virtual_machine_scale_sets.begin_create_or_update(
3237+
resource_group_name, vmss_name, vmss))
3238+
logger.info('Guest Attestation Extension has been successfully installed by default'
3239+
'when Trusted Launch configuration is met')
3240+
except Exception as e:
3241+
logger.error('Failed to install Guest Attestation Extension for Trusted Launch. %s', e)
3242+
31823243
return deployment_result
31833244

31843245

src/azure-cli/azure/cli/command_modules/vm/linter_exclusions.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ vmss create:
2727
prioritize_unhealthy_instances:
2828
rule_exclusions:
2929
- option_length_too_long
30+
disable_integrity_monitoring:
31+
rule_exclusions:
32+
- option_length_too_long
3033
vmss update:
3134
parameters:
3235
enable_cross_zone_upgrade:
@@ -57,6 +60,9 @@ vm create:
5760
public_ip_address_allocation:
5861
rule_exclusions:
5962
- missing_parameter_help
63+
disable_integrity_monitoring:
64+
rule_exclusions:
65+
- option_length_too_long
6066
vm unmanaged-disk attach:
6167
parameters:
6268
size_gb:

0 commit comments

Comments
 (0)