diff --git a/.web-docs/components/builder/arm/README.md b/.web-docs/components/builder/arm/README.md index e7bc3f4b..76f37efc 100644 --- a/.web-docs/components/builder/arm/README.md +++ b/.web-docs/components/builder/arm/README.md @@ -526,12 +526,14 @@ Providing `temp_resource_group_name` or `location` in combination with or [Linux](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/azure-hybrid-benefit-linux) -- `secure_boot_enabled` (bool) - Specifies if Secure Boot and Trusted Launch is enabled for the Virtual Machine. +- `secure_boot_enabled` (bool) - Specifies if Secure Boot is enabled for the Virtual Machine. For Trusted Launch or Confidential VMs, Secure Boot must be enabled. - `encryption_at_host` (\*bool) - Specifies if Encryption at host is enabled for the Virtual Machine. Requires enabling encryption at host in the Subscription read more [here](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-enable-host-based-encryption-portal?tabs=azure-powershell) -- `vtpm_enabled` (bool) - Specifies if vTPM (virtual Trusted Platform Module) and Trusted Launch is enabled for the Virtual Machine. +- `vtpm_enabled` (bool) - Specifies if vTPM (virtual Trusted Platform Module) is enabled for the Virtual Machine. For Trusted Launch or Confidential VMs, Secure Boot must be enabled. + +- `security_type` (string) - Specifies the type of security to use for the VM. "TrustedLaunch" or "ConfidentialVM" - `async_resourcegroup_delete` (bool) - If you want packer to delete the temporary resource group asynchronously set this value. It's a boolean diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index dab26842..5c41263c 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -575,15 +575,18 @@ type Config struct { // or // [Linux](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/azure-hybrid-benefit-linux) LicenseType string `mapstructure:"license_type" required:"false"` - // Specifies if Secure Boot and Trusted Launch is enabled for the Virtual Machine. + // Specifies if Secure Boot is enabled for the Virtual Machine. For Trusted Launch or Confidential VMs, Secure Boot must be enabled. SecureBootEnabled bool `mapstructure:"secure_boot_enabled" required:"false"` // Specifies if Encryption at host is enabled for the Virtual Machine. // Requires enabling encryption at host in the Subscription read more [here](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-enable-host-based-encryption-portal?tabs=azure-powershell) EncryptionAtHost *bool `mapstructure:"encryption_at_host" required:"false"` - // Specifies if vTPM (virtual Trusted Platform Module) and Trusted Launch is enabled for the Virtual Machine. + // Specifies if vTPM (virtual Trusted Platform Module) is enabled for the Virtual Machine. For Trusted Launch or Confidential VMs, Secure Boot must be enabled. VTpmEnabled bool `mapstructure:"vtpm_enabled" required:"false"` + // Specifies the type of security to use for the VM. "TrustedLaunch" or "ConfidentialVM" + SecurityType string `mapstructure:"security_type" required:"false"` + // Runtime Values UserName string `mapstructure-to-hcl2:",skip"` Password string `mapstructure-to-hcl2:",skip"` diff --git a/builder/azure/arm/config.hcl2spec.go b/builder/azure/arm/config.hcl2spec.go index ab737d3a..d8cabaa5 100644 --- a/builder/azure/arm/config.hcl2spec.go +++ b/builder/azure/arm/config.hcl2spec.go @@ -94,6 +94,7 @@ type FlatConfig struct { SecureBootEnabled *bool `mapstructure:"secure_boot_enabled" required:"false" cty:"secure_boot_enabled" hcl:"secure_boot_enabled"` EncryptionAtHost *bool `mapstructure:"encryption_at_host" required:"false" cty:"encryption_at_host" hcl:"encryption_at_host"` VTpmEnabled *bool `mapstructure:"vtpm_enabled" required:"false" cty:"vtpm_enabled" hcl:"vtpm_enabled"` + SecurityType *string `mapstructure:"security_type" required:"false" cty:"security_type" hcl:"security_type"` Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` @@ -240,6 +241,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "secure_boot_enabled": &hcldec.AttrSpec{Name: "secure_boot_enabled", Type: cty.Bool, Required: false}, "encryption_at_host": &hcldec.AttrSpec{Name: "encryption_at_host", Type: cty.Bool, Required: false}, "vtpm_enabled": &hcldec.AttrSpec{Name: "vtpm_enabled", Type: cty.Bool, Required: false}, + "security_type": &hcldec.AttrSpec{Name: "security_type", Type: cty.String, Required: false}, "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, diff --git a/builder/azure/arm/template_factory.go b/builder/azure/arm/template_factory.go index 92926bf7..6086d299 100644 --- a/builder/azure/arm/template_factory.go +++ b/builder/azure/arm/template_factory.go @@ -285,7 +285,24 @@ func GetVirtualMachineTemplateBuilder(config *Config) (*template.TemplateBuilder } if config.SecureBootEnabled || config.VTpmEnabled || config.EncryptionAtHost != nil { - err = builder.SetSecurityProfile(config.SecureBootEnabled, config.VTpmEnabled, config.EncryptionAtHost) + var chosenSecurityType *hashiVMSDK.SecurityTypes + switch config.SecurityType { + case constants.TrustedLaunch: + trustedlaunch := hashiVMSDK.SecurityTypesTrustedLaunch + chosenSecurityType = &trustedlaunch + case constants.ConfidentialVM: + confidentialVM := hashiVMSDK.SecurityTypesConfidentialVM + chosenSecurityType = &confidentialVM + case "": + if config.EncryptionAtHost != nil { + chosenSecurityType = nil + break + } + fallthrough + default: + return nil, fmt.Errorf("template: invalid security type %s. Valid options are 'TrustedLaunch' or 'ConfidentialVM'", config.SecurityType) + } + err = builder.SetSecurityProfile(config.SecureBootEnabled, config.VTpmEnabled, config.EncryptionAtHost, chosenSecurityType) if err != nil { return nil, err } diff --git a/builder/azure/arm/template_factory_test.TestConfidentialVM01.approved.json b/builder/azure/arm/template_factory_test.TestConfidentialVM01.approved.json new file mode 100644 index 00000000..57389f90 --- /dev/null +++ b/builder/azure/arm/template_factory_test.TestConfidentialVM01.approved.json @@ -0,0 +1,207 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "adminPassword": { + "type": "securestring" + }, + "adminUsername": { + "type": "string" + }, + "commandToExecute": { + "type": "string" + }, + "dataDiskName": { + "type": "string" + }, + "dnsNameForPublicIP": { + "type": "string" + }, + "nicName": { + "type": "string" + }, + "nsgName": { + "type": "string" + }, + "osDiskName": { + "type": "string" + }, + "publicIPAddressName": { + "type": "string" + }, + "storageAccountBlobEndpoint": { + "type": "string" + }, + "subnetName": { + "type": "string" + }, + "virtualNetworkName": { + "type": "string" + }, + "vmName": { + "type": "string" + }, + "vmSize": { + "type": "string" + } + }, + "resources": [ + { + "apiVersion": "[variables('networkApiVersion')]", + "location": "[variables('location')]", + "name": "[parameters('publicIPAddressName')]", + "properties": { + "dnsSettings": { + "domainNameLabel": "[parameters('dnsNameForPublicIP')]" + }, + "publicIPAllocationMethod": "[variables('publicIPAddressType')]" + }, + "type": "Microsoft.Network/publicIPAddresses" + }, + { + "apiVersion": "[variables('networkApiVersion')]", + "location": "[variables('location')]", + "name": "[variables('virtualNetworkName')]", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "[variables('addressPrefix')]" + ] + }, + "subnets": [ + { + "name": "[variables('subnetName')]", + "properties": { + "addressPrefix": "[variables('subnetAddressPrefix')]" + } + } + ] + }, + "type": "Microsoft.Network/virtualNetworks" + }, + { + "apiVersion": "[variables('networkApiVersion')]", + "dependsOn": [ + "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", + "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" + ], + "location": "[variables('location')]", + "name": "[parameters('nicName')]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "publicIPAddress": { + "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" + }, + "subnet": { + "id": "[variables('subnetRef')]" + } + } + } + ] + }, + "type": "Microsoft.Network/networkInterfaces" + }, + { + "apiVersion": "[variables('computeApiVersion')]", + "dependsOn": [ + "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" + ], + "location": "[variables('location')]", + "name": "[parameters('vmName')]", + "properties": { + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" + } + ] + }, + "osProfile": { + "adminPassword": "[parameters('adminPassword')]", + "adminUsername": "[parameters('adminUsername')]", + "computerName": "[parameters('vmName')]", + "linuxConfiguration": { + "ssh": { + "publicKeys": [ + { + "keyData": "", + "path": "[variables('sshKeyPath')]" + } + ] + } + } + }, + "securityProfile": { + "securityType": "ConfidentialVM", + "uefiSettings": { + "secureBootEnabled": true, + "vTpmEnabled": true + } + }, + "storageProfile": { + "imageReference": { + "offer": "ignored00", + "publisher": "ignored00", + "sku": "ignored00", + "version": "latest" + }, + "osDisk": { + "caching": "ReadWrite", + "createOption": "FromImage", + "name": "[parameters('osDiskName')]", + "vhd": { + "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" + } + } + } + }, + "type": "Microsoft.Compute/virtualMachines" + }, + { + "apiVersion": "[variables('computeApiVersion')]", + "condition": "[not(empty(parameters('commandToExecute')))]", + "dependsOn": [ + "[resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName'))]" + ], + "location": "[variables('location')]", + "name": "[concat(parameters('vmName'), '/extension-customscript')]", + "properties": { + "autoUpgradeMinorVersion": true, + "publisher": "Microsoft.Compute", + "settings": { + "commandToExecute": "[parameters('commandToExecute')]" + }, + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.10" + }, + "type": "Microsoft.Compute/virtualMachines/extensions" + } + ], + "variables": { + "addressPrefix": "10.0.0.0/16", + "computeApiVersion": "2023-03-01", + "location": "[resourceGroup().location]", + "networkApiVersion": "2023-04-01", + "publicIPAddressType": "Dynamic", + "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", + "subnetAddressPrefix": "10.0.0.0/24", + "subnetName": "[parameters('subnetName')]", + "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", + "virtualNetworkName": "[parameters('virtualNetworkName')]", + "virtualNetworkResourceGroup": "[resourceGroup().name]", + "vmStorageAccountContainerName": "images", + "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" + } +} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.go b/builder/azure/arm/template_factory_test.go index bfa2dac4..58d0683f 100644 --- a/builder/azure/arm/template_factory_test.go +++ b/builder/azure/arm/template_factory_test.go @@ -733,6 +733,26 @@ func TestTrustedLaunch01(t *testing.T) { m := getArmBuilderConfiguration() m["secure_boot_enabled"] = "true" m["vtpm_enabled"] = "true" + m["security_type"] = "TrustedLaunch" + + var c Config + _, err := c.Prepare(m, getPackerConfiguration(), getPackerSSHPasswordCommunicatorConfiguration()) + if err != nil { + t.Fatal(err) + } + deployment, err := GetVirtualMachineDeployment(&c) + if err != nil { + t.Fatal(err) + } + + approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) +} + +func TestConfidentialVM01(t *testing.T) { + m := getArmBuilderConfiguration() + m["secure_boot_enabled"] = "true" + m["vtpm_enabled"] = "true" + m["security_type"] = "ConfidentialVM" var c Config _, err := c.Prepare(m, getPackerConfiguration(), getPackerSSHPasswordCommunicatorConfiguration()) diff --git a/builder/azure/common/constants/securityTypes.go b/builder/azure/common/constants/securityTypes.go new file mode 100644 index 00000000..d3d4b8a5 --- /dev/null +++ b/builder/azure/common/constants/securityTypes.go @@ -0,0 +1,10 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package constants + +// Security types +const ( + TrustedLaunch string = "TrustedLaunch" + ConfidentialVM string = "ConfidentialVM" +) diff --git a/builder/azure/common/template/template_builder.go b/builder/azure/common/template/template_builder.go index 946ec879..29b4895c 100644 --- a/builder/azure/common/template/template_builder.go +++ b/builder/azure/common/template/template_builder.go @@ -512,17 +512,17 @@ func (s *TemplateBuilder) SetLicenseType(licenseType string) error { return nil } -func (s *TemplateBuilder) SetSecurityProfile(secureBootEnabled bool, vtpmEnabled bool, encryptionAtHost *bool) error { +func (s *TemplateBuilder) SetSecurityProfile(secureBootEnabled bool, vtpmEnabled bool, encryptionAtHost *bool, securityType *hashiVMSDK.SecurityTypes) error { resource, err := s.getResourceByType(resourceVirtualMachine) if err != nil { return err } resource.Properties.SecurityProfile = &hashiVMSDK.SecurityProfile{} - securityTrustedLaunch := hashiVMSDK.SecurityTypesTrustedLaunch + if secureBootEnabled || vtpmEnabled { resource.Properties.SecurityProfile.UefiSettings = &hashiVMSDK.UefiSettings{} - resource.Properties.SecurityProfile.SecurityType = &securityTrustedLaunch + resource.Properties.SecurityProfile.SecurityType = securityType resource.Properties.SecurityProfile.UefiSettings.SecureBootEnabled = common.BoolPtr(secureBootEnabled) resource.Properties.SecurityProfile.UefiSettings.VTpmEnabled = common.BoolPtr(vtpmEnabled) } diff --git a/docs-partials/builder/azure/arm/Config-not-required.mdx b/docs-partials/builder/azure/arm/Config-not-required.mdx index 62d3806f..b05f785a 100644 --- a/docs-partials/builder/azure/arm/Config-not-required.mdx +++ b/docs-partials/builder/azure/arm/Config-not-required.mdx @@ -385,12 +385,14 @@ or [Linux](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/azure-hybrid-benefit-linux) -- `secure_boot_enabled` (bool) - Specifies if Secure Boot and Trusted Launch is enabled for the Virtual Machine. +- `secure_boot_enabled` (bool) - Specifies if Secure Boot is enabled for the Virtual Machine. For Trusted Launch or Confidential VMs, Secure Boot must be enabled. - `encryption_at_host` (\*bool) - Specifies if Encryption at host is enabled for the Virtual Machine. Requires enabling encryption at host in the Subscription read more [here](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-enable-host-based-encryption-portal?tabs=azure-powershell) -- `vtpm_enabled` (bool) - Specifies if vTPM (virtual Trusted Platform Module) and Trusted Launch is enabled for the Virtual Machine. +- `vtpm_enabled` (bool) - Specifies if vTPM (virtual Trusted Platform Module) is enabled for the Virtual Machine. For Trusted Launch or Confidential VMs, Secure Boot must be enabled. + +- `security_type` (string) - Specifies the type of security to use for the VM. "TrustedLaunch" or "ConfidentialVM" - `async_resourcegroup_delete` (bool) - If you want packer to delete the temporary resource group asynchronously set this value. It's a boolean