diff --git a/etc/neutron/rootwrap.d/vpnaas.filters b/etc/neutron/rootwrap.d/vpnaas.filters index f896a83a3..cfefdcf17 100644 --- a/etc/neutron/rootwrap.d/vpnaas.filters +++ b/etc/neutron/rootwrap.d/vpnaas.filters @@ -14,3 +14,4 @@ ipsec: CommandFilter, ipsec, root strongswan: CommandFilter, strongswan, root neutron_netns_wrapper: CommandFilter, neutron-vpn-netns-wrapper, root neutron_netns_wrapper_local: CommandFilter, /usr/local/bin/neutron-vpn-netns-wrapper, root +chown: CommandFilter, chown, root diff --git a/neutron_vpnaas/services/vpn/device_drivers/libreswan_ipsec.py b/neutron_vpnaas/services/vpn/device_drivers/libreswan_ipsec.py index d6dda6a4d..30336ec85 100644 --- a/neutron_vpnaas/services/vpn/device_drivers/libreswan_ipsec.py +++ b/neutron_vpnaas/services/vpn/device_drivers/libreswan_ipsec.py @@ -60,6 +60,14 @@ class LibreSwanProcess(ipsec.OpenSwanProcess): Initialise the nssdb, otherwise pluto daemon will fail to run. """ super(LibreSwanProcess, self).ensure_configs() + + # LibreSwan uses the capabilities library to restrict access to + # ipsec.secrets to users that have explicit access. Since pluto is + # running as root and the file has 0600 perms, we must set the + # owner of the file to root. + secrets_file = self._get_config_filename('ipsec.secrets') + self._execute(['chown', 'root:root', secrets_file]) + # Load the ipsec kernel module if not loaded self._execute([self.binary, '_stackmanager', 'start']) # checknss creates nssdb only if it is missing diff --git a/neutron_vpnaas/tests/unit/services/vpn/device_drivers/test_ipsec.py b/neutron_vpnaas/tests/unit/services/vpn/device_drivers/test_ipsec.py index 1fd3603a1..759a2e6e0 100644 --- a/neutron_vpnaas/tests/unit/services/vpn/device_drivers/test_ipsec.py +++ b/neutron_vpnaas/tests/unit/services/vpn/device_drivers/test_ipsec.py @@ -992,22 +992,28 @@ class TestLibreSwanProcess(base.BaseTestCase): openswan_ipsec.OpenSwanProcess.ensure_configs = mock.Mock() with mock.patch.object(self.ipsec_process, '_execute') as fake_execute: self.ipsec_process.ensure_configs() - expected = [mock.call(['ipsec', '_stackmanager', 'start']), + expected = [mock.call(['chown', 'root:root', + self.ipsec_process._get_config_filename( + 'ipsec.secrets')]), + mock.call(['ipsec', '_stackmanager', 'start']), mock.call(['ipsec', 'checknss', self.ipsec_process.etc_dir])] fake_execute.assert_has_calls(expected) - self.assertEqual(2, fake_execute.call_count) + self.assertEqual(3, fake_execute.call_count) with mock.patch.object(self.ipsec_process, '_execute') as fake_execute: - fake_execute.side_effect = [None, RuntimeError, None] + fake_execute.side_effect = [None, None, RuntimeError, None] self.ipsec_process.ensure_configs() - expected = [mock.call(['ipsec', '_stackmanager', 'start']), + expected = [mock.call(['chown', 'root:root', + self.ipsec_process._get_config_filename( + 'ipsec.secrets')]), + mock.call(['ipsec', '_stackmanager', 'start']), mock.call(['ipsec', 'checknss', self.ipsec_process.etc_dir]), mock.call(['ipsec', 'initnss', self.ipsec_process.etc_dir])] fake_execute.assert_has_calls(expected) - self.assertEqual(3, fake_execute.call_count) + self.assertEqual(4, fake_execute.call_count) class IPsecStrongswanDeviceDriverLegacy(IPSecDeviceLegacy):