diff --git a/defaults/main.yml b/defaults/main.yml index e754e055..364441b8 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -477,14 +477,87 @@ calico_felix_sha256: 076936b985379fb8221db9b9a798714f6f97429a630da9c46da89bfcb0f calico_felix_validate_certs: yes # OVN Defaults +neutron_ovn_ssl: True +ovn_proto: "{{ (neutron_ovn_ssl) | ternary('ssl','tcp') }}" neutron_ovn_primary_cluster_node: "{{ groups[neutron_services['neutron-ovn-northd']['group']] | first }}" neutron_ovn_northd_service_name: ovn-northd neutron_ovn_controller_service_name: ovn-controller neutron_ovn_l3_scheduler: leastloaded -neutron_ovn_nb_connection: "tcp:{{ groups['neutron_ovn_northd'] | map('extract', hostvars, ['ansible_host']) | join(':6641,tcp:') }}:6641" -neutron_ovn_sb_connection: "tcp:{{ groups['neutron_ovn_northd'] | map('extract', hostvars, ['ansible_host']) | join(':6642,tcp:') }}:6642" +neutron_ovn_nb_connection: "{{ ovn_proto }}:{{ groups['neutron_ovn_northd'] | map('extract', hostvars, ['ansible_host']) | join(':6641,'+ ovn_proto + ':') }}:6641" +neutron_ovn_sb_connection: "{{ ovn_proto }}:{{ groups['neutron_ovn_northd'] | map('extract', hostvars, ['ansible_host']) | join(':6642,' + ovn_proto + ':') }}:6642" neutron_ovsdb_manager: ptcp:6640:127.0.0.1 +# Storage location for SSL certificate authority +neutron_ovn_pki_dir: "{{ openstack_pki_dir }}" +# Delegated host for operating the certificate authority +neutron_ovn_pki_setup_host: "{{ openstack_pki_setup_host | default('localhost') }}" +# The local address used for the neutron_ovn node +neutron_ovn_node_address: "{{ management_address | default('127.0.0.1') }}" +# neutron OVN server certificate +neutron_ovn_pki_keys_path: "{{ neutron_ovn_pki_dir ~ '/certs/private/' }}" +neutron_ovn_pki_certs_path: "{{ neutron_ovn_pki_dir ~ '/certs/certs/' }}" +neutron_ovn_pki_intermediate_cert_name: "{{ openstack_pki_service_intermediate_cert_name }}" +neutron_ovn_pki_intermediate_chain_path: "{{ neutron_ovn_pki_dir ~ '/roots/' ~ neutron_ovn_pki_intermediate_cert_name ~ '/certs/' ~ neutron_ovn_pki_intermediate_cert_name ~ '-chain.crt' }}" +neutron_ovn_pki_regen_cert: "" +neutron_ovn_pki_certificates: + - name: "neutron_ovn_{{ ansible_facts['hostname'] }}" + provider: ownca + cn: "{{ ansible_facts['hostname'] }}" + san: "{{ 'DNS:' ~ ansible_facts['hostname'] ~ ',IP:' ~ neutron_ovn_node_address }}" + signed_by: "{{ neutron_ovn_pki_intermediate_cert_name }}" + +# OVN destination files for SSL certificates +neutron_ovn_ssl_cert: "neutron_ovn.pem" +neutron_ovn_ssl_key: "neutron_ovn.key" +neutron_ovn_ssl_ca_cert: "neutron_ovn-ca.pem" +neutron_ovn_conf_dir: "/etc/openvswitch" +# Installation details for SSL certificates +neutron_ovn_pki_install_certificates: + - src: "{{ neutron_ovn_user_ssl_cert | default(neutron_ovn_pki_certs_path ~ 'neutron_ovn_' ~ ansible_facts['hostname'] ~ '-chain.crt') }}" + + dest: "{{ [neutron_ovn_conf_dir, neutron_ovn_ssl_cert] | join('/') }}" + owner: "{{ neutron_ovn_system_user_name }}" + group: "{{ neutron_ovn_system_user_name }}" + mode: "0644" + condition: "{{ (neutron_ovn_ssl and neutron_needs_openvswitch and neutron_plugin_type == 'ml2.ovn') }}" + - src: "{{ neutron_ovn_user_ssl_key | default(neutron_ovn_pki_keys_path ~ 'neutron_ovn_' ~ ansible_facts['hostname'] ~ '.key.pem') }}" + dest: "{{ [neutron_ovn_conf_dir, neutron_ovn_ssl_key] | join('/') }}" + owner: "{{ neutron_ovn_system_user_name }}" + group: "{{ neutron_ovn_system_user_name }}" + mode: "0600" + condition: "{{ (neutron_ovn_ssl and neutron_needs_openvswitch) }}" + - src: "{{ neutron_ovn_user_ssl_ca_cert | default(neutron_ovn_pki_intermediate_chain_path) }}" + dest: "{{ [neutron_ovn_conf_dir, neutron_ovn_ssl_ca_cert] | join('/') }}" + owner: "{{ (neutron_services['neutron-server']['group'] in group_names) | ternary( neutron_service_user_name, neutron_ovn_system_user_name) }}" + group: "{{ (neutron_services['neutron-server']['group'] in group_names) | ternary( neutron_service_user_name, neutron_ovn_system_user_name) }}" + mode: "0644" + condition: "{{ (neutron_ovn_ssl and neutron_needs_openvswitch and neutron_plugin_type == 'ml2.ovn') }}" + - src: "{{ neutron_ovn_user_ssl_cert | default(neutron_ovn_pki_certs_path ~ 'neutron_ovn_' ~ ansible_facts['hostname'] ~ '-chain.crt') }}" + dest: "{{ [neutron_conf_version_dir, neutron_ovn_ssl_cert] | join('/') }}" + owner: "{{ neutron_service_user_name }}" + group: "{{ neutron_service_user_name }}" + mode: "0644" + condition: "{{ (neutron_ovn_ssl and neutron_plugin_type == 'ml2.ovn' and (filtered_neutron_services |length + uwsgi_neutron_services | length ) > 0) }}" + - src: "{{ neutron_ovn_user_ssl_key | default(neutron_ovn_pki_keys_path ~ 'neutron_ovn_' ~ ansible_facts['hostname'] ~ '.key.pem') }}" + dest: "{{ [neutron_conf_version_dir, neutron_ovn_ssl_key] | join('/') }}" + owner: "{{ neutron_service_user_name }}" + group: "{{ neutron_service_user_name }}" + mode: "0600" + condition: "{{ (neutron_ovn_ssl and neutron_plugin_type == 'ml2.ovn' and (filtered_neutron_services |length + uwsgi_neutron_services | length ) > 0) }}" + - src: "{{ neutron_ovn_user_ssl_ca_cert | default(neutron_ovn_pki_intermediate_chain_path) }}" + dest: "{{ [neutron_conf_version_dir, neutron_ovn_ssl_ca_cert] | join('/') }}" + owner: "{{ neutron_service_user_name }}" + group: "{{ neutron_service_user_name }}" + mode: "0644" + condition: "{{ (neutron_ovn_ssl and neutron_plugin_type == 'ml2.ovn' and (filtered_neutron_services |length + uwsgi_neutron_services | length ) > 0) }}" + +# Define user-provided SSL certificates in: +# /etc/openstack_deploy/user_variables.yml +#neutron_ovnnb_user_ssl_cert: +#neutron_ovnnb_user_ssl_key: +#neutron_ovnsb_user_ssl_cert: +#neutron_ovnsb_user_ssl_key: + ### ### DPDK Configuration ### diff --git a/releasenotes/notes/ovn-ssl-e9cb73e0713cf8bc.yaml b/releasenotes/notes/ovn-ssl-e9cb73e0713cf8bc.yaml new file mode 100644 index 00000000..ba4e3641 --- /dev/null +++ b/releasenotes/notes/ovn-ssl-e9cb73e0713cf8bc.yaml @@ -0,0 +1,11 @@ +--- +features: + - | + OVN is now protected via SSL. you can disable it via `neutron_ovn_ssl`. It + is not supported to switch from non-ssl to ssl. +upgrade: + - | + OVN is now configured with SSL enabled by default, upgrading existing ovn + deployment is not tested. When upgrading it might be wise to set `neutron_ovn_ssl` + to `false` and manage the ssl configuration at a later stage. + diff --git a/tasks/main.yml b/tasks/main.yml index 1ba18186..fe7f82de 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -123,6 +123,25 @@ tags: - neutron-config +# create the ssl certs before the installation of the services. +- name: Create and install SSL certificates + include_role: + name: pki + tasks_from: main_certs.yml + vars: + pki_setup_host: "{{ neutron_ovn_pki_setup_host }}" + pki_dir: "{{ neutron_ovn_pki_dir }}" + pki_create_certificates: "{{ neutron_ovn_user_ssl_cert is not defined and neutron_ovn_user_ssl_key is not defined }}" + pki_regen_cert: "{{ neutron_ovn_pki_regen_cert }}" + pki_certificates: "{{ neutron_ovn_pki_certificates }}" + pki_install_certificates: "{{ neutron_ovn_pki_install_certificates }}" + when: + - neutron_ovn_ssl + - (neutron_services['neutron-ovn-controller']['group'] in group_names) or (neutron_services['neutron-ovn-northd']['group'] in group_names) or (neutron_services['neutron-server']['group'] in group_names) + tags: + - neutron_ovn-config + - pki + # Include provider specific config(s) - include_tasks: "{{ item }}" with_first_found: diff --git a/tasks/neutron_pre_install.yml b/tasks/neutron_pre_install.yml index 6065b326..f9da30a4 100644 --- a/tasks/neutron_pre_install.yml +++ b/tasks/neutron_pre_install.yml @@ -72,6 +72,7 @@ - path: "{{ neutron_system_home_folder }}" mode: "0755" - path: "{{ neutron_system_home_folder }}/ha_confs" + state: "{{ (neutron_plugin_type == 'ml2.ovn') | ternary('absent','directory') }}" - name: Add dependency repos for Neutron package: diff --git a/tasks/providers/ovn_cluster_setup.yml b/tasks/providers/ovn_cluster_setup.yml index 61c9d012..c94486b4 100644 --- a/tasks/providers/ovn_cluster_setup.yml +++ b/tasks/providers/ovn_cluster_setup.yml @@ -45,8 +45,10 @@ args: executable: /bin/bash ignore_errors: true - delegate_to: "{{ item }}" + delegate_to: "{{ container }}" with_items: "{{ groups['neutron_ovn_northd'] }}" + loop_control: + loop_var: container run_once: true failed_when: false register: _find_leader @@ -56,7 +58,7 @@ # set leader_node variable - name: Set leader_node fact set_fact: - leader_node: "{{ (_find_leader.results | selectattr('stdout', 'search', 'leader')) | map(attribute='item') | list }}" + leader_node: "{{ (_find_leader.results | selectattr('stdout', 'search', 'leader')) | map(attribute='container') | list }}" # This play only run first time to build cluster using primary node. - name: Setup ovn cluster using primary node. @@ -67,9 +69,33 @@ - "inventory_hostname == neutron_ovn_primary_cluster_node" - _check_cluster_db.rc != 0 - not leader_node - notify: - - start ovn service - - restart ovn service + register: ovn_northd_opts + +- name: Start ovn service + service: + name: "{{ neutron_ovn_northd_service_name }}" + state: started + when: + - "inventory_hostname == neutron_ovn_primary_cluster_node" + - _check_cluster_db.rc != 0 + - not leader_node + - ovn_northd_opts.changed + +- name: set ssl for ovn-nb and ovn-sb + command: "{{ cmd }}" + with_items: + - "ovn-nbctl set-connection pssl:6641" + - "ovn-sbctl set-connection pssl:6642" + when: + - neutron_ovn_ssl + - "inventory_hostname == neutron_ovn_primary_cluster_node" + - _check_cluster_db.rc != 0 + - not leader_node + - ovn_northd_opts.changed + loop_control: + loop_var: cmd + tags: + - neutron_ovn-config # This play will add nodes in existing cluster using leader_node var. - name: Join new nodes to ovn cluster using leader node diff --git a/tasks/providers/ovn_config.yml b/tasks/providers/ovn_config.yml index 042e8f8e..b462f3e6 100644 --- a/tasks/providers/ovn_config.yml +++ b/tasks/providers/ovn_config.yml @@ -40,6 +40,15 @@ when: - neutron_services['neutron-ovn-controller']['group'] in group_names +- name: Configure ovn-controller + template: + src: ovn-controller-opts.j2 + dest: "{{ neutron_ovn_controller_opts_file }}" + register: ovn_controller_config + when: + - neutron_services['neutron-ovn-controller']['group'] in group_names + - neutron_ovn_ssl + - name: Ensure ovn-northd service is started and enabled systemd: name: "{{ neutron_ovn_northd_service_name }}" @@ -51,7 +60,7 @@ - name: Ensure ovn-controller service is started and enabled systemd: name: "{{ neutron_ovn_controller_service_name }}" - state: started + state: "{{ (ovn_controller_config.changed) | ternary('restarted','started') }}" enabled: yes when: - neutron_services['neutron-ovn-controller']['group'] in group_names diff --git a/templates/ovn-controller-opts.j2 b/templates/ovn-controller-opts.j2 new file mode 100644 index 00000000..08a6c7ef --- /dev/null +++ b/templates/ovn-controller-opts.j2 @@ -0,0 +1,9 @@ +# {{ ansible_managed }} + +# OVN controller parameters + +{{ neutron_ovn_controller_opts }}="--ovn-controller-ssl-key={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_key] | join('/') }} \ + --ovn-controller-ssl-cert={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_cert] | join('/') }} \ + --ovn-controller-ssl-ca-cert={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_ca_cert] | join('/') }} \ +" + diff --git a/templates/ovn-northd-opts.j2 b/templates/ovn-northd-opts.j2 index c83bb7a5..bc2e26fe 100644 --- a/templates/ovn-northd-opts.j2 +++ b/templates/ovn-northd-opts.j2 @@ -2,8 +2,8 @@ # OVN cluster parameters {{ neutron_ovn_northd_opts }}=" \ - --db-nb-create-insecure-remote=yes \ - --db-sb-create-insecure-remote=yes \ + --db-nb-create-insecure-remote={{ (neutron_ovn_ssl) | ternary('no','yes') }} \ + --db-sb-create-insecure-remote={{ (neutron_ovn_ssl) | ternary('no','yes') }} \ --db-nb-addr={{ ansible_host }} \ --db-sb-addr={{ ansible_host }} \ --db-nb-cluster-local-addr={{ ansible_host }} \ @@ -12,6 +12,21 @@ --db-nb-cluster-remote-addr={% for item in leader_node %}{{ item }} {% endfor %} \ --db-sb-cluster-remote-addr={% for item in leader_node %}{{ item }} {% endfor %} \ {% endif %} - --ovn-northd-nb-db=tcp:{{ groups['neutron_ovn_northd'] | map('extract', hostvars, ['ansible_host']) | join(':6641,tcp:') }}:6641 \ - --ovn-northd-sb-db=tcp:{{ groups['neutron_ovn_northd'] | map('extract', hostvars, ['ansible_host']) | join(':6642,tcp:') }}:6642 \ + --ovn-northd-nb-db={{ neutron_ovn_nb_connection }} \ + --ovn-northd-sb-db={{ neutron_ovn_sb_connection }} \ + {% if neutron_ovn_ssl %} + --db-nb-cluster-remote-proto=ssl \ + --db-sb-cluster-remote-proto=ssl \ + --db-nb-cluster-local-proto=ssl \ + --db-sb-cluster-local-proto=ssl \ + --ovn-northd-ssl-key={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_key] | join('/') }} \ + --ovn-northd-ssl-cert={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_cert] | join('/') }} \ + --ovn-northd-ssl-ca-cert={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_ca_cert] | join('/') }} \ + --ovn-nb-db-ssl-key={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_key] | join('/') }} \ + --ovn-nb-db-ssl-cert={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_cert] | join('/') }} \ + --ovn-nb-db-ssl-ca-cert={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_ca_cert] | join('/') }} \ + --ovn-sb-db-ssl-key={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_key] | join('/') }} \ + --ovn-sb-db-ssl-cert={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_cert] | join('/') }} \ + --ovn-sb-db-ssl-ca-cert={{ [neutron_ovn_conf_dir, neutron_ovn_ssl_ca_cert] | join('/') }} \ + {% endif %} " diff --git a/templates/plugins/ml2/ml2_conf.ini.j2 b/templates/plugins/ml2/ml2_conf.ini.j2 index dc15b64d..5f0c29ec 100644 --- a/templates/plugins/ml2/ml2_conf.ini.j2 +++ b/templates/plugins/ml2/ml2_conf.ini.j2 @@ -44,17 +44,24 @@ max_header_size = 38 {% endif %} -{% if neutron_plugin_type == 'ml2.ovn' and (neutron_services['neutron-server']['group'] or neutron_services['neutron-ovn-controller']['group'] in group_names) %} - +{% if neutron_plugin_type == 'ml2.ovn' %} +{% if (neutron_services['neutron-server']['group'] in group_names or neutron_services['neutron-ovn-controller']['group'] in group_names) %} [ovn] ovn_native_dhcp = True ovn_nb_connection = {{ neutron_ovn_nb_connection }} ovn_sb_connection = {{ neutron_ovn_sb_connection }} ovn_l3_scheduler = {{ neutron_ovn_l3_scheduler }} ovn_metadata_enabled = True - +{% endif %} +{% if neutron_ovn_ssl and (neutron_services['neutron-server']['group'] in group_names or neutron_services['neutron-ovn-controller']['group'] in group_names) %} +ovn_sb_ca_cert={{ [neutron_conf_version_dir, neutron_ovn_ssl_ca_cert] | join('/') }} +ovn_sb_certificate={{ [neutron_conf_version_dir, neutron_ovn_ssl_cert] | join('/') }} +ovn_sb_private_key={{ [neutron_conf_version_dir, neutron_ovn_ssl_key] | join('/') }} +ovn_nb_ca_cert={{ [neutron_conf_version_dir, neutron_ovn_ssl_ca_cert] | join('/') }} +ovn_nb_certificate={{ [neutron_conf_version_dir, neutron_ovn_ssl_cert] | join('/') }} +ovn_nb_private_key={{ [neutron_conf_version_dir, neutron_ovn_ssl_key] | join('/') }} +{% endif %} {% endif %} - # Security groups [securitygroup] enable_security_group = True diff --git a/vars/debian.yml b/vars/debian.yml index ab62da14..a908f5b6 100644 --- a/vars/debian.yml +++ b/vars/debian.yml @@ -29,6 +29,12 @@ neutron_ovn_northd_opts: "OVN_CTL_OPTS" neutron_ovn_northd_opts_file: "/etc/default/ovn-central" +neutron_ovn_controller_opts: "OVN_CTL_OPTS" + +neutron_ovn_controller_opts_file: "/etc/default/ovn-host" + +neutron_ovn_system_user_name: root + neutron_ovs_dpdk_required_packages: - openvswitch-common - openvswitch-switch-dpdk diff --git a/vars/redhat.yml b/vars/redhat.yml index e8fa7091..070d7a44 100644 --- a/vars/redhat.yml +++ b/vars/redhat.yml @@ -36,6 +36,12 @@ neutron_ovn_northd_opts: "OVN_NORTHD_OPTS" neutron_ovn_northd_opts_file: "/etc/sysconfig/ovn-northd" +neutron_ovn_controller_opts: "OVN_CONTROLLER_OPTS" + +neutron_ovn_controller_opts_file: "/etc/sysconfig/ovn-controller" + +neutron_ovn_system_user_name: openvswitch + neutron_distro_packages: - conntrack-tools - dnsmasq