diff --git a/README.rst b/README.rst
index 15f4bf0..97a1584 100644
--- a/README.rst
+++ b/README.rst
@@ -277,7 +277,7 @@ To support this, the region list can actually be a list of dicts, and any
 setting that can be set at the cloud level can be overridden for that
 region.
 
-::
+.. code-block:: yaml
 
   clouds:
     internap:
diff --git a/doc/source/index.rst b/doc/source/index.rst
index bf667b7..f7263c9 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -6,6 +6,7 @@
    vendor-support
    contributing
    installation
+   network-config
    api-reference
    releasenotes
 
diff --git a/doc/source/network-config.rst b/doc/source/network-config.rst
new file mode 100644
index 0000000..9bbbf9d
--- /dev/null
+++ b/doc/source/network-config.rst
@@ -0,0 +1,47 @@
+==============
+Network Config
+==============
+
+There are several different qualities that networks in OpenStack might have
+that might not be able to be automatically inferred from the available
+metadata. To help users navigate more complex setups, `os-client-config`
+allows configuring a list of network metadata.
+
+.. code-block:: yaml
+
+  clouds:
+    amazing:
+      networks:
+      - name: blue
+        routes_externally: true
+      - name: purple
+        routes_externally: true
+        default_interface: true
+      - name: green
+        routes_externally: false
+      - name: purple
+        routes_externally: false
+        nat_destination: true
+
+Every entry must have a name field, which can hold either the name or the id
+of the network.
+
+`routes_externally` is a boolean field that labels the network as handling
+north/south traffic off of the cloud. In a public cloud this might be thought
+of as the "public" network, but in private clouds it's possible it might
+be an RFC1918 address. In either case, it's provides IPs to servers that
+things not on the cloud can use. This value defaults to `false`, which
+indicates only servers on the same network can talk to it.
+
+`default_interface` is a boolean field that indicates that the network is the
+one that programs should use. It defaults to false. An example of needing to
+use this value is a cloud with two private networks, and where a user is
+running ansible in one of the servers to talk to other servers on the private
+network. Because both networks are private, there would otherwise be no way
+to determine which one should be used for the traffic.
+
+`nat_destination` is a boolean field that indicates which network floating
+ips should be attached to. It defaults to false. Normally this can be inferred
+by looking for a network that has subnets that have a gateway_ip. But it's
+possible to have more than one network that satisfies that condition, so the
+user might want to tell programs which one to pick.
diff --git a/os_client_config/cloud_config.py b/os_client_config/cloud_config.py
index b19607e..e63bd12 100644
--- a/os_client_config/cloud_config.py
+++ b/os_client_config/cloud_config.py
@@ -438,3 +438,27 @@ class CloudConfig(object):
             if resource not in expiration:
                 return default
             return float(expiration[resource])
+
+    def get_external_networks(self):
+        """Get list of network names for external networks."""
+        return [
+            net['name'] for net in self._openstack_config['networks']
+            if net['routes_externally']]
+
+    def get_internal_networks(self):
+        """Get list of network names for internal networks."""
+        return [
+            net['name'] for net in self._openstack_config['networks']
+            if not net['routes_externally']]
+
+    def get_default_network(self):
+        """Get network used for default interactions."""
+        for net in self._openstack_config['networks']:
+            if net['default_interface']:
+                return net
+
+    def get_nat_destination(self):
+        """Get network used for NAT destination."""
+        for net in self._openstack_config['networks']:
+            if net['nat_destination']:
+                return net
diff --git a/os_client_config/config.py b/os_client_config/config.py
index 98870f6..2dd49c3 100644
--- a/os_client_config/config.py
+++ b/os_client_config/config.py
@@ -83,6 +83,8 @@ def set_default(key, value):
 
 
 def get_boolean(value):
+    if value is None:
+        return False
     if type(value) is bool:
         return value
     if value.lower() == 'true':
@@ -486,10 +488,37 @@ class OpenStackConfig(object):
                 or 'project_id' in cloud['auth']
                 or 'project_name' in cloud['auth'])
 
+    def _validate_networks(self, networks, key):
+        value = None
+        for net in networks:
+            if value and net[key]:
+                raise exceptions.OpenStackConfigException(
+                    "Duplicate network entries for {key}: {net1} and {net2}."
+                    " Only one network can be flagged with {key}".format(
+                        key=key,
+                        net1=value['name'],
+                        net2=net['name']))
+            if not value and net[key]:
+                value = net
+
     def _fix_backwards_networks(self, cloud):
         # Leave the external_network and internal_network keys in the
         # dict because consuming code might be expecting them.
-        networks = cloud.get('networks', [])
+        networks = []
+        # Normalize existing network entries
+        for net in cloud.get('networks', []):
+            name = net.get('name')
+            if not name:
+                raise exceptions.OpenStackConfigException(
+                    'Entry in network list is missing required field "name".')
+            network = dict(
+                name=name,
+                routes_externally=get_boolean(net.get('routes_externally')),
+                nat_destination=get_boolean(net.get('nat_destination')),
+                default_interface=get_boolean(net.get('default_interface')),
+            )
+            networks.append(network)
+
         for key in ('external_network', 'internal_network'):
             external = key.startswith('external')
             if key in cloud and 'networks' in cloud:
@@ -505,7 +534,14 @@ class OpenStackConfig(object):
                         key=key, name=cloud[key], external=external))
                 networks.append(dict(
                     name=cloud[key],
-                    routes_externally=external))
+                    routes_externally=external,
+                    nat_destination=not external,
+                    default_interface=external))
+
+        # Validate that we don't have duplicates
+        self._validate_networks(networks, 'nat_destination')
+        self._validate_networks(networks, 'default_interface')
+
         cloud['networks'] = networks
         return cloud
 
diff --git a/os_client_config/tests/test_config.py b/os_client_config/tests/test_config.py
index 0db1457..7c2bec0 100644
--- a/os_client_config/tests/test_config.py
+++ b/os_client_config/tests/test_config.py
@@ -779,8 +779,40 @@ class TestBackwardsCompatibility(base.TestCase):
             'external_network': 'public',
             'internal_network': 'private',
             'networks': [
-                {'name': 'public', 'routes_externally': True},
-                {'name': 'private', 'routes_externally': False},
+                {'name': 'public', 'routes_externally': True,
+                 'nat_destination': False, 'default_interface': True},
+                {'name': 'private', 'routes_externally': False,
+                 'nat_destination': True, 'default_interface': False},
             ]
         }
         self.assertEqual(expected, result)
+
+    def test_normalize_network(self):
+        c = config.OpenStackConfig(config_files=[self.cloud_yaml],
+                                   vendor_files=[self.vendor_yaml])
+        cloud = {
+            'networks': [
+                {'name': 'private'}
+            ]
+        }
+        result = c._fix_backwards_networks(cloud)
+        expected = {
+            'networks': [
+                {'name': 'private', 'routes_externally': False,
+                 'nat_destination': False, 'default_interface': False},
+            ]
+        }
+        self.assertEqual(expected, result)
+
+    def test_single_default_interface(self):
+        c = config.OpenStackConfig(config_files=[self.cloud_yaml],
+                                   vendor_files=[self.vendor_yaml])
+        cloud = {
+            'networks': [
+                {'name': 'blue', 'default_interface': True},
+                {'name': 'purple', 'default_interface': True},
+            ]
+        }
+        self.assertRaises(
+            exceptions.OpenStackConfigException,
+            c._fix_backwards_networks, cloud)
diff --git a/releasenotes/notes/network-list-e6e9dafdd8446263.yaml b/releasenotes/notes/network-list-e6e9dafdd8446263.yaml
index 8375488..8f793c2 100644
--- a/releasenotes/notes/network-list-e6e9dafdd8446263.yaml
+++ b/releasenotes/notes/network-list-e6e9dafdd8446263.yaml
@@ -3,9 +3,8 @@ features:
   - Support added for configuring metadata about networks
     for a cloud in a list of dicts, rather than in the
     external_network and internal_network entries. The dicts
-    support a name and a routes_externally field, as well as
-    any other arbitrary metadata needed by consuming
-    applications.
+    support a name, a routes_externally field, a nat_destination
+    field and a default_interface field.
 deprecations:
   - external_network and internal_network are deprecated and
     should be replaced with the list of network dicts.