Skip to content

This project is a Terraform module that creates an Avi (NSX ALB) Controller on Azure. This module can create all of the day 0 Cloud prerequisites (IAM, networks, Firewall policy), initial Avi configuration, and additional configuration for GSLB, DNS, and IPAM/DNS profiles.

License

Notifications You must be signed in to change notification settings

vmware/terraform-azurerm-avi-alb-deployment-azure

NSX ALB - AVI Controller Deployment on Azure Terraform module

This Terraform module creates and configures an AVI (NSX Advanced Load Balancer) Controller on Azure Avi - Single Site Deployment Avi - 2 Site GSLB Deployment

Module Functions

The module is meant to be modular and can create all or none of the prerequisite resources needed for the AVI Azure Deployment including:

  • VNET and Subnet for the Controller and SEs (configured with create_networking variable)
  • VNET Peering (configured with the configure_vnet_peering variable)
  • Azure Active Directory Application, Service Principal, Custom Role, and Role Assignment for the Controller (configured with create_iam variable)
  • Network Security Groups for AVI Controller and SE communication (future work)
  • Azure Virtual Machine Instance using an official AVI Azure Marketplace image
  • High Availability AVI Controller Deployment (configured with controller_ha variable)

During the creation of the Controller instance the following initialization steps are performed:

  • Copy Ansible playbook to controller using the assigned public IP
  • Run Ansible playbook to configure initial settings and Azure Full Access Cloud

The Ansible playbook can optionally add these configurations:

  • Create DNS Profile (configured with the configure_dns_profile variable)
  • Create Avi DNS Virtual Service (configured with the configure_dns_vs variable)
  • Configure GSLB (configured with the configure_gslb variable)

Environment Requirements

Azure Prequisites

The following are Azure prerequisites for running this module:

  • Subscription created
  • Account with either Contributor role (if create_iam is false) or Owner (if create_iam is true)

Azure Provider

For authenticating to the Azure Provider the instructions found here should be followed - https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs

The azurerm provider block may need to be configured for setting addtional settings depending on the environment. The settings as shown in the example below have been tested sucessfully:

provider "azurerm" {
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
  skip_provider_registration = "true"
}

Avi Controller Image

This module will use the Azure Marketplace for deploying the Avi image. The terms of the image and more information can be found in this link - https://azuremarketplace.microsoft.com/en-us/marketplace/apps/avi-networks.avi-vantage-adc. By default the marketplace agreement is accepted with the create_marketplace_agreement variable.

Host OS

The following packages must be installed on the host operating system:

  • curl

Usage

This is an example of an HA controller deployment that creates the controller and all other requisite Azure resources.

terraform {
  backend "local" {
  }
}
provider "azurerm" {
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
  skip_provider_registration = "true"
}
module "avi_controller_azure" {
  source  = "vmware/avi-alb-deployment-azure/azurerm"
  version = "1.0.x"

  region                       = "westus2"
  name_prefix                  = "companyname"
  controller_default_password  = "Value Redacted and available within the VMware Customer Portal"
  controller_password          = "<newpassword>"
  create_networking            = true
  create_iam                   = true
  controller_ha                = true
  controller_public_address    = true
  custom_tags                  = { "Role" : "Avi-Controller", "Owner" : "[email protected]", "Department" : "IT" }
  se_ha_mode                   = "active/active"
  vnet_address_space           = "10.255.0.0/16"
  avi_subnet                   = "10.255.0.0/24"
}
output "controller_info" { 
  value = module.avi_controller_azure.controllers
}

GSLB Deployment

For GSLB to be configured successfully the configure_gslb and configure_dns_vs variables must be configured. By default a new Service Engine Group (g-dns) and user (gslb-admin) will be created for the configuration.

The following is a description of the configure_gslb variable parameters and their usage:

Parameter Description Type
enabled Must be set to "true" for Active GSLB sites bool
leader Must be set to "true" for only one GSLB site that will be the leader bool
site_name Name of the GSLB site string
domains List of GSLB domains that will be configured list(string)
create_se_group Determines whether a g-dns SE group will be created bool
se_size The Azure VM Size used for the Avi Service Engines string
additional_sites Additional sites that will be configured. This parameter should only be set for the primary GSLB site string

The example below shows a GSLB deployment with 2 regions utilized. VNET Peering is configured (with configure_vnet_peering variable) between the two newly created Avi VNETs so that the controllers can communicate.

terraform {
  backend "local" {
  }
}
provider "azurerm" {
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
  skip_provider_registration = "true"
}
module "avi_controller_azure_westus2" {
  source    = "vmware/avi-alb-deployment-azure/azurerm"
  version   = "1.0.x"

  region                      = "westus2"
  name_prefix                 = "companyname"
  controller_default_password = "Value Redacted and available within the VMware Customer Portal"
  controller_password         = "<newpassword>"
  create_networking           = true
  configure_vnet_peering         = { enabled = true, global_peering = true, resource_group = "rg-<name_prefix>-avi-<region>", vnet_name = "<name_prefix>-avi-vnet-<region>" }
  create_iam                  = true
  controller_ha               = true
  controller_public_address   = true
  custom_tags                 = { "Role" : "Avi-Controller", "Owner" : "[email protected]", "Department" : "IT" }
  se_ha_mode                  = "active/active"
  vnet_address_space          = "10.251.0.0/16"
  avi_subnet                  = "10.251.0.0/24"
  configure_dns_profile       = { "enabled" = "true", usable_domains = ["west2.avidemo.net"] }
  configure_dns_vs            = { "enabled" = "true", allocate_public_ip = "false" }
  configure_gslb              = {"enabled = "true", site_name = "West2" }
}
module "avi_controller_azure_eastus2" {
  source  = "vmware/avi-alb-deployment-azure/azurerm"
  version = "1.0.x"

  region                          = "eastus2"
  name_prefix                     = "companyname"
  controller_default_password     = "Value Redacted and available within the VMware Customer Portal"
  controller_password             = "<newpassword>"
  create_networking               = true
  configure_vnet_peering             = { enabled = true, global_peering = true, resource_group = "rg-<name_prefix>-avi-<region>", vnet_name = "<name_prefix>-avi-vnet-<region>" }
  create_iam                      = true
  controller_ha                   = true
  controller_public_address       = true
  custom_tags                     = { "Role" : "Avi-Controller", "Owner" : "[email protected]", "Department" : "IT" }
  se_ha_mode                      = "active/active"
  vnet_address_space              = "10.252.0.0/16"
  avi_subnet                      = "10.252.0.0/24"
  configure_dns_profile       = { "enabled" = "true", usable_domains = ["east2.avidemo.net"] }
  configure_dns_vs            = { "enabled" = "true", allocate_public_ip = "false" }
  configure_gslb              = {"enabled = "true", leader = "true", site_name = "East2", domains = ["gslb.avidemo.net"], additional_sites = [{name = "West2", ip_address_list = module.avi_controller_azure_westus2.controllers[*].private_ip_address }] }
}
output "eastus2_controller_info" {
  value = module.avi_controller_azure_eastus2.controllers
}
output "westus2_controller_info" {
  value = module.avi_controller_azure_westus2.controllers
}

Private IP Controller Deployment

For a controller deployment that is only accesible via private IPs the controller_public_address should be set to false to enable this connectivity. In addition it is recommended to either configure VNET peering with the configure_vnet_peering or manually create resource group and VNET/Subnets and specify them with the create-networking = false, custom_controller_resource_group, custom_vnet_name, and custom_subnet_name variables. This is needed so that the controller IPs can be reached by the Ansible provisioner.

Day 1 Ansible Configuration and Avi Resource Cleanup

The module copies and runs an Ansible play for configuring the initial day 1 Avi config. The plays listed below can be reviewed by connecting to the Avi Controller by SSH. In an HA setup the first controller will have these files.

avi-controller-azure-all-in-one-play.yml

This play will configure the Avi Cloud, Network, IPAM/DNS profiles, DNS Virtual Service, GSLB depending on the variables used. The initial run of this play will output into the ansible-playbook.log file which can be reviewed to determine what tasks were ran.

Example run (appropriate variable values should be used):

~$ ansible-playbook avi-controller-azure-all-in-one-play.yml -e password=${var.controller_password} -e azure_app_id=${var.controller_az_app_id} -e azure_auth_token=${var.controller_az_client_secret} -e azure_tenant_id=${data.azurerm_subscription.current.tenant_id} > ansible-playbook-run.log

avi-upgrade.yml

This play will upgrade or patch the Avi Controller and SEs depending on the variables used. When ran this play will output into the ansible-playbook.log file which can be reviewed to determine what tasks were ran. This play can be ran during the initial Terraform deployment with the avi_upgrade variable as shown in the example below:

avi_upgrade = { enabled = "true", upgrade_type = "patch", upgrade_file_uri = "URL Copied From portal.avipulse.vmware.com"}

An full version upgrade can be done by changing changing the upgrade_type to "system". It is recommended to run this play in a lower environment before running in a production environment and is not recommended for a GSLB setup at this time.

Example run (appropriate variable values should be used):

~$ ansible-playbook avi-upgrade.yml -e password=${var.controller_password} -e upgrade_type=${var.avi_upgrade.upgrade_type} -e upgrade_file_uri=${var.avi_upgrade.upgrade_file_uri} > ansible-playbook-run.log

avi-cloud-services-registration.yml

This play will register the Controller with Avi Cloud Services. This can be done to enable centralized licensing, live security threat updates, and proactive support. When ran this play will output into the ansible-playbook.log file which can be reviewed to determine what tasks were ran. This play can be ran during the initial Terraform deployment with the register_controller variable as shown in the example below:

register_controller = { enabled = "true", jwt_token = "TOKEN", email = "EMAIL", organization_id = "LONG_ORG_ID" }

The organization_id can be found as the Long Organization ID field from https://console.cloud.vmware.com/csp/gateway/portal/#/organization/info.

The jwt_token can be retrieved at https://portal.avipulse.vmware.com/portal/controller/auth/cspctrllogin.

Example run (appropriate variable values should be used):

~$ ansible-playbook avi-cloud-services-registration.yml -e password=${var.controller_password} -e register_controller.jwt_token=${var.register_controller.jwt_token} > ansible-playbook-run.log

avi-cleanup.yml

This play will disable all Virtual Services, delete all existing Avi service engines, and de-register the controller from Cloud Services. This playbook should be ran before deleting the controller with terraform destroy to clean up the resources created by the Avi Controller. Note that additional items created by the controller may be created and need to be manually removed.

Example run (appropriate variable values should be used and -e register_controller.jwt_token is only needed when register_controller.enabled is set to true):

~$ ansible-playbook avi-cleanup.yml -e password=${var.controller_password} -e register_controller.jwt_token=${var.register_controller.jwt_token}

Contributing

The terraform-azurerm-avi-alb-deployment-azure project team welcomes contributions from the community. Before you start working with this project please read and sign our Contributor License Agreement (https://cla.vmware.com/cla/1/preview). If you wish to contribute code and you have not signed our Contributor Licence Agreement (CLA), our bot will prompt you to do so when you open a Pull Request. For any questions about the CLA process, please refer to our FAQ. For more detailed information, refer to CONTRIBUTING.md.

Requirements

Name Version
terraform >= 1.3.0
azuread ~> 2.30.0
azurerm ~> 3.29.1
null ~> 3.2.0
random ~> 3.4.3

Providers

Name Version
azuread 2.26.1
azurerm 3.14.0
null 3.1.1
random 3.3.2

Modules

No modules.

Resources

Name Type
azuread_application.avi resource
azuread_application_password.avi resource
azuread_service_principal.avi resource
azurerm_linux_virtual_machine.avi_controller resource
azurerm_marketplace_agreement.avi resource
azurerm_network_interface.avi resource
azurerm_network_interface_security_group_association.controller resource
azurerm_network_security_group.avi_controller_mgmt resource
azurerm_public_ip.avi resource
azurerm_resource_group.avi resource
azurerm_role_assignment.contributor resource
azurerm_role_assignment.custom_controller resource
azurerm_role_definition.custom_controller resource
azurerm_subnet.avi resource
azurerm_virtual_network.avi resource
azurerm_virtual_network_peering.avi resource
null_resource.ansible_provisioner resource
random_uuid.role_definition resource
azuread_client_config.current data source
azurerm_resource_group.custom data source
azurerm_subnet.custom data source
azurerm_subscription.current data source
azurerm_virtual_network.custom data source

Inputs

Name Description Type Default Required
avi_subnet The CIDR that will be used for creating a subnet in the Avi VNET string "10.255.0.0/24" no
avi_upgrade This variable determines if a patch upgrade is performed after install. The enabled key should be set to true and the url from the Avi Cloud Services portal for the should be set for the upgrade_file_uri key. Valid upgrade_type values are patch or system
object({
enabled = bool,
upgrade_type = string,
upgrade_file_uri = string
})
{
"enabled": "false",
"upgrade_file_uri": "",
"upgrade_type": "patch"
}
no
avi_version The major and minor version of the AVI Controller version that will be deployed. 20.1, 21.1, or 22.1 are valid values. string "21.1" no
ca_certificates Import one or more Root or Intermediate Certificate Authority SSL certificates for the controller. The certificate must be in the PEM format and base64 encoded without line breaks. An example command for generating the proper format is 'base64 -w 0 ca.pem > ca.base64'
list(object({
name = string,
certificate = string
}))
[
{
"certificate": "",
"name": ""
}
]
no
cluster_ip Sets the IP address of the Avi Controller cluster. This address must be in the same subnet as the Avi Controller VMs. string null no
configure_controller Configure the Avi Cloud via Ansible after controller deployment. If not set to true this must be done manually with the desired config bool "true" no
configure_dns_profile Configure a DNS Profile for DNS Record Creation for Virtual Services. The usable_domains is a list of domains that Avi will be the Authoritative Nameserver for and NS records may need to be created pointing to the Avi Service Engine addresses. Supported profiles for the type parameter are AWS or AVI
object({
enabled = bool,
type = optional(string, "AVI"),
usable_domains = list(string),
ttl = optional(string, "30"),
aws_profile = optional(object({ iam_assume_role = string, region = string, vpc_id = string, access_key_id = string, secret_access_key = string }))
})
{
"enabled": false,
"type": "AVI",
"usable_domains": []
}
no
configure_dns_vs Create Avi DNS Virtual Service. The subnet_name parameter must be an existing AWS Subnet. If the allocate_public_ip parameter is set to true a EIP will be allocated for the VS. The VS IP address will automatically be allocated via the AWS IPAM
object({
enabled = bool,
allocate_public_ip = bool
})
{
"allocate_public_ip": "false",
"enabled": "false"
}
no
configure_gslb Configures GSLB. In addition the configure_dns_vs variable must also be set for GSLB to be configured. See the GSLB Deployment README section for more information.
object({
enabled = bool,
leader = optional(bool, false),
site_name = string,
domains = optional(list(string)),
create_se_group = optional(bool, true),
se_size = optional(string, "Standard_F2s"),
additional_sites = optional(list(object({ name = string, ip_address_list = list(string) })))
})
{
"domains": [
""
],
"enabled": "false",
"site_name": ""
}
no
configure_vnet_peering This variable is used to peer the created VNET with another VNET
object({
enabled = bool,
resource_group = string,
vnet_name = string,
global_peering = bool
})
{
"enabled": false,
"global_peering": true,
"resource_group": "",
"vnet_name": ""
}
no
controller_az_app_id If the create_iam variable is set to false, this is the Azure Application ID that the Avi Controller will use to create Azure resources string null no
controller_az_client_secret If the create_iam variable is set to false, this is the Azure Client Secret that the Avi Controller will use to create Azure resources string null no
controller_default_password This is the default password for the AVI controller image and can be found in the image download page. string n/a yes
controller_disk_size The root disk size for the AVI controller number 128 no
controller_disk_type The Type of Storage Account which should back this the Internal OS Disk. Possible values are Premium_LRS, Standard_LRS, StandardSSD_LRS string "Premium_LRS" no
controller_ha If true a HA controller cluster is deployed and configured bool "false" no
controller_password The password that will be used authenticating with the AVI Controller. This password be a minimum of 8 characters and contain at least one each of uppercase, lowercase, numbers, and special characters string n/a yes
controller_public_address This variable controls if the Controller has a Public IP Address. When set to false the Ansible provisioner will connect to the private IP of the Controller. bool "false" no
controller_vm_size The VM size for the AVI Controller string "Standard_D8s_v3" no
create_firewall_rules This variable controls the Network Security Group (NSG) rule creation for the Avi Controllers. When set to false the necessary firewall rules must be in place before the deployment bool "true" no
create_iam Create Azure AD Application and Service Principal, Controller Custom Role, and Application Role Binding for Avi Azure Full Access Cloud bool "false" no
create_marketplace_agreement If set to true the user agrees to the terms and conditions for the Avi Marketplace image as found here https://azuremarketplace.microsoft.com/en-us/marketplace/apps/avi-networks.avi-vantage-adc. When multiple instances of this module are used only 1 should have this value set to true to prevent duplicate deployments bool "true" no
create_networking This variable controls the VNET and subnet creation for the AVI Controller. When set to false the custom_controller_resource_group, custom_vnet_name and custom_subnet_name variables must be configured. bool "true" no
create_resource_group If true a Resource Group is created and used for the AVI Controllers and Service Engines bool "true" no
custom_controller_resource_group This field can be used to specify an existing Resource Group for AVI Controllers. The create_resource_group variable must also be set to false for this resource group to be used. string "" no
custom_se_resource_group This field can be used to specify an existing Resource Group for Service Engines. string null no
custom_subnet_name This field can be used to specify a list of existing VNET Subnet for the controller and SEs. The create_networking variable must also be set to false for this network to be used. string "" no
custom_tags Custom tags added to Resources created by the module map(string) {} no
custom_vnet_name This field can be used to specify an existing VNET for the controller and SEs. The create_networking variable must also be set to false for this network to be used. string "" no
dns_search_domain The optional DNS search domain that will be used by the controller string null no
dns_servers The optional DNS servers that will be used for local DNS resolution by the controller. The dns_search_domain variable must also be specified if this variable is set. Example ["8.8.4.4", "8.8.8.8"] list(string) null no
email_config The Email settings that will be used for sending password reset information or for trigged alerts. The default setting will send emails directly from the Avi Controller
object({
smtp_type = string,
from_email = string,
mail_server_name = string,
mail_server_port = string,
auth_username = string,
auth_password = string
})
{
"auth_password": "",
"auth_username": "",
"from_email": "[email protected]",
"mail_server_name": "localhost",
"mail_server_port": "25",
"smtp_type": "SMTP_LOCAL_HOST"
}
no
license_key The license key that will be applied when the tier is set to ENTERPRISE with the license_tier variable string "" no
license_tier The license tier to use for Avi. Possible values are ENTERPRISE_WITH_CLOUD_SERVICES or ENTERPRISE string "ENTERPRISE_WITH_CLOUD_SERVICES" no
name_prefix This prefix is appended to the names of the Controller and SEs string n/a yes
ntp_servers The NTP Servers that the Avi Controllers will use. The server should be a valid IP address (v4 or v6) or a DNS name. Valid options for type are V4, DNS, or V6
list(object({
addr = string,
type = string
}))
[
{
"addr": "0.us.pool.ntp.org",
"type": "DNS"
},
{
"addr": "1.us.pool.ntp.org",
"type": "DNS"
},
{
"addr": "2.us.pool.ntp.org",
"type": "DNS"
},
{
"addr": "3.us.pool.ntp.org",
"type": "DNS"
}
]
no
portal_certificate Import a SSL certificate for the controller's web portal. The key and certificate must be in the PEM format and base64 encoded without line breaks. An example command for generating the proper format is 'base64 -w 0 certificate.pem > cert.base64'
object({
key = string,
certificate = string,
key_passphrase = optional(string)
})
{
"certificate": "",
"key": ""
}
no
region The Region that the AVI controller and SEs will be deployed to string n/a yes
register_controller If enabled is set to true the controller will be registered and licensed with Avi Cloud Services. The Long Organization ID (organization_id) can be found from https://console.cloud.vmware.com/csp/gateway/portal/#/organization/info. The jwt_token can be retrieved at https://portal.avipulse.vmware.com/portal/controller/auth/cspctrllogin. Optionally the controller name and description used during the registration can be set; otherwise, the name_prefix and configure_gslb.site_name variables will be used.
object({
enabled = bool,
jwt_token = string,
email = string,
organization_id = string,
name = optional(string),
description = optional(string)
})
{
"email": "",
"enabled": "false",
"jwt_token": "",
"organization_id": ""
}
no
se_ha_mode The HA mode of the Service Engine Group. Possible values active/active, n+m, or active/standby string "active/active" no
se_vm_size The VM size for the AVI Service Engines. This value can be changed in the Service Engine Group configuration after deployment. string "Standard_F2s" no
securechannel_certificate Import a SSL certificate for the controller's secure channel communication. Only if there is strict policy that requires all SSL certificates to be signed a specific CA should this variable be used otherwise the default generated certificate is recommended. The full cert chain is necessary and can be provided within the certificate PEM file or separately with the ca_certificates variable. The key and certificate must be in the PEM format and base64 encoded without line breaks. An example command for generating the proper format is 'base64 -w 0 certificate.pem > cert.base64'
object({
key = string,
certificate = string,
key_passphrase = optional(string)
})
{
"certificate": "",
"key": ""
}
no
use_azure_dns If true the AVI Cloud is configured to use Azure DNS bool "false" no
use_standard_alb If true the AVI Cloud is configured to use standard SKU for the Azure LBs that route to Avi SEs bool "false" no
vnet_address_space The CIDR that will be used for creating a VNET for Avi resources string "10.255.0.0/16" no

Outputs

Name Description
controller_private_addresses The Private IP Addresses allocated for the Avi Controller(s)
controller_resource_group The Resource Group used for the Avi Controller
controller_vnet The VNET that the Avi Controller is deployed to
controllers The AVI Controller(s) Information

About

This project is a Terraform module that creates an Avi (NSX ALB) Controller on Azure. This module can create all of the day 0 Cloud prerequisites (IAM, networks, Firewall policy), initial Avi configuration, and additional configuration for GSLB, DNS, and IPAM/DNS profiles.

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published