diff --git a/ansible/roles/nova-cell/defaults/main.yml b/ansible/roles/nova-cell/defaults/main.yml index f08302bd18..bcb50f2063 100644 --- a/ansible/roles/nova-cell/defaults/main.yml +++ b/ansible/roles/nova-cell/defaults/main.yml @@ -529,6 +529,14 @@ migration_hostname: "{{ ansible_facts.nodename }}" # It does not change that often (in fact, most likely never ever). qemu_user_gid: 42427 +# Whether to enable libvirt SASL authentication. +libvirt_enable_sasl: true +# Username for libvirt SASL. +libvirt_sasl_authname: "nova" +# List of enabled libvirt SASL authentication mechanisms. +libvirt_sasl_mech_list: + - "{{ 'SCRAM-SHA-256' if libvirt_tls | bool else 'DIGEST-MD5' }}" + #################### # Kolla #################### diff --git a/ansible/roles/nova-cell/handlers/main.yml b/ansible/roles/nova-cell/handlers/main.yml index 79aae420f0..6ff3e3b497 100644 --- a/ansible/roles/nova-cell/handlers/main.yml +++ b/ansible/roles/nova-cell/handlers/main.yml @@ -93,6 +93,7 @@ vars: service_name: "nova-libvirt" service: "{{ nova_cell_services[service_name] }}" + nova_libvirt_notify: "{{ ['Create libvirt SASL user'] if libvirt_enable_sasl | bool else [] }}" become: true kolla_docker: action: "recreate_or_restart_container" @@ -112,6 +113,20 @@ until: restart_nova_libvirt is success when: - kolla_action != "config" + notify: "{{ nova_libvirt_notify }}" + +# The SASL user needs to exist in order for nova-compute to start successfully. +- name: Create libvirt SASL user + become: true + shell: + cmd: > + set -o pipefail && + echo {{ libvirt_sasl_password }} | + docker exec -i nova_libvirt + saslpasswd2 -c -p -a libvirt {{ libvirt_sasl_authname }} + executable: /bin/bash + changed_when: true + no_log: true - name: Restart nova-compute container vars: diff --git a/ansible/roles/nova-cell/tasks/config.yml b/ansible/roles/nova-cell/tasks/config.yml index 8e4a2c29b7..59dff485a5 100644 --- a/ansible/roles/nova-cell/tasks/config.yml +++ b/ansible/roles/nova-cell/tasks/config.yml @@ -97,6 +97,26 @@ - libvirt_tls | bool - libvirt_tls_manage_certs | bool +- name: Copying over libvirt SASL configuration + become: true + vars: + service_name: "{{ item.service }}" + service: "{{ nova_cell_services[service_name] }}" + template: + src: "{{ item.src }}" + dest: "{{ node_config_directory }}/{{ service_name }}/{{ item.dest }}" + mode: "0660" + when: + - libvirt_enable_sasl | bool + - inventory_hostname in groups[service.group] + - service.enabled | bool + with_items: + - { src: "auth.conf.j2", dest: "auth.conf", service: "nova-compute" } + - { src: "auth.conf.j2", dest: "auth.conf", service: "nova-libvirt" } + - { src: "sasl.conf.j2", dest: "sasl.conf", service: "nova-libvirt" } + notify: + - Restart {{ service_name }} container + - name: Copying files for nova-ssh become: true vars: diff --git a/ansible/roles/nova-cell/templates/auth.conf.j2 b/ansible/roles/nova-cell/templates/auth.conf.j2 new file mode 100644 index 0000000000..75576757ff --- /dev/null +++ b/ansible/roles/nova-cell/templates/auth.conf.j2 @@ -0,0 +1,6 @@ +[credentials-default] +authname={{ libvirt_sasl_authname }} +password={{ libvirt_sasl_password }} + +[auth-libvirt-default] +credentials=default diff --git a/ansible/roles/nova-cell/templates/libvirtd.conf.j2 b/ansible/roles/nova-cell/templates/libvirtd.conf.j2 index 6023456269..aa01f743d8 100644 --- a/ansible/roles/nova-cell/templates/libvirtd.conf.j2 +++ b/ansible/roles/nova-cell/templates/libvirtd.conf.j2 @@ -5,10 +5,11 @@ tls_port = "{{ nova_libvirt_port }}" key_file = "/etc/pki/libvirt/private/serverkey.pem" cert_file = "/etc/pki/libvirt/servercert.pem" ca_file = "/etc/pki/CA/cacert.pem" +auth_tls = "{{ 'sasl' if libvirt_enable_sasl | bool else 'none' }}" {% else %} listen_tcp = 1 listen_tls = 0 -auth_tcp = "none" +auth_tcp = "{{ 'sasl' if libvirt_enable_sasl | bool else 'none' }}" tcp_port = "{{ nova_libvirt_port }}" ca_file = "" {% endif %} diff --git a/ansible/roles/nova-cell/templates/nova-compute.json.j2 b/ansible/roles/nova-cell/templates/nova-compute.json.j2 index 2a762ae2b2..93cf50dfeb 100644 --- a/ansible/roles/nova-cell/templates/nova-compute.json.j2 +++ b/ansible/roles/nova-cell/templates/nova-compute.json.j2 @@ -55,7 +55,13 @@ "owner": "nova", "perm": "0600", "optional": true - } + }{% if nova_compute_virt_type in ['kvm', 'qemu'] and libvirt_enable_sasl | bool %}, + { + "source": "{{ container_config_directory }}/auth.conf", + "dest": "/var/lib/nova/.config/libvirt/auth.conf", + "owner": "nova", + "perm": "0600" + }{% endif %} ], "permissions": [ { diff --git a/ansible/roles/nova-cell/templates/nova-libvirt.json.j2 b/ansible/roles/nova-cell/templates/nova-libvirt.json.j2 index f4160c6af4..d2ddc9e6f9 100644 --- a/ansible/roles/nova-cell/templates/nova-libvirt.json.j2 +++ b/ansible/roles/nova-cell/templates/nova-libvirt.json.j2 @@ -55,6 +55,18 @@ "dest": "/etc/ceph/ceph.conf", "owner": "nova", "perm": "0600" + }{% endif %}{% if libvirt_enable_sasl | bool %}, + { + "source": "{{ container_config_directory }}/sasl.conf", + "dest": "/etc/sasl2/libvirt.conf", + "owner": "root", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/auth.conf", + "dest": "/root/.config/libvirt/auth.conf", + "owner": "root", + "perm": "0600" }{% endif %} ] } diff --git a/ansible/roles/nova-cell/templates/sasl.conf.j2 b/ansible/roles/nova-cell/templates/sasl.conf.j2 new file mode 100644 index 0000000000..a2c1271c47 --- /dev/null +++ b/ansible/roles/nova-cell/templates/sasl.conf.j2 @@ -0,0 +1,2 @@ +mech_list: {{ libvirt_sasl_mech_list | join(' ') }} +sasldb_path: /etc/libvirt/passwd.db diff --git a/doc/source/reference/compute/libvirt-guide.rst b/doc/source/reference/compute/libvirt-guide.rst index 3aae36690b..6776c1f98d 100644 --- a/doc/source/reference/compute/libvirt-guide.rst +++ b/doc/source/reference/compute/libvirt-guide.rst @@ -1,5 +1,3 @@ -.. libvirt-tls-guide: - ==================================== Libvirt - Nova Virtualisation Driver ==================================== @@ -23,16 +21,39 @@ hardware virtualisation (e.g. Virtualisation Technology (VT) BIOS configuration on Intel systems), ``qemu`` may be used to provide less performant software-emulated virtualisation. +SASL Authentication +=================== + +The default configuration of Kolla Ansible is to run libvirt over TCP, +authenticated with SASL. This should not be considered as providing a secure, +encrypted channel, since the username/password SASL mechanisms available for +TCP are no longer considered cryptographically secure. However, it does at +least provide some authentication for the libvirt API. For a more secure +encrypted channel, use :ref`libvirt TLS `. + +SASL is enabled according to the ``libvirt_enable_sasl`` flag, which defaults +to ``true``. + +The username is configured via ``libvirt_sasl_authname``, and defaults to +``kolla``. The password is configured via ``libvirt_sasl_password``, and is +generated with other passwords using and stored in ``passwords.yml``. + +The list of enabled authentication mechanisms is configured via +``libvirt_sasl_mech_list``, and defaults to ``["SCRAM-SHA-256"]`` if libvirt +TLS is enabled, or ``["DIGEST-MD5"]`` otherwise. + +.. libvirt-tls: + Libvirt TLS =========== The default configuration of Kolla Ansible is to run libvirt over TCP, with -authentication disabled. As long as one takes steps to protect who can access -the port this works well. However, in the case where you want live-migration to -be allowed across hypervisors one may want to either add some level of -authentication to the connections or make sure VM data is passed between -hypervisors in a secure manner. To do this we can enable TLS for libvirt and -make nova use it. +SASL authentication. As long as one takes steps to protect who can access +the network this works well. However, in a less trusted environment one may +want to use encryption when accessing the libvirt API. To do this we can enable +TLS for libvirt and make nova use it. Mutual TLS is configured, providing +authentication of clients via certificates. SASL authentication provides a +further level of security. Using libvirt TLS ~~~~~~~~~~~~~~~~~ diff --git a/etc/kolla/passwords.yml b/etc/kolla/passwords.yml index b343496b9e..33667cd8d0 100644 --- a/etc/kolla/passwords.yml +++ b/etc/kolla/passwords.yml @@ -253,3 +253,8 @@ keystone_federation_openid_crypto_password: # Ceph RadosGW options #################### ceph_rgw_keystone_password: + +################## +# libvirt options +################## +libvirt_sasl_password: diff --git a/releasenotes/notes/libvirt-sasl-404199143610fb75.yaml b/releasenotes/notes/libvirt-sasl-404199143610fb75.yaml new file mode 100644 index 0000000000..31461b647a --- /dev/null +++ b/releasenotes/notes/libvirt-sasl-404199143610fb75.yaml @@ -0,0 +1,27 @@ +--- +features: + - | + Adds support for libvirt SASL authentication. It is enabled by default. + `LP#1964013 `__ +security: + - | + Fixes an issue where the default configuration of libvirt did not use + authentication for the API exposed over TCP on the internal API network. + This allowed anyone with access to the internal API network read-write + access to libvirt. While the internal API network is typically trusted, + other services on this network generally at least require authentication. + + SASL authentication is now enabled for libvirt by default. Kolla Ansible + supports libvirt TLS since the Train release, and this is recommended to + provide a higher level of security. `LP#1964013 + `__ +upgrade: + - | + The addition of libvirt SASL authentication requires a new password in + ``passwords.yml``, ``libvirt_sasl_password``. This may be generated using + the existing ``kolla-genpwd`` and ``kolla-mergepwd`` tooling. + - | + The addition of libvirt SASL authentication requires both the + ``nova_libvirt`` and ``nova_compute`` containers to be updated + simultaneously, using new images with the necessary Cyrus SASL + dependencies, as well as configuration containing the SASL credentials.