Add inside and outside roles for VLANs
Will probably rename inside/outside and office/server to int/ext.
This commit is contained in:
parent
0802dc8637
commit
aeb124e346
51
README.md
51
README.md
|
@ -44,7 +44,40 @@ The following values are used throughout the network and should be defined in a
|
|||
* `wg_net`: client wireguard IPv4 addresses are assigned from this range
|
||||
* `wg_net6`: client wireguard IPv6 addresses are assigned from this range
|
||||
|
||||
### Common setup
|
||||
Device‐ and network‐specific configuration is described in the following sections. All JSON samples in this document are subsets of the inventory as returned by Ansible. Omitted values should be set to null or empty unless stated otherwise (except for foreign keys such as `type` and `role`, where some values are omitted for brevity).
|
||||
|
||||
### Network
|
||||
|
||||
Each VLAN is EVPNed among all leaves, so it can be used with any port on any access switch. All non‐local traffic leaves and enters a VLAN through exit leaves and optionally the firewall. Each firewalled or “inside” VLAN is placed in a separate VRF on the exits, so inter-VLAN traffic is also filtered. For example:
|
||||
|
||||
{
|
||||
"vid": 3208, "name": "office-rc",
|
||||
"group": { "name": "new-net" }, "role": { "name": "inside" },
|
||||
"tenant": { "slug": "fri-it" }
|
||||
},
|
||||
{
|
||||
"vid": 3308, "name": "server-rc",
|
||||
"group": { "name": "new-net" }, "role": { "name": "outside" },
|
||||
"tenant": { "slug": "fri-it" }
|
||||
}
|
||||
|
||||
The `group` property is used to filter out legacy VLANs and should match the value in `group_vars/all/main.yml`. Set the `role` to `inside` or `outside` to place the network behind a firewall or not.
|
||||
|
||||
Associate one or more IPv4 and IPv6 prefixes to each VLAN. Assign the role `dhcp-pool` to an IPv4 prefix to enable a DHCP relay on the exits for that subnet. For example:
|
||||
|
||||
{
|
||||
"prefix": "2001:1470:fffd:3208::/64", "family": { "value": 6 },
|
||||
"tenant": { "slug": "fri-it" },
|
||||
"vlan": { "name": "office-rc" }
|
||||
},
|
||||
{
|
||||
"prefix": "10.32.8.0/24", "family": { "value": 4 },
|
||||
"tenant": { "slug": "fri-it" },
|
||||
"vlan": { "name": "office-rc" }
|
||||
"role": { "slug": "dhcp-pool" },
|
||||
}
|
||||
|
||||
### Devices
|
||||
|
||||
For most devices a management interface must be defined to run Ansible scripts, with at least the IP address and default gateway set:
|
||||
|
||||
|
@ -56,7 +89,7 @@ For most devices a management interface must be defined to run Ansible scripts,
|
|||
"custom_fields": { "gateway": { "address": "10.20.30.1/24" } }
|
||||
}
|
||||
|
||||
The MAC address is only used in some playbooks to set the interface name. All JSON samples in this document are subsets of the inventory as returned by Ansible. Omitted values should be set to null or empty unless stated otherwise (except for foreign keys such as `type` and `role`, where some values are omitted for brevity).
|
||||
The MAC address is only used in some playbooks to set the interface name.
|
||||
|
||||
#### L1 setup
|
||||
|
||||
|
@ -126,19 +159,19 @@ For dual-attached devices we form a MLAG between two leaf switches. Each leaf mu
|
|||
"connected_endpoints": [ { "device": { "name": "exit-2" }, "name": "swp30" } ]
|
||||
},
|
||||
|
||||
For each dual‐attached L2 device (server or switch) first create a bond on each leaf. Note that, on Cumulus Linux on Mellanox switches, a bond must be created even if a single interface is used on a particular switch. For example, the bond for [access-bdc-1](https://netbox.fri.uni-lj.si/search/?q=access-bdc-1&obj_types=dcim.device&lookup=iexact) on [exit-1](https://netbox.fri.uni-lj.si/search/?q=exit-1&obj_types=dcim.device&lookup=iexact):
|
||||
For each dual‐attached L2 device (server or switch) first create a bond on each leaf. Note that, on Cumulus Linux on Mellanox switches, a bond must be created even if a single interface is used on a particular switch. For example, the bond for [sw-bdc-c3-1](https://netbox.fri.uni-lj.si/search/?q=sw-bdc-c3-1&obj_types=dcim.device&lookup=iexact) on [exit-1](https://netbox.fri.uni-lj.si/search/?q=exit-1&obj_types=dcim.device&lookup=iexact):
|
||||
|
||||
{
|
||||
"name": "access-bdc-1", "type": { "value": "lag" },
|
||||
"name": "sw-bdc-c3-1", "type": { "value": "lag" },
|
||||
"bridge": { "name": "bridge" }
|
||||
}
|
||||
|
||||
Assign the new bond all interfaces connecting to the device (here the bond has the name of the attached L2 switch `access-bdc-1`):
|
||||
Assign the new bond all interfaces connecting to the device (here the bond has the name of the attached L2 switch `sw-bdc-c3-1`):
|
||||
|
||||
{
|
||||
"name": "swp23s0",
|
||||
"lag": { "name": "access-bdc-1" },
|
||||
"connected_endpoints": [ { "device": { "name": "access-bdc-1" }, "name": "ethernet 1/0/49" } ]
|
||||
"lag": { "name": "sw-bdc-c3-1" },
|
||||
"connected_endpoints": [ { "device": { "name": "sw-bdc-c3-1" }, "name": "ethernet 1/0/49" } ]
|
||||
}
|
||||
|
||||
If a bond with the same name (except `peerlink`) exists on both peer switches, a [MLAG ID](https://docs.nvidia.com/networking-ethernet-software/cumulus-linux/Layer-2/Multi-Chassis-Link-Aggregation-MLAG/#basic-configuration) is assigned automatically. In this case the (same) [VXLAN anycast IP](https://docs.nvidia.com/networking-ethernet-software/cumulus-linux/Network-Virtualization/VXLAN-Active-Active-Mode/#configure-vxlan-active-active) should be set on each leaf’s loopback interface.
|
||||
|
@ -149,9 +182,9 @@ The device on the other end of the bond should use the active‐active 802.3ad (
|
|||
|
||||
### Access switches
|
||||
|
||||
Currently all [access switches](https://netbox.fri.uni-lj.si/search/?q=access-%5Bbcr%5Ddc-%28poe-%29%3F%5B0-9%5D%2B&obj_types=dcim.device&lookup=iregex) are D-Link DGS-1510. Connection parameters are set for those device types in a [config context](https://netbox.fri.uni-lj.si/extras/config-contexts/1/) and applied automatically by Ansible.
|
||||
Current [access switches](https://netbox.fri.uni-lj.si/search/?q=sw-%5Bbcr%5Ddc-%5Bcr%5D%5B0-9%5D-%5B0-9%5D%2B&obj_types=dcim.device&lookup=iregex) are D-Link DGS-1510 and FS 5860. Connection parameters for each device type are set in [config contexts](https://netbox.fri.uni-lj.si/extras/config-contexts/?q=ansible) and applied automatically by Ansible.
|
||||
|
||||
The config template supports configuring the port channels and tagging ports, but is otherwise limited to this setup. Further additions should attempt to preserve (fake) idempotency by filtering out unimportant differing lines.
|
||||
[Configuration templates](https://netbox.fri.uni-lj.si/extras/config-templates/) for access switches are stored in NetBox. The templates support setting up port channels and port tagging.
|
||||
|
||||
To set up a bonded interface to exit switches, configure these interfaces:
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
vlans: "{{ query('netbox.netbox.nb_lookup', 'vlans', api_filter='group=new-net', raw_data=true) | sort(attribute='vid') }}"
|
||||
vlans: "{{ query('netbox.netbox.nb_lookup', 'vlans', api_filter='group=new-net', raw_data=true) | selectattr('role') | sort(attribute='vid') }}"
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
| map(attribute='address') %}
|
||||
{% set my_index = inventory_hostname.split('-')[1]|int %}
|
||||
{% set bridge = interfaces | selectattr('type') | selectattr('type.value', '==', 'bridge') | first %}
|
||||
{% set my_vlans = bridge.tagged_vlans | sort(attribute='vid') -%}
|
||||
{% set bridge_vlans = vlans | selectattr('vid', 'in', bridge.tagged_vlans | map(attribute='vid')) -%}
|
||||
{% set inside_vlans = bridge_vlans | selectattr('role.slug', '==', 'inside') -%}
|
||||
|
||||
frr defaults datacenter
|
||||
log syslog informational
|
||||
|
@ -162,7 +163,7 @@ router bgp {{ asn.asn }} vrf inside
|
|||
{% endfor %}
|
||||
|
||||
redistribute connected route-map loopback-inside
|
||||
{% for vlan in my_vlans %}
|
||||
{% for vlan in inside_vlans %}
|
||||
import vrf {{ vlan.name }}
|
||||
{% endfor %}
|
||||
import vrf default
|
||||
|
@ -184,7 +185,7 @@ router bgp {{ asn.asn }} vrf inside
|
|||
{% endfor %}
|
||||
|
||||
redistribute connected route-map loopback-inside
|
||||
{% for vlan in my_vlans %}
|
||||
{% for vlan in inside_vlans %}
|
||||
import vrf {{ vlan.name }}
|
||||
{% endfor %}
|
||||
import vrf default
|
||||
|
@ -192,7 +193,7 @@ router bgp {{ asn.asn }} vrf inside
|
|||
exit-address-family
|
||||
|
||||
|
||||
{% for vlan in my_vlans %}
|
||||
{% for vlan in inside_vlans %}
|
||||
# VRF for L2 network {{ vlan.name }}. Imports gateway from inside VRF.
|
||||
router bgp {{ asn.asn }} vrf {{ vlan.name }}
|
||||
bgp bestpath as-path multipath-relax
|
||||
|
@ -218,7 +219,7 @@ ipv6 prefix-list default permit ::/0
|
|||
ip prefix-list fabric permit 10.34.0.0/24 ge 32
|
||||
ipv6 prefix-list fabric permit 2001:1470:fffd:3400::/64 ge 128
|
||||
|
||||
{% for vlan in my_vlans %}
|
||||
{% for vlan in inside_vlans %}
|
||||
{% set prefixes = query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vlan_id='~vlan.id, raw_data=true) %}
|
||||
{% for prefix in prefixes %}
|
||||
{% if prefix.family.value == 4 %}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{# Note that there must be exactly one VLAN-aware bridge. #}
|
||||
{% set bridge = interfaces | selectattr('type') | selectattr('type.value', '==', 'bridge') | first %}
|
||||
{% set my_vlans = bridge.tagged_vlans | sort(attribute='vid') -%}
|
||||
{% set bridge_vlans = vlans | selectattr('vid', 'in', bridge.tagged_vlans | map(attribute='vid')) -%}
|
||||
|
||||
# VRFs.
|
||||
{% for vlan in my_vlans %}
|
||||
# A separate VRF for each inside network so we can firewall between them.
|
||||
{% for vlan in bridge_vlans | selectattr('role.slug', '==', 'inside') %}
|
||||
auto {{ vlan.name }}
|
||||
iface {{ vlan.name }}
|
||||
vrf-table auto
|
||||
|
@ -11,12 +11,12 @@ iface {{ vlan.name }}
|
|||
{% endfor %}
|
||||
|
||||
# Interfaces.
|
||||
{% for vlan in my_vlans %}
|
||||
{% for vlan in bridge_vlans %}
|
||||
{% set prefixes = query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vlan_id='~vlan.id, raw_data=true)
|
||||
| map(attribute='prefix') %}
|
||||
auto {{ bridge.name }}.{{ vlan.vid }}
|
||||
iface {{ bridge.name }}.{{ vlan.vid }}
|
||||
vrf {{ vlan.name }}
|
||||
vrf {% if vlan.role.slug == 'outside' %}outside{% else %}{{ vlan.name }}{% endif +%}
|
||||
mtu 9216
|
||||
{% if peer is defined %}
|
||||
{% set my_index = inventory_hostname.split('-')[1]|int %}
|
||||
|
|
|
@ -86,11 +86,11 @@ ipv6 prefix-list default permit ::/0
|
|||
|
||||
ip prefix-list fabric permit 10.34.0.0/24 ge 32
|
||||
|
||||
{% for vlan in vlans %}
|
||||
{% for vlan in vlans | selectattr('role.slug', '==', 'inside') %}
|
||||
{% for prefix in query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vlan_id='~vlan.id, raw_data=true) %}
|
||||
{% if prefix.family.value == 4 %}
|
||||
ip prefix-list office permit {{ prefix.prefix }} ge 24
|
||||
{% else %}
|
||||
{% elif prefix.family.value == 6 %}
|
||||
ipv6 prefix-list office permit {{ prefix.prefix }} ge 64
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
9
roles/firewall/templates/networks.nft.j2
Normal file
9
roles/firewall/templates/networks.nft.j2
Normal file
|
@ -0,0 +1,9 @@
|
|||
{% for vlan in vlans %}
|
||||
set {{ vlan.name }} {
|
||||
type ipv4_addr; flags interval
|
||||
}
|
||||
set {{ vlan.name }}/6 {
|
||||
type ipv6_addr; flags interval
|
||||
}
|
||||
|
||||
{% endfor %}
|
Loading…
Reference in a new issue