cloud-init/backport-netplan-keep-custom-strict-perms-when-50-cloud-init.patch

179 lines
7.5 KiB
Diff

From 483f79cb3b94c8c7d176e748892a040c71132cb3 Mon Sep 17 00:00:00 2001
From: Chad Smith <chad.smith@canonical.com>
Date: Sat, 4 Feb 2023 13:37:02 -0700
Subject: [PATCH] netplan: keep custom strict perms when 50-cloud-init.yaml
exists
Retain existing config file permissions when those permissions are
more strict than the default permissions set on
/etc/netplan/50-cloud-init.yaml.
---
cloudinit/net/netplan.py | 5 ++
.../unittests/test_distros/test_netconfig.py | 74 ++++++++++++-------
2 files changed, 53 insertions(+), 26 deletions(-)
diff --git a/cloudinit/net/netplan.py b/cloudinit/net/netplan.py
index 6bb2cb5..894b5db 100644
--- a/cloudinit/net/netplan.py
+++ b/cloudinit/net/netplan.py
@@ -237,6 +237,11 @@ class Renderer(renderer.Renderer):
header += "\n"
mode = 0o600 if features.NETPLAN_CONFIG_ROOT_READ_ONLY else 0o644
+ if os.path.exists(fpnplan):
+ current_mode = util.get_permissions(fpnplan)
+ if current_mode & mode == current_mode:
+ # preserve mode if existing perms are more strict than default
+ mode = current_mode
util.write_file(fpnplan, header + content, mode=mode)
if self.clean_default:
diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py
index bae2dc4..97659c4 100644
--- a/tests/unittests/test_distros/test_netconfig.py
+++ b/tests/unittests/test_distros/test_netconfig.py
@@ -391,7 +391,6 @@ class TestNetCfgDistroUbuntuEni(TestNetCfgDistroBase):
expected_cfgs = {
self.eni_path(): V1_NET_CFG_OUTPUT,
}
- # ub_distro.apply_network_config(V1_NET_CFG, False)
self._apply_and_verify_eni(self.distro.apply_network_config,
V1_NET_CFG,
expected_cfgs=expected_cfgs.copy())
@@ -411,8 +410,14 @@ class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
self.distro = self._get_distro('ubuntu', renderers=['netplan'])
self.devlist = ['eth0', 'lo']
- def _apply_and_verify_netplan(self, apply_fn, config, expected_cfgs=None,
- bringup=False):
+ def _apply_and_verify_netplan(
+ self,
+ apply_fn,
+ config,
+ expected_cfgs=None,
+ bringup=False,
+ previous_files=(),
+ ):
if not expected_cfgs:
raise ValueError('expected_cfg must not be None')
@@ -422,12 +427,12 @@ class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
with mock.patch("cloudinit.net.netplan.get_devicelist",
return_value=self.devlist):
with self.reRooted(tmpd) as tmpd:
+ for previous_path, content, mode in previous_files:
+ util.write_file(previous_path, content, mode=mode)
apply_fn(config, bringup)
results = dir2dict(tmpd)
-
- mode = 0o600 if features.NETPLAN_CONFIG_ROOT_READ_ONLY else 0o644
- for cfgpath, expected in expected_cfgs.items():
+ for cfgpath, expected, mode in expected_cfgs:
print("----------")
print(expected)
print("^^^^ expected | rendered VVVVVVV")
@@ -440,39 +445,56 @@ class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
return '/etc/netplan/50-cloud-init.yaml'
def test_apply_network_config_v1_to_netplan_ub(self):
- expected_cfgs = {
- self.netplan_path(): V1_TO_V2_NET_CFG_OUTPUT,
- }
+ expected_cfgs = (
+ (self.netplan_path(), V1_TO_V2_NET_CFG_OUTPUT, 0o600),
+ )
- # ub_distro.apply_network_config(V1_NET_CFG, False)
self._apply_and_verify_netplan(self.distro.apply_network_config,
V1_NET_CFG,
- expected_cfgs=expected_cfgs.copy())
+ expected_cfgs=expected_cfgs)
def test_apply_network_config_v1_ipv6_to_netplan_ub(self):
- expected_cfgs = {
- self.netplan_path(): V1_TO_V2_NET_CFG_IPV6_OUTPUT,
- }
+ expected_cfgs = (
+ (self.netplan_path(), V1_TO_V2_NET_CFG_IPV6_OUTPUT, 0o600),
+ )
- # ub_distro.apply_network_config(V1_NET_CFG_IPV6, False)
self._apply_and_verify_netplan(self.distro.apply_network_config,
V1_NET_CFG_IPV6,
- expected_cfgs=expected_cfgs.copy())
+ expected_cfgs=expected_cfgs)
def test_apply_network_config_v2_passthrough_ub(self):
- expected_cfgs = {
- self.netplan_path(): V2_TO_V2_NET_CFG_OUTPUT,
- }
- # ub_distro.apply_network_config(V2_NET_CFG, False)
+ expected_cfgs = (
+ (self.netplan_path(), V2_TO_V2_NET_CFG_OUTPUT, 0o600),
+ )
self._apply_and_verify_netplan(self.distro.apply_network_config,
V2_NET_CFG,
- expected_cfgs=expected_cfgs.copy())
+ expected_cfgs=expected_cfgs)
+
+ def test_apply_network_config_v2_passthrough_retain_orig_perms(self):
+ """Custom permissions on existing netplan is kept when more strict."""
+ expected_cfgs = (
+ (self.netplan_path(), V2_TO_V2_NET_CFG_OUTPUT, 0o640),
+ )
+ with mock.patch.object(
+ features, "NETPLAN_CONFIG_ROOT_READ_ONLY", False
+ ):
+ # When NETPLAN_CONFIG_ROOT_READ_ONLY is False default perms are 644
+ # we keep 640 because it's more strict.
+ # 1640 is used to assert sticky bit preserved across write
+ self._apply_and_verify_netplan(
+ self.distro.apply_network_config,
+ V2_NET_CFG,
+ expected_cfgs=expected_cfgs,
+ previous_files=(
+ ("/etc/netplan/50-cloud-init.yaml", "a", 0o640),
+ ),
+ )
def test_apply_network_config_v2_passthrough_ub_old_behavior(self):
"""Kinetic and earlier have 50-cloud-init.yaml world-readable"""
- expected_cfgs = {
- self.netplan_path(): V2_TO_V2_NET_CFG_OUTPUT,
- }
+ expected_cfgs = (
+ (self.netplan_path(), V2_TO_V2_NET_CFG_OUTPUT, 0o644),
+ )
# ub_distro.apply_network_config(V2_NET_CFG, False)
with mock.patch.object(
features, "NETPLAN_CONFIG_ROOT_READ_ONLY", False
@@ -480,7 +502,7 @@ class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
self._apply_and_verify_netplan(
self.distro.apply_network_config,
V2_NET_CFG,
- expected_cfgs=expected_cfgs.copy(),
+ expected_cfgs=expected_cfgs,
)
class TestNetCfgDistroRedhat(TestNetCfgDistroBase):
@@ -771,7 +793,6 @@ class TestNetCfgDistroArch(TestNetCfgDistroBase):
"""),
}
- # ub_distro.apply_network_config(V1_NET_CFG, False)
self._apply_and_verify(self.distro.apply_network_config,
V1_NET_CFG,
expected_cfgs=expected_cfgs.copy(),
@@ -920,6 +941,7 @@ class TestNetCfgDistroPhoton(TestNetCfgDistroBase):
def get_mode(path, target=None):
+ # Mask upper st_mode bits like S_IFREG bit preserve sticky and isuid/osgid
return os.stat(subp.target_path(target, path)).st_mode & 0o777
# vi: ts=4 expandtab
--
2.33.0