Configuring an A/S Tier-0 with a Tier-1 and 3-tier app topology with NSX-T Terraform Provider

Configuring an A/S Tier-0 with a Tier-1 and 3-tier app topology with NSX-T Terraform Provider

This blog post and demo shows how you can use the Terraform NSX-T Provider to quickly configure an Active-Standby Tier-0 with a Tier-1 and a typical 3-tier app topology.

VMware is working with Terraform on a NSX-T Provider which support Policy UI. This project is currently on Github and is not officially released by Terraform or VMware yet but ready to be used and tested.

This Terraform NSX-T Provider example can be useful to quickly deploy a typical 3-tier application topology on a NSX-T environment to configure and test the following NSX-T objects:

  • Active-Standby Tier-0 Gateway
  • Uplink interfaces on the Tier-0 Gateway
  • BGP Configuration on the Tier-0 Gateway,
  • BGP Neighbor Configuration
  • Tier-1 Gateway
  • Route Advertisement rule on the Tier-1
  • Overlay Segments for the Web, App and DB tiers.
  • VLAN101 Segment for north-south traffic and BGP peering with ToR-A
  • VLAN102 Segment for north-south traffic and BGP peering with ToR-B
  • Security Groups for the Web, App and DB tiers based on Tags
  • Custom Service (TCP 8443) for Web to App communication.
  • Distributed Firewall Rules for accessing the Application and communication between the tiers, including a default deny rule and using Applied To.

Below a logical diagram of the target topology:

NSX-T Topology

Requirements:

  • NSX Manager(s) ready and configured
  • Compute Manager configured
  • Overlay and VLAN Transport Zones configured
  • Two Edge Nodes configured
  • Edge Cluster configured with the two Edge Nodes as members.

Below is the “`variables.tf“` file:

# Variables
 
variable "nsx_manager" {
    default = "10.10.10.10"
}
 
# Username & Password for NSX-T Manager
variable "username" {
  default = "admin"
}
 
variable "password" {
    default = "yourpassword"
}
 
# Enter Edge Nodes Display Name. Required for external interfaces.
variable "edge_node_1" {
    default = "edge-01"
}
variable "edge_node_2" {
    default = "edge-02"
}
 
# Segment Names
variable "nsx_segment_web" {
    default = "TF-Segment-Web"
}
variable "nsx_segment_app" {
    default = "TF-Segment-App"
}
 
variable "nsx_segment_db" {
    default = "TF-Segment-DB"
}
 
# Security Group names.
variable "nsx_group_web" {
    default = "Web Servers"
}
 
variable "nsx_group_app" {
    default = "App Servers"
}
 
variable "nsx_group_db" {
    default = "DB Servers"
}
 
variable "nsx_group_blue" {
    default = "Blue Application"
}

Below is the “`main.tf“` file:

# Data Sources we need for reference later
data "nsxt_policy_transport_zone" "overlay_tz" {
    display_name = "Overlay-TZ"
}
 
 
data "nsxt_policy_transport_zone" "vlan_tz" {
    display_name = "VLAN-TZ"
}
 
data "nsxt_policy_edge_cluster" "edge_cluster" {
    display_name = "TF"
}
 
data "nsxt_policy_service" "ssh" {
    display_name = "SSH"
}
 
data "nsxt_policy_service" "http" {
    display_name = "HTTP"
}
 
data "nsxt_policy_service" "https" {
    display_name = "HTTPS"
}
 
data "nsxt_policy_edge_node" "edge_node_1" {
    edge_cluster_path   = data.nsxt_policy_edge_cluster.edge_cluster.path
    display_name        = var.edge_node_1
}
 
data "nsxt_policy_edge_node" "edge_node_2" {
    edge_cluster_path   = data.nsxt_policy_edge_cluster.edge_cluster.path
    display_name        = var.edge_node_2
}
 
# NSX-T Manager Credentials
provider "nsxt" {
    host                     = var.nsx_manager
    username                 = var.username
    password                 = var.password
    allow_unverified_ssl     = true
    max_retries              = 10
    retry_min_delay          = 500
    retry_max_delay          = 5000
    retry_on_status_codes    = [429]
}
 
# Create NSX-T VLAN Segments
resource "nsxt_policy_vlan_segment" "vlan101" {
    display_name = "VLAN101"
    description = "VLAN Segment created by Terraform"
    transport_zone_path = data.nsxt_policy_transport_zone.vlan_tz.path
    vlan_ids = ["101"]
}
 
resource "nsxt_policy_vlan_segment" "vlan102" {
    display_name = "VLAN102"
    description = "VLAN Segment created by Terraform"
    transport_zone_path = data.nsxt_policy_transport_zone.vlan_tz.path
    vlan_ids = ["102"]
}
 
# Create Tier-0 Gateway
resource "nsxt_policy_tier0_gateway" "tier0_gw" {
    display_name              = "TF_Tier_0"
    description               = "Tier-0 provisioned by Terraform"
    failover_mode             = "NON_PREEMPTIVE"
    default_rule_logging      = false
    enable_firewall           = false
    force_whitelisting        = true
    ha_mode                   = "ACTIVE_STANDBY"
    edge_cluster_path         = data.nsxt_policy_edge_cluster.edge_cluster.path
 
    bgp_config {
        ecmp            = false              
        local_as_num    = "65003"
        inter_sr_ibgp   = false
        multipath_relax = false
    }
 
    tag {
        scope = "color"
        tag   = "blue"
    }
}
 
# Create Tier-0 Gateway Uplink Interfaces
resource "nsxt_policy_tier0_gateway_interface" "uplink1" {
    display_name        = "Uplink-01"
    description         = "Uplink to VLAN101"
    type                = "EXTERNAL"
    edge_node_path      = data.nsxt_policy_edge_node.edge_node_1.path
    gateway_path        = nsxt_policy_tier0_gateway.tier0_gw.path
    segment_path        = nsxt_policy_vlan_segment.vlan101.path
    subnets             = ["192.168.101.254/24"]
    mtu                 = 1500
}
 
resource "nsxt_policy_tier0_gateway_interface" "uplink2" {
    display_name        = "Uplink-02"
    description         = "Uplink to VLAN102"
    type                = "EXTERNAL"
    edge_node_path      = data.nsxt_policy_edge_node.edge_node_2.path
    gateway_path        = nsxt_policy_tier0_gateway.tier0_gw.path
    segment_path        = nsxt_policy_vlan_segment.vlan102.path
    subnets             = ["192.168.102.254/24"]
    mtu                 = 1500
}
 
# BGP Neighbor Configuration
resource "nsxt_policy_bgp_neighbor" "router_a" {
    display_name        = "ToR-A"
    description         = "Terraform provisioned BGP Neighbor Configuration"
    bgp_path            = nsxt_policy_tier0_gateway.tier0_gw.bgp_config.0.path
    neighbor_address    = "192.168.101.1"
    remote_as_num       = "65001"
}
 
resource "nsxt_policy_bgp_neighbor" "router_b" {
    display_name        = "ToR-B"
    description         = "Terraform provisioned BGP Neighbor Configuration"
    bgp_path            = nsxt_policy_tier0_gateway.tier0_gw.bgp_config.0.path
    neighbor_address    = "192.168.102.1"
    remote_as_num       = "65002"
}
 
# Create Tier-1 Gateway
resource "nsxt_policy_tier1_gateway" "tier1_gw" {
    description               = "Tier-1 provisioned by Terraform"
    display_name              = "TF-Tier-1-01"
    nsx_id                    = "predefined_id"
    edge_cluster_path         = data.nsxt_policy_edge_cluster.edge_cluster.path
    failover_mode             = "NON_PREEMPTIVE"
    default_rule_logging      = "false"
    enable_firewall           = "true"
    enable_standby_relocation = "false"
    force_whitelisting        = "true"
    tier0_path                = nsxt_policy_tier0_gateway.tier0_gw.path
    route_advertisement_types = ["TIER1_STATIC_ROUTES", "TIER1_CONNECTED"]
 
    tag {
        scope = "color"
        tag   = "blue"
    }
 
    route_advertisement_rule {
        name                      = "Tier 1 Networks"
        action                    = "PERMIT"
        subnets                   = ["172.16.10.0/24", "172.16.20.0/24", "172.16.30.0/24"]
        prefix_operator           = "GE"
        route_advertisement_types = ["TIER1_CONNECTED"]
    }
}
 
# Create NSX-T Overlay Segments
resource "nsxt_policy_segment" "tf_segment_web" {
    display_name        = var.nsx_segment_web
    description         = "Segment created by Terraform"
    transport_zone_path = data.nsxt_policy_transport_zone.overlay_tz.path
    connectivity_path   = nsxt_policy_tier1_gateway.tier1_gw.path
 
    subnet {   
        cidr        = "172.16.10.1/24"
        # dhcp_ranges = ["172.16.10.50-172.16.10.100"] 
     
        # dhcp_v4_config {
        #     lease_time  = 36000
        #     dns_servers = ["10.29.12.197"]
        # }
    }
}
 
resource "nsxt_policy_segment" "tf_segment_app" {
    display_name = var.nsx_segment_app
    description = "Segment created by Terraform"
    transport_zone_path = data.nsxt_policy_transport_zone.overlay_tz.path
    connectivity_path   = nsxt_policy_tier1_gateway.tier1_gw.path
 
    subnet {   
        cidr        = "172.16.20.1/24"
    }
}
 
resource "nsxt_policy_segment" "tf_segment_db" {
    display_name = var.nsx_segment_db
    description = "Segment created by Terraform"
    transport_zone_path = data.nsxt_policy_transport_zone.overlay_tz.path
    connectivity_path   = nsxt_policy_tier1_gateway.tier1_gw.path
 
    subnet {   
        cidr        = "172.16.30.1/24"
    }
     
}
 
# Create Security Groups
resource "nsxt_policy_group" "web_servers" {
    display_name = var.nsx_group_web
    description  = "Terraform provisioned Group"
 
    criteria {
        condition {
            key         = "Tag"
            member_type = "VirtualMachine"
            operator    = "CONTAINS"
            value       = "Web"
        }
    }
}
 
resource "nsxt_policy_group" "app_servers" {
    display_name = var.nsx_group_app
    description  = "Terraform provisioned Group"
 
    criteria {
        condition {
            key         = "Tag"
            member_type = "VirtualMachine"
            operator    = "CONTAINS"
            value       = "App"
        }
    }
}
 
resource "nsxt_policy_group" "db_servers" {
    display_name = var.nsx_group_db
    description  = "Terraform provisioned Group"
 
    criteria {
        condition {
            key         = "Tag"
            member_type = "VirtualMachine"
            operator    = "CONTAINS"
            value       = "DB"
        }
    }
}
 
resource "nsxt_policy_group" "blue_servers" {
    display_name = var.nsx_group_blue
    description  = "Terraform provisioned Group"
 
    criteria {
        condition {
            key         = "Tag"
            member_type = "VirtualMachine"
            operator    = "CONTAINS"
            value       = "Blue"
        }
    }
}
 
# Create Custom Services
resource "nsxt_policy_service" "service_tcp8443" {
    description  = "HTTPS service provisioned by Terraform"
    display_name = "TCP 8443"
 
    l4_port_set_entry {
        display_name      = "TCP8443"
        description       = "TCP port 8443 entry"
        protocol          = "TCP"
        destination_ports = [ "8443" ]
    }
 
    tag {
        scope = "color"
        tag   = "blue"
    }
}
 
# Create Security Policies
resource "nsxt_policy_security_policy" "allow_blue" {
    display_name = "Allow Blue Application"
    description  = "Terraform provisioned Security Policy"
    category     = "Application"
    locked       = false
    stateful     = true
    tcp_strict   = false
    scope        = [nsxt_policy_group.web_servers.path]
 
    rule {
        display_name        = "Allow SSH to Blue Servers"
        destination_groups  = [nsxt_policy_group.blue_servers.path]
        action              = "ALLOW"
        services            = [data.nsxt_policy_service.ssh.path]
        logged              = true
        scope               = [nsxt_policy_group.blue_servers.path]
    }   
 
    rule {
        display_name        = "Allow HTTPS to Web Servers"
        destination_groups  = [nsxt_policy_group.web_servers.path]
        action              = "ALLOW"
        services            = [data.nsxt_policy_service.https.path]
        logged              = true
        scope               = [nsxt_policy_group.web_servers.path]
    }
 
    rule {
        display_name        = "Allow TCP 8443 to App Servers"
        source_groups       = [nsxt_policy_group.web_servers.path]
        destination_groups  = [nsxt_policy_group.app_servers.path]
        action              = "ALLOW"
        services            = [nsxt_policy_service.service_tcp8443.path]
        logged              = true
        scope               = [nsxt_policy_group.web_servers.path,nsxt_policy_group.app_servers.path]
    }
 
    rule {
        display_name        = "Allow HTTP to DB Servers"
        source_groups       = [nsxt_policy_group.app_servers.path]
        destination_groups  = [nsxt_policy_group.db_servers.path]
        action              = "ALLOW"
        services            = [data.nsxt_policy_service.http.path]
        logged              = true
        scope               = [nsxt_policy_group.app_servers.path,nsxt_policy_group.db_servers.path]
    }
 
    rule {
        display_name        = "Any Deny"
        action              = "REJECT"
        logged              = false
        scope               = [nsxt_policy_group.blue_servers.path]
    }
}

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *