aboutsummaryrefslogtreecommitdiff
path: root/roles
diff options
context:
space:
mode:
authorMaximilian Stinsky <maximilian.stinsky-damke@wiit.cloud>2024-07-19 12:35:19 +0200
committerPiotr Milewski <vurmil@gmail.com>2026-04-17 09:07:00 +0000
commit4f5dda873762438b3ba296da289dae5f3312c9da (patch)
treee5dc0742dcb8c48c3125e00c601c9ffb20a28a5d /roles
parent88aecb6009d2ef6e543849cd9930d1bd80cfca2f (diff)
downloadkolla-ansible-4f5dda873762438b3ba296da289dae5f3312c9da.tar.gz
kolla-ansible-4f5dda873762438b3ba296da289dae5f3312c9da.zip
Implement neutron-ovn-vpn-agent
This patch implements vpnaas for OVN environments. It deploys a standalone neutron-ovn-vpn-agent on neutron nodes. The container no longer requires 'privileged: true'. Running as the 'neutron' user with specific kernel capabilities ensures the agent can manage network namespaces and interfaces without full privileges. Added capabilities: - NET_ADMIN # manage interfaces, IPs, routing, firewall - SYS_ADMIN # create/manage network namespaces - SYS_PTRACE # allow 'ip netns exec' attach to processes - DAC_OVERRIDE # bypass file read/write restrictions - DAC_READ_SEARCH # allow directory traversal and file read - SETPCAP # retain capabilities for privileged ops Added security options: - apparmor=unconfined # disable AppArmor confinement - seccomp=unconfined # disable seccomp filtering - label=disable # disable SELinux/labeling Depends-On: https://review.opendev.org/c/openstack/kolla/+/924302 Closes-Bug: #2048392 Change-Id: I961b1407ae1402d146f0c09924df8e007e331af5 Signed-off-by: Joachim de Groot <joachim.de.groot@menzel-it.net> Signed-off-by: Piotr Milewski <vurmil@gmail.com>
Diffstat (limited to 'roles')
-rw-r--r--roles/openstack-clients/defaults/main.yml2
-rw-r--r--roles/test-ovn-vpnaas/defaults/main.yml14
-rw-r--r--roles/test-ovn-vpnaas/tasks/cleanup_site.yml46
-rw-r--r--roles/test-ovn-vpnaas/tasks/init_env.yml33
-rw-r--r--roles/test-ovn-vpnaas/tasks/main.yml211
-rw-r--r--roles/test-ovn-vpnaas/tasks/setup_site.yml76
6 files changed, 382 insertions, 0 deletions
diff --git a/roles/openstack-clients/defaults/main.yml b/roles/openstack-clients/defaults/main.yml
index 6b1e3c6d9..e1f53e279 100644
--- a/roles/openstack-clients/defaults/main.yml
+++ b/roles/openstack-clients/defaults/main.yml
@@ -14,6 +14,8 @@ openstack_clients_pip_packages:
enabled: "{{ scenario == 'ironic' }}"
- package: python-magnumclient
enabled: "{{ scenario == 'magnum' }}"
+ - package: python-neutronclient
+ enabled: "{{ scenario == 'ovn' }}"
- package: python-masakariclient
enabled: "{{ scenario == 'masakari' }}"
- package: python-mistralclient
diff --git a/roles/test-ovn-vpnaas/defaults/main.yml b/roles/test-ovn-vpnaas/defaults/main.yml
new file mode 100644
index 000000000..e55c4d338
--- /dev/null
+++ b/roles/test-ovn-vpnaas/defaults/main.yml
@@ -0,0 +1,14 @@
+---
+ovn_vpnaas_openrc: "/etc/kolla/admin-openrc.sh"
+ovn_vpnaas_venv: "{{ ansible_env.HOME }}/openstackclient-venv"
+
+ovn_vpnaas_activate: ". {{ ovn_vpnaas_venv }}/bin/activate &&"
+
+ovn_vpnaas_west_cidr: "192.168.10.0/24"
+ovn_vpnaas_east_cidr: "192.168.20.0/24"
+ovn_vpnaas_psk: "secret"
+
+ovn_vpnaas_consistency_retries: 10
+ovn_vpnaas_consistency_delay: 5
+ovn_vpnaas_tunnel_retries: 20
+ovn_vpnaas_tunnel_delay: 15
diff --git a/roles/test-ovn-vpnaas/tasks/cleanup_site.yml b/roles/test-ovn-vpnaas/tasks/cleanup_site.yml
new file mode 100644
index 000000000..403e3020d
--- /dev/null
+++ b/roles/test-ovn-vpnaas/tasks/cleanup_site.yml
@@ -0,0 +1,46 @@
+---
+- name: "VPNaaS | Cleanup | Site: {{ site_to_clean }}"
+ block:
+ - name: "VPNaaS | Cleanup | Delete Connection"
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn ipsec site connection delete "conn_{{ site_to_clean }}" || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+ - name: "VPNaaS | Cleanup | Delete VPN Service"
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn service delete "vpn_{{ site_to_clean }}" || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+ - name: "VPNaaS | Cleanup | Delete Endpoint Groups"
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn endpoint group delete "{{ site_to_clean }}-local-epg" || true
+ openstack vpn endpoint group delete "{{ site_to_clean }}-peer-epg" || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+ - name: "VPNaaS | Cleanup | Remove Subnet from Router"
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack router remove subnet "router_{{ site_to_clean }}" "subnet_{{ site_to_clean }}" || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+ - name: "VPNaaS | Cleanup | Delete Router"
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack router delete "router_{{ site_to_clean }}" || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+ - name: "VPNaaS | Cleanup | Delete Network/Subnet"
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack subnet delete "subnet_{{ site_to_clean }}" || true
+ openstack network delete "net_{{ site_to_clean }}" || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
diff --git a/roles/test-ovn-vpnaas/tasks/init_env.yml b/roles/test-ovn-vpnaas/tasks/init_env.yml
new file mode 100644
index 000000000..d448c95fc
--- /dev/null
+++ b/roles/test-ovn-vpnaas/tasks/init_env.yml
@@ -0,0 +1,33 @@
+---
+- name: VPNaaS | Install requirements in venv
+ ansible.builtin.pip:
+ name:
+ - "python-neutronclient"
+ - "openstacksdk"
+ virtualenv: "{{ ovn_vpnaas_venv }}"
+ state: present
+
+- name: VPNaaS | Load OpenStack credentials from openrc
+ ansible.builtin.shell: |
+ set -o pipefail
+ . {{ ovn_vpnaas_openrc }}
+ env | grep ^OS_
+ args:
+ executable: /bin/bash
+ register: openrc_env
+ changed_when: false
+
+- name: VPNaaS | Convert OS_* env to dict
+ ansible.builtin.set_fact:
+ os_auth_env: >-
+ {{
+ dict(
+ openrc_env.stdout_lines
+ | map('split', '=', 1)
+ | list
+ )
+ }}
+
+- name: VPNaaS | Add venv to PATH
+ ansible.builtin.set_fact:
+ os_auth_env: "{{ os_auth_env | combine({'PATH': ovn_vpnaas_venv + '/bin:' + ansible_facts['env']['PATH']}) }}"
diff --git a/roles/test-ovn-vpnaas/tasks/main.yml b/roles/test-ovn-vpnaas/tasks/main.yml
new file mode 100644
index 000000000..ee5a718e0
--- /dev/null
+++ b/roles/test-ovn-vpnaas/tasks/main.yml
@@ -0,0 +1,211 @@
+---
+- name: VPNaaS | Init ENV
+ ansible.builtin.include_tasks: init_env.yml
+
+- name: VPNaaS | Check if VPN agents are alive and reporting
+ ansible.builtin.shell: |
+ set -o pipefail
+ {{ ovn_vpnaas_activate }}
+ openstack network agent list -f value -c Binary -c Alive | grep "vpn-agent" | awk '{print $2}'
+ args:
+ executable: /bin/bash
+ register: vpn_agents_alive
+ until:
+ - vpn_agents_alive.stdout != ""
+ - "'False' not in vpn_agents_alive.stdout"
+ retries: 10
+ delay: 5
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | Create IKE and IPsec Policies
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn ike policy create ikepolicy --ike-version v2 --auth-algorithm sha256 --encryption-algorithm aes-256 --pfs group14 || true
+ openstack vpn ipsec policy create ipsecpolicy --auth-algorithm sha256 --encryption-algorithm aes-256 --pfs group14 || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | Setup Network Infrastructure
+ ansible.builtin.include_tasks: setup_site.yml
+ vars:
+ site_name: "{{ item.name }}"
+ site_cidr: "{{ item.cidr }}"
+ peer_cidr: "{{ item.peer }}"
+ loop:
+ - { name: 'west', cidr: "{{ ovn_vpnaas_west_cidr }}", peer: "{{ ovn_vpnaas_east_cidr }}" }
+ - { name: 'east', cidr: "{{ ovn_vpnaas_east_cidr }}", peer: "{{ ovn_vpnaas_west_cidr }}" }
+
+- name: VPNaaS | Wait for OVN Agent to settle
+ ansible.builtin.pause:
+ minutes: 2
+
+- name: VPNaaS | Check if VPN service west exists
+ ansible.builtin.shell: |
+ set -o pipefail
+ {{ ovn_vpnaas_activate }}
+ openstack vpn service list -f value -c ID -c Name | awk '$2=="vpn_west" {print $1}' | head -n 1
+ args:
+ executable: /bin/bash
+ environment: "{{ os_auth_env }}"
+ register: check_vpn_west
+ changed_when: false
+
+- name: VPNaaS | Create VPN service | west
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn service create --router "router_west" "vpn_west"
+ environment: "{{ os_auth_env }}"
+ when: check_vpn_west.stdout | trim == ""
+ failed_when: false
+ changed_when: false
+
+- name: VPNaaS | Settle database consistency before next service
+ ansible.builtin.pause:
+ seconds: 20
+
+- name: VPNaaS | Ensure VPN service west exists and get ID
+ ansible.builtin.shell: |
+ set -o pipefail
+ {{ ovn_vpnaas_activate }}
+ openstack vpn service list -f value -c ID -c Name | awk '$2=="vpn_west" {print $1}' | head -n 1
+ args:
+ executable: /bin/bash
+ register: vpn_svc_west_out
+ until:
+ - vpn_svc_west_out.rc == 0
+ - vpn_svc_west_out.stdout | trim != ""
+ retries: 20
+ delay: 10
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | Check if VPN service east exists
+ ansible.builtin.shell: |
+ set -o pipefail
+ {{ ovn_vpnaas_activate }}
+ openstack vpn service list -f value -c ID -c Name | awk '$2=="vpn_east" {print $1}' | head -n 1
+ args:
+ executable: /bin/bash
+ environment: "{{ os_auth_env }}"
+ register: check_vpn_east
+ changed_when: false
+
+- name: VPNaaS | Create VPN service | east
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn service create --router "router_east" "vpn_east"
+ environment: "{{ os_auth_env }}"
+ when: check_vpn_east.stdout | trim == ""
+ failed_when: false
+ changed_when: false
+
+- name: VPNaaS | Settle database consistency before next service
+ ansible.builtin.pause:
+ seconds: 20
+
+- name: VPNaaS | Ensure VPN service east exists in DB
+ ansible.builtin.shell: |
+ set -o pipefail
+ {{ ovn_vpnaas_activate }}
+ openstack vpn service list -f value -c ID -c Name | awk '$2=="vpn_east" {print $1}' | head -n 1
+ args:
+ executable: /bin/bash
+ register: vpn_svc_east_out
+ until:
+ - vpn_svc_east_out.rc == 0
+ - vpn_svc_east_out.stdout | trim != ""
+ retries: 20
+ delay: 10
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | Create Endpoint Groups
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn endpoint group create --type subnet --value "subnet_{{ item.name }}" "{{ item.name }}-local-epg" || true
+ openstack vpn endpoint group create --type cidr --value "{{ item.peer }}" "{{ item.name }}-peer-epg" || true
+ loop:
+ - { name: 'west', peer: "{{ ovn_vpnaas_east_cidr }}" }
+ - { name: 'east', peer: "{{ ovn_vpnaas_west_cidr }}" }
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | Get Public IPs
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn service show "{{ item }}" -f value -c ext_v4_ip
+ register: vpn_ips
+ until:
+ - vpn_ips.stdout | trim != ""
+ - vpn_ips.stdout | trim != "None"
+ retries: 24
+ delay: 10
+ loop:
+ - "{{ vpn_svc_west_out.stdout.strip() }}"
+ - "{{ vpn_svc_east_out.stdout.strip() }}"
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | Establish Connections
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn ipsec site connection create "conn_east" --vpnservice "{{ vpn_svc_east_out.stdout.strip() }}" --ikepolicy ikepolicy \
+ --ipsecpolicy ipsecpolicy --local-endpoint-group east-local-epg --peer-address "{{ vpn_ips.results[0].stdout.strip() }}" \
+ --peer-id "{{ vpn_ips.results[0].stdout.strip() }}" --peer-endpoint-group east-peer-epg --psk {{ ovn_vpnaas_psk }} || true
+
+ openstack vpn ipsec site connection create "conn_west" --vpnservice "{{ vpn_svc_west_out.stdout.strip() }}" --ikepolicy ikepolicy \
+ --ipsecpolicy ipsecpolicy --local-endpoint-group west-local-epg --peer-address "{{ vpn_ips.results[1].stdout.strip() }}" \
+ --peer-id "{{ vpn_ips.results[1].stdout.strip() }}" --peer-endpoint-group west-peer-epg --psk {{ ovn_vpnaas_psk }} || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | Wait for Tunnel to be ACTIVE
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn ipsec site connection show "conn_{{ item }}" -f value -c status
+ register: tunnel_status
+ until: tunnel_status.stdout == "ACTIVE"
+ retries: "{{ ovn_vpnaas_tunnel_retries }}"
+ delay: "{{ ovn_vpnaas_tunnel_delay }}"
+ loop: ["west", "east"]
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | SHOW TUNNEL STATUS RESULT
+ ansible.builtin.debug:
+ msg:
+ - "************************************************************"
+ - "CONNECTION: conn_{{ item.item }}"
+ - "STATUS: {{ item.stdout }}"
+ - "RESULT: TUNNEL ESTABLISHED SUCCESSFULLY!"
+ - "************************************************************"
+ loop: "{{ tunnel_status.results }}"
+ loop_control:
+ label: "{{ item.item }}"
+
+- name: VPNaaS | Show Full Connection Details
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn ipsec site connection list
+ environment: "{{ os_auth_env }}"
+ register: final_list
+ changed_when: false
+
+- name: VPNaaS | Print Connection List Table
+ ansible.builtin.debug:
+ var: final_list.stdout_lines
+
+- name: VPNaaS | Final Cleanup
+ ansible.builtin.include_tasks: cleanup_site.yml
+ loop: ["west", "east"]
+ loop_control:
+ loop_var: site_to_clean
+
+- name: VPNaaS | Cleanup | Global Policies
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack vpn ipsec policy delete ipsecpolicy || true
+ openstack vpn ike policy delete ikepolicy || true
+ environment: "{{ os_auth_env }}"
+ changed_when: false
diff --git a/roles/test-ovn-vpnaas/tasks/setup_site.yml b/roles/test-ovn-vpnaas/tasks/setup_site.yml
new file mode 100644
index 000000000..f683dc596
--- /dev/null
+++ b/roles/test-ovn-vpnaas/tasks/setup_site.yml
@@ -0,0 +1,76 @@
+---
+- name: VPNaaS | Create network | {{ site_name }}
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack network create "net_{{ site_name }}"
+ environment: "{{ os_auth_env }}"
+ register: net_create
+ failed_when:
+ - net_create.rc != 0
+ - "'already exists' not in net_create.stderr"
+ retries: "{{ ovn_vpnaas_consistency_retries }}"
+ delay: "{{ ovn_vpnaas_consistency_delay }}"
+ until: net_create.rc == 0 or 'already exists' in net_create.stderr
+ changed_when: false
+
+- name: VPNaaS | Create subnet | {{ site_name }}
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack subnet create --network "net_{{ site_name }}" --subnet-range "{{ site_cidr }}" "subnet_{{ site_name }}"
+ environment: "{{ os_auth_env }}"
+ register: subnet_create
+ failed_when:
+ - subnet_create.rc != 0
+ - "'already exists' not in subnet_create.stderr"
+ retries: "{{ ovn_vpnaas_consistency_retries }}"
+ delay: "{{ ovn_vpnaas_consistency_delay }}"
+ until: subnet_create.rc == 0 or 'already exists' in subnet_create.stderr
+ changed_when: false
+
+- name: VPNaaS | Create router | {{ site_name }}
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack router create --external-gateway public1 "router_{{ site_name }}"
+ environment: "{{ os_auth_env }}"
+ failed_when: false
+ changed_when: false
+
+- name: VPNaaS | Debug | List all routers
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack router list
+ environment: "{{ os_auth_env }}"
+ register: all_routers_debug
+ changed_when: false
+
+- name: VPNaaS | Debug | Show router list output
+ ansible.builtin.debug:
+ var: all_routers_debug.stdout_lines
+
+- name: VPNaaS | Get router ID | {{ site_name }}
+ ansible.builtin.shell: |
+ set -o pipefail
+ {{ ovn_vpnaas_activate }}
+ openstack router list --name "router_{{ site_name }}" -f value -c ID | head -n 1
+ args:
+ executable: /bin/bash
+ register: current_router_id
+ until: current_router_id.stdout != ""
+ retries: 5
+ delay: 10
+ environment: "{{ os_auth_env }}"
+ changed_when: false
+
+- name: VPNaaS | Attach subnet to router | {{ site_name }}
+ ansible.builtin.shell: |
+ {{ ovn_vpnaas_activate }}
+ openstack router add subnet "{{ current_router_id.stdout.strip() }}" "subnet_{{ site_name }}"
+ environment: "{{ os_auth_env }}"
+ register: router_add_result
+ failed_when:
+ - router_add_result.rc != 0
+ - "'already has an interface' not in router_add_result.stderr"
+ retries: "{{ ovn_vpnaas_consistency_retries }}"
+ delay: "{{ ovn_vpnaas_consistency_delay }}"
+ until: router_add_result.rc == 0 or 'already has an interface' in router_add_result.stderr
+ changed_when: false