exit: store VLAN interface addresses in NetBox
… instead of generating them from prefixes. A NetBox script can be used to create and configure all necessary data for a new VLAN. Instead of VLAN roles “inside" and “outside” we now create separate VRFs for inside VLANs to match the actual exit/firewall configuration. The “outside” VRF is for all VLANs that are directly accessible from the internet.
This commit is contained in:
parent
ece3b8a377
commit
db397cb2b1
|
@ -1 +1 @@
|
||||||
vlans: "{{ query('netbox.netbox.nb_lookup', 'vlans', api_filter='group=new-net', raw_data=true) | selectattr('role') | sort(attribute='vid') }}"
|
vlans: "{{ query('netbox.netbox.nb_lookup', 'vlans', api_filter='group=new-net', raw_data=true) | sort(attribute='vid') }}"
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
| map(attribute='ip_addresses') | first
|
| map(attribute='ip_addresses') | first
|
||||||
| selectattr('role') | selectattr('role.value', '==', 'loopback')
|
| selectattr('role') | selectattr('role.value', '==', 'loopback')
|
||||||
| map(attribute='address') %}
|
| map(attribute='address') %}
|
||||||
{% set my_index = inventory_hostname.split('-')[1]|int %}
|
{% set inside_vrfs = interfaces | selectattr('parent') | selectattr('parent.name', '==', 'bridge')
|
||||||
{% set bridge = interfaces | selectattr('type') | selectattr('type.value', '==', 'bridge') | first %}
|
| selectattr('vrf') | map(attribute='vrf') | rejectattr('name', '==', 'outside') -%}
|
||||||
{% 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
|
frr defaults datacenter
|
||||||
log syslog informational
|
log syslog informational
|
||||||
|
@ -159,8 +157,8 @@ router bgp {{ asn.asn }} vrf inside
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
redistribute connected route-map loopback-inside
|
redistribute connected route-map loopback-inside
|
||||||
{% for vlan in inside_vlans %}
|
{% for vrf in inside_vrfs %}
|
||||||
import vrf {{ vlan.name }}
|
import vrf {{ vrf.name }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
import vrf default
|
import vrf default
|
||||||
import vrf route-map inside-import
|
import vrf route-map inside-import
|
||||||
|
@ -181,17 +179,17 @@ router bgp {{ asn.asn }} vrf inside
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
redistribute connected route-map loopback-inside
|
redistribute connected route-map loopback-inside
|
||||||
{% for vlan in inside_vlans %}
|
{% for vrf in inside_vrfs %}
|
||||||
import vrf {{ vlan.name }}
|
import vrf {{ vrf.name }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
import vrf default
|
import vrf default
|
||||||
import vrf route-map inside-import
|
import vrf route-map inside-import
|
||||||
exit-address-family
|
exit-address-family
|
||||||
|
|
||||||
|
|
||||||
{% for vlan in inside_vlans %}
|
{% for vrf in inside_vrfs %}
|
||||||
# VRF for L2 network {{ vlan.name }}. Imports gateway from inside VRF.
|
# VRF for L2 network {{ vrf.name }}. Imports gateway from inside VRF.
|
||||||
router bgp {{ asn.asn }} vrf {{ vlan.name }}
|
router bgp {{ asn.asn }} vrf {{ vrf.name }}
|
||||||
bgp bestpath as-path multipath-relax
|
bgp bestpath as-path multipath-relax
|
||||||
|
|
||||||
address-family ipv4 unicast
|
address-family ipv4 unicast
|
||||||
|
@ -215,8 +213,8 @@ ipv6 prefix-list default permit ::/0
|
||||||
ip prefix-list fabric permit 10.34.0.0/24 ge 32
|
ip prefix-list fabric permit 10.34.0.0/24 ge 32
|
||||||
ipv6 prefix-list fabric permit 2001:1470:fffd:3400::/64 ge 128
|
ipv6 prefix-list fabric permit 2001:1470:fffd:3400::/64 ge 128
|
||||||
|
|
||||||
{% for vlan in inside_vlans %}
|
{% for vrf in inside_vrfs %}
|
||||||
{% set prefixes = query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vlan_id='~vlan.id, raw_data=true)
|
{% set prefixes = query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vrf_id='~vrf.id, raw_data=true)
|
||||||
| sort(attribute='family.value') %}
|
| sort(attribute='family.value') %}
|
||||||
{% for prefix in prefixes %}
|
{% for prefix in prefixes %}
|
||||||
{% if prefix.family.value == 4 %}
|
{% if prefix.family.value == 4 %}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
{% set bridge = interfaces | selectattr('type') | selectattr('type.value', '==', 'bridge') | first %}
|
|
||||||
{% set dhcp_networks = query('netbox.netbox.nb_lookup', 'prefixes', api_filter='role=dhcp-pool', raw_data=true)
|
{% set dhcp_networks = query('netbox.netbox.nb_lookup', 'prefixes', api_filter='role=dhcp-pool', raw_data=true)
|
||||||
| selectattr('vlan') | map(attribute='vlan.vid') | sort -%}
|
| selectattr('vlan') | map(attribute='vlan.vid') | sort -%}
|
||||||
|
|
||||||
|
@ -10,7 +9,9 @@ SERVERS="{{ dhcp }}"
|
||||||
# This variable requires a -i for each interface configured above.
|
# This variable requires a -i for each interface configured above.
|
||||||
# This will be used in the actual dhcrelay command
|
# This will be used in the actual dhcrelay command
|
||||||
# For example, "-i eth0 -i eth1"
|
# For example, "-i eth0 -i eth1"
|
||||||
INTF_CMD="{{ bridge.tagged_vlans | map(attribute='vid') | intersect(dhcp_networks) | sort | map('regex_replace', '^', '-id bridge.') | join(' ') }} -iu {{ iface_uplink }} -iu peerlink.4"
|
INTF_CMD="{{ interfaces | selectattr('parent') | selectattr('parent.name', '==', 'bridge')
|
||||||
|
| selectattr('untagged_vlan') | selectattr('untagged_vlan.vid', 'in', dhcp_networks)
|
||||||
|
| map(attribute='name') | sort | map('regex_replace', '^', '-id ') | join(' ') }} -iu {{ iface_uplink }} -iu peerlink.4"
|
||||||
|
|
||||||
# Additional options that are passed to the DHCP relay daemon?
|
# Additional options that are passed to the DHCP relay daemon?
|
||||||
OPTIONS="-U outside"
|
OPTIONS="-U outside"
|
||||||
|
|
|
@ -1,35 +1,11 @@
|
||||||
{# Note that there must be exactly one VLAN-aware bridge. #}
|
{# VRF outside is special, all others are inside but also firewalled from each other. #}
|
||||||
{% set bridge = interfaces | selectattr('type') | selectattr('type.value', '==', 'bridge') | first %}
|
{% set inside_vrfs = interfaces | selectattr('parent') | selectattr('parent.name', '==', 'bridge')
|
||||||
{% set bridge_vlans = vlans | selectattr('vid', 'in', bridge.tagged_vlans | map(attribute='vid')) -%}
|
| selectattr('vrf') | map(attribute='vrf') | rejectattr('name', '==', 'outside') -%}
|
||||||
|
|
||||||
# A separate VRF for each inside network so we can firewall between them.
|
# A separate VRF for each inside network so we can firewall between them.
|
||||||
{% for vlan in bridge_vlans | selectattr('role.slug', '==', 'inside') %}
|
{% for vrf in inside_vrfs %}
|
||||||
auto {{ vlan.name }}
|
auto {{ vrf.name }}
|
||||||
iface {{ vlan.name }}
|
iface {{ vrf.name }}
|
||||||
vrf-table auto
|
vrf-table auto
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
# Interfaces.
|
|
||||||
{% for vlan in bridge_vlans %}
|
|
||||||
{% set prefixes = query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vlan_id='~vlan.id, raw_data=true)
|
|
||||||
| sort(attribute='family.value') | map(attribute='prefix') %}
|
|
||||||
auto {{ bridge.name }}.{{ vlan.vid }}
|
|
||||||
iface {{ bridge.name }}.{{ vlan.vid }}
|
|
||||||
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 %}
|
|
||||||
{% for prefix in prefixes %}
|
|
||||||
address {{ prefix | ipaddr(1 + my_index) }}
|
|
||||||
{% endfor %}
|
|
||||||
{% if prefixes %}
|
|
||||||
address-virtual 00:00:5e:00:01:01 {{ prefixes | ipaddr(1) | join(' ') }}
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
{% for prefix in prefixes %}
|
|
||||||
address {{ prefix }}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{# Note that there must be exactly one VLAN-aware bridge. #}
|
{% set my_vlans = interfaces | selectattr('parent') | selectattr('parent.name', '==', 'bridge')
|
||||||
{% set bridge = interfaces | selectattr('type') | selectattr('type.value', '==', 'bridge') | first %}
|
| selectattr('untagged_vlan') | map(attribute='untagged_vlan') -%}
|
||||||
{% set my_vlans = bridge.tagged_vlans | sort(attribute='vid') -%}
|
|
||||||
|
|
||||||
# Send IPv6 RAs from virtual router IP for each network. Also set DNS options.
|
# Send IPv6 RAs from virtual router IP for each network. Also set DNS options.
|
||||||
# Both exits announce the same gateway, so don’t revoke it if we go down.
|
# Both exits announce the same gateway, so don’t revoke it if we go down.
|
||||||
|
|
|
@ -37,8 +37,13 @@ iface {{ iface.name }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{#- Addresses. #}
|
{#- Addresses. #}
|
||||||
{% for addr in iface.ip_addresses %}
|
{% for addr in iface.ip_addresses | rejectattr('role') %}
|
||||||
address {{ addr.address }}
|
address {{ addr.address }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% set anycast = iface.ip_addresses | selectattr('role') | selectattr('role.value', '==', 'anycast')
|
||||||
|
| map(attribute='address') %}
|
||||||
|
{% if anycast %}
|
||||||
|
address-virtual 00:00:5e:00:01:01 {{ anycast | ipaddr(1) | join(' ') }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -82,13 +82,15 @@ ipv6 prefix-list default permit ::/0
|
||||||
|
|
||||||
ip prefix-list fabric permit 10.34.0.0/24 ge 32
|
ip prefix-list fabric permit 10.34.0.0/24 ge 32
|
||||||
|
|
||||||
{% for vlan in vlans | selectattr('role.slug', '==', 'inside') %}
|
{% for vlan in vlans %}
|
||||||
{% for prefix in query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vlan_id='~vlan.id, raw_data=true) %}
|
{% for prefix in query('netbox.netbox.nb_lookup', 'prefixes', api_filter='vlan_id='~vlan.id, raw_data=true) %}
|
||||||
|
{% if prefix.vrf and prefix.vrf.name != 'outside' %}
|
||||||
{% if prefix.family.value == 4 %}
|
{% if prefix.family.value == 4 %}
|
||||||
ip prefix-list office permit {{ prefix.prefix }} ge 24
|
ip prefix-list office permit {{ prefix.prefix }} ge 24
|
||||||
{% elif prefix.family.value == 6 %}
|
{% elif prefix.family.value == 6 %}
|
||||||
ipv6 prefix-list office permit {{ prefix.prefix }} ge 64
|
ipv6 prefix-list office permit {{ prefix.prefix }} ge 64
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue