Skip to content

Commit

Permalink
Merge pull request #629 from rguthriemsft/pull-request-619
Browse files Browse the repository at this point in the history
feat: adding Azure NSG module
  • Loading branch information
yorinasub17 authored Sep 28, 2020
2 parents 2cc5a98 + 960fdd0 commit 08383ea
Show file tree
Hide file tree
Showing 9 changed files with 875 additions and 0 deletions.
39 changes: 39 additions & 0 deletions examples/azure/terraform-azure-nsg-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Terraform Azure NSG Example

This folder contains a simple Terraform module that deploys resources in [Azure](https://azure.microsoft.com/) to demonstrate how you can use Terratest to write automated tests for your Azure Terraform code. This module deploys the following:

* A [Virtual Machine](https://azure.microsoft.com/en-us/services/virtual-machines/) that gives the module the following:
* [Virtual Machine](https://docs.microsoft.com/en-us/azure/virtual-machines/) with the value specified in the `vm_name` variable along with a random value for the `postfix` variable (set from test code).
* A [Network Security Group](https://docs.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview) created with a single custom rule to allow SSH (port 22) with the nsg name specified in the `nsg_name` variable along with a random value for the `postfix` variable (set from test code).

Check out [test/azure/terraform_azure_nsg_example_test.go](/test/azure/terraform_azure_nsg_example_test.go) to see how you can write
automated tests for this module.

Note that the resources deployed in this module don't actually do anything; it just runs the resources for
demonstration purposes.

**WARNING**: This module and the automated tests for it deploy real resources into your Azure account which can cost you
money. The resources are all part of the [Azure Free Account](https://azure.microsoft.com/en-us/free/), so if you haven't used that up,
it should be free, but you are completely responsible for all Azure charges.

## Running this module manually

1. Sign up for [Azure](https://azure.microsoft.com/)
1. Configure your Azure credentials using one of the [supported methods for Azure CLI
tools](https://docs.microsoft.com/en-us/cli/azure/azure-cli-configuration?view=azure-cli-latest)
1. Install [Terraform](https://www.terraform.io/) and make sure it's on your `PATH`
1. Ensure [environment variables](../README.md#review-environment-variables) are available
1. Run `terraform init`
1. Run `terraform apply`
1. When you're done, run `terraform destroy`

## Running automated tests against this module

1. Sign up for [Azure](https://azure.microsoft.com/)
1. Configure your Azure credentials using one of the [supported methods for Azure CLI
tools](https://docs.microsoft.com/en-us/cli/azure/azure-cli-configuration?view=azure-cli-latest)
1. Install [Terraform](https://www.terraform.io/) and make sure it's on your `PATH`
1. Configure your Terratest [Go test environment](../README.md)
1. `cd test/azure`
1. `go build terraform_azure_nsg_example_test.go`
1. `go test -v -run TestTerraformAzureNsgExample`
156 changes: 156 additions & 0 deletions examples/azure/terraform-azure-nsg-example/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY AN AZURE VM ALONG WITH AN EXAMPLE NETWORK SECURITY GROUP (NSG)
# This is an example of how to deploy an NSG along with the minimum networking resources
# to support a basic virtual machine.
# ---------------------------------------------------------------------------------------------------------------------
# See test/azure/terraform_azure_nsg_example_test.go for how to write automated tests for this code.
# ---------------------------------------------------------------------------------------------------------------------

provider "azurerm" {
version = "~>2.20"
features {}
}

# ---------------------------------------------------------------------------------------------------------------------
# PIN TERRAFORM VERSION TO >= 0.12
# The examples have been upgraded to 0.12 syntax
# ---------------------------------------------------------------------------------------------------------------------

terraform {
required_version = ">= 0.12"
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY A RESOURCE GROUP
# See test/terraform_azure_nsg_example_test.go for how to write automated tests for this code.
# ---------------------------------------------------------------------------------------------------------------------

resource "azurerm_resource_group" "nsg_rg" {
name = "${var.resource_group_name}-${var.postfix}"
location = var.location
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY VIRTUAL NETWORK RESOURCES
# ---------------------------------------------------------------------------------------------------------------------

resource "azurerm_virtual_network" "vnet" {
name = "${var.vnet_name}-${var.postfix}"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.nsg_rg.location
resource_group_name = azurerm_resource_group.nsg_rg.name
}

resource "azurerm_subnet" "internal" {
name = "${var.subnet_name}-${var.postfix}"
resource_group_name = azurerm_resource_group.nsg_rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.17.0/24"]
}

resource "azurerm_network_interface" "main" {
name = "${var.vm_nic_name}-${var.postfix}"
location = azurerm_resource_group.nsg_rg.location
resource_group_name = azurerm_resource_group.nsg_rg.name

ip_configuration {
name = "${var.vm_nic_ip_config_name}-${var.postfix}"
subnet_id = azurerm_subnet.internal.id
private_ip_address_allocation = "Dynamic"
}
}

resource "azurerm_network_security_group" "nsg_example" {
name = "${var.nsg_name}-${var.postfix}"
location = azurerm_resource_group.nsg_rg.location
resource_group_name = azurerm_resource_group.nsg_rg.name
}

resource "azurerm_network_interface_security_group_association" "main" {
network_interface_id = azurerm_network_interface.main.id
network_security_group_id = azurerm_network_security_group.nsg_example.id
}

resource "azurerm_network_security_rule" "allow_ssh" {
name = "${var.nsg_ssh_rule_name}-${var.postfix}"
description = "${var.nsg_ssh_rule_name}-${var.postfix}"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = 22
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.nsg_rg.name
network_security_group_name = azurerm_network_security_group.nsg_example.name
}

resource "azurerm_network_security_rule" "block_http" {
name = "${var.nsg_http_rule_name}-${var.postfix}"
description = "${var.nsg_http_rule_name}-${var.postfix}"
priority = 200
direction = "Inbound"
access = "Deny"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = 80
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.nsg_rg.name
network_security_group_name = azurerm_network_security_group.nsg_example.name
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY A VIRTUAL MACHINE RUNNING UBUNTU
# This VM does not actually do anything and is the smallest size VM available with an Ubuntu image
# ---------------------------------------------------------------------------------------------------------------------

resource "azurerm_virtual_machine" "vm_example" {
name = "${var.vm_name}-${var.postfix}"
location = azurerm_resource_group.nsg_rg.location
resource_group_name = azurerm_resource_group.nsg_rg.name
network_interface_ids = [azurerm_network_interface.main.id]
vm_size = var.vm_size
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true

storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}

storage_os_disk {
name = "${var.os_disk_name}-${var.postfix}"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}

os_profile {
computer_name = var.hostname
admin_username = var.username
admin_password = random_password.nsg.result
}

os_profile_linux_config {
disable_password_authentication = false
}

# Correctly setup the dependencies to make sure resources are correctly destroyed.
depends_on = [
azurerm_network_interface_security_group_association.main
]
}

resource "random_password" "nsg" {
length = 16
override_special = "-_%@"
min_upper = "1"
min_lower = "1"
min_numeric = "1"
min_special = "1"
}

19 changes: 19 additions & 0 deletions examples/azure/terraform-azure-nsg-example/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
output "vm_name" {
value = azurerm_virtual_machine.vm_example.name
}

output "resource_group_name" {
value = azurerm_resource_group.nsg_rg.name
}

output "nsg_name" {
value = azurerm_network_security_group.nsg_example.name
}

output "ssh_rule_name" {
value = azurerm_network_security_rule.allow_ssh.name
}

output "http_rule_name" {
value = azurerm_network_security_rule.block_http.name
}
115 changes: 115 additions & 0 deletions examples/azure/terraform-azure-nsg-example/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# ---------------------------------------------------------------------------------------------------------------------
# ENVIRONMENT VARIABLES
# Define these secrets as environment variables
# ---------------------------------------------------------------------------------------------------------------------

# ARM_CLIENT_ID
# ARM_CLIENT_SECRET
# ARM_SUBSCRIPTION_ID
# ARM_TENANT_ID

# ---------------------------------------------------------------------------------------------------------------------
# REQUIRED PARAMETERS
# You must provide a value for each of these parameters.
# ---------------------------------------------------------------------------------------------------------------------

# ---------------------------------------------------------------------------------------------------------------------
# OPTIONAL PARAMETERS
# These parameters have reasonable defaults.
# ---------------------------------------------------------------------------------------------------------------------

variable "postfix" {
description = "Random postfix string used for each test run; set from the test file at runtime."
type = string
default = "qwefgt"
}

variable "resource_group_name" {
description = "Name for the resource group holding resources for this example"
type = string
default = "terratest-nsg-rg"
}

variable "location" {
description = "The Azure region in which to deploy this sample"
type = string
default = "East US"
}

variable "vnet_name" {
description = "Name for the example virtual network"
type = string
default = "vnet01"
}

variable "subnet_name" {
description = "Name for the example virtual network default subnet"
type = string
default = "subnet01"
}

variable "vm_nic_name" {
description = "Name for the NIC attached to our example VM."
type = string
default = "nic01"
}

variable "vm_nic_ip_config_name" {
description = "Name for the NIC IP configuration attached to our example VM."
type = string
default = "nic_ipconfig01"
}

variable "nsg_name" {
description = "Name for the example NSG."
type = string
default = "nsg01"
}

variable "nsg_ssh_rule_name" {
description = "Name for the example SSH NSG rule used in this example."
type = string
default = "nsgrule01"
}

variable "nsg_http_rule_name" {
description = "Name for the example HTTP NSG rule used in this example."
type = string
default = "nsgrule02"
}

variable "vm_name" {
description = "The name of the VM used in this example"
type = string
default = "vm01"
}

variable "vm_size" {
description = "The size of the VM to deploy"
type = string
default = "Standard_B1s"
}

variable "hostname" {
description = "The hostname of the new VM to be configured"
type = string
default = "vm01"
}

variable "os_disk_name" {
description = "The of the OS disk to use on our example VM."
type = string
default = "osdisk01"
}

variable "username" {
description = "The username to be provisioned into your VM"
type = string
default = "testadmin"
}

variable "password" {
description = "The password to configure for SSH access"
type = string
default = "!@#PasswordSetInCode!@#"
}
16 changes: 16 additions & 0 deletions modules/azure/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,19 @@ func getTargetAzureResourceGroupName(resourceGroupName string) (string, error) {

return resourceGroupName, nil
}

// safePtrToString converts a string pointer to a non-pointer string value, or to "" if the pointer is nil.
func safePtrToString(raw *string) string {
if raw == nil {
return ""
}
return *raw
}

// safePtrToInt32 converts a int32 pointer to a non-pointer int32 value, or to 0 if the pointer is nil.
func safePtrToInt32(raw *int32) int32 {
if raw == nil {
return 0
}
return *raw
}
25 changes: 25 additions & 0 deletions modules/azure/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -74,3 +75,27 @@ func TestGetTargetAzureResourceGroupName(t *testing.T) {
})
}
}

func TestSafePtrToString(t *testing.T) {
// When given a nil, should always return an empty string
var nilPtr *string = nil
nilResult := safePtrToString(nilPtr)
assert.Equal(t, "", nilResult)

// When given a string, should just de-ref and return
stringPtr := "Test"
stringResult := safePtrToString(&stringPtr)
assert.Equal(t, "Test", stringResult)
}

func TestSafePtrToInt32(t *testing.T) {
// When given a nil, should always return an zero value int32
var nilPtr *int32 = nil
nilResult := safePtrToInt32(nilPtr)
assert.Equal(t, int32(0), nilResult)

// When given a string, should just de-ref and return
intPtr := int32(42)
intResult := safePtrToInt32(&intPtr)
assert.Equal(t, int32(42), intResult)
}
Loading

0 comments on commit 08383ea

Please sign in to comment.