Skip to content

Commit af6b3ed

Browse files
committed
libvirt: support SASL authentication
In Kolla Ansible OpenStack deployments, by default, libvirt is configured to allow read-write access via an unauthenticated, unencrypted TCP connection, using the internal API network. This is to facilitate migration between hosts. By default, Kolla Ansible does not use encryption for services on the internal network (and did not support it until Ussuri). However, most other services on the internal network are at least authenticated (usually via passwords), ensuring that they cannot be used by anyone with access to the network, unless they have credentials. The main issue here is the lack of authentication. Any client with access to the internal network is able to connect to the libvirt TCP port and make arbitrary changes to the hypervisor. This could include starting a VM, modifying an existing VM, etc. Given the flexibility of the domain options, it could be seen as equivalent to having root access to the hypervisor. Kolla Ansible supports libvirt TLS [1] since the Train release, using client and server certificates for mutual authentication and encryption. However, this feature is not enabled by default, and requires certificates to be generated for each compute host. This change adds support for libvirt SASL authentication, and enables it by default. This provides base level of security. Deployments requiring further security should use libvirt TLS. [1] https://docs.openstack.org/kolla-ansible/latest/reference/compute/libvirt-guide.html#libvirt-tls Depends-On: https://review.opendev.org/c/openstack/kolla/+/833021 Closes-Bug: #1964013 Change-Id: Ia91ceeb609e4cdb144433122b443028c0278b71e (cherry picked from commit d2d4b53)
1 parent ac08a0d commit af6b3ed

File tree

11 files changed

+133
-10
lines changed

11 files changed

+133
-10
lines changed

ansible/roles/nova-cell/defaults/main.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,14 @@ migration_hostname: "{{ ansible_facts.nodename }}"
530530
# It does not change that often (in fact, most likely never ever).
531531
qemu_user_gid: 42427
532532

533+
# Whether to enable libvirt SASL authentication.
534+
libvirt_enable_sasl: true
535+
# Username for libvirt SASL.
536+
libvirt_sasl_authname: "nova"
537+
# List of enabled libvirt SASL authentication mechanisms.
538+
libvirt_sasl_mech_list:
539+
- "{{ 'SCRAM-SHA-256' if libvirt_tls | bool else 'DIGEST-MD5' }}"
540+
533541
####################
534542
# Kolla
535543
####################

ansible/roles/nova-cell/handlers/main.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
vars:
9494
service_name: "nova-libvirt"
9595
service: "{{ nova_cell_services[service_name] }}"
96+
nova_libvirt_notify: "{{ ['Create libvirt SASL user'] if libvirt_enable_sasl | bool else [] }}"
9697
become: true
9798
kolla_docker:
9899
action: "recreate_or_restart_container"
@@ -112,6 +113,20 @@
112113
until: restart_nova_libvirt is success
113114
when:
114115
- kolla_action != "config"
116+
notify: "{{ nova_libvirt_notify }}"
117+
118+
# The SASL user needs to exist in order for nova-compute to start successfully.
119+
- name: Create libvirt SASL user
120+
become: true
121+
shell:
122+
cmd: >
123+
set -o pipefail &&
124+
echo {{ libvirt_sasl_password }} |
125+
docker exec -i nova_libvirt
126+
saslpasswd2 -c -p -a libvirt {{ libvirt_sasl_authname }}
127+
executable: /bin/bash
128+
changed_when: true
129+
no_log: true
115130

116131
- name: Restart nova-compute container
117132
vars:

ansible/roles/nova-cell/tasks/config.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,26 @@
9797
- libvirt_tls | bool
9898
- libvirt_tls_manage_certs | bool
9999

100+
- name: Copying over libvirt SASL configuration
101+
become: true
102+
vars:
103+
service_name: "{{ item.service }}"
104+
service: "{{ nova_cell_services[service_name] }}"
105+
template:
106+
src: "{{ item.src }}"
107+
dest: "{{ node_config_directory }}/{{ service_name }}/{{ item.dest }}"
108+
mode: "0660"
109+
when:
110+
- libvirt_enable_sasl | bool
111+
- inventory_hostname in groups[service.group]
112+
- service.enabled | bool
113+
with_items:
114+
- { src: "auth.conf.j2", dest: "auth.conf", service: "nova-compute" }
115+
- { src: "auth.conf.j2", dest: "auth.conf", service: "nova-libvirt" }
116+
- { src: "sasl.conf.j2", dest: "sasl.conf", service: "nova-libvirt" }
117+
notify:
118+
- Restart {{ service_name }} container
119+
100120
- name: Copying files for nova-ssh
101121
become: true
102122
vars:
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[credentials-default]
2+
authname={{ libvirt_sasl_authname }}
3+
password={{ libvirt_sasl_password }}
4+
5+
[auth-libvirt-default]
6+
credentials=default

ansible/roles/nova-cell/templates/libvirtd.conf.j2

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ tls_port = "{{ nova_libvirt_port }}"
55
key_file = "/etc/pki/libvirt/private/serverkey.pem"
66
cert_file = "/etc/pki/libvirt/servercert.pem"
77
ca_file = "/etc/pki/CA/cacert.pem"
8+
auth_tls = "{{ 'sasl' if libvirt_enable_sasl | bool else 'none' }}"
89
{% else %}
910
listen_tcp = 1
1011
listen_tls = 0
11-
auth_tcp = "none"
12+
auth_tcp = "{{ 'sasl' if libvirt_enable_sasl | bool else 'none' }}"
1213
tcp_port = "{{ nova_libvirt_port }}"
1314
ca_file = ""
1415
{% endif %}

ansible/roles/nova-cell/templates/nova-compute.json.j2

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@
5555
"owner": "nova",
5656
"perm": "0600",
5757
"optional": true
58-
}
58+
}{% if nova_compute_virt_type in ['kvm', 'qemu'] and libvirt_enable_sasl | bool %},
59+
{
60+
"source": "{{ container_config_directory }}/auth.conf",
61+
"dest": "/var/lib/nova/.config/libvirt/auth.conf",
62+
"owner": "nova",
63+
"perm": "0600"
64+
}{% endif %}
5965
],
6066
"permissions": [
6167
{

ansible/roles/nova-cell/templates/nova-libvirt.json.j2

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@
5454
"dest": "/etc/ceph/ceph.conf",
5555
"owner": "nova",
5656
"perm": "0600"
57+
}{% endif %}{% if libvirt_enable_sasl | bool %},
58+
{
59+
"source": "{{ container_config_directory }}/sasl.conf",
60+
"dest": "/etc/sasl2/libvirt.conf",
61+
"owner": "root",
62+
"perm": "0600"
63+
},
64+
{
65+
"source": "{{ container_config_directory }}/auth.conf",
66+
"dest": "/root/.config/libvirt/auth.conf",
67+
"owner": "root",
68+
"perm": "0600"
5769
}{% endif %}
5870
]
5971
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mech_list: {{ libvirt_sasl_mech_list | join(' ') }}
2+
sasldb_path: /etc/libvirt/passwd.db

doc/source/reference/compute/libvirt-guide.rst

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
.. libvirt-tls-guide:
2-
31
====================================
42
Libvirt - Nova Virtualisation Driver
53
====================================
@@ -23,16 +21,39 @@ hardware virtualisation (e.g. Virtualisation Technology (VT) BIOS configuration
2321
on Intel systems), ``qemu`` may be used to provide less performant
2422
software-emulated virtualisation.
2523

24+
SASL Authentication
25+
===================
26+
27+
The default configuration of Kolla Ansible is to run libvirt over TCP,
28+
authenticated with SASL. This should not be considered as providing a secure,
29+
encrypted channel, since the username/password SASL mechanisms available for
30+
TCP are no longer considered cryptographically secure. However, it does at
31+
least provide some authentication for the libvirt API. For a more secure
32+
encrypted channel, use :ref`libvirt TLS <libvirt-tls>`.
33+
34+
SASL is enabled according to the ``libvirt_enable_sasl`` flag, which defaults
35+
to ``true``.
36+
37+
The username is configured via ``libvirt_sasl_authname``, and defaults to
38+
``kolla``. The password is configured via ``libvirt_sasl_password``, and is
39+
generated with other passwords using and stored in ``passwords.yml``.
40+
41+
The list of enabled authentication mechanisms is configured via
42+
``libvirt_sasl_mech_list``, and defaults to ``["SCRAM-SHA-256"]`` if libvirt
43+
TLS is enabled, or ``["DIGEST-MD5"]`` otherwise.
44+
45+
.. libvirt-tls:
46+
2647
Libvirt TLS
2748
===========
2849

2950
The default configuration of Kolla Ansible is to run libvirt over TCP, with
30-
authentication disabled. As long as one takes steps to protect who can access
31-
the port this works well. However, in the case where you want live-migration to
32-
be allowed across hypervisors one may want to either add some level of
33-
authentication to the connections or make sure VM data is passed between
34-
hypervisors in a secure manner. To do this we can enable TLS for libvirt and
35-
make nova use it.
51+
SASL authentication. As long as one takes steps to protect who can access
52+
the network this works well. However, in a less trusted environment one may
53+
want to use encryption when accessing the libvirt API. To do this we can enable
54+
TLS for libvirt and make nova use it. Mutual TLS is configured, providing
55+
authentication of clients via certificates. SASL authentication provides a
56+
further level of security.
3657

3758
Using libvirt TLS
3859
~~~~~~~~~~~~~~~~~

etc/kolla/passwords.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,8 @@ prometheus_alertmanager_password:
251251
# OpenStack identity federation
252252
###############################
253253
keystone_federation_openid_crypto_password:
254+
255+
##################
256+
# libvirt options
257+
##################
258+
libvirt_sasl_password:

0 commit comments

Comments
 (0)