Merge pull request #8203 from sumit-kalra/master

Azure-ARM builder: Deploy NSG if list of IP addresses is provided in config
This commit is contained in:
Megan Marsh 2019-10-21 11:10:58 -07:00 committed by GitHub
commit 836aaafaa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 888 additions and 9 deletions

View File

@ -37,6 +37,7 @@ type AzureClient struct {
network.InterfacesClient
network.SubnetsClient
network.VirtualNetworksClient
network.SecurityGroupsClient
compute.ImagesClient
compute.VirtualMachinesClient
common.VaultClient
@ -190,6 +191,12 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string
azureClient.VirtualNetworksClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.VirtualNetworksClient.UserAgent)
azureClient.VirtualNetworksClient.Client.PollingDuration = PollingDuration
azureClient.SecurityGroupsClient = network.NewSecurityGroupsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
azureClient.SecurityGroupsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
azureClient.SecurityGroupsClient.RequestInspector = withInspection(maxlen)
azureClient.SecurityGroupsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
azureClient.SecurityGroupsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.SecurityGroupsClient.UserAgent)
azureClient.PublicIPAddressesClient = network.NewPublicIPAddressesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
azureClient.PublicIPAddressesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
azureClient.PublicIPAddressesClient.RequestInspector = withInspection(maxlen)

View File

@ -12,6 +12,7 @@ import (
"fmt"
"io/ioutil"
"math/big"
"net"
"regexp"
"strings"
"time"
@ -350,6 +351,13 @@ type Config struct {
// are None, ReadOnly, and ReadWrite. The default value is ReadWrite.
DiskCachingType string `mapstructure:"disk_caching_type" required:"false"`
diskCachingType compute.CachingTypes
// Specify the list of IP addresses and CIDR blocks that should be
// allowed access to the VM. If provided, an Azure Network Security
// Group will be created with corresponding rules and be bound to
// the subnet of the VM.
// Providing `allowed_inbound_ip_addresses` in combination with
// `virtual_network_name` is not allowed.
AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses"`
// Runtime Values
UserName string
@ -365,6 +373,7 @@ type Config struct {
tmpOSDiskName string
tmpSubnetName string
tmpVirtualNetworkName string
tmpNsgName string
tmpWinRMCertificateUrl string
// Authentication with the VM via SSH
@ -612,6 +621,7 @@ func setRuntimeValues(c *Config) {
c.tmpOSDiskName = tempName.OSDiskName
c.tmpSubnetName = tempName.SubnetName
c.tmpVirtualNetworkName = tempName.VirtualNetworkName
c.tmpNsgName = tempName.NsgName
c.tmpKeyVaultName = tempName.KeyVaultName
}
@ -880,6 +890,16 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_subnet_name is specified, so must virtual_network_name"))
}
if c.AllowedInboundIpAddresses != nil && len(c.AllowedInboundIpAddresses) >= 1 {
if c.VirtualNetworkName != "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_name is specified, allowed_inbound_ip_addresses cannot be specified"))
} else {
if ok, err := assertAllowedInboundIpAddresses(c.AllowedInboundIpAddresses, "allowed_inbound_ip_addresses"); !ok {
errs = packer.MultiErrorAppend(errs, err)
}
}
}
/////////////////////////////////////////////
// Plan Info
if c.PlanInfo.PlanName != "" || c.PlanInfo.PlanProduct != "" || c.PlanInfo.PlanPublisher != "" || c.PlanInfo.PlanPromotionCode != "" {
@ -958,6 +978,17 @@ func assertManagedImageDataDiskSnapshotName(name, setting string) (bool, error)
return true, nil
}
func assertAllowedInboundIpAddresses(ipAddresses []string, setting string) (bool, error) {
for _, ipAddress := range ipAddresses {
if net.ParseIP(ipAddress) == nil {
if _, _, err := net.ParseCIDR(ipAddress); err != nil {
return false, fmt.Errorf("The setting %s must only contain valid IP addresses or CIDR blocks", setting)
}
}
}
return true, nil
}
func assertResourceGroupName(rgn, setting string) (bool, error) {
if !isValidAzureName(reResourceGroupName, rgn) {
return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validResourceGroupNameRe)

View File

@ -270,6 +270,132 @@ func TestConfigVirtualNetworkSubnetNameMustBeSetWithVirtualNetworkName(t *testin
}
}
func TestConfigAllowedInboundIpAddressesIsOptional(t *testing.T) {
config := map[string]string{
"capture_name_prefix": "ignore",
"capture_container_name": "ignore",
"location": "ignore",
"image_url": "ignore",
"storage_account": "ignore",
"resource_group_name": "ignore",
"subscription_id": "ignore",
"os_type": constants.Target_Linux,
"communicator": "none",
"virtual_network_name": "MyVirtualNetwork",
}
c, _, err := newConfig(config, getPackerConfiguration())
if err != nil {
t.Fatal(err)
}
if c.AllowedInboundIpAddresses != nil {
t.Errorf("Expected Config to set allowed_inbound_ip_addresses to nil, but got %v", c.AllowedInboundIpAddresses)
}
}
func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) {
ipValue0 := "127.0.0.1"
ipValue1 := "127.0.0.2"
cidrValue2 := "192.168.100.0/24"
cidrValue3 := "10.10.1.16/32"
config := map[string]interface{}{
"capture_name_prefix": "ignore",
"capture_container_name": "ignore",
"location": "ignore",
"image_url": "ignore",
"storage_account": "ignore",
"resource_group_name": "ignore",
"subscription_id": "ignore",
"os_type": constants.Target_Linux,
"communicator": "none",
}
config["allowed_inbound_ip_addresses"] = ipValue0
c, _, err := newConfig(config, getPackerConfiguration())
if err != nil {
t.Fatal(err)
}
if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 1 ||
c.AllowedInboundIpAddresses[0] != ipValue0 {
t.Errorf("Expected 'allowed_inbound_ip_addresses' to have one element (%s), but got '%v'.", ipValue0, c.AllowedInboundIpAddresses)
}
config["allowed_inbound_ip_addresses"] = cidrValue2
c, _, err = newConfig(config, getPackerConfiguration())
if err != nil {
t.Fatal(err)
}
if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 1 ||
c.AllowedInboundIpAddresses[0] != cidrValue2 {
t.Errorf("Expected 'allowed_inbound_ip_addresses' to have one element (%s), but got '%v'.", cidrValue2, c.AllowedInboundIpAddresses)
}
config["allowed_inbound_ip_addresses"] = []string{ipValue0, cidrValue2, ipValue1, cidrValue3}
c, _, err = newConfig(config, getPackerConfiguration())
if err != nil {
t.Fatal(err)
}
if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 4 ||
c.AllowedInboundIpAddresses[0] != ipValue0 || c.AllowedInboundIpAddresses[1] != cidrValue2 ||
c.AllowedInboundIpAddresses[2] != ipValue1 || c.AllowedInboundIpAddresses[3] != cidrValue3 {
t.Errorf("Expected 'allowed_inbound_ip_addresses' to have four elements (%s %s %s %s), but got '%v'.", ipValue0, cidrValue2, ipValue1,
cidrValue3, c.AllowedInboundIpAddresses)
}
}
func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) {
config := map[string]interface{}{
"capture_name_prefix": "ignore",
"capture_container_name": "ignore",
"location": "ignore",
"image_url": "ignore",
"storage_account": "ignore",
"resource_group_name": "ignore",
"subscription_id": "ignore",
"os_type": constants.Target_Linux,
"communicator": "none",
}
config["allowed_inbound_ip_addresses"] = []string{"127.0.0.1", "127.0.0.two"}
c, _, err := newConfig(config, getPackerConfiguration())
if err == nil {
t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses)
}
config["allowed_inbound_ip_addresses"] = []string{"192.168.100.1000/24", "10.10.1.16/32"}
c, _, err = newConfig(config, getPackerConfiguration())
if err == nil {
// 192.168.100.1000/24 is invalid
t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses)
}
}
func TestConfigShouldRejectInboundIpAddressesWithVirtualNetwork(t *testing.T) {
config := map[string]interface{}{
"capture_name_prefix": "ignore",
"capture_container_name": "ignore",
"location": "ignore",
"image_url": "ignore",
"storage_account": "ignore",
"resource_group_name": "ignore",
"subscription_id": "ignore",
"os_type": constants.Target_Linux,
"communicator": "none",
"allowed_inbound_ip_addresses": "127.0.0.1",
}
_, _, err := newConfig(config, getPackerConfiguration())
if err != nil {
t.Fatal(err)
}
config["virtual_network_name"] = "some_vnet_name"
_, _, err = newConfig(config, getPackerConfiguration())
if err == nil {
t.Errorf("Expected configuration creation to fail, but it succeeded with allowed_inbound_ip_addresses and virtual_network_name both specified")
}
}
func TestConfigShouldDefaultToPublicCloud(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration())
@ -380,6 +506,10 @@ func TestSystemShouldDefineRuntimeValues(t *testing.T) {
if c.tmpOSDiskName == "" {
t.Errorf("Expected tmpOSDiskName to not be empty, but it was '%s'!", c.tmpOSDiskName)
}
if c.tmpNsgName == "" {
t.Errorf("Expected tmpNsgName to not be empty, but it was '%s'!", c.tmpNsgName)
}
}
func TestConfigShouldTransformToVirtualMachineCaptureParameters(t *testing.T) {

View File

@ -115,6 +115,12 @@ func deleteResource(ctx context.Context, client *AzureClient, resourceType strin
err = f.WaitForCompletionRef(ctx, client.VirtualNetworksClient.Client)
}
return err
case "Microsoft.Network/networkSecurityGroups":
f, err := client.SecurityGroupsClient.Delete(ctx, resourceGroupName, resourceName)
if err == nil {
err = f.WaitForCompletionRef(ctx, client.SecurityGroupsClient.Client)
}
return err
case "Microsoft.Network/publicIPAddresses":
f, err := client.PublicIPAddressesClient.Delete(ctx, resourceGroupName, resourceName)
if err == nil {

View File

@ -40,6 +40,7 @@ func GetVirtualMachineDeployment(config *Config) (*resources.Deployment, error)
SubnetName: &template.TemplateParameter{Value: config.tmpSubnetName},
StorageAccountBlobEndpoint: &template.TemplateParameter{Value: config.storageAccountBlobEndpoint},
VirtualNetworkName: &template.TemplateParameter{Value: config.tmpVirtualNetworkName},
NsgName: &template.TemplateParameter{Value: config.tmpNsgName},
VMSize: &template.TemplateParameter{Value: config.VMSize},
VMName: &template.TemplateParameter{Value: config.tmpComputeName},
}
@ -117,6 +118,13 @@ func GetVirtualMachineDeployment(config *Config) (*resources.Deployment, error)
config.VirtualNetworkSubnetName)
}
if config.AllowedInboundIpAddresses != nil && len(config.AllowedInboundIpAddresses) >= 1 && config.Comm.Port() != 0 {
err = builder.SetNetworkSecurityGroup(config.AllowedInboundIpAddresses, config.Comm.Port())
if err != nil {
return nil, err
}
}
builder.SetTags(&config.AzureTags)
doc, _ := builder.ToJSON()
return createDeploymentParameters(*doc, params)

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -189,6 +192,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -194,6 +197,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -160,6 +163,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -158,6 +161,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -119,6 +122,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -178,6 +181,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -159,6 +162,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -158,6 +161,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -161,6 +164,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -139,6 +142,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -172,6 +175,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -173,6 +176,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -0,0 +1,227 @@
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"adminPassword": {
"type": "string"
},
"adminUsername": {
"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('publicIPAddressApiVersion')]",
"location": "[variables('location')]",
"name": "[parameters('publicIPAddressName')]",
"properties": {
"dnsSettings": {
"domainNameLabel": "[parameters('dnsNameForPublicIP')]"
},
"publicIPAllocationMethod": "[variables('publicIPAddressType')]"
},
"type": "Microsoft.Network/publicIPAddresses"
},
{
"apiVersion": "[variables('networkInterfacesApiVersion')]",
"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('apiVersion')]",
"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')]",
"secrets": [
{
"sourceVault": {
"id": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults', '--keyvault-name--')]"
},
"vaultCertificates": [
{
"certificateStore": "My",
"certificateUrl": ""
}
]
}
],
"windowsConfiguration": {
"provisionVMAgent": true,
"winRM": {
"listeners": [
{
"certificateUrl": "",
"protocol": "https"
}
]
}
}
},
"storageProfile": {
"imageReference": {
"offer": "--image-offer--",
"publisher": "--image-publisher--",
"sku": "--image-sku--",
"version": "--version--"
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"name": "[parameters('osDiskName')]",
"osType": "Windows"
}
}
},
"type": "Microsoft.Compute/virtualMachines"
},
{
"apiVersion": "[variables('networkSecurityGroupsApiVersion')]",
"location": "[variables('location')]",
"name": "[parameters('nsgName')]",
"properties": {
"securityRules": [
{
"name": "AllowIPsToSshWinRMInbound",
"properties": {
"access": "Allow",
"description": "Allow inbound traffic from specified IP addresses",
"destinationAddressPrefix": "VirtualNetwork",
"destinationPortRange": "5985",
"direction": "Inbound",
"priority": 100,
"protocol": "Tcp",
"sourceAddressPrefixes": [
"127.0.0.1",
"192.168.100.0/24"
],
"sourcePortRange": "*"
}
}
]
},
"type": "Microsoft.Network/networkSecurityGroups"
},
{
"apiVersion": "[variables('virtualNetworksApiVersion')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', parameters('nsgName'))]"
],
"location": "[variables('location')]",
"name": "[variables('virtualNetworkName')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetAddressPrefix')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('nsgName'))]"
}
}
}
]
},
"type": "Microsoft.Network/virtualNetworks"
}
],
"variables": {
"addressPrefix": "10.0.0.0/16",
"apiVersion": "2017-03-30",
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-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]",
"virtualNetworksApiVersion": "2017-04-01",
"vmStorageAccountContainerName": "images",
"vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
}
}

View File

@ -425,6 +425,40 @@ func TestVirtualMachineDeployment12(t *testing.T) {
}
}
// Ensure the VM template is correct when building with list of allowed IP addresses
func TestVirtualMachineDeployment13(t *testing.T) {
config := map[string]interface{}{
"location": "ignore",
"subscription_id": "ignore",
"os_type": constants.Target_Windows,
"communicator": "winrm",
"winrm_username": "ignore",
"image_publisher": "--image-publisher--",
"image_offer": "--image-offer--",
"image_sku": "--image-sku--",
"image_version": "--version--",
"managed_image_name": "ManagedImageName",
"managed_image_resource_group_name": "ManagedImageResourceGroupName",
"allowed_inbound_ip_addresses": []string{"127.0.0.1", "192.168.100.0/24"},
}
c, _, err := newConfig(config, getPackerConfiguration())
if err != nil {
t.Fatal(err)
}
c.tmpKeyVaultName = "--keyvault-name--"
deployment, err := GetVirtualMachineDeployment(c)
if err != nil {
t.Fatal(err)
}
err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template)
if err != nil {
t.Fatal(err)
}
}
// Ensure the link values are not set, and the concrete values are set.
func TestKeyVaultDeployment00(t *testing.T) {
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration())

View File

@ -19,6 +19,7 @@ type TempName struct {
SubnetName string
PublicIPAddressName string
VirtualNetworkName string
NsgName string
}
func NewTempName() *TempName {
@ -33,6 +34,7 @@ func NewTempName() *TempName {
tempName.PublicIPAddressName = fmt.Sprintf("pkrip%s", suffix)
tempName.SubnetName = fmt.Sprintf("pkrsn%s", suffix)
tempName.VirtualNetworkName = fmt.Sprintf("pkrvn%s", suffix)
tempName.NsgName = fmt.Sprintf("pkrsg%s", suffix)
tempName.ResourceGroupName = fmt.Sprintf("packer-Resource-Group-%s", suffix)
tempName.AdminPassword = generatePassword()

View File

@ -41,6 +41,10 @@ func TestTempNameShouldCreatePrefixedRandomNames(t *testing.T) {
if strings.Index(tempName.VirtualNetworkName, "pkrvn") != 0 {
t.Errorf("Expected VirtualNetworkName to begin with 'pkrvn', but got '%s'!", tempName.VirtualNetworkName)
}
if strings.Index(tempName.NsgName, "pkrsg") != 0 {
t.Errorf("Expected NsgName to begin with 'pkrsg', but got '%s'!", tempName.NsgName)
}
}
func TestTempAdminPassword(t *testing.T) {
@ -92,4 +96,8 @@ func TestTempNameShouldHaveSameSuffix(t *testing.T) {
if strings.HasSuffix(tempName.VirtualNetworkName, suffix) != true {
t.Errorf("Expected VirtualNetworkName to end with '%s', but the value is '%s'!", suffix, tempName.VirtualNetworkName)
}
if strings.HasSuffix(tempName.NsgName, suffix) != true {
t.Errorf("Expected NsgName to end with '%s', but the value is '%s'!", suffix, tempName.NsgName)
}
}

View File

@ -91,10 +91,11 @@ type Properties struct {
PublicIPAllocatedMethod *network.IPAllocationMethod `json:"publicIPAllocationMethod,omitempty"`
Sku *Sku `json:"sku,omitempty"`
//StorageProfile3 *compute.StorageProfile `json:"storageProfile,omitempty"`
StorageProfile *StorageProfileUnion `json:"storageProfile,omitempty"`
Subnets *[]network.Subnet `json:"subnets,omitempty"`
TenantId *string `json:"tenantId,omitempty"`
Value *string `json:"value,omitempty"`
StorageProfile *StorageProfileUnion `json:"storageProfile,omitempty"`
Subnets *[]network.Subnet `json:"subnets,omitempty"`
SecurityRules *[]network.SecurityRule `json:"securityRules,omitempty"`
TenantId *string `json:"tenantId,omitempty"`
Value *string `json:"value,omitempty"`
}
type AccessPolicies struct {

View File

@ -3,9 +3,11 @@ package template
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-01-01/network"
"github.com/Azure/go-autorest/autorest/to"
)
@ -13,11 +15,12 @@ const (
jsonPrefix = ""
jsonIndent = " "
resourceKeyVaults = "Microsoft.KeyVault/vaults"
resourceNetworkInterfaces = "Microsoft.Network/networkInterfaces"
resourcePublicIPAddresses = "Microsoft.Network/publicIPAddresses"
resourceVirtualMachine = "Microsoft.Compute/virtualMachines"
resourceVirtualNetworks = "Microsoft.Network/virtualNetworks"
resourceKeyVaults = "Microsoft.KeyVault/vaults"
resourceNetworkInterfaces = "Microsoft.Network/networkInterfaces"
resourcePublicIPAddresses = "Microsoft.Network/publicIPAddresses"
resourceVirtualMachine = "Microsoft.Compute/virtualMachines"
resourceVirtualNetworks = "Microsoft.Network/virtualNetworks"
resourceNetworkSecurityGroups = "Microsoft.Network/networkSecurityGroups"
variableSshKeyPath = "sshKeyPath"
)
@ -309,6 +312,39 @@ func (s *TemplateBuilder) SetPrivateVirtualNetworkWithPublicIp(virtualNetworkRes
return nil
}
func (s *TemplateBuilder) SetNetworkSecurityGroup(ipAddresses []string, port int) error {
nsgResource, dependency, resourceId := s.createNsgResource(ipAddresses, port)
if err := s.addResource(nsgResource); err != nil {
return err
}
vnetResource, err := s.getResourceByType(resourceVirtualNetworks)
if err != nil {
return err
}
s.deleteResourceByType(resourceVirtualNetworks)
s.addResourceDependency(vnetResource, dependency)
if vnetResource.Properties == nil || vnetResource.Properties.Subnets == nil || len(*vnetResource.Properties.Subnets) != 1 {
return fmt.Errorf("template: could not find virtual network/subnet to add default network security group to")
}
subnet := ((*vnetResource.Properties.Subnets)[0])
if subnet.SubnetPropertiesFormat == nil {
subnet.SubnetPropertiesFormat = &network.SubnetPropertiesFormat{}
}
if subnet.SubnetPropertiesFormat.NetworkSecurityGroup != nil {
return fmt.Errorf("template: subnet already has an associated network security group")
}
subnet.SubnetPropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{
ID: to.StringPtr(resourceId),
}
s.addResource(vnetResource)
return nil
}
func (s *TemplateBuilder) SetTags(tags *map[string]*string) error {
if tags == nil || len(*tags) == 0 {
return nil
@ -366,6 +402,18 @@ func (s *TemplateBuilder) toVariable(name string) string {
return fmt.Sprintf("[variables('%s')]", name)
}
func (s *TemplateBuilder) addResource(newResource *Resource) error {
for _, resource := range *s.template.Resources {
if *resource.Type == *newResource.Type {
return fmt.Errorf("template: found an existing resource of type %s", *resource.Type)
}
}
resources := append(*s.template.Resources, *newResource)
s.template.Resources = &resources
return nil
}
func (s *TemplateBuilder) deleteResourceByType(resourceType string) {
resources := make([]Resource, 0)
@ -379,6 +427,15 @@ func (s *TemplateBuilder) deleteResourceByType(resourceType string) {
s.template.Resources = &resources
}
func (s *TemplateBuilder) addResourceDependency(resource *Resource, dep string) {
if resource.DependsOn != nil {
deps := append(*resource.DependsOn, dep)
resource.DependsOn = &deps
} else {
resource.DependsOn = &[]string{dep}
}
}
func (s *TemplateBuilder) deleteResourceDependency(resource *Resource, predicate func(string) bool) {
deps := make([]string, 0)
@ -391,6 +448,38 @@ func (s *TemplateBuilder) deleteResourceDependency(resource *Resource, predicate
*resource.DependsOn = deps
}
func (s *TemplateBuilder) createNsgResource(srcIpAddresses []string, port int) (*Resource, string, string) {
resource := &Resource{
ApiVersion: to.StringPtr("[variables('networkSecurityGroupsApiVersion')]"),
Name: to.StringPtr("[parameters('nsgName')]"),
Type: to.StringPtr(resourceNetworkSecurityGroups),
Location: to.StringPtr("[variables('location')]"),
Properties: &Properties{
SecurityRules: &[]network.SecurityRule{
{
Name: to.StringPtr("AllowIPsToSshWinRMInbound"),
SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
Description: to.StringPtr("Allow inbound traffic from specified IP addresses"),
Protocol: network.SecurityRuleProtocolTCP,
Priority: to.Int32Ptr(100),
Access: network.SecurityRuleAccessAllow,
Direction: network.SecurityRuleDirectionInbound,
SourceAddressPrefixes: &srcIpAddresses,
SourcePortRange: to.StringPtr("*"),
DestinationAddressPrefix: to.StringPtr("VirtualNetwork"),
DestinationPortRange: to.StringPtr(strconv.Itoa(port)),
},
},
},
},
}
dependency := fmt.Sprintf("[concat('%s/', parameters('nsgName'))]", resourceNetworkSecurityGroups)
resourceId := fmt.Sprintf("[resourceId('%s', parameters('nsgName'))]", resourceNetworkSecurityGroups)
return resource, dependency, resourceId
}
// See https://github.com/Azure/azure-quickstart-templates for a extensive list of templates.
// Template to deploy a KeyVault.
@ -496,6 +585,9 @@ const BasicTemplate = `{
"virtualNetworkName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"vmSize": {
"type": "string"
},
@ -510,6 +602,7 @@ const BasicTemplate = `{
"networkInterfacesApiVersion": "2017-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"virtualNetworksApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"location": "[resourceGroup().location]",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -160,6 +163,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -158,6 +161,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -120,6 +123,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -174,6 +177,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -197,6 +200,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -190,6 +193,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -0,0 +1,212 @@
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"adminPassword": {
"type": "string"
},
"adminUsername": {
"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('publicIPAddressApiVersion')]",
"location": "[variables('location')]",
"name": "[parameters('publicIPAddressName')]",
"properties": {
"dnsSettings": {
"domainNameLabel": "[parameters('dnsNameForPublicIP')]"
},
"publicIPAllocationMethod": "[variables('publicIPAddressType')]"
},
"type": "Microsoft.Network/publicIPAddresses"
},
{
"apiVersion": "[variables('networkInterfacesApiVersion')]",
"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('apiVersion')]",
"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": "--test-ssh-authorized-key--",
"path": "[variables('sshKeyPath')]"
}
]
}
}
},
"storageProfile": {
"imageReference": {
"offer": "UbuntuServer",
"publisher": "Canonical",
"sku": "16.04",
"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('networkSecurityGroupsApiVersion')]",
"location": "[variables('location')]",
"name": "[parameters('nsgName')]",
"properties": {
"securityRules": [
{
"name": "AllowIPsToSshWinRMInbound",
"properties": {
"access": "Allow",
"description": "Allow inbound traffic from specified IP addresses",
"destinationAddressPrefix": "VirtualNetwork",
"destinationPortRange": "123",
"direction": "Inbound",
"priority": 100,
"protocol": "Tcp",
"sourceAddressPrefixes": [
"127.0.0.1",
"192.168.100.0/24"
],
"sourcePortRange": "*"
}
}
]
},
"type": "Microsoft.Network/networkSecurityGroups"
},
{
"apiVersion": "[variables('virtualNetworksApiVersion')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', parameters('nsgName'))]"
],
"location": "[variables('location')]",
"name": "[variables('virtualNetworkName')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetAddressPrefix')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('nsgName'))]"
}
}
}
]
},
"type": "Microsoft.Network/virtualNetworks"
}
],
"variables": {
"addressPrefix": "10.0.0.0/16",
"apiVersion": "2017-03-30",
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-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]",
"virtualNetworksApiVersion": "2017-04-01",
"vmStorageAccountContainerName": "images",
"vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
}
}

View File

@ -14,6 +14,9 @@
"nicName": {
"type": "string"
},
"nsgName": {
"type": "string"
},
"osDiskName": {
"type": "string"
},
@ -155,6 +158,7 @@
"location": "[resourceGroup().location]",
"managedDiskApiVersion": "2017-03-30",
"networkInterfacesApiVersion": "2017-04-01",
"networkSecurityGroupsApiVersion": "2019-04-01",
"publicIPAddressApiVersion": "2017-04-01",
"publicIPAddressType": "Dynamic",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",

View File

@ -210,3 +210,36 @@ func TestSharedImageGallery00(t *testing.T) {
t.Fatal(err)
}
}
// Linux build with Network Security Group
func TestNetworkSecurityGroup00(t *testing.T) {
testSubject, err := NewTemplateBuilder(BasicTemplate)
if err != nil {
t.Fatal(err)
}
err = testSubject.BuildLinux("--test-ssh-authorized-key--")
if err != nil {
t.Fatal(err)
}
err = testSubject.SetMarketPlaceImage("Canonical", "UbuntuServer", "16.04", "latest", compute.CachingTypesReadWrite)
if err != nil {
t.Fatal(err)
}
err = testSubject.SetNetworkSecurityGroup([]string{"127.0.0.1", "192.168.100.0/24"}, 123)
if err != nil {
t.Fatal(err)
}
doc, err := testSubject.ToJSON()
if err != nil {
t.Fatal(err)
}
err = approvaltests.VerifyJSONBytes(t, []byte(*doc))
if err != nil {
t.Fatal(err)
}
}

View File

@ -31,6 +31,7 @@ type TemplateParameters struct {
SubnetName *TemplateParameter `json:"subnetName,omitempty"`
TenantId *TemplateParameter `json:"tenantId,omitempty"`
VirtualNetworkName *TemplateParameter `json:"virtualNetworkName,omitempty"`
NsgName *TemplateParameter `json:"nsgName,omitempty"`
VMSize *TemplateParameter `json:"vmSize,omitempty"`
VMName *TemplateParameter `json:"vmName,omitempty"`
}

View File

@ -16,6 +16,7 @@ func TestTemplateParametersShouldHaveExpectedKeys(t *testing.T) {
StorageAccountBlobEndpoint: &TemplateParameter{Value: "sentinel"},
VMName: &TemplateParameter{Value: "sentinel"},
VMSize: &TemplateParameter{Value: "sentinel"},
NsgName: &TemplateParameter{Value: "sentinel"},
}
bs, err := json.Marshal(params)
@ -38,6 +39,7 @@ func TestTemplateParametersShouldHaveExpectedKeys(t *testing.T) {
"storageAccountBlobEndpoint",
"vmSize",
"vmName",
"nsgName",
}
for _, expectedKey := range expectedKeys {
@ -57,6 +59,7 @@ func TestParameterValuesShouldBeSet(t *testing.T) {
StorageAccountBlobEndpoint: &TemplateParameter{Value: "storageaccountblobendpoint00"},
VMName: &TemplateParameter{Value: "vmname00"},
VMSize: &TemplateParameter{Value: "vmsize00"},
NsgName: &TemplateParameter{Value: "nsgname00"},
}
bs, err := json.Marshal(params)

View File

@ -225,6 +225,13 @@
- `disk_caching_type` (string) - Specify the disk caching type. Valid values
are None, ReadOnly, and ReadWrite. The default value is ReadWrite.
- `allowed_inbound_ip_addresses` ([]string) - Specify the list of IP addresses and CIDR blocks that should be
allowed access to the VM. If provided, an Azure Network Security
Group will be created with corresponding rules and be bound to
the subnet of the VM.
Providing `allowed_inbound_ip_addresses` in combination with
`virtual_network_name` is not allowed.
- `async_resourcegroup_delete` (bool) - If you want packer to delete the
temporary resource group asynchronously set this value. It's a boolean
value and defaults to false. Important Setting this true means that