Merge "libvirt: Add config option to require secure SPICE."

This commit is contained in:
Zuul
2024-08-30 00:28:04 +00:00
committed by Gerrit Code Review
7 changed files with 150 additions and 5 deletions
+4 -1
View File
@@ -318,7 +318,6 @@ be told where to find them. This requires editing :file:`nova.conf` to set.
vencrypt_client_cert=/etc/pki/nova-novncproxy/client-cert.pem
vencrypt_ca_certs=/etc/pki/nova-novncproxy/ca-cert.pem
.. _spice-console:
SPICE console
@@ -403,6 +402,10 @@ for SPICE consoles.
- :oslo.config:option:`spice.playback_compression`
- :oslo.config:option:`spice.streaming_mode`
As well as the following option to require that connections be protected by TLS:
- :oslo.config:option:`spice.require_secure`
.. _serial-console:
Serial console
+17
View File
@@ -194,6 +194,23 @@ Related options:
* This option depends on the ``server_listen`` option.
The proxy client must be able to access the address specified in
``server_listen`` using the value of this option.
"""),
cfg.BoolOpt('require_secure',
default=False,
help="""
Whether to require secure TLS connections to SPICE consoles.
If you're providing direct access to SPICE consoles instead of using the HTML5
proxy, you may wish those connections to be encrypted. If so, set this value to
True.
Note that use of secure consoles requires that you setup TLS certificates on
each hypervisor.
Possible values:
* False: console traffic is not encrypted.
* True: console traffic is required to be protected by TLS.
"""),
]
+73 -4
View File
@@ -1715,9 +1715,9 @@ class LibvirtConfigGuestGraphicsTest(LibvirtConfigBaseTest):
obj.listen = "127.0.0.1"
xml = obj.to_xml()
self.assertXmlEqual(xml, """
self.assertXmlEqual("""
<graphics type="vnc" autoport="yes" keymap="en_US" listen="127.0.0.1"/>
""")
""", xml)
def test_config_graphics_spice(self):
obj = config.LibvirtConfigGuestGraphics()
@@ -1726,6 +1726,18 @@ class LibvirtConfigGuestGraphicsTest(LibvirtConfigBaseTest):
obj.keymap = "en_US"
obj.listen = "127.0.0.1"
xml = obj.to_xml()
self.assertXmlEqual("""
<graphics type="spice" autoport="no" keymap="en_US" listen="127.0.0.1"/>
""", xml)
def test_config_graphics_spice_compression(self):
obj = config.LibvirtConfigGuestGraphics()
obj.type = "spice"
obj.autoport = False
obj.keymap = "en_US"
obj.listen = "127.0.0.1"
obj.image_compression = "auto_glz"
obj.jpeg_compression = "auto"
obj.zlib_compression = "always"
@@ -1733,7 +1745,7 @@ class LibvirtConfigGuestGraphicsTest(LibvirtConfigBaseTest):
obj.streaming_mode = "filter"
xml = obj.to_xml()
self.assertXmlEqual(xml, """
self.assertXmlEqual("""
<graphics type="spice" autoport="no" keymap="en_US" listen="127.0.0.1">
<image compression="auto_glz"/>
<jpeg compression="auto"/>
@@ -1741,7 +1753,64 @@ class LibvirtConfigGuestGraphicsTest(LibvirtConfigBaseTest):
<playback compression="on"/>
<streaming mode="filter"/>
</graphics>
""")
""", xml)
def test_config_graphics_spice_secure(self):
obj = config.LibvirtConfigGuestGraphics()
obj.type = "spice"
obj.autoport = False
obj.keymap = "en_US"
obj.listen = "127.0.0.1"
obj.secure = True
xml = obj.to_xml()
self.assertXmlEqual("""
<graphics type="spice" autoport="no" keymap="en_US" listen="127.0.0.1">
<channel name="main" mode="secure"/>
<channel name="display" mode="secure"/>
<channel name="inputs" mode="secure"/>
<channel name="cursor" mode="secure"/>
<channel name="playback" mode="secure"/>
<channel name="record" mode="secure"/>
<channel name="smartcard" mode="secure"/>
<channel name="usbredir" mode="secure"/>
</graphics>
""", xml)
def test_config_graphics_spice_secure_compression(self):
obj = config.LibvirtConfigGuestGraphics()
obj.type = "spice"
obj.autoport = False
obj.keymap = "en_US"
obj.listen = "127.0.0.1"
obj.secure = True
obj.image_compression = "auto_glz"
obj.jpeg_compression = "auto"
obj.zlib_compression = "always"
obj.playback_compression = True
obj.streaming_mode = "filter"
xml = obj.to_xml()
self.assertXmlEqual("""
<graphics type="spice" autoport="no" keymap="en_US" listen="127.0.0.1">
<image compression="auto_glz"/>
<jpeg compression="auto"/>
<zlib compression="always"/>
<playback compression="on"/>
<streaming mode="filter"/>
<channel name="main" mode="secure"/>
<channel name="display" mode="secure"/>
<channel name="inputs" mode="secure"/>
<channel name="cursor" mode="secure"/>
<channel name="playback" mode="secure"/>
<channel name="record" mode="secure"/>
<channel name="smartcard" mode="secure"/>
<channel name="usbredir" mode="secure"/>
</graphics>
""", xml)
class LibvirtConfigGuestHostdev(LibvirtConfigBaseTest):
@@ -5907,6 +5907,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
self.assertIsNone(cfg.devices[3].zlib_compression)
self.assertIsNone(cfg.devices[3].playback_compression)
self.assertIsNone(cfg.devices[3].streaming_mode)
self.assertFalse(cfg.devices[3].secure)
def test_get_guest_config_with_vnc_and_tablet(self):
self.flags(enabled=True, group='vnc')
@@ -5942,6 +5943,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
self.assertIsNone(cfg.devices[3].zlib_compression)
self.assertIsNone(cfg.devices[3].playback_compression)
self.assertIsNone(cfg.devices[3].streaming_mode)
self.assertFalse(cfg.devices[3].secure)
self.assertEqual(cfg.devices[5].type, 'tablet')
def test_get_guest_config_with_spice_and_tablet(self):
@@ -5983,6 +5985,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
self.assertIsNone(cfg.devices[3].zlib_compression)
self.assertIsNone(cfg.devices[3].playback_compression)
self.assertIsNone(cfg.devices[3].streaming_mode)
self.assertFalse(cfg.devices[3].secure)
self.assertEqual(cfg.devices[5].type, 'tablet')
@mock.patch.object(host.Host, "_check_machine_type", new=mock.Mock())
@@ -6047,6 +6050,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
self.assertIsNone(cfg.devices[4].zlib_compression)
self.assertIsNone(cfg.devices[4].playback_compression)
self.assertIsNone(cfg.devices[4].streaming_mode)
self.assertFalse(cfg.devices[4].secure)
self.assertEqual(cfg.devices[5].type, video_type)
def test_get_guest_config_with_spice_compression(self):
@@ -6092,6 +6096,43 @@ class LibvirtConnTestCase(test.NoDBTestCase,
self.assertEqual(cfg.devices[3].zlib_compression, 'always')
self.assertFalse(cfg.devices[3].playback_compression)
self.assertEqual(cfg.devices[3].streaming_mode, 'all')
self.assertFalse(cfg.devices[3].secure)
def test_get_guest_config_with_spice_secure(self):
self.flags(enabled=False, group='vnc')
self.flags(virt_type='kvm', group='libvirt')
self.flags(enabled=True,
agent_enabled=False,
require_secure=True,
server_listen='10.0.0.1',
group='spice')
self.flags(pointer_model='usbtablet')
cfg = self._get_guest_config_with_graphics()
self.assertEqual(len(cfg.devices), 9)
self.assertIsInstance(cfg.devices[0],
vconfig.LibvirtConfigGuestDisk)
self.assertIsInstance(cfg.devices[1],
vconfig.LibvirtConfigGuestDisk)
self.assertIsInstance(cfg.devices[2],
vconfig.LibvirtConfigGuestSerial)
self.assertIsInstance(cfg.devices[3],
vconfig.LibvirtConfigGuestGraphics)
self.assertIsInstance(cfg.devices[4],
vconfig.LibvirtConfigGuestVideo)
self.assertIsInstance(cfg.devices[5],
vconfig.LibvirtConfigGuestInput)
self.assertIsInstance(cfg.devices[6],
vconfig.LibvirtConfigGuestRng)
self.assertIsInstance(cfg.devices[7],
vconfig.LibvirtConfigGuestUSBHostController)
self.assertIsInstance(cfg.devices[8],
vconfig.LibvirtConfigMemoryBalloon)
self.assertEqual(cfg.devices[3].type, 'spice')
self.assertEqual(cfg.devices[3].listen, '10.0.0.1')
self.assertTrue(cfg.devices[3].secure)
@mock.patch.object(host.Host, 'get_guest')
@mock.patch.object(libvirt_driver.LibvirtDriver,
+6
View File
@@ -2188,6 +2188,7 @@ class LibvirtConfigGuestGraphics(LibvirtConfigGuestDevice):
self.autoport = True
self.keymap = None
self.listen = None
self.secure = None
self.image_compression = None
self.jpeg_compression = None
@@ -2222,6 +2223,11 @@ class LibvirtConfigGuestGraphics(LibvirtConfigGuestDevice):
if self.streaming_mode is not None:
dev.append(etree.Element(
'streaming', mode=self.streaming_mode))
if self.secure:
for channel in ['main', 'display', 'inputs', 'cursor',
'playback', 'record', 'smartcard', 'usbredir']:
dev.append(etree.Element('channel', name=channel,
mode='secure'))
return dev
+1
View File
@@ -7711,6 +7711,7 @@ class LibvirtDriver(driver.ComputeDriver):
graphics.zlib_compression = CONF.spice.zlib_compression
graphics.playback_compression = CONF.spice.playback_compression
graphics.streaming_mode = CONF.spice.streaming_mode
graphics.secure = CONF.spice.require_secure
guest.add_device(graphics)
add_video_driver = True
@@ -0,0 +1,8 @@
---
features:
- |
This release adds a new config option require_secure to the spice
configuration group. Defaulting to false to match the previous
behavior, if set to true the SPICE consoles will require TLS
protected connections. Unencrypted connections will be gracefully
redirected to the TLS port via the SPICE protocol.