summaryrefslogtreecommitdiff
path: root/extensions
diff options
context:
space:
mode:
authoromnom62 <omnom62@outlook.com>2026-10-05 20:56:05 +1000
committeromnom62 <omnom62@outlook.com>2026-10-05 20:56:05 +1000
commit8ee802e41374942965b6b93cfb4534725ef45145 (patch)
treeef3e5579bd767422caa6fe77cea6a7b5d2d8562c /extensions
parent748df2bc1d35fa285dd3fe46916e1230408778c7 (diff)
downloadvyos.blueprints-main.tar.gz
vyos.blueprints-main.zip
T9393: new rolesmain
Diffstat (limited to 'extensions')
-rw-r--r--extensions/molecule/bgp_unnumbered/converge.yml6
-rw-r--r--extensions/molecule/bgp_unnumbered/inventory.yml23
-rw-r--r--extensions/molecule/bgp_unnumbered/molecule.yml28
-rw-r--r--extensions/molecule/bgp_unnumbered/topology.clab.yml14
-rw-r--r--extensions/molecule/bgp_unnumbered/verify.yml20
-rw-r--r--extensions/molecule/bridge_firewall/converge.yml7
-rw-r--r--extensions/molecule/bridge_firewall/inventory.yml94
-rw-r--r--extensions/molecule/bridge_firewall/molecule.yml27
-rw-r--r--extensions/molecule/bridge_firewall/topology.clab.yml63
-rw-r--r--extensions/molecule/bridge_firewall/verify.yml37
-rw-r--r--extensions/molecule/gre_tunnel/converge.yml7
-rw-r--r--extensions/molecule/gre_tunnel/inventory.yml24
-rw-r--r--extensions/molecule/gre_tunnel/molecule.yml28
-rw-r--r--extensions/molecule/gre_tunnel/topology.clab.yml12
-rw-r--r--extensions/molecule/gre_tunnel/verify.yml14
-rw-r--r--extensions/molecule/ipsec_route_based/converge.yml7
-rw-r--r--extensions/molecule/ipsec_route_based/inventory.yml61
-rw-r--r--extensions/molecule/ipsec_route_based/molecule.yml28
-rw-r--r--extensions/molecule/ipsec_route_based/topology.clab.yml32
-rw-r--r--extensions/molecule/ipsec_route_based/verify.yml29
-rw-r--r--extensions/molecule/ipsec_route_based_bgp/converge.yml7
-rw-r--r--extensions/molecule/ipsec_route_based_bgp/inventory.yml86
-rw-r--r--extensions/molecule/ipsec_route_based_bgp/molecule.yml28
-rw-r--r--extensions/molecule/ipsec_route_based_bgp/topology.clab.yml28
-rw-r--r--extensions/molecule/ipsec_route_based_bgp/verify.yml29
-rw-r--r--extensions/molecule/ipsec_route_based_bgp_dual/converge.yml7
-rw-r--r--extensions/molecule/ipsec_route_based_bgp_dual/inventory.yml115
-rw-r--r--extensions/molecule/ipsec_route_based_bgp_dual/molecule.yml29
-rw-r--r--extensions/molecule/ipsec_route_based_bgp_dual/topology.clab.yml39
-rw-r--r--extensions/molecule/ipsec_route_based_bgp_dual/verify.yml47
-rw-r--r--extensions/molecule/ospf_unnumbered/converge.yml7
-rw-r--r--extensions/molecule/ospf_unnumbered/inventory.yml26
-rw-r--r--extensions/molecule/ospf_unnumbered/molecule.yml28
-rw-r--r--extensions/molecule/ospf_unnumbered/topology.clab.yml20
-rw-r--r--extensions/molecule/ospf_unnumbered/verify.yml27
-rw-r--r--extensions/molecule/policy_ipsec_firewall/converge.yml9
-rw-r--r--extensions/molecule/policy_ipsec_firewall/inventory.yml131
-rw-r--r--extensions/molecule/policy_ipsec_firewall/molecule.yml28
-rw-r--r--extensions/molecule/policy_ipsec_firewall/topology.clab.yml51
-rw-r--r--extensions/molecule/policy_ipsec_firewall/verify.yml35
-rw-r--r--extensions/molecule/vrf_firewall/converge.yml7
-rw-r--r--extensions/molecule/vrf_firewall/inventory.yml54
-rw-r--r--extensions/molecule/vrf_firewall/molecule.yml27
-rw-r--r--extensions/molecule/vrf_firewall/topology.clab.yml43
-rw-r--r--extensions/molecule/vrf_firewall/verify.yml36
-rw-r--r--extensions/molecule/zone_firewall/converge.yml7
-rw-r--r--extensions/molecule/zone_firewall/inventory.yml33
-rw-r--r--extensions/molecule/zone_firewall/molecule.yml27
-rw-r--r--extensions/molecule/zone_firewall/topology.clab.yml34
-rw-r--r--extensions/molecule/zone_firewall/verify.yml30
50 files changed, 1636 insertions, 0 deletions
diff --git a/extensions/molecule/bgp_unnumbered/converge.yml b/extensions/molecule/bgp_unnumbered/converge.yml
new file mode 100644
index 0000000..3b3260a
--- /dev/null
+++ b/extensions/molecule/bgp_unnumbered/converge.yml
@@ -0,0 +1,6 @@
+---
+- name: Converge
+ hosts: fabric
+ gather_facts: false
+ roles:
+ - vyos.blueprints.bgp_unnumbered
diff --git a/extensions/molecule/bgp_unnumbered/inventory.yml b/extensions/molecule/bgp_unnumbered/inventory.yml
new file mode 100644
index 0000000..1785087
--- /dev/null
+++ b/extensions/molecule/bgp_unnumbered/inventory.yml
@@ -0,0 +1,23 @@
+---
+all:
+ children:
+ vyos:
+ children:
+ fabric:
+ hosts:
+ r1:
+ ansible_host: clab-bp-bgp-r1
+ bgp_unnumbered_asn: 64496
+ bgp_unnumbered_router_id: 192.168.0.1
+ r2:
+ ansible_host: clab-bp-bgp-r2
+ bgp_unnumbered_asn: 64499
+ bgp_unnumbered_router_id: 192.168.0.2
+ vars:
+ bgp_unnumbered_interfaces: [eth1, eth2]
+ bgp_unnumbered_group: fabric
+ vars:
+ ansible_network_os: vyos.vyos.vyos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_user: admin
+ ansible_password: admin
diff --git a/extensions/molecule/bgp_unnumbered/molecule.yml b/extensions/molecule/bgp_unnumbered/molecule.yml
new file mode 100644
index 0000000..9fa905c
--- /dev/null
+++ b/extensions/molecule/bgp_unnumbered/molecule.yml
@@ -0,0 +1,28 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+ - name: r2
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/bgp_unnumbered/topology.clab.yml b/extensions/molecule/bgp_unnumbered/topology.clab.yml
new file mode 100644
index 0000000..a370c2f
--- /dev/null
+++ b/extensions/molecule/bgp_unnumbered/topology.clab.yml
@@ -0,0 +1,14 @@
+name: bp-bgp
+topology:
+ kinds:
+ vyosnetworks_vyos:
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ nodes:
+ r1:
+ kind: vyosnetworks_vyos
+ r2:
+ kind: vyosnetworks_vyos
+ links:
+ # two parallel links without IP addresses; BGP peers over IPv6 link-local
+ - endpoints: ["r1:eth1", "r2:eth1"]
+ - endpoints: ["r1:eth2", "r2:eth2"]
diff --git a/extensions/molecule/bgp_unnumbered/verify.yml b/extensions/molecule/bgp_unnumbered/verify.yml
new file mode 100644
index 0000000..3f251af
--- /dev/null
+++ b/extensions/molecule/bgp_unnumbered/verify.yml
@@ -0,0 +1,20 @@
+---
+- name: Verify
+ hosts: fabric
+ gather_facts: false
+ tasks:
+ - name: Wait for BGP sessions and routes
+ ansible.builtin.pause:
+ seconds: 45
+ run_once: true
+
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.bgp_unnumbered
+ tasks_from: verify
+
+ - name: Ping the other router's loopback from this loopback, as on the docs page
+ vyos.vyos.vyos_ping:
+ dest: "{{ '192.168.0.2' if inventory_hostname == 'r1' else '192.168.0.1' }}"
+ source: "{{ bgp_unnumbered_router_id }}"
+ count: 3
diff --git a/extensions/molecule/bridge_firewall/converge.yml b/extensions/molecule/bridge_firewall/converge.yml
new file mode 100644
index 0000000..89558a3
--- /dev/null
+++ b/extensions/molecule/bridge_firewall/converge.yml
@@ -0,0 +1,7 @@
+---
+- name: Converge
+ hosts: vyos
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.bridge_firewall
diff --git a/extensions/molecule/bridge_firewall/inventory.yml b/extensions/molecule/bridge_firewall/inventory.yml
new file mode 100644
index 0000000..dface0d
--- /dev/null
+++ b/extensions/molecule/bridge_firewall/inventory.yml
@@ -0,0 +1,94 @@
+---
+all:
+ children:
+ vyos:
+ hosts:
+ r1:
+ ansible_host: clab-bp-bridge-r1
+ vars:
+ ansible_network_os: vyos.vyos.vyos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_user: admin
+ ansible_password: admin
+ # internet uplink: eth8 here, eth0 on the docs page (management in containerlab)
+ base_interfaces:
+ - {name: eth8, addresses: [203.0.113.1/24]}
+ bridge_firewall_bridges:
+ - name: br0
+ description: Isolated L2 bridge
+ members:
+ - {interface: eth1, description: br0}
+ - {interface: eth2, description: br0}
+ prerouting:
+ default_action: drop
+ rules:
+ - {number: 10, description: Accept IPv6 traffic, ethernet_type: ipv6}
+ forward:
+ default_action: accept
+
+ - name: br1
+ description: L3 bridge br1
+ addresses: [10.1.1.1/24]
+ members:
+ - {interface: eth3, description: br1}
+ - {interface: eth4, description: br1}
+ prerouting:
+ default_action: accept
+ rules:
+ - number: 10
+ description: Drop DHCP discover
+ action: drop
+ protocol: udp
+ source: {port: "68"}
+ destination: {port: "67", mac_address: "ff:ff:ff:ff:ff:ff"}
+ log: true
+ - {number: 20, description: Drop IPv6 traffic, action: drop, ethernet_type: ipv6}
+ forward:
+ default_action: drop
+ rules:
+ - {number: 10, description: Accept ARP, ethernet_type: arp}
+ - {number: 20, description: Accept ipv4 from host, source: {address: 10.1.1.102}, state: [new]}
+ ip_forward:
+ rules:
+ - {number: 10, description: br1 - allow internet access, outbound_interface: eth8}
+ router_access: accept
+
+ - name: br2
+ description: L3 bridge br2
+ addresses: [10.2.2.1/24]
+ members:
+ - {interface: eth5, description: br2 - Host}
+ - {interface: eth6, description: br2 - Trusted DHCP Server}
+ - {interface: eth7, description: br2}
+ prerouting:
+ default_action: accept
+ rules:
+ - {number: 10, description: Drop IPv6 traffic, action: drop, ethernet_type: ipv6}
+ forward:
+ default_action: drop
+ rules:
+ - number: 10
+ description: Accept DHCP discover
+ protocol: udp
+ source: {port: "68"}
+ destination: {port: "67", mac_address: "ff:ff:ff:ff:ff:ff"}
+ - number: 20
+ description: Accept DHCP offers from trusted interface
+ protocol: udp
+ source: {port: "67"}
+ destination: {port: "68"}
+ inbound_interface: eth6
+ - number: 22
+ description: Drop all other DHCP offers
+ action: drop
+ protocol: udp
+ source: {port: "67"}
+ destination: {port: "68"}
+ log: true
+ - {number: 30, description: Accept ARP, ethernet_type: arp}
+ - {number: 40, description: Accept ipv4, ethernet_type: ipv4}
+ ip_forward:
+ rules:
+ - {number: 10, description: br2 - allow internet access, outbound_interface: eth8}
+ - {number: 20, description: br2 - allow access to br1, outbound_bridge: br1}
+ router_access: drop
diff --git a/extensions/molecule/bridge_firewall/molecule.yml b/extensions/molecule/bridge_firewall/molecule.yml
new file mode 100644
index 0000000..612af0a
--- /dev/null
+++ b/extensions/molecule/bridge_firewall/molecule.yml
@@ -0,0 +1,27 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/bridge_firewall/topology.clab.yml b/extensions/molecule/bridge_firewall/topology.clab.yml
new file mode 100644
index 0000000..1b70e89
--- /dev/null
+++ b/extensions/molecule/bridge_firewall/topology.clab.yml
@@ -0,0 +1,63 @@
+name: bp-bridge
+topology:
+ nodes:
+ r1:
+ kind: vyosnetworks_vyos
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ h1:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 192.168.0.1/24 dev eth1
+ - ip -6 addr add fd00:b0::1/64 dev eth1
+ h2:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 192.168.0.2/24 dev eth1
+ - ip -6 addr add fd00:b0::2/64 dev eth1
+ h3:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 10.1.1.102/24 dev eth1
+ - ip route replace default via 10.1.1.1
+ h4:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 10.1.1.103/24 dev eth1
+ - ip route replace default via 10.1.1.1
+ h5:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 10.2.2.5/24 dev eth1
+ - ip route replace default via 10.2.2.1
+ h6:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 10.2.2.6/24 dev eth1
+ - ip route replace default via 10.2.2.1
+ h7:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 10.2.2.7/24 dev eth1
+ - ip route replace default via 10.2.2.1
+ wan:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 203.0.113.100/24 dev eth1
+ - ip route replace default via 203.0.113.1
+ links:
+ - endpoints: ["r1:eth1", "h1:eth1"]
+ - endpoints: ["r1:eth2", "h2:eth1"]
+ - endpoints: ["r1:eth3", "h3:eth1"]
+ - endpoints: ["r1:eth4", "h4:eth1"]
+ - endpoints: ["r1:eth5", "h5:eth1"]
+ - endpoints: ["r1:eth6", "h6:eth1"]
+ - endpoints: ["r1:eth7", "h7:eth1"]
+ - endpoints: ["r1:eth8", "wan:eth1"]
diff --git a/extensions/molecule/bridge_firewall/verify.yml b/extensions/molecule/bridge_firewall/verify.yml
new file mode 100644
index 0000000..dd2f042
--- /dev/null
+++ b/extensions/molecule/bridge_firewall/verify.yml
@@ -0,0 +1,37 @@
+---
+- name: Verify role state
+ hosts: vyos
+ gather_facts: false
+ tasks:
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.bridge_firewall
+ tasks_from: verify
+
+- name: Verify the page's requirements with traffic
+ hosts: localhost
+ gather_facts: false
+ vars:
+ _flows:
+ - {from: h1, ping: "-6 fd00:b0::2", allowed: true, why: "br0 accepts IPv6 within the bridge"}
+ - {from: h1, ping: "192.168.0.2", allowed: false, why: "br0 drops everything but IPv6"}
+ - {from: h3, ping: "10.1.1.103", allowed: true, why: "br1 accepts new IPv4 from 10.1.1.102"}
+ - {from: h4, ping: "10.1.1.102", allowed: false, why: "br1 drops other IPv4 connections"}
+ - {from: h3, ping: "10.1.1.1", allowed: true, why: "br1 may access the router"}
+ - {from: h3, ping: "203.0.113.100", allowed: true, why: "br1 may reach the internet"}
+ - {from: h3, ping: "10.2.2.5", allowed: false, why: "br1 may not reach other LANs"}
+ - {from: h5, ping: "10.2.2.7", allowed: true, why: "br2 accepts all IPv4"}
+ - {from: h5, ping: "10.2.2.1", allowed: false, why: "br2 may not access the router"}
+ - {from: h5, ping: "203.0.113.100", allowed: true, why: "br2 may reach the internet"}
+ - {from: h5, ping: "10.1.1.102", allowed: true, why: "br2 may connect to br1"}
+ tasks:
+ - name: Ping per requirement
+ ansible.builtin.command:
+ cmd: docker exec clab-bp-bridge-{{ item.from }} ping -c 2 -W 2 {{ item.ping }}
+ become: "{{ lookup('ansible.builtin.env', 'CLAB_BECOME', default='true') | bool }}"
+ register: _ping
+ changed_when: false
+ failed_when: (_ping.rc == 0) != item.allowed
+ loop: "{{ _flows }}"
+ loop_control:
+ label: "{{ item.from }} -> {{ item.ping }} ({{ item.why }})"
diff --git a/extensions/molecule/gre_tunnel/converge.yml b/extensions/molecule/gre_tunnel/converge.yml
new file mode 100644
index 0000000..913e659
--- /dev/null
+++ b/extensions/molecule/gre_tunnel/converge.yml
@@ -0,0 +1,7 @@
+---
+- name: Converge
+ hosts: gre
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.gre_tunnel
diff --git a/extensions/molecule/gre_tunnel/inventory.yml b/extensions/molecule/gre_tunnel/inventory.yml
new file mode 100644
index 0000000..191ed70
--- /dev/null
+++ b/extensions/molecule/gre_tunnel/inventory.yml
@@ -0,0 +1,24 @@
+---
+all:
+ children:
+ vyos:
+ children:
+ gre:
+ hosts:
+ r1:
+ ansible_host: clab-bp-gre-r1
+ base_interfaces:
+ - {name: eth1, addresses: [198.51.100.1/24]}
+ gre_tunnel_interfaces:
+ - {name: tun1, source_address: 198.51.100.1, remote: 198.51.100.2, mtu: 1376, adjust_mss: "1336", addresses: [172.16.122.1/30]}
+ r2:
+ ansible_host: clab-bp-gre-r2
+ base_interfaces:
+ - {name: eth1, addresses: [198.51.100.2/24]}
+ gre_tunnel_interfaces:
+ - {name: tun1, source_address: 198.51.100.2, remote: 198.51.100.1, mtu: 1376, adjust_mss: "1336", addresses: [172.16.122.2/30]}
+ vars:
+ ansible_network_os: vyos.vyos.vyos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_user: admin
+ ansible_password: admin
diff --git a/extensions/molecule/gre_tunnel/molecule.yml b/extensions/molecule/gre_tunnel/molecule.yml
new file mode 100644
index 0000000..9fa905c
--- /dev/null
+++ b/extensions/molecule/gre_tunnel/molecule.yml
@@ -0,0 +1,28 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+ - name: r2
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/gre_tunnel/topology.clab.yml b/extensions/molecule/gre_tunnel/topology.clab.yml
new file mode 100644
index 0000000..7a5e955
--- /dev/null
+++ b/extensions/molecule/gre_tunnel/topology.clab.yml
@@ -0,0 +1,12 @@
+name: bp-gre
+topology:
+ kinds:
+ vyosnetworks_vyos:
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ nodes:
+ r1:
+ kind: vyosnetworks_vyos
+ r2:
+ kind: vyosnetworks_vyos
+ links:
+ - endpoints: ["r1:eth1", "r2:eth1"]
diff --git a/extensions/molecule/gre_tunnel/verify.yml b/extensions/molecule/gre_tunnel/verify.yml
new file mode 100644
index 0000000..88f2442
--- /dev/null
+++ b/extensions/molecule/gre_tunnel/verify.yml
@@ -0,0 +1,14 @@
+---
+- name: Verify
+ hosts: gre
+ gather_facts: false
+ tasks:
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.gre_tunnel
+ tasks_from: verify
+
+ - name: Ping the other end through the tunnel
+ vyos.vyos.vyos_ping:
+ dest: "{{ '172.16.122.2' if inventory_hostname == 'r1' else '172.16.122.1' }}"
+ count: 3
diff --git a/extensions/molecule/ipsec_route_based/converge.yml b/extensions/molecule/ipsec_route_based/converge.yml
new file mode 100644
index 0000000..0fb7a50
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based/converge.yml
@@ -0,0 +1,7 @@
+---
+- name: Converge
+ hosts: vpn
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.ipsec_route_based
diff --git a/extensions/molecule/ipsec_route_based/inventory.yml b/extensions/molecule/ipsec_route_based/inventory.yml
new file mode 100644
index 0000000..92b460c
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based/inventory.yml
@@ -0,0 +1,61 @@
+---
+all:
+ children:
+ vyos:
+ children:
+ vpn:
+ hosts:
+ r1:
+ ansible_host: clab-bp-ipsec-vyos
+ base_interfaces:
+ - {name: eth1, addresses: [10.0.1.2/30]}
+ - {name: eth2, addresses: [192.168.0.1/24]}
+ ipsec_route_based_peers:
+ - name: CISCO
+ local_address: 10.0.1.2
+ remote_address: 10.0.2.2
+ psk: molecule-psk
+ connection_type: initiate
+ vti: {interface: vti1, address: 10.100.100.1/30, mtu: 1438}
+ ipsec_route_based_ospf:
+ router_id: 2.2.2.2
+ networks: [10.100.100.0/30, 192.168.0.0/24]
+ passive_interfaces: [eth2]
+ ipsec_route_based_default_gateway: 10.0.1.1
+ r2:
+ ansible_host: clab-bp-ipsec-cisco
+ base_interfaces:
+ - {name: eth1, addresses: [10.0.2.2/30]}
+ - {name: eth2, addresses: [192.168.10.1/24]}
+ ipsec_route_based_peers:
+ - name: VYOS
+ local_address: 10.0.2.2
+ remote_address: 10.0.1.2
+ psk: molecule-psk
+ connection_type: none
+ vti: {interface: vti1, address: 10.100.100.2/30, mtu: 1438}
+ ipsec_route_based_ospf:
+ router_id: 1.1.1.1
+ networks: [10.100.100.0/30, 192.168.10.0/24]
+ passive_interfaces: [eth2]
+ ipsec_route_based_default_gateway: 10.0.2.1
+ vars:
+ # proposals from the page's IKE and IPsec parameter tables
+ ipsec_route_based_ike_group:
+ name: IKE-GROUP
+ key_exchange: ikev1
+ lifetime: 28800
+ dh_group: 14
+ encryption: aes128
+ hash: sha1
+ ipsec_route_based_esp_group:
+ name: ESP-GROUP
+ lifetime: 3600
+ pfs: disable
+ encryption: aes256
+ hash: sha256
+ vars:
+ ansible_network_os: vyos.vyos.vyos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_user: admin
+ ansible_password: admin
diff --git a/extensions/molecule/ipsec_route_based/molecule.yml b/extensions/molecule/ipsec_route_based/molecule.yml
new file mode 100644
index 0000000..9fa905c
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based/molecule.yml
@@ -0,0 +1,28 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+ - name: r2
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/ipsec_route_based/topology.clab.yml b/extensions/molecule/ipsec_route_based/topology.clab.yml
new file mode 100644
index 0000000..f6b9b29
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based/topology.clab.yml
@@ -0,0 +1,32 @@
+name: bp-ipsec
+topology:
+ kinds:
+ vyosnetworks_vyos:
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ nodes:
+ vyos:
+ kind: vyosnetworks_vyos
+ # second VyOS standing in for the page's Cisco router
+ cisco:
+ kind: vyosnetworks_vyos
+ isp:
+ kind: linux
+ image: alpine:3
+ exec:
+ - sysctl -w net.ipv4.ip_forward=1
+ - ip addr add 10.0.1.1/30 dev eth1
+ - ip addr add 10.0.2.1/30 dev eth2
+ pc1:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 192.168.0.2/24 dev eth1", "ip route replace default via 192.168.0.1"]
+ pc3:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 192.168.10.2/24 dev eth1", "ip route replace default via 192.168.10.1"]
+ links:
+ # WAN is eth1 here (eth0 on the page; eth0 is containerlab management)
+ - endpoints: ["vyos:eth1", "isp:eth1"]
+ - endpoints: ["cisco:eth1", "isp:eth2"]
+ - endpoints: ["vyos:eth2", "pc1:eth1"]
+ - endpoints: ["cisco:eth2", "pc3:eth1"]
diff --git a/extensions/molecule/ipsec_route_based/verify.yml b/extensions/molecule/ipsec_route_based/verify.yml
new file mode 100644
index 0000000..e190a90
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based/verify.yml
@@ -0,0 +1,29 @@
+---
+- name: Verify role state
+ hosts: vpn
+ gather_facts: false
+ tasks:
+ - name: Wait for IKE, IPsec and OSPF
+ ansible.builtin.pause:
+ seconds: 45
+ run_once: true
+
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.ipsec_route_based
+ tasks_from: verify
+
+- name: Verify traffic through the tunnel, as in the page's "Checking Connectivity"
+ hosts: localhost
+ gather_facts: false
+ tasks:
+ - name: Ping across the VPN in both directions
+ ansible.builtin.command:
+ cmd: docker exec clab-bp-ipsec-{{ item.from }} ping -c 3 -W 2 {{ item.to }}
+ become: "{{ lookup('ansible.builtin.env', 'CLAB_BECOME', default='true') | bool }}"
+ changed_when: false
+ loop:
+ - {from: pc1, to: 192.168.10.2}
+ - {from: pc3, to: 192.168.0.2}
+ loop_control:
+ label: "{{ item.from }} -> {{ item.to }}"
diff --git a/extensions/molecule/ipsec_route_based_bgp/converge.yml b/extensions/molecule/ipsec_route_based_bgp/converge.yml
new file mode 100644
index 0000000..0fb7a50
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp/converge.yml
@@ -0,0 +1,7 @@
+---
+- name: Converge
+ hosts: vpn
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.ipsec_route_based
diff --git a/extensions/molecule/ipsec_route_based_bgp/inventory.yml b/extensions/molecule/ipsec_route_based_bgp/inventory.yml
new file mode 100644
index 0000000..dff75f1
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp/inventory.yml
@@ -0,0 +1,86 @@
+---
+# Values from docs.vyos.io/en/1.5/configexamples/azure-vpn-bgp.html, except:
+# - no NAT in the lab, so local_address is the public IP 198.51.100.3;
+# - disable-route-autoinstall is set (the page does not set it): without it
+# IPsec installs a route for the VTI's catch-all selector that would also
+# capture containerlab management traffic;
+# - both sides announce a LAN so the test can ping across BGP-learned routes.
+all:
+ children:
+ vyos:
+ children:
+ vpn:
+ hosts:
+ r1:
+ ansible_host: clab-bp-azure-vyos
+ base_interfaces:
+ - {name: eth1, addresses: [198.51.100.3/24]}
+ - {name: eth2, addresses: [10.10.2.1/24]}
+ ipsec_route_based_peers:
+ - name: 203.0.113.2
+ description: AZURE PRIMARY TUNNEL
+ psk_name: azure
+ psk: molecule-psk
+ local_address: 198.51.100.3
+ remote_address: 203.0.113.2
+ connection_type: initiate
+ ikev2_reauth: inherit
+ esp_group_on_vti: true
+ vti: {interface: vti1, address: 10.10.1.5/32, description: Azure Tunnel, adjust_mss: "1350"}
+ ipsec_route_based_interfaces: [eth1]
+ ipsec_route_based_interface_routes:
+ - {dest: 10.0.0.4/32, interface: vti1}
+ ipsec_route_based_bgp:
+ asn: 64499
+ networks: [10.10.2.0/24]
+ neighbors:
+ - {address: 10.0.0.4, remote_as: 65540, holdtime: 30, keepalive: 10, soft_reconfiguration_inbound: true}
+ ipsec_route_based_default_gateway: 198.51.100.1
+ r2:
+ ansible_host: clab-bp-azure-azure
+ base_interfaces:
+ - {name: eth1, addresses: [203.0.113.2/24]}
+ - {name: eth2, addresses: [10.0.1.1/24]}
+ ipsec_route_based_peers:
+ - name: 198.51.100.3
+ psk_name: onprem
+ psk: molecule-psk
+ local_address: 203.0.113.2
+ remote_address: 198.51.100.3
+ connection_type: none
+ esp_group_on_vti: true
+ vti: {interface: vti1, address: 10.0.0.4/32}
+ ipsec_route_based_interfaces: [eth1]
+ ipsec_route_based_interface_routes:
+ - {dest: 10.10.1.5/32, interface: vti1}
+ ipsec_route_based_bgp:
+ asn: 65540
+ networks: [10.0.1.0/24]
+ neighbors:
+ - {address: 10.10.1.5, remote_as: 64499, holdtime: 30, keepalive: 10}
+ ipsec_route_based_default_gateway: 203.0.113.1
+ vars:
+ ipsec_route_based_ike_group:
+ name: AZURE
+ key_exchange: ikev2
+ ikev2_reauth: true
+ lifetime: 28800
+ proposal_id: 1
+ dh_group: 2
+ encryption: aes256
+ hash: sha1
+ dead_peer_detection: {action: restart, interval: 15, timeout: 30}
+ ipsec_route_based_esp_group:
+ name: AZURE
+ lifetime: 3600
+ mode: tunnel
+ pfs: dh-group2
+ proposal_id: 1
+ encryption: aes256
+ hash: sha1
+ ipsec_route_based_disable_route_autoinstall: true
+ vars:
+ ansible_network_os: vyos.vyos.vyos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_user: admin
+ ansible_password: admin
diff --git a/extensions/molecule/ipsec_route_based_bgp/molecule.yml b/extensions/molecule/ipsec_route_based_bgp/molecule.yml
new file mode 100644
index 0000000..9fa905c
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp/molecule.yml
@@ -0,0 +1,28 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+ - name: r2
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/ipsec_route_based_bgp/topology.clab.yml b/extensions/molecule/ipsec_route_based_bgp/topology.clab.yml
new file mode 100644
index 0000000..e8ba878
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp/topology.clab.yml
@@ -0,0 +1,28 @@
+name: bp-azure
+topology:
+ kinds:
+ vyosnetworks_vyos:
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ nodes:
+ vyos:
+ kind: vyosnetworks_vyos
+ # second VyOS standing in for the Azure VNet gateway
+ azure:
+ kind: vyosnetworks_vyos
+ isp:
+ kind: linux
+ image: alpine:3
+ exec: ["sysctl -w net.ipv4.ip_forward=1", "ip addr add 198.51.100.1/24 dev eth1", "ip addr add 203.0.113.1/24 dev eth2"]
+ onprem:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 10.10.2.10/24 dev eth1", "ip route replace default via 10.10.2.1"]
+ vm:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 10.0.1.10/24 dev eth1", "ip route replace default via 10.0.1.1"]
+ links:
+ - endpoints: ["vyos:eth1", "isp:eth1"]
+ - endpoints: ["azure:eth1", "isp:eth2"]
+ - endpoints: ["vyos:eth2", "onprem:eth1"]
+ - endpoints: ["azure:eth2", "vm:eth1"]
diff --git a/extensions/molecule/ipsec_route_based_bgp/verify.yml b/extensions/molecule/ipsec_route_based_bgp/verify.yml
new file mode 100644
index 0000000..04ad7c2
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp/verify.yml
@@ -0,0 +1,29 @@
+---
+- name: Verify role state
+ hosts: vpn
+ gather_facts: false
+ tasks:
+ - name: Wait for IKE, IPsec and BGP
+ ansible.builtin.pause:
+ seconds: 60
+ run_once: true
+
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.ipsec_route_based
+ tasks_from: verify
+
+- name: Verify traffic over BGP-learned routes through the tunnel
+ hosts: localhost
+ gather_facts: false
+ tasks:
+ - name: Ping between on-premises and the "Azure" LAN
+ ansible.builtin.command:
+ cmd: docker exec clab-bp-azure-{{ item.from }} ping -c 3 -W 2 {{ item.to }}
+ become: "{{ lookup('ansible.builtin.env', 'CLAB_BECOME', default='true') | bool }}"
+ changed_when: false
+ loop:
+ - {from: onprem, to: 10.0.1.10}
+ - {from: vm, to: 10.10.2.10}
+ loop_control:
+ label: "{{ item.from }} -> {{ item.to }}"
diff --git a/extensions/molecule/ipsec_route_based_bgp_dual/converge.yml b/extensions/molecule/ipsec_route_based_bgp_dual/converge.yml
new file mode 100644
index 0000000..0fb7a50
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp_dual/converge.yml
@@ -0,0 +1,7 @@
+---
+- name: Converge
+ hosts: vpn
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.ipsec_route_based
diff --git a/extensions/molecule/ipsec_route_based_bgp_dual/inventory.yml b/extensions/molecule/ipsec_route_based_bgp_dual/inventory.yml
new file mode 100644
index 0000000..84d5c9d
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp_dual/inventory.yml
@@ -0,0 +1,115 @@
+---
+# Values from docs.vyos.io/en/1.5/configexamples/azure-vpn-dual-bgp.html, except:
+# - no NAT in the lab, so local_address is the public IP 198.51.100.3;
+# - the second gateway instance is on its own ISP subnet (203.0.114.0/24);
+# - disable-route-autoinstall is set (see ipsec_route_based_bgp/inventory.yml);
+# - both sides announce a LAN so the test can ping across BGP-learned routes.
+all:
+ children:
+ vyos:
+ children:
+ vpn:
+ hosts:
+ r1:
+ ansible_host: clab-bp-azure2-vyos
+ base_interfaces:
+ - name: eth1
+ addresses: [198.51.100.3/24]
+ - name: eth2
+ addresses: [10.10.2.1/24]
+ ipsec_route_based_peers:
+ - name: azure-primary
+ description: AZURE PRIMARY TUNNEL
+ psk_name: azure
+ psk: molecule-psk
+ local_address: 198.51.100.3
+ remote_address: 203.0.113.2
+ connection_type: initiate
+ ikev2_reauth: inherit
+ esp_group_on_vti: true
+ vti: {interface: vti1, address: 10.10.1.5/32, adjust_mss: '1350'}
+ - name: azure-secondary
+ description: AZURE secondary TUNNEL
+ psk_name: azure
+ psk: molecule-psk
+ local_address: 198.51.100.3
+ remote_address: 203.0.114.3
+ connection_type: initiate
+ ikev2_reauth: inherit
+ esp_group_on_vti: true
+ vti: {interface: vti2, address: 10.10.1.6/32, adjust_mss: '1350'}
+ ipsec_route_based_interfaces: [eth1]
+ ipsec_route_based_interface_routes:
+ - {dest: 10.0.0.4/32, interface: vti1}
+ - {dest: 10.0.0.5/32, interface: vti2}
+ ipsec_route_based_bgp:
+ asn: 64499
+ networks: [10.10.2.0/24]
+ neighbors:
+ - {address: 10.0.0.4, remote_as: 65540, holdtime: 30, keepalive: 10, soft_reconfiguration_inbound: true}
+ - {address: 10.0.0.5, remote_as: 65540, holdtime: 30, keepalive: 10, soft_reconfiguration_inbound: true}
+ ipsec_route_based_default_gateway: 198.51.100.1
+ r2:
+ ansible_host: clab-bp-azure2-azure1
+ base_interfaces:
+ - name: eth1
+ addresses: [203.0.113.2/24]
+ - name: eth2
+ addresses: [10.0.1.1/24]
+ ipsec_route_based_peers:
+ - name: 198.51.100.3
+ psk_name: onprem
+ psk: molecule-psk
+ local_address: 203.0.113.2
+ remote_address: 198.51.100.3
+ connection_type: none
+ esp_group_on_vti: true
+ vti: {interface: vti1, address: 10.0.0.4/32}
+ ipsec_route_based_interfaces: [eth1]
+ ipsec_route_based_interface_routes:
+ - {dest: 10.10.1.5/32, interface: vti1}
+ ipsec_route_based_bgp:
+ asn: 65540
+ networks: [10.0.1.0/24]
+ neighbors:
+ - {address: 10.10.1.5, remote_as: 64499, holdtime: 30, keepalive: 10}
+ ipsec_route_based_default_gateway: 203.0.113.1
+ r3:
+ ansible_host: clab-bp-azure2-azure2
+ base_interfaces:
+ - name: eth1
+ addresses: [203.0.114.3/24]
+ - name: eth2
+ addresses: [10.0.1.2/24]
+ ipsec_route_based_peers:
+ - name: 198.51.100.3
+ psk_name: onprem
+ psk: molecule-psk
+ local_address: 203.0.114.3
+ remote_address: 198.51.100.3
+ connection_type: none
+ esp_group_on_vti: true
+ vti: {interface: vti1, address: 10.0.0.5/32}
+ ipsec_route_based_interfaces: [eth1]
+ ipsec_route_based_interface_routes:
+ - {dest: 10.10.1.6/32, interface: vti1}
+ ipsec_route_based_bgp:
+ asn: 65540
+ networks: [10.0.1.0/24]
+ neighbors:
+ - {address: 10.10.1.6, remote_as: 64499, holdtime: 30, keepalive: 10}
+ ipsec_route_based_default_gateway: 203.0.114.1
+ vars:
+ ipsec_route_based_ike_group:
+ name: AZURE
+ key_exchange: ikev2
+ ikev2_reauth: true
+ lifetime: 28800
+ proposal_id: 1
+ dh_group: 2
+ encryption: aes256
+ hash: sha1
+ dead_peer_detection: {action: restart, interval: 15, timeout: 30}
+ ipsec_route_based_esp_group: {name: AZURE, lifetime: 3600, mode: tunnel, pfs: dh-group2, proposal_id: 1, encryption: aes256, hash: sha1}
+ ipsec_route_based_disable_route_autoinstall: true
+ vars: {ansible_network_os: vyos.vyos.vyos, ansible_connection: ansible.netcommon.network_cli, ansible_user: admin, ansible_password: admin}
diff --git a/extensions/molecule/ipsec_route_based_bgp_dual/molecule.yml b/extensions/molecule/ipsec_route_based_bgp_dual/molecule.yml
new file mode 100644
index 0000000..11a5f84
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp_dual/molecule.yml
@@ -0,0 +1,29 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+ - name: r2
+ - name: r3
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/ipsec_route_based_bgp_dual/topology.clab.yml b/extensions/molecule/ipsec_route_based_bgp_dual/topology.clab.yml
new file mode 100644
index 0000000..140aee6
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp_dual/topology.clab.yml
@@ -0,0 +1,39 @@
+name: bp-azure2
+topology:
+ kinds:
+ vyosnetworks_vyos:
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ nodes:
+ vyos:
+ kind: vyosnetworks_vyos
+ # two VyOS standing in for the active-active Azure VNet gateway instances
+ azure1:
+ kind: vyosnetworks_vyos
+ azure2:
+ kind: vyosnetworks_vyos
+ isp:
+ kind: linux
+ image: alpine:3
+ exec: ["sysctl -w net.ipv4.ip_forward=1", "ip addr add 198.51.100.1/24 dev eth1", "ip addr add 203.0.113.1/24 dev eth2", "ip addr add 203.0.114.1/24 dev eth3"]
+ onprem:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 10.10.2.10/24 dev eth1", "ip route replace default via 10.10.2.1"]
+ # the "VNet": one host behind both gateway instances
+ vm:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip link add br0 type bridge
+ - ip link set eth1 master br0
+ - ip link set eth2 master br0
+ - ip link set br0 up
+ - ip addr add 10.0.1.10/24 dev br0
+ - ip route replace 10.10.0.0/16 nexthop via 10.0.1.1 nexthop via 10.0.1.2
+ links:
+ - endpoints: ["vyos:eth1", "isp:eth1"]
+ - endpoints: ["azure1:eth1", "isp:eth2"]
+ - endpoints: ["azure2:eth1", "isp:eth3"]
+ - endpoints: ["vyos:eth2", "onprem:eth1"]
+ - endpoints: ["azure1:eth2", "vm:eth1"]
+ - endpoints: ["azure2:eth2", "vm:eth2"]
diff --git a/extensions/molecule/ipsec_route_based_bgp_dual/verify.yml b/extensions/molecule/ipsec_route_based_bgp_dual/verify.yml
new file mode 100644
index 0000000..34bee33
--- /dev/null
+++ b/extensions/molecule/ipsec_route_based_bgp_dual/verify.yml
@@ -0,0 +1,47 @@
+---
+- name: Verify both tunnels and BGP sessions
+ hosts: vpn
+ gather_facts: false
+ tasks:
+ - name: Wait for IKE, IPsec and BGP
+ ansible.builtin.pause:
+ seconds: 60
+ run_once: true
+
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.ipsec_route_based
+ tasks_from: verify
+
+- name: Verify redundancy - traffic survives losing the primary tunnel
+ hosts: r1
+ gather_facts: false
+ vars:
+ _ping: docker exec clab-bp-azure2-onprem ping -c 3 -W 2 10.0.1.10
+ _become: "{{ lookup('ansible.builtin.env', 'CLAB_BECOME', default='true') | bool }}"
+ tasks:
+ - name: Ping the VNet with both tunnels up
+ ansible.builtin.command: "{{ _ping }}"
+ delegate_to: localhost
+ become: "{{ _become }}"
+ changed_when: false
+
+ - name: Take the primary tunnel down
+ vyos.vyos.vyos_config:
+ lines:
+ - set vpn ipsec site-to-site peer azure-primary disable
+
+ - name: Wait for BGP to converge on the secondary path
+ ansible.builtin.pause:
+ seconds: 40
+
+ - name: Ping the VNet over the secondary tunnel only
+ ansible.builtin.command: "{{ _ping }}"
+ delegate_to: localhost
+ become: "{{ _become }}"
+ changed_when: false
+
+ - name: Bring the primary tunnel back
+ vyos.vyos.vyos_config:
+ lines:
+ - delete vpn ipsec site-to-site peer azure-primary disable
diff --git a/extensions/molecule/ospf_unnumbered/converge.yml b/extensions/molecule/ospf_unnumbered/converge.yml
new file mode 100644
index 0000000..c5e906b
--- /dev/null
+++ b/extensions/molecule/ospf_unnumbered/converge.yml
@@ -0,0 +1,7 @@
+---
+- name: Converge
+ hosts: fabric
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.ospf_unnumbered
diff --git a/extensions/molecule/ospf_unnumbered/inventory.yml b/extensions/molecule/ospf_unnumbered/inventory.yml
new file mode 100644
index 0000000..efaf93f
--- /dev/null
+++ b/extensions/molecule/ospf_unnumbered/inventory.yml
@@ -0,0 +1,26 @@
+---
+all:
+ children:
+ vyos:
+ children:
+ fabric:
+ hosts:
+ r1:
+ ansible_host: clab-bp-ospf-r1
+ ospf_unnumbered_router_id: 192.168.0.1
+ base_interfaces:
+ - {name: eth3, addresses: [10.1.0.1/24]}
+ r2:
+ ansible_host: clab-bp-ospf-r2
+ ospf_unnumbered_router_id: 192.168.0.2
+ base_interfaces:
+ - {name: eth3, addresses: [10.2.0.1/24]}
+ vars:
+ ospf_unnumbered_interfaces: [eth1, eth2]
+ ospf_unnumbered_md5_key: molecule-ospf
+ ospf_unnumbered_group: fabric
+ vars:
+ ansible_network_os: vyos.vyos.vyos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_user: admin
+ ansible_password: admin
diff --git a/extensions/molecule/ospf_unnumbered/molecule.yml b/extensions/molecule/ospf_unnumbered/molecule.yml
new file mode 100644
index 0000000..9fa905c
--- /dev/null
+++ b/extensions/molecule/ospf_unnumbered/molecule.yml
@@ -0,0 +1,28 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+ - name: r2
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/ospf_unnumbered/topology.clab.yml b/extensions/molecule/ospf_unnumbered/topology.clab.yml
new file mode 100644
index 0000000..e2fb3c9
--- /dev/null
+++ b/extensions/molecule/ospf_unnumbered/topology.clab.yml
@@ -0,0 +1,20 @@
+name: bp-ospf
+topology:
+ kinds:
+ vyosnetworks_vyos:
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ nodes:
+ r1:
+ kind: vyosnetworks_vyos
+ r2:
+ kind: vyosnetworks_vyos
+ lan:
+ kind: linux
+ image: alpine:3
+ links:
+ # two parallel unnumbered links -> ECMP, as on the docs page
+ - endpoints: ["r1:eth1", "r2:eth1"]
+ - endpoints: ["r1:eth2", "r2:eth2"]
+ # LAN side (eth0 on the docs page; eth0 is management in containerlab)
+ - endpoints: ["r1:eth3", "lan:eth1"]
+ - endpoints: ["r2:eth3", "lan:eth2"]
diff --git a/extensions/molecule/ospf_unnumbered/verify.yml b/extensions/molecule/ospf_unnumbered/verify.yml
new file mode 100644
index 0000000..d75a2ea
--- /dev/null
+++ b/extensions/molecule/ospf_unnumbered/verify.yml
@@ -0,0 +1,27 @@
+---
+- name: Verify
+ hosts: fabric
+ gather_facts: false
+ tasks:
+ - name: Wait for OSPF adjacencies and routes
+ ansible.builtin.pause:
+ seconds: 45
+ run_once: true
+
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.ospf_unnumbered
+ tasks_from: verify
+
+ - name: Read the route to the other router's LAN
+ vyos.vyos.vyos_command:
+ commands:
+ - "show ip route {{ '10.2.0.0/24' if inventory_hostname == 'r1' else '10.1.0.0/24' }}"
+ register: _lan_route
+
+ - name: The other LAN is learned via OSPF (redistribute connected) over both links
+ ansible.builtin.assert:
+ that:
+ - _lan_route.stdout[0] is search('Known via "ospf"')
+ - _lan_route.stdout[0] | regex_findall('via \S+ onlink') | length == 2
+ quiet: true
diff --git a/extensions/molecule/policy_ipsec_firewall/converge.yml b/extensions/molecule/policy_ipsec_firewall/converge.yml
new file mode 100644
index 0000000..1696e59
--- /dev/null
+++ b/extensions/molecule/policy_ipsec_firewall/converge.yml
@@ -0,0 +1,9 @@
+---
+- name: Converge
+ hosts: sites
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.ipsec_policy_based
+ - vyos.blueprints.firewall
+ - vyos.blueprints.nat
diff --git a/extensions/molecule/policy_ipsec_firewall/inventory.yml b/extensions/molecule/policy_ipsec_firewall/inventory.yml
new file mode 100644
index 0000000..afc0223
--- /dev/null
+++ b/extensions/molecule/policy_ipsec_firewall/inventory.yml
@@ -0,0 +1,131 @@
+---
+all:
+ children:
+ vyos:
+ children:
+ sites:
+ hosts:
+ left:
+ ansible_host: clab-bp-pif-left
+ ipsec_policy_based_peers:
+ - name: RIGHT
+ psk_name: RIGHT
+ psk: molecule-psk
+ authentication_ids: false
+ local_address: 198.51.100.14
+ remote_address: 192.0.2.130
+ connection_type: initiate
+ tunnels:
+ - {id: 0, local_prefix: 10.1.11.0/24, remote_prefix: 10.2.21.0/24}
+ - {id: 1, local_prefix: 10.1.11.0/24, remote_prefix: 10.2.22.0/24}
+ - {id: 2, local_prefix: 10.1.12.0/24, remote_prefix: 10.2.21.0/24}
+ - {id: 3, local_prefix: 10.1.12.0/24, remote_prefix: 10.2.22.0/24}
+ ipsec_policy_based_default_gateway: 198.51.100.13
+ firewall_groups:
+ network:
+ - name: LOCAL-NETS
+ networks: [10.1.11.0/24, 10.1.12.0/24]
+ - name: REMOTE-NETS
+ networks: [10.2.21.0/24, 10.2.22.0/24]
+ - name: TRUSTED
+ networks: [198.51.100.125/32, 203.0.113.0/24, 10.1.11.0/24, 192.168.70.0/24]
+ firewall_ipv4:
+ forward:
+ default_action: drop
+ rules:
+ - number: 1
+ action: accept
+ state: {established: true, related: true}
+ - number: 2
+ action: drop
+ state: {invalid: true}
+ - number: 10
+ action: accept
+ source:
+ group: {network_group: LOCAL-NETS}
+ - number: 20
+ action: accept
+ source:
+ group: {network_group: REMOTE-NETS}
+ destination:
+ group: {network_group: LOCAL-NETS}
+ input:
+ default_action: drop
+ rules:
+ - number: 1
+ action: accept
+ state: {established: true, related: true}
+ - number: 2
+ action: drop
+ state: {invalid: true}
+ - number: 5
+ action: accept
+ description: containerlab management
+ inbound_interface: {name: eth0}
+ - number: 10
+ action: accept
+ protocol: udp
+ destination: {port: '500,4500'}
+ inbound_interface: {name: eth3}
+ - number: 15
+ action: accept
+ protocol: esp
+ inbound_interface: {name: eth3}
+ - number: 20
+ action: accept
+ protocol: tcp
+ destination: {port: '22'}
+ source:
+ group: {network_group: TRUSTED}
+ - number: 25
+ action: accept
+ protocol: udp
+ destination: {port: '53'}
+ source:
+ group: {network_group: LOCAL-NETS}
+ - {number: 30, action: accept, protocol: icmp}
+ nat_source_rules:
+ - id: 10
+ exclude: true
+ outbound_interface: {name: eth3}
+ source: {network_group: LOCAL-NETS}
+ destination: {network_group: REMOTE-NETS}
+ - id: 20
+ outbound_interface: {name: eth3}
+ source: {network_group: LOCAL-NETS}
+ translation: {address: masquerade}
+ base_interfaces:
+ - name: eth3
+ addresses: [198.51.100.14/30]
+ - name: eth1.111
+ addresses: [10.1.11.1/24]
+ - name: eth2.112
+ addresses: [10.1.12.1/24]
+ right:
+ ansible_host: clab-bp-pif-right
+ ipsec_policy_based_peers:
+ - name: LEFT
+ psk_name: LEFT
+ psk: molecule-psk
+ authentication_ids: false
+ local_address: 192.0.2.130
+ remote_address: 198.51.100.14
+ connection_type: none
+ tunnels:
+ - {id: 0, local_prefix: 10.2.21.0/24, remote_prefix: 10.1.11.0/24}
+ - {id: 1, local_prefix: 10.2.22.0/24, remote_prefix: 10.1.11.0/24}
+ - {id: 2, local_prefix: 10.2.21.0/24, remote_prefix: 10.1.12.0/24}
+ - {id: 3, local_prefix: 10.2.22.0/24, remote_prefix: 10.1.12.0/24}
+ base_interfaces:
+ - name: eth3
+ addresses: [192.0.2.130/30]
+ - name: eth1.221
+ addresses: [10.2.21.1/24]
+ - name: eth2.222
+ addresses: [10.2.22.1/24]
+ ipsec_policy_based_default_gateway: 192.0.2.129
+ vars:
+ ipsec_policy_based_ike_group: {name: IKE-GROUP, key_exchange: ikev2, proposal_id: 1, dh_group: 14, encryption: aes256, hash: sha256}
+ ipsec_policy_based_esp_group: {name: ESP-GROUP, mode: tunnel, proposal_id: 1, encryption: aes256, hash: sha256}
+ ipsec_policy_based_interfaces: [eth3]
+ vars: {ansible_network_os: vyos.vyos.vyos, ansible_connection: ansible.netcommon.network_cli, ansible_user: admin, ansible_password: admin}
diff --git a/extensions/molecule/policy_ipsec_firewall/molecule.yml b/extensions/molecule/policy_ipsec_firewall/molecule.yml
new file mode 100644
index 0000000..9fa905c
--- /dev/null
+++ b/extensions/molecule/policy_ipsec_firewall/molecule.yml
@@ -0,0 +1,28 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+ - name: r2
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/policy_ipsec_firewall/topology.clab.yml b/extensions/molecule/policy_ipsec_firewall/topology.clab.yml
new file mode 100644
index 0000000..a94822e
--- /dev/null
+++ b/extensions/molecule/policy_ipsec_firewall/topology.clab.yml
@@ -0,0 +1,51 @@
+name: bp-pif
+topology:
+ kinds:
+ vyosnetworks_vyos:
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ nodes:
+ left:
+ kind: vyosnetworks_vyos
+ right:
+ kind: vyosnetworks_vyos
+ isp:
+ kind: linux
+ image: alpine:3
+ exec:
+ - sysctl -w net.ipv4.ip_forward=1
+ - ip addr add 198.51.100.13/30 dev eth1
+ - ip addr add 192.0.2.129/30 dev eth2
+ - ip addr add 203.0.113.1/24 dev eth3
+ internet:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 203.0.113.10/24 dev eth1", "ip route replace default via 203.0.113.1"]
+ l11:
+ kind: linux
+ image: alpine:3
+ exec: ["ip link add link eth1 name eth1.111 type vlan id 111", "ip link set eth1.111 up",
+ "ip addr add 10.1.11.10/24 dev eth1.111", "ip route replace default via 10.1.11.1"]
+ l12:
+ kind: linux
+ image: alpine:3
+ exec: ["ip link add link eth1 name eth1.112 type vlan id 112", "ip link set eth1.112 up",
+ "ip addr add 10.1.12.10/24 dev eth1.112", "ip route replace default via 10.1.12.1"]
+ r21:
+ kind: linux
+ image: alpine:3
+ exec: ["ip link add link eth1 name eth1.221 type vlan id 221", "ip link set eth1.221 up",
+ "ip addr add 10.2.21.10/24 dev eth1.221", "ip route replace default via 10.2.21.1"]
+ r22:
+ kind: linux
+ image: alpine:3
+ exec: ["ip link add link eth1 name eth1.222 type vlan id 222", "ip link set eth1.222 up",
+ "ip addr add 10.2.22.10/24 dev eth1.222", "ip route replace default via 10.2.22.1"]
+ links:
+ # WAN is eth3 here (eth0 on the page; eth0 is containerlab management)
+ - endpoints: ["left:eth3", "isp:eth1"]
+ - endpoints: ["right:eth3", "isp:eth2"]
+ - endpoints: ["isp:eth3", "internet:eth1"]
+ - endpoints: ["left:eth1", "l11:eth1"]
+ - endpoints: ["left:eth2", "l12:eth1"]
+ - endpoints: ["right:eth1", "r21:eth1"]
+ - endpoints: ["right:eth2", "r22:eth1"]
diff --git a/extensions/molecule/policy_ipsec_firewall/verify.yml b/extensions/molecule/policy_ipsec_firewall/verify.yml
new file mode 100644
index 0000000..5502dc4
--- /dev/null
+++ b/extensions/molecule/policy_ipsec_firewall/verify.yml
@@ -0,0 +1,35 @@
+---
+- name: Verify role state
+ hosts: sites
+ gather_facts: false
+ tasks:
+ - name: Wait for IKE and IPsec
+ ansible.builtin.pause:
+ seconds: 30
+ run_once: true
+
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: "vyos.blueprints.{{ item }}"
+ tasks_from: verify
+ loop: "{{ ['ipsec_policy_based', 'firewall', 'nat'] if inventory_hostname == 'left' else ['ipsec_policy_based'] }}"
+
+- name: Verify the page's requirements with traffic
+ hosts: localhost
+ gather_facts: false
+ vars:
+ _flows:
+ - {from: l11, to: 10.2.21.10, why: "LAN to LAN through the tunnel, without NAT"}
+ - {from: l12, to: 10.2.22.10, why: "second LAN pair through the tunnel"}
+ - {from: r21, to: 10.1.11.10, why: "remote LANs may connect to local LANs"}
+ - {from: l11, to: 203.0.113.10, why: "local subnets reach the internet using source NAT"}
+ - {from: internet, to: 198.51.100.14, why: "ICMP is allowed on all interfaces"}
+ tasks:
+ - name: Ping per requirement
+ ansible.builtin.command:
+ cmd: docker exec clab-bp-pif-{{ item.from }} ping -c 3 -W 2 {{ item.to }}
+ become: "{{ lookup('ansible.builtin.env', 'CLAB_BECOME', default='true') | bool }}"
+ changed_when: false
+ loop: "{{ _flows }}"
+ loop_control:
+ label: "{{ item.from }} -> {{ item.to }} ({{ item.why }})"
diff --git a/extensions/molecule/vrf_firewall/converge.yml b/extensions/molecule/vrf_firewall/converge.yml
new file mode 100644
index 0000000..bdf90f7
--- /dev/null
+++ b/extensions/molecule/vrf_firewall/converge.yml
@@ -0,0 +1,7 @@
+---
+- name: Converge
+ hosts: vyos
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.vrf_firewall
diff --git a/extensions/molecule/vrf_firewall/inventory.yml b/extensions/molecule/vrf_firewall/inventory.yml
new file mode 100644
index 0000000..4d3b6f7
--- /dev/null
+++ b/extensions/molecule/vrf_firewall/inventory.yml
@@ -0,0 +1,54 @@
+---
+all:
+ children:
+ vyos:
+ hosts:
+ r1:
+ ansible_host: clab-bp-vrf-r1
+ vars:
+ ansible_network_os: vyos.vyos.vyos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_user: admin
+ ansible_password: admin
+ base_interfaces:
+ - {name: eth1, addresses: [10.100.100.1/24]}
+ - {name: eth2}
+ - {name: eth2.150, addresses: [10.150.150.1/24]}
+ - {name: eth2.3500, addresses: [172.16.20.1/24]}
+ - {name: eth3, addresses: [203.0.113.1/24]}
+ vrf_firewall_vrfs:
+ - name: MGMT
+ table: 102
+ interfaces: [eth1]
+ routes:
+ - {dest: 10.150.150.0/24, interface: eth2.150, vrf: LAN}
+ - {dest: 172.16.20.0/24, interface: eth2.3500, vrf: PROD}
+ - name: WAN
+ table: 101
+ interfaces: [eth3]
+ routes:
+ - {dest: 10.150.150.0/24, interface: eth2.150, vrf: LAN}
+ - {dest: 172.16.20.0/24, interface: eth2.3500, vrf: PROD}
+ - name: LAN
+ table: 103
+ interfaces: [eth2.150]
+ routes:
+ - {dest: 0.0.0.0/0, interface: eth3, vrf: WAN}
+ - {dest: 10.100.100.0/24, interface: eth1, vrf: MGMT}
+ - {dest: 172.16.20.0/24, interface: eth2.3500, vrf: PROD}
+ - name: PROD
+ table: 104
+ interfaces: [eth2.3500]
+ routes:
+ - {dest: 0.0.0.0/0, interface: eth3, vrf: WAN}
+ - {dest: 10.100.100.0/24, interface: eth1, vrf: MGMT}
+ - {dest: 10.150.150.0/24, interface: eth2.150, vrf: LAN}
+ vrf_firewall_forward_rules:
+ - {number: 10, description: MGMT - Allow to LAN and PROD, inbound_interface: MGMT, outbound_interface: eth2*}
+ - {number: 99, action: drop, description: MGMT - Drop all going to mgmt, outbound_interface: eth1}
+ - {number: 120, description: LAN - Allow to PROD, inbound_interface: LAN, outbound_interface: eth2.3500}
+ - {number: 130, description: LAN - Allow internet, inbound_interface: LAN, outbound_interface: eth3}
+ vrf_firewall_input_rules:
+ # containerlab management; keeps Ansible's SSH session working
+ - {number: 5, description: containerlab management, inbound_interface: eth0}
+ - {number: 10, description: MGMT - Allow input, inbound_interface: MGMT}
diff --git a/extensions/molecule/vrf_firewall/molecule.yml b/extensions/molecule/vrf_firewall/molecule.yml
new file mode 100644
index 0000000..612af0a
--- /dev/null
+++ b/extensions/molecule/vrf_firewall/molecule.yml
@@ -0,0 +1,27 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/vrf_firewall/topology.clab.yml b/extensions/molecule/vrf_firewall/topology.clab.yml
new file mode 100644
index 0000000..567cd56
--- /dev/null
+++ b/extensions/molecule/vrf_firewall/topology.clab.yml
@@ -0,0 +1,43 @@
+name: bp-vrf
+topology:
+ nodes:
+ r1:
+ kind: vyosnetworks_vyos
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ mgmt:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 10.100.100.10/24 dev eth1", "ip route replace default via 10.100.100.1"]
+ # VLAN-aware bridge for the eth2 trunk (vif 150 = LAN, vif 3500 = PROD)
+ sw:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip link add br0 type bridge vlan_filtering 1
+ - ip link set eth1 master br0
+ - ip link set eth2 master br0
+ - ip link set eth3 master br0
+ - bridge vlan add dev eth1 vid 150
+ - bridge vlan add dev eth1 vid 3500
+ - bridge vlan add dev eth2 vid 150 pvid untagged
+ - bridge vlan add dev eth3 vid 3500 pvid untagged
+ - ip link set br0 up
+ lan:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 10.150.150.10/24 dev eth1", "ip route replace default via 10.150.150.1"]
+ prod:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 172.16.20.10/24 dev eth1", "ip route replace default via 172.16.20.1"]
+ # stands in for the page's PPPoE uplink
+ wan:
+ kind: linux
+ image: alpine:3
+ exec: ["ip addr add 203.0.113.100/24 dev eth1", "ip route replace default via 203.0.113.1"]
+ links:
+ - endpoints: ["r1:eth1", "mgmt:eth1"]
+ - endpoints: ["r1:eth2", "sw:eth1"]
+ - endpoints: ["sw:eth2", "lan:eth1"]
+ - endpoints: ["sw:eth3", "prod:eth1"]
+ - endpoints: ["r1:eth3", "wan:eth1"]
diff --git a/extensions/molecule/vrf_firewall/verify.yml b/extensions/molecule/vrf_firewall/verify.yml
new file mode 100644
index 0000000..82989cc
--- /dev/null
+++ b/extensions/molecule/vrf_firewall/verify.yml
@@ -0,0 +1,36 @@
+---
+- name: Verify role state
+ hosts: vyos
+ gather_facts: false
+ tasks:
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.vrf_firewall
+ tasks_from: verify
+
+- name: Verify traffic between VRFs against the page's requirements
+ hosts: localhost
+ gather_facts: false
+ vars:
+ _flows:
+ - {from: mgmt, to: 10.150.150.10, allowed: true, why: "MGMT may connect to LAN"}
+ - {from: mgmt, to: 172.16.20.10, allowed: true, why: "MGMT may connect to PROD"}
+ - {from: mgmt, to: 203.0.113.100, allowed: false, why: "MGMT may not reach the internet"}
+ - {from: lan, to: 172.16.20.10, allowed: true, why: "LAN may connect to PROD"}
+ - {from: lan, to: 203.0.113.100, allowed: true, why: "LAN may reach the internet"}
+ - {from: lan, to: 10.100.100.10, allowed: false, why: "nothing may connect to MGMT"}
+ - {from: prod, to: 10.150.150.10, allowed: false, why: "PROD only accepts connections"}
+ # The page's text says WAN may connect to PROD, but its configuration has
+ # no rule for it, so the configuration (default drop) is what is tested.
+ - {from: wan, to: 172.16.20.10, allowed: false, why: "no WAN->PROD rule in the page's configuration"}
+ tasks:
+ - name: Ping across VRFs
+ ansible.builtin.command:
+ cmd: docker exec clab-bp-vrf-{{ item.from }} ping -c 2 -W 2 {{ item.to }}
+ become: "{{ lookup('ansible.builtin.env', 'CLAB_BECOME', default='true') | bool }}"
+ register: _ping
+ changed_when: false
+ failed_when: (_ping.rc == 0) != item.allowed
+ loop: "{{ _flows }}"
+ loop_control:
+ label: "{{ item.from }} -> {{ item.to }} ({{ item.why }})"
diff --git a/extensions/molecule/zone_firewall/converge.yml b/extensions/molecule/zone_firewall/converge.yml
new file mode 100644
index 0000000..03e3ad7
--- /dev/null
+++ b/extensions/molecule/zone_firewall/converge.yml
@@ -0,0 +1,7 @@
+---
+- name: Converge
+ hosts: vyos
+ gather_facts: false
+ roles:
+ - vyos.blueprints.base
+ - vyos.blueprints.zone_firewall
diff --git a/extensions/molecule/zone_firewall/inventory.yml b/extensions/molecule/zone_firewall/inventory.yml
new file mode 100644
index 0000000..6e9f461
--- /dev/null
+++ b/extensions/molecule/zone_firewall/inventory.yml
@@ -0,0 +1,33 @@
+---
+all:
+ children:
+ vyos:
+ hosts:
+ r1:
+ ansible_host: clab-bp-zfw-r1
+ vars:
+ ansible_network_os: vyos.vyos.vyos
+ ansible_connection: ansible.netcommon.network_cli
+ ansible_user: admin
+ ansible_password: admin
+ base_interfaces:
+ - {name: eth1, addresses: [172.16.10.1/24]}
+ - {name: eth2, addresses: [192.168.100.1/24]}
+ - {name: eth3, addresses: [192.168.200.1/24]}
+ zone_firewall_zones:
+ # containerlab management; keeps Ansible's SSH session working
+ - {name: mgmt, interfaces: [eth0]}
+ - {name: wan, interfaces: [eth1]}
+ - {name: lan, interfaces: [eth2]}
+ - {name: dmz, interfaces: [eth3]}
+ - {name: local, local: true}
+ zone_firewall_policies:
+ - {from: mgmt, to: local, default_action: accept}
+ - from: wan
+ to: dmz
+ rules:
+ - {number: 200, protocol: tcp, destination: {address: 192.168.200.200, port: "80,443"}}
+ - from: lan
+ to: dmz
+ rules:
+ - {number: 200, protocol: tcp, destination: {port: "80,443"}}
diff --git a/extensions/molecule/zone_firewall/molecule.yml b/extensions/molecule/zone_firewall/molecule.yml
new file mode 100644
index 0000000..612af0a
--- /dev/null
+++ b/extensions/molecule/zone_firewall/molecule.yml
@@ -0,0 +1,27 @@
+---
+# VyOS runs as a container (containerlab kind vyosnetworks_vyos);
+# the lab is deployed in prepare and destroyed in cleanup.
+dependency:
+ name: galaxy
+ enabled: false
+driver:
+ name: default
+ options:
+ managed: false
+platforms:
+ - name: r1
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ host_key_checking: false
+ persistent_connection:
+ command_timeout: 60
+ inventory:
+ links:
+ hosts: inventory.yml
+ playbooks:
+ prepare: ../_shared/lab_up.yml
+ cleanup: ../_shared/lab_down.yml
+verifier:
+ name: ansible
diff --git a/extensions/molecule/zone_firewall/topology.clab.yml b/extensions/molecule/zone_firewall/topology.clab.yml
new file mode 100644
index 0000000..9be83a6
--- /dev/null
+++ b/extensions/molecule/zone_firewall/topology.clab.yml
@@ -0,0 +1,34 @@
+name: bp-zfw
+topology:
+ nodes:
+ r1:
+ kind: vyosnetworks_vyos
+ image: ${VYOS_IMAGE:=vyos:blueprints-ci}
+ wan:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 172.16.10.100/24 dev eth1
+ - ip route replace default via 172.16.10.1
+ - apk add --no-cache busybox-extras
+ - httpd -p 80 -h /tmp
+ lan:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 192.168.100.10/24 dev eth1
+ - ip route replace default via 192.168.100.1
+ - apk add --no-cache busybox-extras
+ - httpd -p 80 -h /tmp
+ dmz:
+ kind: linux
+ image: alpine:3
+ exec:
+ - ip addr add 192.168.200.200/24 dev eth1
+ - ip route replace default via 192.168.200.1
+ - apk add --no-cache busybox-extras
+ - httpd -p 80 -h /tmp
+ links:
+ - endpoints: ["r1:eth1", "wan:eth1"]
+ - endpoints: ["r1:eth2", "lan:eth1"]
+ - endpoints: ["r1:eth3", "dmz:eth1"]
diff --git a/extensions/molecule/zone_firewall/verify.yml b/extensions/molecule/zone_firewall/verify.yml
new file mode 100644
index 0000000..16584f3
--- /dev/null
+++ b/extensions/molecule/zone_firewall/verify.yml
@@ -0,0 +1,30 @@
+---
+- name: Verify role state
+ hosts: vyos
+ gather_facts: false
+ tasks:
+ - name: Run role checks
+ ansible.builtin.include_role:
+ name: vyos.blueprints.zone_firewall
+ tasks_from: verify
+
+- name: Verify traffic between zones
+ hosts: localhost
+ gather_facts: false
+ vars:
+ _flows:
+ - {from: lan, to: 192.168.200.200, allowed: true, why: "LAN can access DMZ resources"}
+ - {from: wan, to: 192.168.200.200, allowed: true, why: "inbound WAN connects to the DMZ host"}
+ - {from: dmz, to: 192.168.100.10, allowed: false, why: "DMZ cannot access LAN resources"}
+ - {from: wan, to: 192.168.100.10, allowed: false, why: "WAN cannot reach the LAN"}
+ tasks:
+ - name: Try HTTP across zones
+ ansible.builtin.command:
+ cmd: docker exec clab-bp-zfw-{{ item.from }} wget -q -T 3 -O /dev/null http://{{ item.to }}/
+ become: "{{ lookup('ansible.builtin.env', 'CLAB_BECOME', default='true') | bool }}"
+ register: _http
+ changed_when: false
+ failed_when: (_http.rc == 0) != item.allowed
+ loop: "{{ _flows }}"
+ loop_control:
+ label: "{{ item.from }} -> {{ item.to }} ({{ item.why }})"