From 595b103bbeefd556f1a71ebf2b7650cc610cdf5e Mon Sep 17 00:00:00 2001 From: Sumit Kalra <44450797+sumit-kalra@users.noreply.github.com> Date: Tue, 8 Oct 2019 14:56:43 -0700 Subject: [PATCH] Adding NSG to the ARM deployment template when needed (#3) * Adding NSG to the ARM eployment template when needed * Adding tests and fixing bugs * Removing denyall rule * Fixing logic to determine which port to open * Fixing config description --- builder/azure/arm/azure_client.go | 7 + builder/azure/arm/config.go | 6 +- builder/azure/arm/config_test.go | 4 + builder/azure/arm/step_deploy_template.go | 6 + builder/azure/arm/template_factory.go | 8 + ..._factory_test.TestPlanInfo01.approved.json | 4 + ..._factory_test.TestPlanInfo02.approved.json | 4 + ...stVirtualMachineDeployment03.approved.json | 4 + ...stVirtualMachineDeployment04.approved.json | 4 + ...stVirtualMachineDeployment05.approved.json | 4 + ...stVirtualMachineDeployment06.approved.json | 4 + ...stVirtualMachineDeployment07.approved.json | 4 + ...stVirtualMachineDeployment08.approved.json | 4 + ...stVirtualMachineDeployment09.approved.json | 4 + ...stVirtualMachineDeployment10.approved.json | 4 + ...stVirtualMachineDeployment11.approved.json | 4 + ...stVirtualMachineDeployment12.approved.json | 4 + ...stVirtualMachineDeployment13.approved.json | 227 ++++++++++++++++++ builder/azure/arm/template_factory_test.go | 34 +++ builder/azure/arm/tempname.go | 2 + builder/azure/arm/tempname_test.go | 8 + builder/azure/common/template/template.go | 9 +- .../azure/common/template/template_builder.go | 103 +++++++- ...uilder_test.TestBuildLinux00.approved.json | 4 + ...uilder_test.TestBuildLinux01.approved.json | 4 + ...uilder_test.TestBuildLinux02.approved.json | 4 + ...lder_test.TestBuildWindows00.approved.json | 4 + ...lder_test.TestBuildWindows01.approved.json | 4 + ...lder_test.TestBuildWindows02.approved.json | 4 + ...t.TestNetworkSecurityGroup00.approved.json | 212 ++++++++++++++++ ...est.TestSharedImageGallery00.approved.json | 4 + .../common/template/template_builder_test.go | 33 +++ .../common/template/template_parameters.go | 1 + .../template/template_parameters_test.go | 3 + 34 files changed, 729 insertions(+), 10 deletions(-) create mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment13.approved.json create mode 100644 builder/azure/common/template/template_builder_test.TestNetworkSecurityGroup00.approved.json diff --git a/builder/azure/arm/azure_client.go b/builder/azure/arm/azure_client.go index ab4330e37..22acda3f6 100644 --- a/builder/azure/arm/azure_client.go +++ b/builder/azure/arm/azure_client.go @@ -37,6 +37,7 @@ type AzureClient struct { network.InterfacesClient network.SubnetsClient network.VirtualNetworksClient + network.SecurityGroupsClient compute.ImagesClient compute.VirtualMachinesClient common.VaultClient @@ -182,6 +183,12 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string azureClient.VirtualNetworksClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.VirtualNetworksClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.VirtualNetworksClient.UserAgent) + 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) diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index eef7599a0..bf072d5da 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -347,7 +347,9 @@ type Config struct { // allowed access to the VM. If provided, an Azure Network Security // Group will be created with corresponding rules and be bound to // the NIC attached to the VM. - AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses"` + // 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 @@ -363,6 +365,7 @@ type Config struct { tmpOSDiskName string tmpSubnetName string tmpVirtualNetworkName string + tmpNsgName string tmpWinRMCertificateUrl string // Authentication with the VM via SSH @@ -610,6 +613,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 } diff --git a/builder/azure/arm/config_test.go b/builder/azure/arm/config_test.go index d90e31f44..d541b2f9f 100644 --- a/builder/azure/arm/config_test.go +++ b/builder/azure/arm/config_test.go @@ -506,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) { diff --git a/builder/azure/arm/step_deploy_template.go b/builder/azure/arm/step_deploy_template.go index c20e4630d..759017526 100644 --- a/builder/azure/arm/step_deploy_template.go +++ b/builder/azure/arm/step_deploy_template.go @@ -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 { diff --git a/builder/azure/arm/template_factory.go b/builder/azure/arm/template_factory.go index 0401f9f9b..80dd296a5 100644 --- a/builder/azure/arm/template_factory.go +++ b/builder/azure/arm/template_factory.go @@ -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) diff --git a/builder/azure/arm/template_factory_test.TestPlanInfo01.approved.json b/builder/azure/arm/template_factory_test.TestPlanInfo01.approved.json index 392dc0ec9..30ede3ae4 100644 --- a/builder/azure/arm/template_factory_test.TestPlanInfo01.approved.json +++ b/builder/azure/arm/template_factory_test.TestPlanInfo01.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestPlanInfo02.approved.json b/builder/azure/arm/template_factory_test.TestPlanInfo02.approved.json index b29616711..657af585d 100644 --- a/builder/azure/arm/template_factory_test.TestPlanInfo02.approved.json +++ b/builder/azure/arm/template_factory_test.TestPlanInfo02.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment03.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment03.approved.json index 463a9e473..cda8c56dc 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment03.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment03.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment04.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment04.approved.json index ee78c0825..8c922bfa5 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment04.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment04.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment05.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment05.approved.json index 51301ea4e..9e66583fb 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment05.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment05.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment06.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment06.approved.json index b7e8d9ba5..ce8b43ed8 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment06.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment06.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment07.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment07.approved.json index 7208af852..66cf47288 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment07.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment07.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment08.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment08.approved.json index d7f3aa148..cdabe3c93 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment08.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment08.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment09.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment09.approved.json index 784e7ce4d..5af5b01bc 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment09.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment09.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment10.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment10.approved.json index 0c7903a3d..a9c3d267c 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment10.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment10.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment11.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment11.approved.json index bf94c8581..5ac3905c0 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment11.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment11.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment12.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment12.approved.json index dc1ec1509..4339b1864 100644 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment12.approved.json +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment12.approved.json @@ -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')]", diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment13.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment13.approved.json new file mode 100644 index 000000000..9127c3bac --- /dev/null +++ b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment13.approved.json @@ -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'))]" + } +} \ 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 382a0b490..069415893 100644 --- a/builder/azure/arm/template_factory_test.go +++ b/builder/azure/arm/template_factory_test.go @@ -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()) diff --git a/builder/azure/arm/tempname.go b/builder/azure/arm/tempname.go index b5289d450..45fb97e63 100644 --- a/builder/azure/arm/tempname.go +++ b/builder/azure/arm/tempname.go @@ -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() diff --git a/builder/azure/arm/tempname_test.go b/builder/azure/arm/tempname_test.go index 0b3608e18..e6a6fd236 100644 --- a/builder/azure/arm/tempname_test.go +++ b/builder/azure/arm/tempname_test.go @@ -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) + } } diff --git a/builder/azure/common/template/template.go b/builder/azure/common/template/template.go index 6c4429c34..b90d0104b 100644 --- a/builder/azure/common/template/template.go +++ b/builder/azure/common/template/template.go @@ -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 { diff --git a/builder/azure/common/template/template_builder.go b/builder/azure/common/template/template_builder.go index 188fdaf7b..1e1eb53d4 100644 --- a/builder/azure/common/template/template_builder.go +++ b/builder/azure/common/template/template_builder.go @@ -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')]", diff --git a/builder/azure/common/template/template_builder_test.TestBuildLinux00.approved.json b/builder/azure/common/template/template_builder_test.TestBuildLinux00.approved.json index b1550d5b5..4ba861566 100644 --- a/builder/azure/common/template/template_builder_test.TestBuildLinux00.approved.json +++ b/builder/azure/common/template/template_builder_test.TestBuildLinux00.approved.json @@ -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')]", diff --git a/builder/azure/common/template/template_builder_test.TestBuildLinux01.approved.json b/builder/azure/common/template/template_builder_test.TestBuildLinux01.approved.json index c8e1455e5..5e5b2ea05 100644 --- a/builder/azure/common/template/template_builder_test.TestBuildLinux01.approved.json +++ b/builder/azure/common/template/template_builder_test.TestBuildLinux01.approved.json @@ -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')]", diff --git a/builder/azure/common/template/template_builder_test.TestBuildLinux02.approved.json b/builder/azure/common/template/template_builder_test.TestBuildLinux02.approved.json index a27074962..b3a2e1e73 100644 --- a/builder/azure/common/template/template_builder_test.TestBuildLinux02.approved.json +++ b/builder/azure/common/template/template_builder_test.TestBuildLinux02.approved.json @@ -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')]", diff --git a/builder/azure/common/template/template_builder_test.TestBuildWindows00.approved.json b/builder/azure/common/template/template_builder_test.TestBuildWindows00.approved.json index 13a581f92..797081807 100644 --- a/builder/azure/common/template/template_builder_test.TestBuildWindows00.approved.json +++ b/builder/azure/common/template/template_builder_test.TestBuildWindows00.approved.json @@ -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')]", diff --git a/builder/azure/common/template/template_builder_test.TestBuildWindows01.approved.json b/builder/azure/common/template/template_builder_test.TestBuildWindows01.approved.json index 3add40537..a7230706d 100644 --- a/builder/azure/common/template/template_builder_test.TestBuildWindows01.approved.json +++ b/builder/azure/common/template/template_builder_test.TestBuildWindows01.approved.json @@ -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')]", diff --git a/builder/azure/common/template/template_builder_test.TestBuildWindows02.approved.json b/builder/azure/common/template/template_builder_test.TestBuildWindows02.approved.json index 7c44163c3..ad8d94bfb 100644 --- a/builder/azure/common/template/template_builder_test.TestBuildWindows02.approved.json +++ b/builder/azure/common/template/template_builder_test.TestBuildWindows02.approved.json @@ -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')]", diff --git a/builder/azure/common/template/template_builder_test.TestNetworkSecurityGroup00.approved.json b/builder/azure/common/template/template_builder_test.TestNetworkSecurityGroup00.approved.json new file mode 100644 index 000000000..b318164a3 --- /dev/null +++ b/builder/azure/common/template/template_builder_test.TestNetworkSecurityGroup00.approved.json @@ -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'))]" + } +} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestSharedImageGallery00.approved.json b/builder/azure/common/template/template_builder_test.TestSharedImageGallery00.approved.json index c180e1e16..49f2a72a4 100644 --- a/builder/azure/common/template/template_builder_test.TestSharedImageGallery00.approved.json +++ b/builder/azure/common/template/template_builder_test.TestSharedImageGallery00.approved.json @@ -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')]", diff --git a/builder/azure/common/template/template_builder_test.go b/builder/azure/common/template/template_builder_test.go index 482107c34..b39af103f 100644 --- a/builder/azure/common/template/template_builder_test.go +++ b/builder/azure/common/template/template_builder_test.go @@ -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) + } +} diff --git a/builder/azure/common/template/template_parameters.go b/builder/azure/common/template/template_parameters.go index 65bc55e75..74b0562a7 100644 --- a/builder/azure/common/template/template_parameters.go +++ b/builder/azure/common/template/template_parameters.go @@ -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"` } diff --git a/builder/azure/common/template/template_parameters_test.go b/builder/azure/common/template/template_parameters_test.go index 9dbb9f243..7a321128f 100644 --- a/builder/azure/common/template/template_parameters_test.go +++ b/builder/azure/common/template/template_parameters_test.go @@ -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)