From 15bb67261a333f140f21208e20a112b99eeb609c Mon Sep 17 00:00:00 2001
From: Dan Sneddon <dsneddon@redhat.com>
Date: Mon, 21 Sep 2015 13:41:21 -0700
Subject: [PATCH] Add Management Network For System Administration.

This change adds a system management network to all overcloud
nodes. The purpose of this network is for system administration,
for access to infrastructure services like DNS or NTP, or for
monitoring. This allows the management network to be placed on a
bond for redundancy, or for the system management network to be
an out-of-band network with no routing in or out. The management
network might also be configured as a default route instead of the
provisioning 'ctlplane' network.

This change does not enable the management network by default. An
environment file named network-management.yaml may be included to
enable the network and ports for each role. The included NIC config
templates have been updated with a block that may be uncommented
when the management network is enabled.

This change also contains some minor cleanup to the NIC templates,
particularly the multiple nic templates.

Change-Id: I0813a13f60a4f797be04b34258a2cffa9ea7e84f
---
 environments/network-isolation.yaml           | 10 +++
 environments/network-management.yaml          | 24 +++++++
 net-config-bond.yaml                          |  4 ++
 net-config-bridge.yaml                        |  4 ++
 net-config-noop.yaml                          |  4 ++
 network/config/bond-with-vlans/README.md      | 26 +++++++-
 .../config/bond-with-vlans/ceph-storage.yaml  | 16 +++++
 .../bond-with-vlans/cinder-storage.yaml       | 16 +++++
 network/config/bond-with-vlans/compute.yaml   | 16 +++++
 .../controller-no-external.yaml               | 17 +++++
 .../config/bond-with-vlans/controller.yaml    | 18 +++++-
 .../config/bond-with-vlans/swift-storage.yaml | 16 +++++
 network/config/multiple-nics/README.md        | 18 ++++++
 .../config/multiple-nics/ceph-storage.yaml    | 20 +++++-
 .../config/multiple-nics/cinder-storage.yaml  | 20 +++++-
 network/config/multiple-nics/compute.yaml     | 32 +++++++++-
 network/config/multiple-nics/controller.yaml  | 23 ++++++-
 .../config/multiple-nics/swift-storage.yaml   | 20 +++++-
 network/config/single-nic-vlans/README.md     | 24 ++++++-
 .../config/single-nic-vlans/ceph-storage.yaml | 15 +++++
 .../single-nic-vlans/cinder-storage.yaml      | 15 +++++
 network/config/single-nic-vlans/compute.yaml  | 15 +++++
 .../controller-no-external.yaml               | 15 +++++
 .../config/single-nic-vlans/controller.yaml   | 14 ++++
 .../single-nic-vlans/swift-storage.yaml       | 15 +++++
 network/management.yaml                       | 64 +++++++++++++++++++
 network/networks.yaml                         |  3 +
 network/ports/management.yaml                 | 42 ++++++++++++
 network/ports/net_ip_list_map.yaml            |  4 ++
 network/ports/net_ip_map.yaml                 |  4 ++
 network/ports/net_ip_subnet_map.yaml          |  4 ++
 overcloud-resource-registry-puppet.yaml       |  6 ++
 overcloud.yaml                                |  3 +-
 puppet/ceph-storage.yaml                      | 11 ++++
 puppet/cinder-storage.yaml                    | 10 +++
 puppet/compute.yaml                           | 10 +++
 puppet/controller.yaml                        | 11 ++++
 puppet/swift-storage.yaml                     | 10 +++
 38 files changed, 581 insertions(+), 18 deletions(-)
 create mode 100644 environments/network-management.yaml
 create mode 100644 network/management.yaml
 create mode 100644 network/ports/management.yaml

diff --git a/environments/network-isolation.yaml b/environments/network-isolation.yaml
index efe2929771..3a47517263 100644
--- a/environments/network-isolation.yaml
+++ b/environments/network-isolation.yaml
@@ -7,6 +7,8 @@ resource_registry:
   OS::TripleO::Network::StorageMgmt: ../network/storage_mgmt.yaml
   OS::TripleO::Network::Storage: ../network/storage.yaml
   OS::TripleO::Network::Tenant: ../network/tenant.yaml
+  # Management network is optional and disabled by default
+  OS::TripleO::Network::Management: ../network/noop.yaml
 
   # Port assignments for the VIPs
   OS::TripleO::Network::Ports::ExternalVipPort: ../network/ports/external.yaml
@@ -21,22 +23,30 @@ resource_registry:
   OS::TripleO::Controller::Ports::StoragePort: ../network/ports/storage.yaml
   OS::TripleO::Controller::Ports::StorageMgmtPort: ../network/ports/storage_mgmt.yaml
   OS::TripleO::Controller::Ports::TenantPort: ../network/ports/tenant.yaml
+  OS::TripleO::Controller::Ports::ManagementPort: ../network/ports/noop.yaml
 
   # Port assignments for the compute role
   OS::TripleO::Compute::Ports::InternalApiPort: ../network/ports/internal_api.yaml
   OS::TripleO::Compute::Ports::StoragePort: ../network/ports/storage.yaml
   OS::TripleO::Compute::Ports::TenantPort: ../network/ports/tenant.yaml
+  OS::TripleO::Compute::Ports::ManagementPort: ../network/ports/noop.yaml
 
   # Port assignments for the ceph storage role
   OS::TripleO::CephStorage::Ports::StoragePort: ../network/ports/storage.yaml
   OS::TripleO::CephStorage::Ports::StorageMgmtPort: ../network/ports/storage_mgmt.yaml
+  OS::TripleO::CephStorage::Ports::ManagementPort: ../network/ports/noop.yaml
 
   # Port assignments for the swift storage role
   OS::TripleO::SwiftStorage::Ports::InternalApiPort: ../network/ports/internal_api.yaml
   OS::TripleO::SwiftStorage::Ports::StoragePort: ../network/ports/storage.yaml
   OS::TripleO::SwiftStorage::Ports::StorageMgmtPort: ../network/ports/storage_mgmt.yaml
+  OS::TripleO::SwiftStorage::Ports::ManagementPort: ../network/ports/noop.yaml
 
   # Port assignments for the block storage role
   OS::TripleO::BlockStorage::Ports::InternalApiPort: ../network/ports/internal_api.yaml
   OS::TripleO::BlockStorage::Ports::StoragePort: ../network/ports/storage.yaml
   OS::TripleO::BlockStorage::Ports::StorageMgmtPort: ../network/ports/storage_mgmt.yaml
+  OS::TripleO::BlockStorage::Ports::ManagementPort: ../network/ports/noop.yaml
+
+  # Port assignments for service virtual IPs for the controller role
+  OS::TripleO::Controller::Ports::RedisVipPort: ../network/ports/vip.yaml
diff --git a/environments/network-management.yaml b/environments/network-management.yaml
new file mode 100644
index 0000000000..2f0cff8b25
--- /dev/null
+++ b/environments/network-management.yaml
@@ -0,0 +1,24 @@
+# Enable the creation of a system management network. This
+# creates a Neutron network for isolated Overcloud
+# system management traffic and configures each role to
+# assign a port (related to that role) on that network.
+# Note that the basic sample NIC configuration templates
+# do not include the management network, see the
+# single-nic-vlans-mgmt templates for an example.
+resource_registry:
+  OS::TripleO::Network::Management: ../network/management.yaml
+
+  # Port assignments for the controller role
+  OS::TripleO::Controller::Ports::ManagementPort: ../network/ports/management.yaml
+
+  # Port assignments for the compute role
+  OS::TripleO::Compute::Ports::ManagementPort: ../network/ports/management.yaml
+
+  # Port assignments for the ceph storage role
+  OS::TripleO::CephStorage::Ports::ManagementPort: ../network/ports/management.yaml
+
+  # Port assignments for the swift storage role
+  OS::TripleO::SwiftStorage::Ports::ManagementPort: ../network/ports/management.yaml
+
+  # Port assignments for the block storage role
+  OS::TripleO::BlockStorage::Ports::ManagementPort: ../network/ports/management.yaml
diff --git a/net-config-bond.yaml b/net-config-bond.yaml
index 797df4bf0c..b624563f15 100644
--- a/net-config-bond.yaml
+++ b/net-config-bond.yaml
@@ -28,6 +28,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet:
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
 
 resources:
   OsNetConfigImpl:
diff --git a/net-config-bridge.yaml b/net-config-bridge.yaml
index ad16ef0bc6..4f7a19dce9 100644
--- a/net-config-bridge.yaml
+++ b/net-config-bridge.yaml
@@ -28,6 +28,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet:
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
 
 resources:
   OsNetConfigImpl:
diff --git a/net-config-noop.yaml b/net-config-noop.yaml
index 30de5846b5..94c492c61d 100644
--- a/net-config-noop.yaml
+++ b/net-config-noop.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet:
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
 
 resources:
   OsNetConfigImpl:
diff --git a/network/config/bond-with-vlans/README.md b/network/config/bond-with-vlans/README.md
index 98879b4f94..afe7177641 100644
--- a/network/config/bond-with-vlans/README.md
+++ b/network/config/bond-with-vlans/README.md
@@ -3,10 +3,9 @@ Vlans on a bonded pair of NICs for each Overcloud role.
 
 There are two versions of the controller role template, one with
 an external network interface, and another without. If the
-external network interface is not configured the ctlplane address
+external network interface is not configured, the ctlplane address
 ranges will be used for external (public) network traffic.
 
-
 Configuration
 -------------
 
@@ -20,8 +19,31 @@ something like this:
     OS::TripleO::ObjectStorage::Net::SoftwareConfig: network/config/bond-with-vlans/swift-storage.yaml
     OS::TripleO::CephStorage::Net::SoftwareConfig: network/config/bond-with-vlans/ceph-storage.yaml
 
+Or use this Heat environment file:
+
+  environments/net-bond-with-vlans.yaml
+
 Configuration with no External Network
 --------------------------------------
+
 Same as above except set the following value for the controller role:
 
     OS::TripleO::Controller::Net::SoftwareConfig: network/config/bond-with-vlans/controller-no-external.yaml
+
+Configuration with System Management Network
+--------------------------------------------
+
+To enable the optional System Management network, create a Heat environment
+that looks something like this:
+
+  resource\_registry:
+    OS::TripleO::Network::Management: ../network/management.yaml
+    OS::TripleO::Controller::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::Compute::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::CephStorage::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::SwiftStorage::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::BlockStorage::Ports::ManagementPort: ../network/ports/management.yaml
+
+Or use this Heat environment file:
+
+  environments/network-management.yaml
diff --git a/network/config/bond-with-vlans/ceph-storage.yaml b/network/config/bond-with-vlans/ceph-storage.yaml
index 620d1f7aef..93db8666c9 100644
--- a/network/config/bond-with-vlans/ceph-storage.yaml
+++ b/network/config/bond-with-vlans/ceph-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   BondInterfaceOvsOptions:
     default: ''
     description: The ovs_options string for the bond interface. Set things like
@@ -42,6 +46,10 @@ parameters:
     default: 40
     description: Vlan ID for the storage mgmt network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -114,6 +122,14 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: StorageMgmtIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  device: bond1
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/bond-with-vlans/cinder-storage.yaml b/network/config/bond-with-vlans/cinder-storage.yaml
index f4c6de8fc0..bea98c1908 100644
--- a/network/config/bond-with-vlans/cinder-storage.yaml
+++ b/network/config/bond-with-vlans/cinder-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   BondInterfaceOvsOptions:
     default: ''
     description: The ovs_options string for the bond interface. Set things like
@@ -46,6 +50,10 @@ parameters:
     default: 40
     description: Vlan ID for the storage mgmt network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -125,6 +133,14 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: StorageMgmtIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  device: bond1
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/bond-with-vlans/compute.yaml b/network/config/bond-with-vlans/compute.yaml
index 8cb3705bb3..774bf02dbd 100644
--- a/network/config/bond-with-vlans/compute.yaml
+++ b/network/config/bond-with-vlans/compute.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   BondInterfaceOvsOptions:
     default: ''
     description: The ovs_options string for the bond interface. Set things like
@@ -46,6 +50,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -125,6 +133,14 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: TenantIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  device: bond1
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/bond-with-vlans/controller-no-external.yaml b/network/config/bond-with-vlans/controller-no-external.yaml
index 22579e8fd2..375d40bea1 100644
--- a/network/config/bond-with-vlans/controller-no-external.yaml
+++ b/network/config/bond-with-vlans/controller-no-external.yaml
@@ -25,6 +25,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   BondInterfaceOvsOptions:
     default: ''
     description: The ovs_options string for the bond interface. Set things like
@@ -50,6 +54,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ExternalInterfaceDefaultRoute:
     default: '10.0.0.1'
     description: default route for the external network
@@ -66,6 +74,7 @@ resources:
             -
               type: ovs_bridge
               name: {get_input: bridge_name}
+              use_dhcp: true
               members:
                 -
                   type: ovs_bond
@@ -107,6 +116,14 @@ resources:
                   addresses:
                   -
                     ip_netmask: {get_param: TenantIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  device: bond1
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/bond-with-vlans/controller.yaml b/network/config/bond-with-vlans/controller.yaml
index eb4399ea55..d3627ead94 100644
--- a/network/config/bond-with-vlans/controller.yaml
+++ b/network/config/bond-with-vlans/controller.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   BondInterfaceOvsOptions:
     default: 'bond_mode=active-backup'
     description: The ovs_options string for the bond interface. Set things like
@@ -54,6 +58,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ExternalInterfaceDefaultRoute:
     default: '10.0.0.1'
     description: default route for the external network
@@ -119,7 +127,7 @@ resources:
                       ip_netmask: {get_param: ExternalIpSubnet}
                   routes:
                     -
-                      ip_netmask: 0.0.0.0/0
+                      default: true
                       next_hop: {get_param: ExternalInterfaceDefaultRoute}
                 -
                   type: vlan
@@ -149,6 +157,14 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: TenantIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  device: bond1
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/bond-with-vlans/swift-storage.yaml b/network/config/bond-with-vlans/swift-storage.yaml
index f6b2a69981..de9121e562 100644
--- a/network/config/bond-with-vlans/swift-storage.yaml
+++ b/network/config/bond-with-vlans/swift-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   BondInterfaceOvsOptions:
     default: ''
     description: The ovs_options string for the bond interface. Set things like
@@ -46,6 +50,10 @@ parameters:
     default: 40
     description: Vlan ID for the storage mgmt network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -125,6 +133,14 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: StorageMgmtIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  device: bond1
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/multiple-nics/README.md b/network/config/multiple-nics/README.md
index 3d81f0beea..0d8a0f03ee 100644
--- a/network/config/multiple-nics/README.md
+++ b/network/config/multiple-nics/README.md
@@ -19,3 +19,21 @@ something like this:
 Or use this Heat environment file:
 
   environments/net-multiple-nics.yaml
+
+Configuration with System Management Network
+--------------------------------------------
+
+To enable the optional System Management network, create a Heat environment
+that looks something like this:
+
+  resource\_registry:
+    OS::TripleO::Network::Management: ../network/management.yaml
+    OS::TripleO::Controller::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::Compute::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::CephStorage::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::SwiftStorage::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::BlockStorage::Ports::ManagementPort: ../network/ports/management.yaml
+
+Or use this Heat environment file:
+
+  environments/network-management.yaml
diff --git a/network/config/multiple-nics/ceph-storage.yaml b/network/config/multiple-nics/ceph-storage.yaml
index 7d650f4bec..a2a6b40d51 100644
--- a/network/config/multiple-nics/ceph-storage.yaml
+++ b/network/config/multiple-nics/ceph-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -49,6 +53,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ExternalInterfaceDefaultRoute:
     default: '10.0.0.1'
     description: default route for the external network
@@ -58,12 +66,12 @@ parameters:
     description: The subnet CIDR of the control plane network.
     type: string
   ControlPlaneDefaultRoute: # Override this via parameter_defaults
-    description: The subnet CIDR of the control plane network.
+    description: The default route of the control plane network.
     type: string
   DnsServers: # Override this via parameter_defaults
     default: []
     description: A list of DNS servers (2 max for some implementations) that will be added to resolv.conf.
-    type: json
+    type: comma_delimited_list
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
@@ -109,6 +117,14 @@ resources:
               addresses:
                 -
                   ip_netmask: {get_param: StorageMgmtIpSubnet}
+            # Uncomment when including environments/network-management.yaml
+            #-
+            #  type: interface
+            #  name: nic7
+            #  use_dhcp: false
+            #  addresses:
+            #    -
+            #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/multiple-nics/cinder-storage.yaml b/network/config/multiple-nics/cinder-storage.yaml
index fdb6c9d8e9..06b4b83f58 100644
--- a/network/config/multiple-nics/cinder-storage.yaml
+++ b/network/config/multiple-nics/cinder-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -49,6 +53,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ExternalInterfaceDefaultRoute:
     default: '10.0.0.1'
     description: default route for the external network
@@ -58,12 +66,12 @@ parameters:
     description: The subnet CIDR of the control plane network.
     type: string
   ControlPlaneDefaultRoute: # Override this via parameter_defaults
-    description: The subnet CIDR of the control plane network.
+    description: The default route of the control plane network.
     type: string
   DnsServers: # Override this via parameter_defaults
     default: []
     description: A list of DNS servers (2 max for some implementations) that will be added to resolv.conf.
-    type: json
+    type: comma_delimited_list
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
@@ -116,6 +124,14 @@ resources:
               addresses:
                 -
                   ip_netmask: {get_param: InternalApiIpSubnet}
+            # Uncomment when including environments/network-management.yaml
+            #-
+            #  type: interface
+            #  name: nic7
+            #  use_dhcp: false
+            #  addresses:
+            #    -
+            #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/multiple-nics/compute.yaml b/network/config/multiple-nics/compute.yaml
index 0032a2870b..97eef52bcc 100644
--- a/network/config/multiple-nics/compute.yaml
+++ b/network/config/multiple-nics/compute.yaml
@@ -29,6 +29,14 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
+  ExternalNetworkVlanID:
+    default: 10
+    description: Vlan ID for the external network traffic.
+    type: number
   InternalApiNetworkVlanID:
     default: 20
     description: Vlan ID for the internal_api network traffic.
@@ -37,21 +45,33 @@ parameters:
     default: 30
     description: Vlan ID for the storage network traffic.
     type: number
+  StorageMgmtNetworkVlanID:
+    default: 40
+    description: Vlan ID for the storage mgmt network traffic.
+    type: number
   TenantNetworkVlanID:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
+  ExternalInterfaceDefaultRoute:
+    default: '10.0.0.1'
+    description: default route for the external network
+    type: string
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
     type: string
   ControlPlaneDefaultRoute: # Override this via parameter_defaults
-    description: The subnet CIDR of the control plane network.
+    description: The default route of the control plane network.
     type: string
   DnsServers: # Override this via parameter_defaults
     default: []
     description: A list of DNS servers (2 max for some implementations) that will be added to resolv.conf.
-    type: json
+    type: comma_delimited_list
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
@@ -112,6 +132,14 @@ resources:
                   use_dhcp: false
                   # force the MAC address of the bridge to this interface
                   primary: true
+            # Uncomment when including environments/network-management.yaml
+            #-
+            #  type: interface
+            #  name: nic7
+            #  use_dhcp: false
+            #  addresses:
+            #    -
+            #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/multiple-nics/controller.yaml b/network/config/multiple-nics/controller.yaml
index 63f53a1f7e..32851cfb7b 100644
--- a/network/config/multiple-nics/controller.yaml
+++ b/network/config/multiple-nics/controller.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -49,6 +53,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ExternalInterfaceDefaultRoute:
     default: '10.0.0.1'
     description: default route for the external network
@@ -58,12 +66,12 @@ parameters:
     description: The subnet CIDR of the control plane network.
     type: string
   ControlPlaneDefaultRoute: # Override this via parameter_defaults
-    description: The subnet CIDR of the control plane network.
+    description: The default route of the control plane network.
     type: string
   DnsServers: # Override this via parameter_defaults
     default: []
     description: A list of DNS servers (2 max for some implementations) that will be added to resolv.conf.
-    type: json
+    type: comma_delimited_list
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
@@ -131,13 +139,14 @@ resources:
             -
               type: ovs_bridge
               name: {get_input: bridge_name}
+              dns_servers: {get_param: DnsServers}
               use_dhcp: false
               addresses:
                 -
                   ip_netmask: {get_param: ExternalIpSubnet}
               routes:
                 -
-                  ip_netmask: 0.0.0.0/0
+                  default: true
                   next_hop: {get_param: ExternalInterfaceDefaultRoute}
               members:
                 -
@@ -145,6 +154,14 @@ resources:
                   name: nic6
                   # force the MAC address of the bridge to this interface
                   primary: true
+            # Uncomment when including environments/network-management.yaml
+            #-
+            #  type: interface
+            #  name: nic7
+            #  use_dhcp: false
+            #  addresses:
+            #    -
+            #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/multiple-nics/swift-storage.yaml b/network/config/multiple-nics/swift-storage.yaml
index 00e4f353d3..4d5a7b99fb 100644
--- a/network/config/multiple-nics/swift-storage.yaml
+++ b/network/config/multiple-nics/swift-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -49,6 +53,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ExternalInterfaceDefaultRoute:
     default: '10.0.0.1'
     description: default route for the external network
@@ -58,12 +66,12 @@ parameters:
     description: The subnet CIDR of the control plane network.
     type: string
   ControlPlaneDefaultRoute: # Override this via parameter_defaults
-    description: The subnet CIDR of the control plane network.
+    description: The default route of the control plane network.
     type: string
   DnsServers: # Override this via parameter_defaults
     default: []
     description: A list of DNS servers (2 max for some implementations) that will be added to resolv.conf.
-    type: json
+    type: comma_delimited_list
   EC2MetadataIp: # Override this via parameter_defaults
     description: The IP address of the EC2 metadata server.
     type: string
@@ -116,6 +124,14 @@ resources:
               addresses:
                 -
                   ip_netmask: {get_param: InternalApiIpSubnet}
+            # Uncomment when including environments/network-management.yaml
+            #-
+            #  type: interface
+            #  name: nic7
+            #  use_dhcp: false
+            #  addresses:
+            #    -
+            #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/single-nic-vlans/README.md b/network/config/single-nic-vlans/README.md
index 6f128650df..f9c2e51280 100644
--- a/network/config/single-nic-vlans/README.md
+++ b/network/config/single-nic-vlans/README.md
@@ -1,9 +1,9 @@
 This directory contains Heat templates to help configure
-Vlans on a single NICs for each Overcloud role.
+Vlans on a single NIC for each Overcloud role.
 
 There are two versions of the controller role template, one with
 an external network interface, and another without. If the
-external network interface is not configured the ctlplane address
+external network interface is not configured, the ctlplane address
 ranges will be used for external (public) network traffic.
 
 Configuration
@@ -23,9 +23,27 @@ Or use this Heat environment file:
 
   environments/net-single-nic-with-vlans.yaml
 
-
 Configuration with no External Network
 --------------------------------------
+
 Same as above except set the following value for the controller role:
 
     OS::TripleO::Controller::Net::SoftwareConfig: network/config/single-nic-vlans/controller-no-external.yaml
+
+Configuration with System Management Network
+--------------------------------------------
+
+To enable the optional System Management network, create a Heat environment
+that looks something like this:
+
+  resource\_registry:
+    OS::TripleO::Network::Management: ../network/management.yaml
+    OS::TripleO::Controller::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::Compute::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::CephStorage::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::SwiftStorage::Ports::ManagementPort: ../network/ports/management.yaml
+    OS::TripleO::BlockStorage::Ports::ManagementPort: ../network/ports/management.yaml
+
+Or use this Heat environment file:
+
+  environments/network-management.yaml
diff --git a/network/config/single-nic-vlans/ceph-storage.yaml b/network/config/single-nic-vlans/ceph-storage.yaml
index 5148c5206e..80bc32d3dc 100644
--- a/network/config/single-nic-vlans/ceph-storage.yaml
+++ b/network/config/single-nic-vlans/ceph-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   StorageNetworkVlanID:
     default: 30
     description: Vlan ID for the storage network traffic.
@@ -37,6 +41,10 @@ parameters:
     default: 40
     description: Vlan ID for the storage mgmt network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -97,6 +105,13 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: StorageMgmtIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/single-nic-vlans/cinder-storage.yaml b/network/config/single-nic-vlans/cinder-storage.yaml
index e79a9f4b7b..e509443a0e 100644
--- a/network/config/single-nic-vlans/cinder-storage.yaml
+++ b/network/config/single-nic-vlans/cinder-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   InternalApiNetworkVlanID:
     default: 20
     description: Vlan ID for the internal_api network traffic.
@@ -41,6 +45,10 @@ parameters:
     default: 40
     description: Vlan ID for the storage mgmt network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -107,6 +115,13 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: StorageMgmtIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/single-nic-vlans/compute.yaml b/network/config/single-nic-vlans/compute.yaml
index 4e93b31c1c..8cf6825d50 100644
--- a/network/config/single-nic-vlans/compute.yaml
+++ b/network/config/single-nic-vlans/compute.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   InternalApiNetworkVlanID:
     default: 20
     description: Vlan ID for the internal_api network traffic.
@@ -41,6 +45,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -107,6 +115,13 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: TenantIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/single-nic-vlans/controller-no-external.yaml b/network/config/single-nic-vlans/controller-no-external.yaml
index faf9e9c238..eb5e1e5a9c 100644
--- a/network/config/single-nic-vlans/controller-no-external.yaml
+++ b/network/config/single-nic-vlans/controller-no-external.yaml
@@ -25,6 +25,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -45,6 +49,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ExternalInterfaceDefaultRoute:
     default: '10.0.0.1'
     description: default route for the external network
@@ -92,6 +100,13 @@ resources:
                   addresses:
                   -
                     ip_netmask: {get_param: TenantIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/single-nic-vlans/controller.yaml b/network/config/single-nic-vlans/controller.yaml
index 3c536d6769..3b22b36b3a 100644
--- a/network/config/single-nic-vlans/controller.yaml
+++ b/network/config/single-nic-vlans/controller.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   ExternalNetworkVlanID:
     default: 10
     description: Vlan ID for the external network traffic.
@@ -49,6 +53,10 @@ parameters:
     default: 50
     description: Vlan ID for the tenant network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ExternalInterfaceDefaultRoute:
     default: '10.0.0.1'
     description: default route for the external network
@@ -129,6 +137,12 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: TenantIpSubnet}
+                #-  # Uncomment when including environments/network-management.yaml
+                #  type: vlan
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/config/single-nic-vlans/swift-storage.yaml b/network/config/single-nic-vlans/swift-storage.yaml
index 83b3304fd8..efc033936c 100644
--- a/network/config/single-nic-vlans/swift-storage.yaml
+++ b/network/config/single-nic-vlans/swift-storage.yaml
@@ -29,6 +29,10 @@ parameters:
     default: ''
     description: IP address/subnet on the tenant network
     type: string
+  ManagementIpSubnet: # Only populated when including environments/network-management.yaml
+    default: ''
+    description: IP address/subnet on the management network
+    type: string
   InternalApiNetworkVlanID:
     default: 20
     description: Vlan ID for the internal_api network traffic.
@@ -41,6 +45,10 @@ parameters:
     default: 40
     description: Vlan ID for the storage mgmt network traffic.
     type: number
+  ManagementNetworkVlanID:
+    default: 60
+    description: Vlan ID for the management network traffic.
+    type: number
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -107,6 +115,13 @@ resources:
                   addresses:
                     -
                       ip_netmask: {get_param: StorageMgmtIpSubnet}
+                # Uncomment when including environments/network-management.yaml
+                #-
+                #  type: vlan
+                #  vlan_id: {get_param: ManagementNetworkVlanID}
+                #  addresses:
+                #    -
+                #      ip_netmask: {get_param: ManagementIpSubnet}
 
 outputs:
   OS::stack_id:
diff --git a/network/management.yaml b/network/management.yaml
new file mode 100644
index 0000000000..9bfaafa2ea
--- /dev/null
+++ b/network/management.yaml
@@ -0,0 +1,64 @@
+heat_template_version: 2015-04-30
+
+description: >
+  Management network. System administration, SSH, DNS, NTP, etc. This network
+  would usually be the default gateway for the non-controller nodes.
+
+parameters:
+  # the defaults here work for static IP assignment (IPAM) only
+  ManagementNetCidr:
+    default: '10.0.1.0/24'
+    description: Cidr for the management network.
+    type: string
+  ManagementNetValueSpecs:
+    default: {'provider:physical_network': 'management', 'provider:network_type': 'flat'}
+    description: Value specs for the management network.
+    type: string
+  ManagementNetAdminStateUp:
+    default: false
+    description: This admin state of of the network.
+    type: boolean
+  ManagementNetEnableDHCP:
+    default: false
+    description: Whether to enable DHCP on the associated subnet.
+    type: boolean
+  ManagementNetShared:
+    default: false
+    description: Whether this network is shared across all tenants.
+    type: boolean
+  ManagementNetName:
+    default: management
+    description: The name of the management network.
+    type: string
+  ManagementSubnetName:
+    default: management_subnet
+    description: The name of the management subnet in Neutron.
+    type: string
+  ManagementAllocationPools:
+    default: [{'start': '10.0.1.4', 'end': '10.0.1.250'}]
+    description: Ip allocation pool range for the management network.
+    type: json
+
+resources:
+  ManagementNetwork:
+    type: OS::Neutron::Net
+    properties:
+      admin_state_up: {get_param: ManagementNetAdminStateUp}
+      name: {get_param: ManagementNetName}
+      shared: {get_param: ManagementNetShared}
+      value_specs: {get_param: ManagementNetValueSpecs}
+
+  ManagementSubnet:
+    type: OS::Neutron::Subnet
+    properties:
+      cidr: {get_param: ManagementNetCidr}
+      enable_dhcp: {get_param: ManagementNetEnableDHCP}
+      name: {get_param: ManagementSubnetName}
+      network: {get_resource: ManagementNetwork}
+      allocation_pools: {get_param: ManagementAllocationPools}
+
+outputs:
+  OS::stack_id:
+    description: Neutron management network
+    value: {get_resource: ManagementNetwork}
+
diff --git a/network/networks.yaml b/network/networks.yaml
index 6618af3850..ab50ae1188 100644
--- a/network/networks.yaml
+++ b/network/networks.yaml
@@ -18,3 +18,6 @@ resources:
 
   TenantNetwork:
     type: OS::TripleO::Network::Tenant
+
+  ManagementNetwork:
+    type: OS::TripleO::Network::Management
diff --git a/network/ports/management.yaml b/network/ports/management.yaml
new file mode 100644
index 0000000000..1d15ca6020
--- /dev/null
+++ b/network/ports/management.yaml
@@ -0,0 +1,42 @@
+heat_template_version: 2015-04-30
+
+description: >
+  Creates a port on the management network. The IP address will be chosen
+  automatically if FixedIPs is empty.
+
+parameters:
+  ManagementNetName:
+    description: Name of the management neutron network
+    default: management
+    type: string
+  PortName:
+    description: Name of the port
+    default: ''
+    type: string
+  ControlPlaneIP: # Here for compatibility with noop.yaml
+    description: IP address on the control plane
+    type: string
+
+resources:
+
+  ManagementPort:
+    type: OS::Neutron::Port
+    properties:
+      network: {get_param: ManagementNetName}
+      name: {get_param: PortName}
+      replacement_policy: AUTO
+
+outputs:
+  ip_address:
+    description: management network IP
+    value: {get_attr: [ManagementPort, fixed_ips, 0, ip_address]}
+  ip_subnet:
+    # FIXME: this assumes a 2 digit subnet CIDR (need more heat functions?)
+    description: IP/Subnet CIDR for the management network IP
+    value:
+          list_join:
+            - ''
+            - - {get_attr: [ManagementPort, fixed_ips, 0, ip_address]}
+              - '/'
+              - {get_attr: [ManagementPort, subnets, 0, cidr, -2]}
+              - {get_attr: [ManagementPort, subnets, 0, cidr, -1]}
diff --git a/network/ports/net_ip_list_map.yaml b/network/ports/net_ip_list_map.yaml
index 257d3f9bef..32272bd67b 100644
--- a/network/ports/net_ip_list_map.yaml
+++ b/network/ports/net_ip_list_map.yaml
@@ -19,6 +19,9 @@ parameters:
   TenantIpList:
     default: []
     type: comma_delimited_list
+  ManagementIpList:
+    default: []
+    type: comma_delimited_list
 
 outputs:
   net_ip_map:
@@ -32,3 +35,4 @@ outputs:
       storage: {get_param: StorageIpList}
       storage_mgmt: {get_param: StorageMgmtIpList}
       tenant: {get_param: TenantIpList}
+      management: {get_param: ManagementIpList}
diff --git a/network/ports/net_ip_map.yaml b/network/ports/net_ip_map.yaml
index 7aaed16022..c63860259f 100644
--- a/network/ports/net_ip_map.yaml
+++ b/network/ports/net_ip_map.yaml
@@ -19,6 +19,9 @@ parameters:
   TenantIp:
     default: ''
     type: string
+  ManagementIp:
+    default: ''
+    type: string
 
 outputs:
   net_ip_map:
@@ -32,3 +35,4 @@ outputs:
       storage: {get_param: StorageIp}
       storage_mgmt: {get_param: StorageMgmtIp}
       tenant: {get_param: TenantIp}
+      management: {get_param: ManagementIp}
diff --git a/network/ports/net_ip_subnet_map.yaml b/network/ports/net_ip_subnet_map.yaml
index cf59adb39c..2f933eaa63 100644
--- a/network/ports/net_ip_subnet_map.yaml
+++ b/network/ports/net_ip_subnet_map.yaml
@@ -19,6 +19,9 @@ parameters:
   TenantIpSubnet:
     default: ''
     type: string
+  ManagementIpSubnet:
+    default: ''
+    type: string
   ControlPlaneSubnetCidr: # Override this via parameter_defaults
     default: '24'
     description: The subnet CIDR of the control plane network.
@@ -41,3 +44,4 @@ outputs:
       storage: {get_param: StorageIpSubnet}
       storage_mgmt: {get_param: StorageMgmtIpSubnet}
       tenant: {get_param: TenantIpSubnet}
+      management: {get_param: ManagementIpSubnet}
diff --git a/overcloud-resource-registry-puppet.yaml b/overcloud-resource-registry-puppet.yaml
index e8291377b4..3567112a4b 100644
--- a/overcloud-resource-registry-puppet.yaml
+++ b/overcloud-resource-registry-puppet.yaml
@@ -61,6 +61,7 @@ resource_registry:
   OS::TripleO::Network::StorageMgmt: network/noop.yaml
   OS::TripleO::Network::Storage: network/noop.yaml
   OS::TripleO::Network::Tenant: network/noop.yaml
+  OS::TripleO::Network::Management: network/noop.yaml
 
   OS::TripleO::Network::Ports::NetVipMap: network/ports/net_ip_map.yaml
   OS::TripleO::Network::Ports::NetIpMap: network/ports/net_ip_map.yaml
@@ -80,25 +81,30 @@ resource_registry:
   OS::TripleO::Controller::Ports::StoragePort: network/ports/noop.yaml
   OS::TripleO::Controller::Ports::StorageMgmtPort: network/ports/noop.yaml
   OS::TripleO::Controller::Ports::TenantPort: network/ports/noop.yaml
+  OS::TripleO::Controller::Ports::ManagementPort: network/ports/noop.yaml
 
   # Port assignments for the compute role
   OS::TripleO::Compute::Ports::InternalApiPort: network/ports/noop.yaml
   OS::TripleO::Compute::Ports::StoragePort: network/ports/noop.yaml
   OS::TripleO::Compute::Ports::TenantPort: network/ports/noop.yaml
+  OS::TripleO::Compute::Ports::ManagementPort: network/ports/noop.yaml
 
   # Port assignments for the ceph storage role
   OS::TripleO::CephStorage::Ports::StoragePort: network/ports/noop.yaml
   OS::TripleO::CephStorage::Ports::StorageMgmtPort: network/ports/noop.yaml
+  OS::TripleO::CephStorage::Ports::ManagementPort: network/ports/noop.yaml
 
   # Port assignments for the swift storage role
   OS::TripleO::SwiftStorage::Ports::InternalApiPort: network/ports/noop.yaml
   OS::TripleO::SwiftStorage::Ports::StoragePort: network/ports/noop.yaml
   OS::TripleO::SwiftStorage::Ports::StorageMgmtPort: network/ports/noop.yaml
+  OS::TripleO::SwiftStorage::Ports::ManagementPort: network/ports/noop.yaml
 
   # Port assignments for the block storage role
   OS::TripleO::BlockStorage::Ports::InternalApiPort: network/ports/noop.yaml
   OS::TripleO::BlockStorage::Ports::StoragePort: network/ports/noop.yaml
   OS::TripleO::BlockStorage::Ports::StorageMgmtPort: network/ports/noop.yaml
+  OS::TripleO::BlockStorage::Ports::ManagementPort: network/ports/noop.yaml
 
   # Service Endpoint Mappings
   OS::TripleO::Endpoint: network/endpoints/endpoint.yaml
diff --git a/overcloud.yaml b/overcloud.yaml
index 416b9d5f89..7292b49e27 100644
--- a/overcloud.yaml
+++ b/overcloud.yaml
@@ -1139,6 +1139,7 @@ resources:
       StorageIpList: {get_attr: [Controller, storage_ip_address]}
       StorageMgmtIpList: {get_attr: [Controller, storage_mgmt_ip_address]}
       TenantIpList: {get_attr: [Controller, tenant_ip_address]}
+      ManagementIpList: {get_attr: [Controller, management_ip_address]}
 
   allNodesConfig:
     type: OS::TripleO::AllNodes::SoftwareConfig
@@ -1248,7 +1249,7 @@ resources:
       InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
       StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
       StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
-      # No tenant VIP required
+      # No tenant or management VIP required
 
   VipConfig:
     type: OS::TripleO::VipConfig
diff --git a/puppet/ceph-storage.yaml b/puppet/ceph-storage.yaml
index b6a1007a54..8291ad555a 100644
--- a/puppet/ceph-storage.yaml
+++ b/puppet/ceph-storage.yaml
@@ -122,12 +122,18 @@ resources:
     properties:
       ControlPlaneIP: {get_attr: [CephStorage, networks, ctlplane, 0]}
 
+  ManagementPort:
+    type: OS::TripleO::CephStorage::Ports::ManagementPort
+    properties:
+      ControlPlaneIP: {get_attr: [CephStorage, networks, ctlplane, 0]}
+
   NetworkConfig:
     type: OS::TripleO::CephStorage::Net::SoftwareConfig
     properties:
       ControlPlaneIp: {get_attr: [CephStorage, networks, ctlplane, 0]}
       StorageIpSubnet: {get_attr: [StoragePort, ip_subnet]}
       StorageMgmtIpSubnet: {get_attr: [StorageMgmtPort, ip_subnet]}
+      ManagementIpSubnet: {get_attr: [ManagementPort, ip_subnet]}
 
   NetIpMap:
     type: OS::TripleO::Network::Ports::NetIpMap
@@ -135,6 +141,7 @@ resources:
       ControlPlaneIp: {get_attr: [CephStorage, networks, ctlplane, 0]}
       StorageIp: {get_attr: [StoragePort, ip_address]}
       StorageMgmtIp: {get_attr: [StorageMgmtPort, ip_address]}
+      ManagementIp: {get_attr: [ManagementPort, ip_address]}
 
   NetIpSubnetMap:
     type: OS::TripleO::Network::Ports::NetIpSubnetMap
@@ -142,6 +149,7 @@ resources:
       ControlPlaneIp: {get_attr: [CephStorage, networks, ctlplane, 0]}
       StorageIpSubnet: {get_attr: [StoragePort, ip_subnet]}
       StorageMgmtIpSubnet: {get_attr: [StorageMgmtPort, ip_subnet]}
+      ManagementIpSubnet: {get_attr: [ManagementPort, ip_subnet]}
 
   NetworkDeployment:
     type: OS::TripleO::SoftwareDeployment
@@ -247,6 +255,9 @@ outputs:
   storage_mgmt_ip_address:
     description: IP address of the server in the storage_mgmt network
     value: {get_attr: [StorageMgmtPort, ip_address]}
+  management_ip_address:
+    description: IP address of the server in the management network
+    value: {get_attr: [ManagementPort, ip_address]}
   config_identifier:
     description: identifier which changes if the node configuration may need re-applying
     value:
diff --git a/puppet/cinder-storage.yaml b/puppet/cinder-storage.yaml
index fc197059c4..3e9eb5a8c2 100644
--- a/puppet/cinder-storage.yaml
+++ b/puppet/cinder-storage.yaml
@@ -181,6 +181,11 @@ resources:
     properties:
       ControlPlaneIP: {get_attr: [BlockStorage, networks, ctlplane, 0]}
 
+  ManagementPort:
+    type: OS::TripleO::BlockStorage::Ports::ManagementPort
+    properties:
+      ControlPlaneIP: {get_attr: [BlockStorage, networks, ctlplane, 0]}
+
   NetworkConfig:
     type: OS::TripleO::BlockStorage::Net::SoftwareConfig
     properties:
@@ -188,6 +193,7 @@ resources:
       InternalApiIpSubnet: {get_attr: [InternalApiPort, ip_subnet]}
       StorageIpSubnet: {get_attr: [StoragePort, ip_subnet]}
       StorageMgmtIpSubnet: {get_attr: [StorageMgmtPort, ip_subnet]}
+      ManagementIpSubnet: {get_attr: [ManagementPort, ip_subnet]}
 
   NetIpMap:
     type: OS::TripleO::Network::Ports::NetIpMap
@@ -196,6 +202,7 @@ resources:
       InternalApiIp: {get_attr: [InternalApiPort, ip_address]}
       StorageIp: {get_attr: [StoragePort, ip_address]}
       StorageMgmtIp: {get_attr: [StorageMgmtPort, ip_address]}
+      ManagementIp: {get_attr: [ManagementPort, ip_address]}
 
   NetworkDeployment:
     type: OS::TripleO::SoftwareDeployment
@@ -325,6 +332,9 @@ outputs:
   storage_mgmt_ip_address:
     description: IP address of the server in the storage_mgmt network
     value: {get_attr: [StorageMgmtPort, ip_address]}
+  management_ip_address:
+    description: IP address of the server in the management network
+    value: {get_attr: [ManagementPort, ip_address]}
   config_identifier:
     description: identifier which changes if the node configuration may need re-applying
     value:
diff --git a/puppet/compute.yaml b/puppet/compute.yaml
index 43ef582001..82129f0b95 100644
--- a/puppet/compute.yaml
+++ b/puppet/compute.yaml
@@ -359,6 +359,11 @@ resources:
     properties:
       ControlPlaneIP: {get_attr: [NovaCompute, networks, ctlplane, 0]}
 
+  ManagementPort:
+    type: OS::TripleO::Compute::Ports::ManagementPort
+    properties:
+      ControlPlaneIP: {get_attr: [NovaCompute, networks, ctlplane, 0]}
+
   NetIpMap:
     type: OS::TripleO::Network::Ports::NetIpMap
     properties:
@@ -366,6 +371,7 @@ resources:
       InternalApiIp: {get_attr: [InternalApiPort, ip_address]}
       StorageIp: {get_attr: [StoragePort, ip_address]}
       TenantIp: {get_attr: [TenantPort, ip_address]}
+      ManagementIp: {get_attr: [ManagementPort, ip_address]}
 
   NetworkConfig:
     type: OS::TripleO::Compute::Net::SoftwareConfig
@@ -374,6 +380,7 @@ resources:
       InternalApiIpSubnet: {get_attr: [InternalApiPort, ip_subnet]}
       StorageIpSubnet: {get_attr: [StoragePort, ip_subnet]}
       TenantIpSubnet: {get_attr: [TenantPort, ip_subnet]}
+      ManagementIpSubnet: {get_attr: [ManagementPort, ip_subnet]}
 
   NetworkDeployment:
     type: OS::TripleO::SoftwareDeployment
@@ -629,6 +636,9 @@ outputs:
   tenant_ip_address:
     description: IP address of the server in the tenant network
     value: {get_attr: [TenantPort, ip_address]}
+  management_ip_address:
+    description: IP address of the server in the management network
+    value: {get_attr: [ManagementPort, ip_address]}
   hostname:
     description: Hostname of the server
     value: {get_attr: [NovaCompute, name]}
diff --git a/puppet/controller.yaml b/puppet/controller.yaml
index 20379292ac..74b9227775 100644
--- a/puppet/controller.yaml
+++ b/puppet/controller.yaml
@@ -760,6 +760,11 @@ resources:
       NodeIndex: {get_param: NodeIndex}
       ControlPlaneIP: {get_attr: [Controller, networks, ctlplane, 0]}
 
+  ManagementPort:
+    type: OS::TripleO::Controller::Ports::ManagementPort
+    properties:
+      ControlPlaneIP: {get_attr: [Controller, networks, ctlplane, 0]}
+
   NetIpMap:
     type: OS::TripleO::Network::Ports::NetIpMap
     properties:
@@ -769,6 +774,7 @@ resources:
       StorageIp: {get_attr: [StoragePort, ip_address]}
       StorageMgmtIp: {get_attr: [StorageMgmtPort, ip_address]}
       TenantIp: {get_attr: [TenantPort, ip_address]}
+      ManagementIp: {get_attr: [ManagementPort, ip_address]}
 
   NetIpSubnetMap:
     type: OS::TripleO::Network::Ports::NetIpSubnetMap
@@ -779,6 +785,7 @@ resources:
       StorageIpSubnet: {get_attr: [StoragePort, ip_subnet]}
       StorageMgmtIpSubnet: {get_attr: [StorageMgmtPort, ip_subnet]}
       TenantIpSubnet: {get_attr: [TenantPort, ip_subnet]}
+      ManagementIpSubnet: {get_attr: [ManagementPort, ip_subnet]}
 
   NetworkConfig:
     type: OS::TripleO::Controller::Net::SoftwareConfig
@@ -789,6 +796,7 @@ resources:
       StorageIpSubnet: {get_attr: [StoragePort, ip_subnet]}
       StorageMgmtIpSubnet: {get_attr: [StorageMgmtPort, ip_subnet]}
       TenantIpSubnet: {get_attr: [TenantPort, ip_subnet]}
+      ManagementIpSubnet: {get_attr: [ManagementPort, ip_subnet]}
 
   NetworkDeployment:
     type: OS::TripleO::SoftwareDeployment
@@ -1489,6 +1497,9 @@ outputs:
   tenant_ip_address:
     description: IP address of the server in the tenant network
     value: {get_attr: [TenantPort, ip_address]}
+  management_ip_address:
+    description: IP address of the server in the management network
+    value: {get_attr: [ManagementPort, ip_address]}
   hostname:
     description: Hostname of the server
     value: {get_attr: [Controller, name]}
diff --git a/puppet/swift-storage.yaml b/puppet/swift-storage.yaml
index 721dcba469..932652f5c8 100644
--- a/puppet/swift-storage.yaml
+++ b/puppet/swift-storage.yaml
@@ -150,6 +150,11 @@ resources:
     properties:
       ControlPlaneIP: {get_attr: [SwiftStorage, networks, ctlplane, 0]}
 
+  ManagementPort:
+    type: OS::TripleO::SwiftStorage::Ports::ManagementPort
+    properties:
+      ControlPlaneIP: {get_attr: [SwiftStorage, networks, ctlplane, 0]}
+
   NetworkConfig:
     type: OS::TripleO::ObjectStorage::Net::SoftwareConfig
     properties:
@@ -157,6 +162,7 @@ resources:
       InternalApiIpSubnet: {get_attr: [InternalApiPort, ip_subnet]}
       StorageIpSubnet: {get_attr: [StoragePort, ip_subnet]}
       StorageMgmtIpSubnet: {get_attr: [StorageMgmtPort, ip_subnet]}
+      ManagementIpSubnet: {get_attr: [ManagementPort, ip_subnet]}
 
   NetIpMap:
     type: OS::TripleO::Network::Ports::NetIpMap
@@ -165,6 +171,7 @@ resources:
       InternalApiIp: {get_attr: [InternalApiPort, ip_address]}
       StorageIp: {get_attr: [StoragePort, ip_address]}
       StorageMgmtIp: {get_attr: [StorageMgmtPort, ip_address]}
+      ManagementIp: {get_attr: [ManagementPort, ip_address]}
 
   NetworkDeployment:
     type: OS::TripleO::SoftwareDeployment
@@ -292,6 +299,9 @@ outputs:
   storage_mgmt_ip_address:
     description: IP address of the server in the storage_mgmt network
     value: {get_attr: [StorageMgmtPort, ip_address]}
+  management_ip_address:
+    description: IP address of the server in the management network
+    value: {get_attr: [ManagementPort, ip_address]}
   config_identifier:
     description: identifier which changes if the node configuration may need re-applying
     value: