恢复 OCI Terraform 与站点网络 IaC
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
---
|
||||
- name: 重载 FRR daemons
|
||||
ansible.builtin.systemd_service:
|
||||
name: frr
|
||||
state: reloaded
|
||||
when: not ansible_check_mode
|
||||
- name: 刷新专用防火墙
|
||||
ansible.builtin.systemd_service:
|
||||
name: oci-wg-firewall
|
||||
daemon_reload: true
|
||||
state: restarted
|
||||
when: not ansible_check_mode
|
||||
- name: 重启 WireGuard
|
||||
ansible.builtin.systemd_service:
|
||||
name: wg-quick@{{ wg_interface }}
|
||||
state: restarted
|
||||
when: not ansible_check_mode
|
||||
- name: 应用 BGP 增量配置
|
||||
ansible.builtin.include_tasks: apply-bgp.yml
|
||||
when: not ansible_check_mode
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: 应用受管 FRR 配置片段
|
||||
ansible.builtin.command: vtysh -f /etc/frr/oci-wireguard.vtysh
|
||||
register: bgp_apply
|
||||
failed_when: bgp_apply.rc != 0 or '% Unknown' in bgp_apply.stdout or '% Unknown' in bgp_apply.stderr
|
||||
|
||||
- name: 保存完整运行配置以便重启恢复
|
||||
ansible.builtin.command: vtysh -c 'write memory'
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
- name: 安装 AMD DN42 loopback 地址启动单元
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/systemd/system/dn42-loopback.service
|
||||
mode: '0644'
|
||||
content: |
|
||||
[Unit]
|
||||
Description=DN42 router loopback addresses
|
||||
Before=frr.service
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/sbin/ip address replace 172.21.111.162/32 dev lo
|
||||
ExecStart=/usr/sbin/ip -6 address replace fdd0:98df:15b0::2/128 dev lo
|
||||
RemainAfterExit=yes
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
register: dn42_loopback_unit
|
||||
|
||||
- name: 启用 AMD DN42 loopback
|
||||
ansible.builtin.systemd_service:
|
||||
name: dn42-loopback
|
||||
daemon_reload: true
|
||||
enabled: true
|
||||
state: "{{ 'restarted' if dn42_loopback_unit.changed else 'started' }}"
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: 开启路由器 IPv6 转发
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv6.conf.all.forwarding
|
||||
value: '1'
|
||||
sysctl_file: /etc/sysctl.d/90-dn42-forwarding.conf
|
||||
sysctl_set: true
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
- name: 安装 WireGuard 与 FRR
|
||||
ansible.builtin.apt:
|
||||
name: [wireguard-tools, frr, iptables]
|
||||
state: present
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
register: packages
|
||||
retries: 3
|
||||
delay: 5
|
||||
until: packages is succeeded
|
||||
|
||||
- name: 创建 WireGuard 受限目录
|
||||
ansible.builtin.file:
|
||||
path: /etc/wireguard
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0700'
|
||||
|
||||
- name: 在站点本机生成私钥,永不复制到控制机
|
||||
ansible.builtin.shell: 'umask 077; wg genkey > /etc/wireguard/{{ wg_interface }}.key'
|
||||
args:
|
||||
creates: '/etc/wireguard/{{ wg_interface }}.key'
|
||||
no_log: true
|
||||
|
||||
- name: 检查现有私钥
|
||||
ansible.builtin.stat:
|
||||
path: '/etc/wireguard/{{ wg_interface }}.key'
|
||||
register: wg_key_file
|
||||
|
||||
- name: 读取可交换的公钥
|
||||
ansible.builtin.shell: 'wg pubkey < /etc/wireguard/{{ wg_interface }}.key'
|
||||
register: wg_public_key
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
when: wg_key_file.stat.exists
|
||||
|
||||
- name: 启用 BGP daemon,保留其他协议
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/frr/daemons
|
||||
regexp: '^bgpd='
|
||||
line: bgpd=yes
|
||||
notify: 重载 FRR daemons
|
||||
when: not ansible_check_mode or not packages.changed
|
||||
|
||||
- name: 确保 FRR 运行
|
||||
ansible.builtin.systemd_service:
|
||||
name: frr
|
||||
enabled: true
|
||||
state: started
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: 配置 DN42 路由器地址
|
||||
ansible.builtin.include_tasks: dn42-loopback.yml
|
||||
when: bgp_export6 is defined
|
||||
|
||||
- name: 开启 IPv4 转发
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: '1'
|
||||
sysctl_file: /etc/sysctl.d/90-oci-wireguard.conf
|
||||
sysctl_set: true
|
||||
|
||||
- name: 安装专用防火墙规则脚本
|
||||
ansible.builtin.template:
|
||||
src: firewall.sh.j2
|
||||
dest: /usr/local/sbin/oci-wg-firewall
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
notify: 刷新专用防火墙
|
||||
|
||||
- name: 安装防火墙启动单元
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/systemd/system/oci-wg-firewall.service
|
||||
mode: '0644'
|
||||
content: |
|
||||
[Unit]
|
||||
Description=OCI WireGuard scoped forwarding (no NAT)
|
||||
After=network-pre.target
|
||||
Before=wg-quick@{{ wg_interface }}.service
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/sbin/oci-wg-firewall
|
||||
RemainAfterExit=yes
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
notify: 刷新专用防火墙
|
||||
|
||||
- name: 启动防火墙规则
|
||||
ansible.builtin.systemd_service:
|
||||
name: oci-wg-firewall
|
||||
daemon_reload: true
|
||||
enabled: true
|
||||
state: started
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: 写入只含公钥的隧道配置
|
||||
ansible.builtin.template:
|
||||
src: wg.conf.j2
|
||||
dest: '/etc/wireguard/{{ wg_interface }}.conf'
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0600'
|
||||
when: wg_key_file.stat.exists and (hostvars[wg_peer_host].wg_key_file | default({"stat":{"exists":false}})).stat.exists
|
||||
notify: 重启 WireGuard
|
||||
|
||||
- name: 启动 WireGuard
|
||||
ansible.builtin.systemd_service:
|
||||
name: 'wg-quick@{{ wg_interface }}'
|
||||
enabled: true
|
||||
state: started
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: 写入受管 BGP 增量配置
|
||||
ansible.builtin.template:
|
||||
src: bgp.conf.j2
|
||||
dest: /etc/frr/oci-wireguard.vtysh
|
||||
owner: frr
|
||||
group: frr
|
||||
mode: '0640'
|
||||
notify: 应用 BGP 增量配置
|
||||
when: not ansible_check_mode or not packages.changed
|
||||
|
||||
- name: 先完成配置变更再验证
|
||||
ansible.builtin.meta: flush_handlers
|
||||
|
||||
- name: 检查 WireGuard 对端握手
|
||||
ansible.builtin.command: 'wg show {{ wg_interface }} latest-handshakes'
|
||||
changed_when: false
|
||||
register: wg_handshake
|
||||
retries: 12
|
||||
delay: 5
|
||||
until: wg_handshake.stdout.split() | length == 2 and (wg_handshake.stdout.split()[-1] | int) > 0
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: 验证隧道互通
|
||||
ansible.builtin.command: "{{ ('ping -6 -I ' ~ wg_interface ~ ' -c 3 -W 3 ' ~ bgp_transport_peer) if bgp_transport_peer is defined else ('ping -I ' ~ wg_interface ~ ' -c 3 -W 3 ' ~ wg_peer_address) }}"
|
||||
changed_when: false
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: 验证 BGP 建邻并收到预期前缀数量
|
||||
ansible.builtin.command: vtysh -c 'show bgp summary json'
|
||||
changed_when: false
|
||||
register: bgp_summary
|
||||
retries: 12
|
||||
delay: 5
|
||||
until: >-
|
||||
(bgp_summary.stdout | from_json).get('ipv4Unicast', {}).get('peers', {}).get(bgp_transport_peer | default(wg_peer_address), {}).get('state') == 'Established'
|
||||
and (bgp_summary.stdout | from_json).get('ipv4Unicast', {}).get('peers', {}).get(bgp_transport_peer | default(wg_peer_address), {}).get('pfxRcd', 0) == bgp_import | length
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: 验证 IPv6 iBGP 建邻与前缀
|
||||
ansible.builtin.command: vtysh -c 'show bgp summary json'
|
||||
changed_when: false
|
||||
register: bgp_summary6
|
||||
retries: 12
|
||||
delay: 5
|
||||
until: >-
|
||||
(bgp_summary6.stdout | from_json).get('ipv6Unicast', {}).get('peers', {}).get(bgp_transport_peer | default(wg_peer_ipv6), {}).get('state') == 'Established'
|
||||
and (bgp_summary6.stdout | from_json).get('ipv6Unicast', {}).get('peers', {}).get(bgp_transport_peer | default(wg_peer_ipv6), {}).get('pfxRcd', 0) == bgp_import6 | length
|
||||
when: not ansible_check_mode and bgp_import6 is defined
|
||||
@@ -0,0 +1,80 @@
|
||||
{% set v4_peer = bgp_transport_peer | default(wg_peer_address) %}
|
||||
{% set v6_peer = bgp_transport_peer | default(wg_peer_ipv6 | default("")) %}
|
||||
! vtysh -f 使用配置模式,write memory 由独立 handler 执行。
|
||||
! 只重建本角色拥有的邻居和过滤器,保留既有 BGP/OSPF。
|
||||
router bgp {{ bgp_asn }}
|
||||
no neighbor {{ v4_peer }}
|
||||
{% for peer in bgp_retired_peers | default([]) %}
|
||||
no neighbor {{ peer }}
|
||||
{% endfor %}
|
||||
exit
|
||||
no ip prefix-list OCI-WG-IN
|
||||
no ip prefix-list OCI-WG-OUT
|
||||
{% for prefix in bgp_import %}
|
||||
ip prefix-list OCI-WG-IN seq {{ loop.index * 10 }} permit {{ prefix }}
|
||||
{% endfor %}
|
||||
{% for prefix in bgp_export + (bgp_summary | default([])) %}
|
||||
ip prefix-list OCI-WG-OUT seq {{ loop.index * 10 }} permit {{ prefix }}
|
||||
{% endfor %}
|
||||
router bgp {{ bgp_asn }}
|
||||
bgp router-id {{ bgp_router_id }}
|
||||
neighbor {{ v4_peer }} remote-as {{ bgp_peer_asn }}
|
||||
neighbor {{ v4_peer }} description OCI-WireGuard
|
||||
neighbor {{ v4_peer }} update-source {{ wg_interface }}
|
||||
{% if bgp_transport_peer is defined %}
|
||||
neighbor {{ v4_peer }} interface {{ wg_interface }}
|
||||
neighbor {{ v4_peer }} capability extended-nexthop
|
||||
{% endif %}
|
||||
address-family ipv4 unicast
|
||||
{% for prefix in bgp_summary | default([]) %}
|
||||
aggregate-address {{ prefix }}
|
||||
{% endfor %}
|
||||
{% for prefix in bgp_export %}
|
||||
network {{ prefix }}
|
||||
{% endfor %}
|
||||
neighbor {{ v4_peer }} activate
|
||||
neighbor {{ v4_peer }} prefix-list OCI-WG-IN in
|
||||
neighbor {{ v4_peer }} prefix-list OCI-WG-OUT out
|
||||
neighbor {{ v4_peer }} maximum-prefix {{ bgp_import | length }}
|
||||
exit-address-family
|
||||
exit
|
||||
! 仅为这些 BGP 路由选择本机业务 IP;转发报文源地址保持不变,不是 NAT。
|
||||
route-map OCI-WG-SOURCE permit 10
|
||||
match ip address prefix-list OCI-WG-IN
|
||||
set src {{ bgp_router_id }}
|
||||
exit
|
||||
route-map OCI-WG-SOURCE permit 100
|
||||
exit
|
||||
ip protocol bgp route-map OCI-WG-SOURCE
|
||||
|
||||
{% if bgp_export6 is defined %}
|
||||
no ipv6 prefix-list OCI-WG6-IN
|
||||
no ipv6 prefix-list OCI-WG6-OUT
|
||||
{% for prefix in bgp_import6 %}
|
||||
ipv6 prefix-list OCI-WG6-IN seq {{ loop.index * 10 }} permit {{ prefix }}
|
||||
{% endfor %}
|
||||
{% for prefix in bgp_export6 + (bgp_summary6 | default([])) %}
|
||||
ipv6 prefix-list OCI-WG6-OUT seq {{ loop.index * 10 }} permit {{ prefix }}
|
||||
{% endfor %}
|
||||
router bgp {{ bgp_asn }}
|
||||
neighbor {{ v6_peer }} remote-as {{ bgp_peer_asn }}
|
||||
neighbor {{ v6_peer }} update-source {{ wg_interface }}
|
||||
{% if bgp_transport_peer is not defined %}
|
||||
address-family ipv4 unicast
|
||||
no neighbor {{ v6_peer }} activate
|
||||
exit-address-family
|
||||
{% endif %}
|
||||
address-family ipv6 unicast
|
||||
{% for prefix in bgp_summary6 | default([]) %}
|
||||
aggregate-address {{ prefix }}
|
||||
{% endfor %}
|
||||
{% for prefix in bgp_export6 %}
|
||||
network {{ prefix }}
|
||||
{% endfor %}
|
||||
neighbor {{ v6_peer }} activate
|
||||
neighbor {{ v6_peer }} prefix-list OCI-WG6-IN in
|
||||
neighbor {{ v6_peer }} prefix-list OCI-WG6-OUT out
|
||||
neighbor {{ v6_peer }} maximum-prefix {{ bgp_import6 | length }}
|
||||
exit-address-family
|
||||
exit
|
||||
{% endif %}
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
# 仅重建专用链,不保存/覆盖 Docker、k3s、Tailscale 或 OCI 的其他动态规则。
|
||||
for chain in OCI-WG-IN OCI-WG-FWD; do
|
||||
iptables -w -nL "$chain" >/dev/null 2>&1 || iptables -w -N "$chain"
|
||||
iptables -w -F "$chain"
|
||||
done
|
||||
iptables -w -A OCI-WG-IN -p udp --dport {{ wg_port }} -j ACCEPT
|
||||
{% for prefix in [wg_peer_address ~ '/32'] + bgp_import %}
|
||||
iptables -w -A OCI-WG-IN -i {{ wg_interface }} -s {{ prefix }} -j ACCEPT
|
||||
{% endfor %}
|
||||
{% for local_prefix in bgp_export %}
|
||||
{% for remote_prefix in bgp_import %}
|
||||
iptables -w -A OCI-WG-FWD -i {{ wg_interface }} -o {{ wg_lan_interface }} -s {{ remote_prefix }} -d {{ local_prefix }} -j ACCEPT
|
||||
iptables -w -A OCI-WG-FWD -i {{ wg_lan_interface }} -o {{ wg_interface }} -s {{ local_prefix }} -d {{ remote_prefix }} -j ACCEPT
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% if dn42_external_interface is defined %}
|
||||
# 仅允许注册地址在内部隧道与外部 DN42 之间转发,保持无 NAT。
|
||||
iptables -w -A OCI-WG-FWD -i {{ wg_interface }} -o {{ dn42_external_interface }} -s {{ dn42_ipv4 }} -d 172.20.0.0/14 -j ACCEPT
|
||||
iptables -w -A OCI-WG-FWD -i {{ dn42_external_interface }} -o {{ wg_interface }} -s 172.20.0.0/14 -d {{ dn42_ipv4 }} -j ACCEPT
|
||||
{% endif %}
|
||||
iptables -w -A OCI-WG-FWD -i {{ wg_interface }} -j DROP
|
||||
iptables -w -A OCI-WG-FWD -o {{ wg_interface }} -j DROP
|
||||
iptables -w -C INPUT -j OCI-WG-IN 2>/dev/null || iptables -w -I INPUT 1 -j OCI-WG-IN
|
||||
iptables -w -C FORWARD -j OCI-WG-FWD 2>/dev/null || iptables -w -I FORWARD 1 -j OCI-WG-FWD
|
||||
|
||||
{% if bgp_import6 is defined %}
|
||||
ip6tables -w -nL OCI-WG6-IN >/dev/null 2>&1 || ip6tables -w -N OCI-WG6-IN
|
||||
ip6tables -w -F OCI-WG6-IN
|
||||
ip6tables -w -A OCI-WG6-IN -i {{ wg_interface }} -s {{ dn42_ipv6 }} -j ACCEPT
|
||||
ip6tables -w -C INPUT -j OCI-WG6-IN 2>/dev/null || ip6tables -w -I INPUT 1 -j OCI-WG6-IN
|
||||
{% endif %}
|
||||
|
||||
{% if dn42_external_interface is defined %}
|
||||
ip6tables -w -nL OCI-DN42-FWD >/dev/null 2>&1 || ip6tables -w -N OCI-DN42-FWD
|
||||
ip6tables -w -F OCI-DN42-FWD
|
||||
ip6tables -w -A OCI-DN42-FWD -i {{ wg_interface }} -o {{ dn42_external_interface }} -s {{ dn42_ipv6 }} -d fd00::/8 -j ACCEPT
|
||||
ip6tables -w -A OCI-DN42-FWD -i {{ dn42_external_interface }} -o {{ wg_interface }} -s fd00::/8 -d {{ dn42_ipv6 }} -j ACCEPT
|
||||
ip6tables -w -A OCI-DN42-FWD -i {{ dn42_external_interface }} -j DROP
|
||||
ip6tables -w -A OCI-DN42-FWD -o {{ dn42_external_interface }} -j DROP
|
||||
ip6tables -w -C FORWARD -j OCI-DN42-FWD 2>/dev/null || ip6tables -w -I FORWARD 1 -j OCI-DN42-FWD
|
||||
{% endif %}
|
||||
@@ -0,0 +1,16 @@
|
||||
[Interface]
|
||||
Address = {{ wg_address }}{% if wg_ipv6_address is defined %}, {{ wg_ipv6_address }}, {{ wg_linklocal_address }}{% endif %}
|
||||
|
||||
ListenPort = {{ wg_port }}
|
||||
MTU = {{ wg_mtu }}
|
||||
Table = off
|
||||
# 私钥在本机生成和读取;配置模板与控制机不保存私钥。
|
||||
PostUp = wg set %i private-key /etc/wireguard/{{ wg_interface }}.key
|
||||
|
||||
[Peer]
|
||||
PublicKey = {{ hostvars[wg_peer_host].wg_public_key.stdout }}
|
||||
AllowedIPs = {{ ([wg_peer_address ~ '/32'] + bgp_import + (bgp_import6 | default([])) + (['fe80::/64'] if bgp_import6 is defined else [])) | join(', ') }}
|
||||
{% if wg_endpoint %}
|
||||
Endpoint = {{ wg_endpoint }}
|
||||
{% endif %}
|
||||
PersistentKeepalive = {{ wg_keepalive }}
|
||||
Reference in New Issue
Block a user