CloudRouterDemo
This commit is contained in:
commit
62c86b96ff
23 files changed
+1382
No files matched your search
@@ -0,0 +1,8 @@
|
||||
---
|
||||
ike_proposal: "aes256-sha256-modp2048"
|
||||
esp_proposal: "aes256-sha256-modp2048"
|
||||
ike_lifetime: 14400
|
||||
esp_lifetime: 7200
|
||||
dpd_timeout: 30
|
||||
|
||||
lan_cidr: "{{ lan_network_address }}/{{ lan_network_prefix }}"
|
||||
@@ -0,0 +1,23 @@
|
||||
[ubuntu_routers]
|
||||
router1 ansible_host=210.0.0.1 wan_ip=210.0.0.1 wan_cidr=24 wan_gw=210.0.0.254 lan_ip=10.200.10.254 remote_main_isp_ip=200.0.0.1 remote_backup_isp_ip=80.0.0.2 remote_ibgp_peer=10.200.10.253 gre_main_ip=172.17.1.1 gre_backup_ip=172.17.1.5 local_pref_main=400 bgp_med_main=100 local_pref_backup=300 bgp_med_backup=200
|
||||
router2 ansible_host=95.0.0.2 wan_ip=95.0.0.2 wan_cidr=24 wan_gw=95.0.0.254 lan_ip=10.200.10.253 remote_main_isp_ip=200.0.0.1 remote_backup_isp_ip=80.0.0.2 remote_ibgp_peer=10.200.10.254 gre_main_ip=172.17.2.1 gre_backup_ip=172.17.2.5 local_pref_main=200 bgp_med_main=300 local_pref_backup=100 bgp_med_backup=400
|
||||
|
||||
[private_servers]
|
||||
|
||||
[all:vars]
|
||||
ansible_user=<Your_CloudOS_User>
|
||||
ansible_ssh_private_key_file=<Your_Path_to_Admin_SSH>
|
||||
|
||||
# LAN network
|
||||
lan_network_address=10.200.10.0
|
||||
lan_network_prefix=24
|
||||
lan_gateway=10.200.10.1
|
||||
vrrp_vip=10.200.10.1
|
||||
|
||||
# BGP
|
||||
local_asn=65021
|
||||
remote_asn=65011
|
||||
# external_cidr=192.0.2.0/24
|
||||
|
||||
# StrongSwan
|
||||
ipsec_psk=YourSecurePreSharedKey123!
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
- name: save iptables
|
||||
command: netfilter-persistent save
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
- name: Update packages
|
||||
apt:
|
||||
upgrade: dist
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Install System Utils Packages
|
||||
apt:
|
||||
name:
|
||||
- net-tools
|
||||
- nmon
|
||||
- htop
|
||||
- bmon
|
||||
- mtr
|
||||
state: present
|
||||
|
||||
- name: Enable IP forwarding
|
||||
sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: '1'
|
||||
state: present
|
||||
reload: yes
|
||||
|
||||
- name: Load GRE module
|
||||
modprobe:
|
||||
name: ip_gre
|
||||
state: present
|
||||
|
||||
- name: Persist GRE module
|
||||
lineinfile:
|
||||
path: /etc/modules
|
||||
line: ip_gre
|
||||
create: yes
|
||||
|
||||
- name: Pre-seed iptables-persistent IPv4
|
||||
debconf:
|
||||
name: iptables-persistent
|
||||
question: iptables-persistent/autosave_v4
|
||||
value: "true"
|
||||
vtype: boolean
|
||||
|
||||
- name: Pre-seed iptables-persistent IPv6
|
||||
debconf:
|
||||
name: iptables-persistent
|
||||
question: iptables-persistent/autosave_v6
|
||||
value: "false"
|
||||
vtype: boolean
|
||||
|
||||
- name: Install iptables-persistent
|
||||
apt:
|
||||
name: iptables-persistent
|
||||
state: present
|
||||
|
||||
- name: NAT masquerade for LAN
|
||||
iptables:
|
||||
table: nat
|
||||
chain: POSTROUTING
|
||||
jump: MASQUERADE
|
||||
source: "{{ lan_cidr }}"
|
||||
out_interface: "eth0"
|
||||
comment: "LAN to Internet"
|
||||
notify: save iptables
|
||||
|
||||
- name: Allow forwarding
|
||||
iptables:
|
||||
chain: FORWARD
|
||||
policy: ACCEPT
|
||||
notify: save iptables
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
- name: Disable IPv6 via sysctl
|
||||
sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '1'
|
||||
sysctl_set: yes
|
||||
state: present
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv6.conf.all.disable_ipv6
|
||||
- net.ipv6.conf.default.disable_ipv6
|
||||
- net.ipv6.conf.lo.disable_ipv6
|
||||
|
||||
- name: Disable IPv6 in GRUB
|
||||
lineinfile:
|
||||
path: /etc/default/grub
|
||||
regexp: '^GRUB_CMDLINE_LINUX='
|
||||
line: 'GRUB_CMDLINE_LINUX="ipv6.disable=1"'
|
||||
|
||||
- name: Update GRUB
|
||||
command: update-grub
|
||||
when: ansible_distribution == "Ubuntu"
|
||||
|
||||
- name: Update initramfs
|
||||
command: update-initramfs -u
|
||||
when: ansible_distribution == "Ubuntu"
|
||||
@@ -0,0 +1,5 @@
|
||||
- name: Restart FRR
|
||||
systemd:
|
||||
name: frr
|
||||
state: restarted
|
||||
daemon_reload: yes
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
- name: Update package cache
|
||||
apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Install FRR and required packages
|
||||
apt:
|
||||
name:
|
||||
- frr
|
||||
- frr-pythontools
|
||||
state: present
|
||||
|
||||
- name: Create FRR configuration directory
|
||||
file:
|
||||
path: /etc/frr
|
||||
state: directory
|
||||
owner: frr
|
||||
group: frr
|
||||
mode: '0755'
|
||||
|
||||
- name: Enable FRR daemons
|
||||
lineinfile:
|
||||
path: /etc/frr/daemons
|
||||
regexp: '^{{ item.daemon }}='
|
||||
line: '{{ item.daemon }}={{ item.state }}'
|
||||
backup: yes
|
||||
loop:
|
||||
- { daemon: 'bgpd', state: 'yes' }
|
||||
- { daemon: 'zebra', state: 'yes' }
|
||||
- { daemon: 'staticd', state: 'yes' }
|
||||
|
||||
- name: Configure FRR startup options
|
||||
lineinfile:
|
||||
path: /etc/frr/daemons
|
||||
regexp: '^{{ item.option }}='
|
||||
line: '{{ item.option }}={{ item.value }}'
|
||||
backup: yes
|
||||
loop:
|
||||
- { option: 'frr_options', value: '"-A 127.0.0.1"' }
|
||||
|
||||
- name: Configure FRR
|
||||
template:
|
||||
src: bgpd_router.conf.j2
|
||||
dest: /etc/frr/frr.conf
|
||||
owner: frr
|
||||
group: frr
|
||||
mode: '0640'
|
||||
notify: Restart FRR
|
||||
|
||||
- name: Restart FRR
|
||||
systemd:
|
||||
name: frr
|
||||
state: restarted
|
||||
daemon_reload: yes
|
||||
|
||||
# - name: Wait for FRR to be fully started
|
||||
# wait_for:
|
||||
# path: /run/frr/bgpd.vty
|
||||
# state: present
|
||||
# timeout: 30
|
||||
# when: ansible_service_mgr == "systemd"
|
||||
@@ -0,0 +1,58 @@
|
||||
!
|
||||
frr version
|
||||
frr defaults traditional
|
||||
hostname {{ inventory_hostname }}
|
||||
log syslog informational
|
||||
!
|
||||
router bgp {{ local_asn }}
|
||||
bgp router-id {{ lan_ip }}
|
||||
!
|
||||
network {{ lan_cidr }}
|
||||
network {{ external_cidr }}
|
||||
!
|
||||
neighbor {{ hostvars['router1'].lan_ip if inventory_hostname != 'router1' else hostvars['router2'].lan_ip }} remote-as {{ local_asn }}
|
||||
neighbor {{ hostvars['router1'].lan_ip if inventory_hostname != 'router1' else hostvars['router2'].lan_ip }} update-source eth1
|
||||
!
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} remote-as {{ remote_asn }}
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} update-source gre-main
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} timers 10 30
|
||||
!
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} remote-as {{ remote_asn }}
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} update-source gre-backup
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} timers 10 30
|
||||
!
|
||||
address-family ipv4 unicast
|
||||
neighbor {{ hostvars['router1'].lan_ip if inventory_hostname != 'router1' else hostvars['router2'].lan_ip }} activate
|
||||
neighbor {{ hostvars['router1'].lan_ip if inventory_hostname != 'router1' else hostvars['router2'].lan_ip }} next-hop-self
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} activate
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} activate
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} route-map SET-PREF-{{ local_pref_main }} in
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} route-map SET-PREF-{{ local_pref_backup }} in
|
||||
neighbor {{ hostvars['router1'].lan_ip if inventory_hostname != 'router1' else hostvars['router2'].lan_ip }} route-map OUT-LAN out
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} route-map OUT-EXTERNAL out
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} route-map OUT-EXTERNAL out
|
||||
exit-address-family
|
||||
!
|
||||
route-map SET-PREF-400 permit 10
|
||||
set local-preference 400
|
||||
!
|
||||
route-map SET-PREF-300 permit 10
|
||||
set local-preference 300
|
||||
!
|
||||
route-map SET-PREF-200 permit 10
|
||||
set local-preference 200
|
||||
!
|
||||
route-map SET-PREF-100 permit 10
|
||||
set local-preference 100
|
||||
!
|
||||
route-map OUT-LAN permit 10
|
||||
match ip address prefix-list LAN-ONLY
|
||||
!
|
||||
route-map OUT-EXTERNAL permit 10
|
||||
match ip address prefix-list EXTERNAL-ONLY
|
||||
!
|
||||
ip prefix-list LAN-ONLY seq 5 permit {{ lan_cidr }}
|
||||
ip prefix-list EXTERNAL-ONLY seq 5 permit {{ external_cidr }}
|
||||
!
|
||||
line vty
|
||||
!
|
||||
@@ -0,0 +1,104 @@
|
||||
!
|
||||
! FRR BGP Configuration Template (Managed by Ansible)
|
||||
!
|
||||
frr version
|
||||
frr defaults traditional
|
||||
hostname {{ inventory_hostname }}
|
||||
log syslog informational
|
||||
!
|
||||
! Static route for originating a network in BGP if it's not directly connected
|
||||
!
|
||||
|
||||
! Interface configurations
|
||||
interface eth1
|
||||
ip address {{ lan_ip }}/{{ lan_network_prefix }}
|
||||
!
|
||||
interface gre-main
|
||||
ip address {{ gre_main_ip }}/30
|
||||
!
|
||||
interface gre-backup
|
||||
ip address {{ gre_backup_ip }}/30
|
||||
!
|
||||
|
||||
! BGP Configuration
|
||||
router bgp {{ local_asn }}
|
||||
bgp router-id {{ lan_ip }}
|
||||
!
|
||||
! Networks to originate from this router
|
||||
network {{ lan_cidr }}
|
||||
!
|
||||
! iBGP neighbor configuration
|
||||
neighbor {{ remote_ibgp_peer }} remote-as {{ local_asn }}
|
||||
neighbor {{ remote_ibgp_peer }} update-source eth1
|
||||
!
|
||||
! eBGP neighbors configuration
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} remote-as {{ remote_asn }}
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} ebgp-multihop 255
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} update-source gre-main
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} timers 10 30
|
||||
!
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} remote-as {{ remote_asn }}
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} ebgp-multihop 255
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} update-source gre-backup
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} timers 10 30
|
||||
!
|
||||
address-family ipv4 unicast
|
||||
! Activate neighbors
|
||||
neighbor {{ remote_ibgp_peer }} activate
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} activate
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} activate
|
||||
|
||||
! Policy configurations for neighbors
|
||||
neighbor {{ remote_ibgp_peer }} next-hop-self
|
||||
neighbor {{ remote_ibgp_peer }} route-map ALLOW-RFC1918-OUT out
|
||||
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} route-map FROM-MAIN-PEER in
|
||||
neighbor {{ gre_main_ip | ipmath(1) }} route-map TO-MAIN-PEER out
|
||||
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} route-map FROM-BACKUP-PEER in
|
||||
neighbor {{ gre_backup_ip | ipmath(1) }} route-map TO-BACKUP-PEER out
|
||||
exit-address-family
|
||||
!
|
||||
|
||||
!
|
||||
! Route Maps for BGP Policy
|
||||
!
|
||||
! Inbound policy from the main external peer
|
||||
route-map FROM-MAIN-PEER permit 10
|
||||
match ip address prefix-list RFC1918-NETS
|
||||
set local-preference {{ local_pref_main | default(400) }}
|
||||
!
|
||||
! Inbound policy from the backup external peer
|
||||
route-map FROM-BACKUP-PEER permit 10
|
||||
match ip address prefix-list RFC1918-NETS
|
||||
set local-preference {{ local_pref_backup | default(300) }}
|
||||
!
|
||||
! Outbound policy for the main external peer
|
||||
route-map TO-MAIN-PEER permit 10
|
||||
match ip address prefix-list RFC1918-NETS
|
||||
set metric {{ bgp_med_main }}
|
||||
!
|
||||
! Outbound policy for the main external peer
|
||||
route-map TO-BACKUP-PEER permit 10
|
||||
match ip address prefix-list RFC1918-NETS
|
||||
set metric {{ bgp_med_backup }}
|
||||
!
|
||||
!
|
||||
! Prefix List for RFC1918 networks and default route filtering
|
||||
!
|
||||
! Rule 1: Explicitly deny the default route
|
||||
ip prefix-list RFC1918-NETS seq 5 deny 0.0.0.0/0
|
||||
|
||||
! Rule 2: Permit 10.0.0.0/8 and all its subnets
|
||||
ip prefix-list RFC1918-NETS seq 10 permit 10.0.0.0/8 le 32
|
||||
|
||||
! Rule 3: Permit 172.16.0.0/12 and all its subnets
|
||||
ip prefix-list RFC1918-NETS seq 15 permit 172.16.0.0/12 le 32
|
||||
|
||||
! Rule 4: Permit 192.168.0.0/16 and all its subnets
|
||||
ip prefix-list RFC1918-NETS seq 20 permit 192.168.0.0/16 le 32
|
||||
!
|
||||
|
||||
! VTY lines for management access
|
||||
line vty
|
||||
!
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
- name: save iptables
|
||||
command: netfilter-persistent save
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
- name: Create GRE tunnels via Netplan
|
||||
template:
|
||||
src: gre-netplan.yaml.j2
|
||||
dest: "/etc/netplan/10-gre-{{ item }}.yaml"
|
||||
mode: '0600'
|
||||
loop:
|
||||
- main
|
||||
- backup
|
||||
|
||||
- name: Apply Netplan
|
||||
command: netplan apply
|
||||
|
||||
- name: Refresh interface facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- 'interfaces'
|
||||
|
||||
- name: Discover GRE interfaces
|
||||
ansible.builtin.set_fact:
|
||||
gre_interfaces: "{{ ansible_interfaces | select('match', '^gre-(m|b).*') | list }}"
|
||||
|
||||
- name: Debug GRE interfaces
|
||||
ansible.builtin.debug:
|
||||
msg: "Found GRE interfaces: {{ gre_interfaces }}"
|
||||
|
||||
- name: Validate that GRE interfaces exist
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- gre_interfaces | length > 0
|
||||
fail_msg: "No GRE interfaces found"
|
||||
success_msg: "GRE interfaces found: {{ gre_interfaces }}"
|
||||
|
||||
- name: Apply MSS clamping rule only if not already exists
|
||||
ansible.builtin.shell: |
|
||||
if ! iptables -t mangle -C FORWARD -d {{ lan_cidr }} -i {{ item }} -p tcp --tcp-flags SYN,RST SYN -m length --length 1321:65535 -j TCPMSS --set-mss 1320 -m comment --comment 'Clamp MSS to 1320 for GRE tunnel {{ item }}' 2>/dev/null; then
|
||||
iptables -t mangle -I FORWARD -d {{ lan_cidr }} -i {{ item }} -p tcp --tcp-flags SYN,RST SYN -m length --length 1321:65535 -j TCPMSS --set-mss 1320 -m comment --comment 'Clamp MSS to 1320 for GRE tunnel {{ item }}'
|
||||
echo "rule_added"
|
||||
else
|
||||
echo "rule_already_exists"
|
||||
fi
|
||||
loop: "{{ gre_interfaces }}"
|
||||
register: iptables_shell
|
||||
changed_when:
|
||||
- iptables_shell.stdout == "rule_added"
|
||||
notify: save iptables
|
||||
|
||||
- name: Apply MSS clamping rule only if not already exists
|
||||
ansible.builtin.shell: |
|
||||
if ! iptables -t mangle -C FORWARD -s {{ lan_cidr }} -o {{ item }} -p tcp --tcp-flags SYN,RST SYN -m length --length 1321:65535 -j TCPMSS --set-mss 1320 -m comment --comment 'Clamp MSS to 1320 for GRE tunnel {{ item }}' 2>/dev/null; then
|
||||
iptables -t mangle -I FORWARD -s {{ lan_cidr }} -o {{ item }} -p tcp --tcp-flags SYN,RST SYN -m length --length 1321:65535 -j TCPMSS --set-mss 1320 -m comment --comment 'Clamp MSS to 1320 for GRE tunnel {{ item }}'
|
||||
echo "rule_added"
|
||||
else
|
||||
echo "rule_already_exists"
|
||||
fi
|
||||
loop: "{{ gre_interfaces }}"
|
||||
register: iptables_shell
|
||||
changed_when:
|
||||
- iptables_shell.stdout == "rule_added"
|
||||
notify: save iptables
|
||||
@@ -0,0 +1,19 @@
|
||||
{% if item == "main" %}
|
||||
{% set gre_ip = gre_main_ip %}
|
||||
{% set remote_wan = remote_main_isp_ip %}
|
||||
{% elif item == "backup" %}
|
||||
{% set gre_ip = gre_backup_ip %}
|
||||
{% set remote_wan = remote_backup_isp_ip %}
|
||||
{% endif %}
|
||||
network:
|
||||
version: 2
|
||||
tunnels:
|
||||
gre-{{ item }}:
|
||||
mode: gre
|
||||
local: {{ wan_ip }}
|
||||
remote: {{ remote_wan }}
|
||||
addresses:
|
||||
- {{ gre_ip }}/30
|
||||
mtu: 1360
|
||||
dhcp4: no
|
||||
dhcp6: no
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Install Keepalived
|
||||
apt:
|
||||
name: keepalived
|
||||
state: present
|
||||
|
||||
- name: Configure Keepalived
|
||||
template:
|
||||
src: keepalived.conf.j2
|
||||
dest: /etc/keepalived/keepalived.conf
|
||||
mode: '0644'
|
||||
|
||||
- name: Enable and start Keepalived
|
||||
systemd:
|
||||
name: keepalived
|
||||
enabled: yes
|
||||
state: restarted
|
||||
@@ -0,0 +1,19 @@
|
||||
vrrp_instance VI_1 {
|
||||
interface eth1
|
||||
state BACKUP
|
||||
|
||||
# set priority
|
||||
priority {% if inventory_hostname == 'router1' %}101{% else %}100{% endif %}
|
||||
|
||||
# set VRRP Router ID
|
||||
virtual_router_id 51
|
||||
|
||||
advert_int 1
|
||||
authentication {
|
||||
auth_type PASS
|
||||
auth_pass secret123
|
||||
}
|
||||
virtual_ipaddress {
|
||||
{{ vrrp_vip }}/{{ lan_network_prefix }}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Update packages
|
||||
apt:
|
||||
upgrade: dist
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Install utilities
|
||||
apt:
|
||||
name:
|
||||
- net-tools
|
||||
- traceroute
|
||||
- iproute2
|
||||
- mtr
|
||||
- bmon
|
||||
- htop
|
||||
state: present
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
- name: Install StrongSwan including extra plugins
|
||||
apt:
|
||||
name: [strongswan, strongswan-swanctl, libstrongswan-extra-plugins]
|
||||
state: present
|
||||
|
||||
- name: Configure swanctl.conf
|
||||
template:
|
||||
src: swanctl.conf.j2
|
||||
dest: /etc/swanctl/conf.d/deployment.conf
|
||||
mode: '0644'
|
||||
|
||||
- name: Configure StrongSwan charon.conf to load all tunnels on startup
|
||||
block:
|
||||
- name: Check if swanctl startup command already exists in charon.conf
|
||||
command: grep -q "swanctl = /usr/sbin/swanctl --load-all" /etc/strongswan.d/charon.conf
|
||||
register: swanctl_exists
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Update charon.conf to include swanctl startup command
|
||||
shell: |
|
||||
sed -i '/start-scripts\s*{/,/}/{
|
||||
/}/i\ swanctl = /usr/sbin/swanctl --load-all
|
||||
}' /etc/strongswan.d/charon.conf
|
||||
when: swanctl_exists.rc != 0
|
||||
|
||||
- name: Restart StrongSwan (using strongswan-starter)
|
||||
systemd:
|
||||
name: strongswan-starter
|
||||
state: restarted
|
||||
enabled: yes
|
||||
@@ -0,0 +1,58 @@
|
||||
connections {
|
||||
gre-main {
|
||||
local_addrs = {{ wan_ip }}
|
||||
remote_addrs = {{ remote_main_isp_ip }}
|
||||
|
||||
local { auth = psk }
|
||||
remote { auth = psk }
|
||||
|
||||
version = 2
|
||||
proposals = {{ ike_proposal }}
|
||||
rekey_time = {{ ike_lifetime }}s
|
||||
|
||||
children {
|
||||
gre-main {
|
||||
local_ts = dynamic[gre]
|
||||
remote_ts = dynamic[gre]
|
||||
esp_proposals = {{ esp_proposal }}
|
||||
rekey_time = {{ esp_lifetime }}s
|
||||
mode = transport
|
||||
dpd_action = restart
|
||||
close_action = restart
|
||||
}
|
||||
}
|
||||
dpd_timeout = {{ dpd_timeout }}s
|
||||
}
|
||||
|
||||
gre-backup {
|
||||
local_addrs = {{ wan_ip }}
|
||||
remote_addrs = {{ remote_backup_isp_ip }}
|
||||
|
||||
local { auth = psk }
|
||||
remote { auth = psk }
|
||||
|
||||
version = 2
|
||||
proposals = {{ ike_proposal }}
|
||||
rekey_time = {{ ike_lifetime }}s
|
||||
|
||||
children {
|
||||
gre-backup {
|
||||
mode = transport
|
||||
local_ts = dynamic[gre]
|
||||
remote_ts = dynamic[gre]
|
||||
esp_proposals = {{ esp_proposal }}
|
||||
rekey_time = {{ esp_lifetime }}s
|
||||
mode = transport
|
||||
dpd_action = restart
|
||||
close_action = restart
|
||||
}
|
||||
}
|
||||
dpd_timeout = {{ dpd_timeout }}s
|
||||
}
|
||||
}
|
||||
|
||||
secrets {
|
||||
ike {
|
||||
secret = "{{ ipsec_psk }}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
### Disable IPv6
|
||||
|
||||
- name: Disable IPv6 on all servers
|
||||
hosts: all
|
||||
become: yes
|
||||
roles:
|
||||
- disable_ipv6
|
||||
|
||||
|
||||
### Configure Routers
|
||||
|
||||
- name: Configure Routers
|
||||
hosts: ubuntu_routers
|
||||
become: yes
|
||||
roles:
|
||||
- base
|
||||
- gre
|
||||
- strongswan
|
||||
- frr_router
|
||||
- keepalived
|
||||
|
||||
### (optional) configure private servers
|
||||
|
||||
- name: Configure Private Servers
|
||||
hosts: private_servers
|
||||
become: yes
|
||||
roles:
|
||||
- private_base
|
||||
@@ -0,0 +1,13 @@
|
||||
# Get all Ubuntu images
|
||||
# data "vkcs_images_images" "images" {
|
||||
# visibility = "public"
|
||||
# default = true
|
||||
# properties = {
|
||||
# mcs_os_distro = "ubuntu"
|
||||
# }
|
||||
# }
|
||||
|
||||
# List all Ubuntu images
|
||||
# output "all_image_names" {
|
||||
# value = [for img in data.vkcs_images_images.images.images : img.name]
|
||||
# }
|
||||
@@ -0,0 +1,293 @@
|
||||
data "vkcs_images_image" "ubuntu24" {
|
||||
visibility = "public"
|
||||
most_recent = true
|
||||
properties = {
|
||||
mcs_os_distro = "ubuntu"
|
||||
mcs_os_version = "24.04"
|
||||
}
|
||||
}
|
||||
|
||||
data "vkcs_networking_network" "extnet" {
|
||||
name = "internet"
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
# LAN Network
|
||||
resource "vkcs_networking_network" "lan_net" {
|
||||
name = "router-lan-net"
|
||||
sdn = "sprut"
|
||||
admin_state_up = true
|
||||
}
|
||||
|
||||
resource "vkcs_networking_subnet" "lan_subnet" {
|
||||
network_id = vkcs_networking_network.lan_net.id
|
||||
name = "router-lan-subnet"
|
||||
cidr = "10.200.10.0/24"
|
||||
gateway_ip = "10.200.10.1"
|
||||
dns_nameservers = ["8.8.8.8", "1.1.1.1"]
|
||||
sdn = "sprut"
|
||||
|
||||
allocation_pool {
|
||||
start = "10.200.10.100"
|
||||
end = "10.200.10.200"
|
||||
}
|
||||
}
|
||||
|
||||
# Security Groups
|
||||
resource "vkcs_networking_secgroup" "router_sg" {
|
||||
name = "router-sg"
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
resource "vkcs_networking_secgroup" "private_sg" {
|
||||
name = "private-sg"
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
# Private SG rules
|
||||
resource "vkcs_networking_secgroup_rule" "from_rfc_net192_in" {
|
||||
direction = "ingress"
|
||||
remote_ip_prefix = "192.168.0.0/16"
|
||||
security_group_id = vkcs_networking_secgroup.private_sg.id
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
resource "vkcs_networking_secgroup_rule" "from_rfc_net172_in" {
|
||||
direction = "ingress"
|
||||
remote_ip_prefix = "172.16.0.0/12"
|
||||
security_group_id = vkcs_networking_secgroup.private_sg.id
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
resource "vkcs_networking_secgroup_rule" "from_rfc_net10_in" {
|
||||
direction = "ingress"
|
||||
remote_ip_prefix = "10.0.0.0/8"
|
||||
security_group_id = vkcs_networking_secgroup.private_sg.id
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
# Router SG rules
|
||||
resource "vkcs_networking_secgroup_rule" "router_ssh" {
|
||||
direction = "ingress"
|
||||
protocol = "tcp"
|
||||
port_range_min = 22
|
||||
port_range_max = 22
|
||||
remote_ip_prefix = "0.0.0.0/0"
|
||||
security_group_id = vkcs_networking_secgroup.router_sg.id
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
resource "vkcs_networking_secgroup_rule" "router_icmp" {
|
||||
direction = "ingress"
|
||||
protocol = "icmp"
|
||||
remote_ip_prefix = "0.0.0.0/0"
|
||||
security_group_id = vkcs_networking_secgroup.router_sg.id
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
resource "vkcs_networking_secgroup_rule" "router_ipsec_ike" {
|
||||
direction = "ingress"
|
||||
protocol = "udp"
|
||||
port_range_min = 500
|
||||
port_range_max = 500
|
||||
remote_ip_prefix = "0.0.0.0/0"
|
||||
security_group_id = vkcs_networking_secgroup.router_sg.id
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
resource "vkcs_networking_secgroup_rule" "router_ipsec_nat_t" {
|
||||
direction = "ingress"
|
||||
protocol = "udp"
|
||||
port_range_min = 4500
|
||||
port_range_max = 4500
|
||||
remote_ip_prefix = "0.0.0.0/0"
|
||||
security_group_id = vkcs_networking_secgroup.router_sg.id
|
||||
sdn = "sprut"
|
||||
}
|
||||
|
||||
# Router LAN Ports
|
||||
resource "vkcs_networking_port" "lan_port1" {
|
||||
name = "router1-lan-port"
|
||||
network_id = vkcs_networking_network.lan_net.id
|
||||
admin_state_up = true
|
||||
port_security_enabled = false
|
||||
full_security_groups_control = true
|
||||
security_group_ids = []
|
||||
sdn = "sprut"
|
||||
fixed_ip {
|
||||
subnet_id = vkcs_networking_subnet.lan_subnet.id
|
||||
ip_address = "10.200.10.254"
|
||||
}
|
||||
}
|
||||
|
||||
resource "vkcs_networking_port" "lan_port2" {
|
||||
name = "router2-lan-port"
|
||||
network_id = vkcs_networking_network.lan_net.id
|
||||
admin_state_up = true
|
||||
port_security_enabled = false
|
||||
full_security_groups_control = true
|
||||
security_group_ids = []
|
||||
sdn = "sprut"
|
||||
fixed_ip {
|
||||
subnet_id = vkcs_networking_subnet.lan_subnet.id
|
||||
ip_address = "10.200.10.253"
|
||||
}
|
||||
}
|
||||
|
||||
resource "vkcs_compute_instance" "router1" {
|
||||
name = "router1"
|
||||
image_id = data.vkcs_images_image.ubuntu24.id
|
||||
flavor_name = "STD3-4-4"
|
||||
availability_zone = "ME1"
|
||||
key_pair = var.ssh_key_name
|
||||
|
||||
security_group_ids = [
|
||||
vkcs_networking_secgroup.router_sg.id,
|
||||
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
|
||||
]
|
||||
|
||||
config_drive = true
|
||||
|
||||
# Configure persistent networking using script
|
||||
user_data = file("${path.module}/scripts/network-init.sh")
|
||||
|
||||
# WAN: dynamically created port
|
||||
network {
|
||||
uuid = data.vkcs_networking_network.extnet.id
|
||||
}
|
||||
|
||||
# LAN: pre-created port
|
||||
network {
|
||||
port = vkcs_networking_port.lan_port1.id
|
||||
}
|
||||
|
||||
block_device {
|
||||
uuid = data.vkcs_images_image.ubuntu24.id
|
||||
source_type = "image"
|
||||
volume_size = 20
|
||||
boot_index = 0
|
||||
destination_type = "volume"
|
||||
volume_type = "ceph-ssd"
|
||||
delete_on_termination = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "vkcs_compute_instance" "router2" {
|
||||
name = "router2"
|
||||
image_id = data.vkcs_images_image.ubuntu24.id
|
||||
flavor_name = "STD3-4-4"
|
||||
availability_zone = "ME1"
|
||||
key_pair = var.ssh_key_name
|
||||
|
||||
security_group_ids = [
|
||||
vkcs_networking_secgroup.router_sg.id,
|
||||
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
|
||||
]
|
||||
|
||||
config_drive = true
|
||||
|
||||
# Configure persistent networking using script
|
||||
user_data = file("${path.module}/scripts/network-init.sh")
|
||||
|
||||
# WAN: dynamically created port
|
||||
network {
|
||||
uuid = data.vkcs_networking_network.extnet.id
|
||||
}
|
||||
|
||||
# LAN: pre-created port
|
||||
network {
|
||||
port = vkcs_networking_port.lan_port2.id
|
||||
}
|
||||
|
||||
block_device {
|
||||
uuid = data.vkcs_images_image.ubuntu24.id
|
||||
source_type = "image"
|
||||
volume_size = 20
|
||||
boot_index = 0
|
||||
destination_type = "volume"
|
||||
volume_type = "ceph-ssd"
|
||||
delete_on_termination = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "vkcs_compute_instance" "priv_srv_01" {
|
||||
name = "Priv-SRV-01"
|
||||
image_id = data.vkcs_images_image.ubuntu24.id
|
||||
flavor_name = "STD3-4-4"
|
||||
availability_zone = "ME1"
|
||||
key_pair = var.ssh_key_name
|
||||
|
||||
security_group_ids = [
|
||||
vkcs_networking_secgroup.private_sg.id,
|
||||
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
|
||||
]
|
||||
|
||||
network {
|
||||
uuid = vkcs_networking_network.lan_net.id
|
||||
}
|
||||
|
||||
block_device {
|
||||
uuid = data.vkcs_images_image.ubuntu24.id
|
||||
source_type = "image"
|
||||
volume_size = 20
|
||||
boot_index = 0
|
||||
destination_type = "volume"
|
||||
volume_type = "ceph-ssd"
|
||||
delete_on_termination = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
resource "vkcs_compute_instance" "priv_srv_02" {
|
||||
name = "Priv-SRV-02"
|
||||
image_id = data.vkcs_images_image.ubuntu24.id
|
||||
flavor_name = "STD3-4-4"
|
||||
availability_zone = "ME1"
|
||||
key_pair = var.ssh_key_name
|
||||
|
||||
security_group_ids = [
|
||||
vkcs_networking_secgroup.private_sg.id,
|
||||
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
|
||||
]
|
||||
|
||||
network {
|
||||
uuid = vkcs_networking_network.lan_net.id
|
||||
}
|
||||
|
||||
block_device {
|
||||
uuid = data.vkcs_images_image.ubuntu24.id
|
||||
source_type = "image"
|
||||
volume_size = 20
|
||||
boot_index = 0
|
||||
destination_type = "volume"
|
||||
volume_type = "ceph-ssd"
|
||||
delete_on_termination = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "vkcs_compute_instance" "priv_srv_03" {
|
||||
name = "Priv-SRV-03"
|
||||
image_id = data.vkcs_images_image.ubuntu24.id
|
||||
flavor_name = "STD3-4-4"
|
||||
availability_zone = "MS1"
|
||||
key_pair = var.ssh_key_name
|
||||
|
||||
security_group_ids = [
|
||||
vkcs_networking_secgroup.private_sg.id,
|
||||
"d479b4d7-55b3-4ff1-bf8d-24d826a38f11"
|
||||
]
|
||||
|
||||
network {
|
||||
uuid = vkcs_networking_network.lan_net.id
|
||||
}
|
||||
|
||||
block_device {
|
||||
uuid = data.vkcs_images_image.ubuntu24.id
|
||||
source_type = "image"
|
||||
volume_size = 20
|
||||
boot_index = 0
|
||||
destination_type = "volume"
|
||||
volume_type = "ceph-ssd"
|
||||
delete_on_termination = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a /var/log/network-config.log
|
||||
}
|
||||
|
||||
log "Starting network configuration..."
|
||||
|
||||
# Validate required commands exist
|
||||
for cmd in ip netplan systemctl; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
log "ERROR: Required command '$cmd' is not available"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate directories exist
|
||||
if [ ! -d "/etc/netplan" ]; then
|
||||
log "ERROR: /etc/netplan directory does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "/sys/class/net" ]; then
|
||||
log "ERROR: /sys/class/net directory does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Enhanced function to check if IP is in private subnet (RFC 1918)
|
||||
is_private_ip() {
|
||||
local ip="$1"
|
||||
local clean_ip=$(echo "$ip" | cut -d'/' -f1) # Remove subnet mask if present
|
||||
|
||||
# Check RFC 1918 private ranges:
|
||||
# 10.0.0.0/8 (10.0.0.0 - 10.255.255.255)
|
||||
# 172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
|
||||
# 192.168.0.0/16 (192.168.0.0 - 192.168.255.255)
|
||||
|
||||
if [[ $clean_ip =~ ^10\. ]]; then
|
||||
return 0 # 10.0.0.0/8
|
||||
elif [[ $clean_ip =~ ^172\.(1[6-9]|2[0-9]|3[0-1])\. ]]; then
|
||||
return 0 # 172.16.0.0/12
|
||||
elif [[ $clean_ip =~ ^192\.168\. ]]; then
|
||||
return 0 # 192.168.0.0/16
|
||||
else
|
||||
return 1 # Is public IP
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to convert CIDR to netmask
|
||||
cidr_to_netmask() {
|
||||
local cidr="$1"
|
||||
|
||||
# Input validation
|
||||
if [[ ! $cidr =~ ^[0-9]+$ ]] || [ "$cidr" -lt 0 ] || [ "$cidr" -gt 32 ]; then
|
||||
echo "Error: CIDR must be a number between 0 and 32" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local netmask=""
|
||||
local full_octets=$((cidr / 8))
|
||||
local remaining_bits=$((cidr % 8))
|
||||
local partial_octet=0
|
||||
|
||||
# Calculate partial octet if there are remaining bits
|
||||
if [ "$remaining_bits" -gt 0 ]; then
|
||||
partial_octet=$((256 - (256 >> remaining_bits)))
|
||||
fi
|
||||
|
||||
for ((i=0; i<4; i++)); do
|
||||
if [ "$i" -lt "$full_octets" ]; then
|
||||
netmask="${netmask}255"
|
||||
elif [ "$i" -eq "$full_octets" ] && [ "$remaining_bits" -gt 0 ]; then
|
||||
netmask="${netmask}${partial_octet}"
|
||||
else
|
||||
netmask="${netmask}0"
|
||||
fi
|
||||
|
||||
if [ "$i" -lt 3 ]; then
|
||||
netmask="${netmask}."
|
||||
fi
|
||||
done
|
||||
|
||||
echo "$netmask"
|
||||
}
|
||||
|
||||
# Function to convert netmask to CIDR
|
||||
netmask_to_cidr() {
|
||||
local netmask="$1"
|
||||
local cidr=0
|
||||
|
||||
# Use -a for array, not -o
|
||||
IFS='.' read -ra octets <<< "$netmask"
|
||||
|
||||
for octet in "${octets[@]}"; do
|
||||
case $octet in
|
||||
255) cidr=$((cidr + 8)) ;;
|
||||
254) cidr=$((cidr + 7)) ;;
|
||||
252) cidr=$((cidr + 6)) ;;
|
||||
248) cidr=$((cidr + 5)) ;;
|
||||
240) cidr=$((cidr + 4)) ;;
|
||||
224) cidr=$((cidr + 3)) ;;
|
||||
192) cidr=$((cidr + 2)) ;;
|
||||
128) cidr=$((cidr + 1)) ;;
|
||||
0) ;;
|
||||
*) echo "32"; return 1 ;; # Invalid netmask, default to /32
|
||||
esac
|
||||
done
|
||||
|
||||
echo "$cidr"
|
||||
}
|
||||
|
||||
# Function to extract IP, netmask, and CIDR from CIDR notation
|
||||
get_ip_netmask_cidr() {
|
||||
local cidr_ip="$1"
|
||||
local ip=$(echo "$cidr_ip" | cut -d'/' -f1)
|
||||
local cidr_part=$(echo "$cidr_ip" | cut -d'/' -f2)
|
||||
local netmask=""
|
||||
local cidr=""
|
||||
|
||||
if [[ $cidr_part =~ ^[0-9]{1,2}$ ]]; then
|
||||
# CIDR notation (e.g., /24)
|
||||
cidr="$cidr_part"
|
||||
netmask=$(cidr_to_netmask "$cidr")
|
||||
elif [[ $cidr_part =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
# Already in netmask format
|
||||
netmask="$cidr_part"
|
||||
cidr=$(netmask_to_cidr "$netmask")
|
||||
else
|
||||
# Default to /32 if no valid netmask found
|
||||
cidr="32"
|
||||
netmask="255.255.255.255"
|
||||
fi
|
||||
|
||||
echo "$ip,$netmask,$cidr"
|
||||
}
|
||||
|
||||
# Function to extract the first private IPv4 address, netmask, and CIDR from an interface
|
||||
get_private_ip_netmask_cidr() {
|
||||
local interface="$1"
|
||||
local ip_addrs=$(ip addr show "$interface" 2>/dev/null | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}')
|
||||
|
||||
if [ -n "$ip_addrs" ]; then
|
||||
while IFS= read -r ip; do
|
||||
if [ -n "$ip" ] && is_private_ip "$ip"; then
|
||||
# Return IP, netmask, and CIDR
|
||||
get_ip_netmask_cidr "$ip"
|
||||
return 0
|
||||
fi
|
||||
done <<< "$ip_addrs"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to extract the first public IPv4 address, netmask, and CIDR from an interface
|
||||
get_public_ip_netmask_cidr() {
|
||||
local interface="$1"
|
||||
local ip_addrs=$(ip addr show "$interface" 2>/dev/null | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}')
|
||||
|
||||
if [ -n "$ip_addrs" ]; then
|
||||
while IFS= read -r ip; do
|
||||
if [ -n "$ip" ] && ! is_private_ip "$ip"; then
|
||||
# Return IP, netmask, and CIDR
|
||||
get_ip_netmask_cidr "$ip"
|
||||
return 0
|
||||
fi
|
||||
done <<< "$ip_addrs"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to get default gateway for an interface
|
||||
get_interface_gateway() {
|
||||
local interface="$1"
|
||||
|
||||
# Try to get gateway from route table for the specific interface
|
||||
local gateway=$(ip route show dev "$interface" 2>/dev/null | grep '^default via' | awk '{print $3}' | head -n1)
|
||||
|
||||
if [ -n "$gateway" ]; then
|
||||
echo "$gateway"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fallback: get default gateway from main route table
|
||||
gateway=$(ip route show 2>/dev/null | grep '^default via' | awk '{print $3}' | head -n1)
|
||||
|
||||
if [ -n "$gateway" ]; then
|
||||
echo "$gateway"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Enhanced function to check if interface has private IP
|
||||
has_private_ip() {
|
||||
local interface="$1"
|
||||
local ip_addrs=$(ip addr show "$interface" 2>/dev/null | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}')
|
||||
|
||||
if [ -n "$ip_addrs" ]; then
|
||||
while IFS= read -r ip; do
|
||||
if [ -n "$ip" ] && is_private_ip "$ip"; then
|
||||
return 0 # Has at least one private IP
|
||||
fi
|
||||
done <<< "$ip_addrs"
|
||||
fi
|
||||
return 1 # No private IP
|
||||
}
|
||||
|
||||
# Identify LAN and WAN interfaces with enhanced logic
|
||||
LAN_IFACE=""
|
||||
LAN_MAC=""
|
||||
LAN_IFACE_IPv4=""
|
||||
LAN_NETMASK=""
|
||||
LAN_CIDR=""
|
||||
WAN_IFACE=""
|
||||
WAN_MAC=""
|
||||
WAN_IFACE_IPv4=""
|
||||
WAN_NETMASK=""
|
||||
WAN_CIDR=""
|
||||
WAN_GW_IPv4=""
|
||||
|
||||
# First pass: Look for interfaces with private IPs (LAN candidates)
|
||||
for iface in $(ls /sys/class/net/ | grep -v lo); do
|
||||
if has_private_ip "$iface"; then
|
||||
if [ -z "$LAN_IFACE" ]; then
|
||||
LAN_IFACE="$iface"
|
||||
LAN_MAC=$(cat "/sys/class/net/$iface/address" 2>/dev/null)
|
||||
|
||||
# Get IP, netmask, and CIDR
|
||||
lan_ip_netmask_cidr=$(get_private_ip_netmask_cidr "$iface")
|
||||
if [ -n "$lan_ip_netmask_cidr" ]; then
|
||||
LAN_IFACE_IPv4=$(echo "$lan_ip_netmask_cidr" | cut -d',' -f1)
|
||||
LAN_NETMASK=$(echo "$lan_ip_netmask_cidr" | cut -d',' -f2)
|
||||
LAN_CIDR=$(echo "$lan_ip_netmask_cidr" | cut -d',' -f3)
|
||||
fi
|
||||
|
||||
log "Identified LAN interface: $iface (MAC: $LAN_MAC) with private IP: $LAN_IFACE_IPv4, Netmask: $LAN_NETMASK, CIDR: /$LAN_CIDR"
|
||||
else
|
||||
log "Multiple LAN interface candidates found: $LAN_IFACE and $iface"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Second pass: Look for WAN interface
|
||||
for iface in $(ls /sys/class/net/ | grep -v lo); do
|
||||
# Skip if this is already identified as LAN
|
||||
[ "$iface" = "$LAN_IFACE" ] && continue
|
||||
|
||||
ip_addrs=$(ip addr show "$iface" 2>/dev/null | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}')
|
||||
|
||||
if [ -n "$ip_addrs" ]; then
|
||||
# Check if interface has public IPs
|
||||
has_public="false"
|
||||
while IFS= read -r ip; do
|
||||
if [ -n "$ip" ] && ! is_private_ip "$ip"; then
|
||||
has_public="true"
|
||||
break
|
||||
fi
|
||||
done <<< "$ip_addrs"
|
||||
|
||||
if [ "$has_public" = "true" ]; then
|
||||
WAN_IFACE="$iface"
|
||||
WAN_MAC=$(cat "/sys/class/net/$iface/address" 2>/dev/null)
|
||||
|
||||
# Get both IP, netmask, and CIDR for WAN
|
||||
wan_ip_netmask_cidr=$(get_public_ip_netmask_cidr "$iface")
|
||||
if [ -n "$wan_ip_netmask_cidr" ]; then
|
||||
WAN_IFACE_IPv4=$(echo "$wan_ip_netmask_cidr" | cut -d',' -f1)
|
||||
WAN_NETMASK=$(echo "$wan_ip_netmask_cidr" | cut -d',' -f2)
|
||||
WAN_CIDR=$(echo "$wan_ip_netmask_cidr" | cut -d',' -f3)
|
||||
fi
|
||||
|
||||
WAN_GW_IPv4=$(get_interface_gateway "$iface")
|
||||
log "Identified WAN interface: $iface (MAC: $WAN_MAC) with public IP: $WAN_IFACE_IPv4, Netmask: $WAN_NETMASK, CIDR: /$WAN_CIDR, Gateway: $WAN_GW_IPv4"
|
||||
break
|
||||
fi
|
||||
else
|
||||
# Interface with no IP - potential WAN candidate
|
||||
if [ -z "$WAN_IFACE" ]; then
|
||||
WAN_IFACE="$iface"
|
||||
WAN_MAC=$(cat "/sys/class/net/$iface/address" 2>/dev/null)
|
||||
WAN_GW_IPv4=$(get_interface_gateway "$iface")
|
||||
log "Identified WAN interface candidate: $iface (MAC: $WAN_MAC) - no IP assigned, Gateway: $WAN_GW_IPv4"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# If no WAN found but we have LAN, pick first non-LAN interface
|
||||
if [ -z "$WAN_IFACE" ] && [ -n "$LAN_IFACE" ]; then
|
||||
for iface in $(ls /sys/class/net/ | grep -v lo); do
|
||||
if [ "$iface" != "$LAN_IFACE" ]; then
|
||||
WAN_IFACE="$iface"
|
||||
WAN_MAC=$(cat "/sys/class/net/$iface/address" 2>/dev/null)
|
||||
WAN_GW_IPv4=$(get_interface_gateway "$iface")
|
||||
log "Assumed WAN interface: $iface (MAC: $WAN_MAC) - default selection, Gateway: $WAN_GW_IPv4"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Final assignment and logging
|
||||
log "Final interface assignment:"
|
||||
log " LAN Interface: $LAN_IFACE (MAC: $LAN_MAC)"
|
||||
|
||||
if [ -n "$LAN_IFACE_IPv4" ]; then
|
||||
log " LAN IPv4: $LAN_IFACE_IPv4"
|
||||
log " LAN Netmask: $LAN_NETMASK"
|
||||
log " LAN CIDR: /$LAN_CIDR"
|
||||
else
|
||||
log " LAN IPv4: Not assigned"
|
||||
LAN_IFACE_IPv4="" # Ensure it's empty if no IP found
|
||||
LAN_NETMASK="" # Ensure netmask is also empty
|
||||
LAN_CIDR="" # Ensure CIDR is also empty
|
||||
fi
|
||||
|
||||
if [ -n "$WAN_IFACE" ]; then
|
||||
# Only set WAN IP, Netmask, CIDR and Gateway if WAN interface is detected
|
||||
log " WAN Interface: $WAN_IFACE (MAC: $WAN_MAC)"
|
||||
|
||||
if [ -n "$WAN_IFACE_IPv4" ]; then
|
||||
log " WAN IPv4: $WAN_IFACE_IPv4"
|
||||
log " WAN Netmask: $WAN_NETMASK"
|
||||
log " WAN CIDR: /$WAN_CIDR"
|
||||
else
|
||||
log " WAN IPv4: Not assigned"
|
||||
log " WAN Netmask: Not available"
|
||||
log " WAN CIDR: Not available"
|
||||
WAN_IFACE_IPv4="" # Ensure it's empty if no IP found
|
||||
WAN_NETMASK="" # Ensure netmask is also empty
|
||||
WAN_CIDR="" # Ensure CIDR is also empty
|
||||
fi
|
||||
|
||||
if [ -n "$WAN_GW_IPv4" ]; then
|
||||
log " WAN Gateway: $WAN_GW_IPv4"
|
||||
else
|
||||
log " WAN Gateway: Not detected"
|
||||
WAN_GW_IPv4="" # Ensure it's empty if no gateway found
|
||||
fi
|
||||
else
|
||||
log " WAN Interface: Not detected"
|
||||
# Ensure WAN-related variables are empty
|
||||
WAN_IFACE_IPv4=""
|
||||
WAN_NETMASK=""
|
||||
WAN_CIDR=""
|
||||
WAN_GW_IPv4=""
|
||||
fi
|
||||
|
||||
# Validate that we have the required information before proceeding
|
||||
if [ -z "$WAN_MAC" ] || [ -z "$WAN_IFACE_IPv4" ] || [ -z "$WAN_CIDR" ] || [ -z "$WAN_GW_IPv4" ] || [ -z "$LAN_MAC" ] || [ -z "$LAN_IFACE_IPv4" ] || [ -z "$LAN_CIDR" ]; then
|
||||
log "ERROR: Required network information is missing. Cannot proceed with network configuration."
|
||||
log "Missing information:"
|
||||
[ -z "$WAN_MAC" ] && log " - WAN MAC address"
|
||||
[ -z "$WAN_IFACE_IPv4" ] && log " - WAN IP address"
|
||||
[ -z "$WAN_CIDR" ] && log " - WAN CIDR"
|
||||
[ -z "$WAN_GW_IPv4" ] && log " - WAN Gateway"
|
||||
[ -z "$LAN_MAC" ] && log " - LAN MAC address"
|
||||
[ -z "$LAN_IFACE_IPv4" ] && log " - LAN IP address"
|
||||
[ -z "$LAN_CIDR" ] && log " - LAN CIDR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create backup of existing netplan config if it exists
|
||||
if [ -f "/etc/netplan/50-cloud-init.yaml" ]; then
|
||||
cp "/etc/netplan/50-cloud-init.yaml" "/etc/netplan/50-cloud-init.yaml.backup.$(date +%s)"
|
||||
log "Backed up existing netplan configuration"
|
||||
fi
|
||||
|
||||
# Disabling Cloud-Init
|
||||
log "Disabling Cloud-Init for Networking..."
|
||||
|
||||
cat > /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg <<'EOF'
|
||||
network: {config: disabled}
|
||||
EOF
|
||||
|
||||
log "Creating network config file"
|
||||
|
||||
# Creating netplan config with proper validation
|
||||
cat > /etc/netplan/50-cloud-init.yaml << EOF
|
||||
network:
|
||||
version: 2
|
||||
ethernets:
|
||||
wan-iface:
|
||||
match:
|
||||
macaddress: "$WAN_MAC"
|
||||
set-name: eth0
|
||||
dhcp4: false
|
||||
addresses:
|
||||
- $WAN_IFACE_IPv4/$WAN_CIDR
|
||||
routes:
|
||||
- to: default
|
||||
via: $WAN_GW_IPv4
|
||||
nameservers:
|
||||
addresses: [8.8.8.8, 1.1.1.1]
|
||||
lan-iface:
|
||||
match:
|
||||
macaddress: "$LAN_MAC"
|
||||
set-name: eth1
|
||||
dhcp4: false
|
||||
addresses:
|
||||
- $LAN_IFACE_IPv4/$LAN_CIDR
|
||||
EOF
|
||||
|
||||
log "Network config file has been created"
|
||||
|
||||
# Test the netplan configuration before applying
|
||||
if netplan --debug generate; then
|
||||
log "Netplan configuration generated successfully"
|
||||
|
||||
# Apply the configuration
|
||||
netplan apply
|
||||
systemctl restart systemd-networkd
|
||||
|
||||
# Wait a moment for network to come up
|
||||
sleep 2
|
||||
|
||||
# Test connectivity to gateway
|
||||
if ping -c 1 -W 5 "$WAN_GW_IPv4" >/dev/null 2>&1; then
|
||||
log "Network configuration applied successfully! Gateway is reachable."
|
||||
|
||||
# Ask for confirmation before rebooting (optional safety measure)
|
||||
log "Network configuration applied. Rebooting in 10 seconds. Press Ctrl+C to cancel."
|
||||
sleep 10
|
||||
reboot
|
||||
else
|
||||
log "WARNING: Gateway is not reachable after configuration. Not rebooting to prevent lockout."
|
||||
log "Please check the network configuration manually."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log "ERROR: Netplan configuration failed to generate. Rolling back changes."
|
||||
# Note: In a real scenario, you'd want to restore the backup here
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,4 @@
|
||||
username = "user@domain.local"
|
||||
password = "DemoUserPassw"
|
||||
project_id = "XXXXXd424998422XXXXXf13ac9XXXXX"
|
||||
ssh_key_name = "AdminSSH"
|
||||
@@ -0,0 +1,26 @@
|
||||
variable "username" {
|
||||
description = "VK Cloud username"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "password" {
|
||||
description = "VK Cloud password"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "Project ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "Region"
|
||||
type = string
|
||||
default = "ME1"
|
||||
}
|
||||
|
||||
variable "ssh_key_name" {
|
||||
description = "Name of SSH key pair in VK Cloud"
|
||||
type = string
|
||||
}
|
||||
Reference in new issue
Block a user