forked from pool/cloud-init
- Sensitive data exposure (bsc#1210277, CVE-2023-1786)
+ Add hidesensitivedata + Add cloud-init-cve-2023-1786-redact-inst-data.patch + Do not expose sensitive data gathered from the CSP OBS-URL: https://build.opensuse.org/package/show/Cloud:Tools/cloud-init?expand=0&rev=207
This commit is contained in:
parent
23246c72e5
commit
6b35b75868
175
cloud-init-cve-2023-1786-redact-instance-data-json-main.patch
Normal file
175
cloud-init-cve-2023-1786-redact-instance-data-json-main.patch
Normal file
@ -0,0 +1,175 @@
|
||||
--- cloudinit/sources/DataSourceLXD.py.orig
|
||||
+++ cloudinit/sources/DataSourceLXD.py
|
||||
@@ -173,6 +173,8 @@ class DataSourceLXD(sources.DataSource):
|
||||
"user.meta-data",
|
||||
"user.vendor-data",
|
||||
"user.user-data",
|
||||
+ "cloud-init.user-data",
|
||||
+ "cloud-init.vendor-data",
|
||||
)
|
||||
|
||||
skip_hotplug_detect = True
|
||||
--- cloudinit/sources/DataSourceVultr.py.orig
|
||||
+++ cloudinit/sources/DataSourceVultr.py
|
||||
@@ -5,6 +5,8 @@
|
||||
# Vultr Metadata API:
|
||||
# https://www.vultr.com/metadata/
|
||||
|
||||
+from typing import Tuple
|
||||
+
|
||||
import cloudinit.sources.helpers.vultr as vultr
|
||||
from cloudinit import log as log
|
||||
from cloudinit import sources, util, version
|
||||
@@ -27,6 +29,9 @@ BUILTIN_DS_CONFIG = {
|
||||
class DataSourceVultr(sources.DataSource):
|
||||
|
||||
dsname = "Vultr"
|
||||
+ sensitive_metadata_keys: Tuple[
|
||||
+ str, ...
|
||||
+ ] = sources.DataSource.sensitive_metadata_keys + ("startup-script",)
|
||||
|
||||
def __init__(self, sys_cfg, distro, paths):
|
||||
super(DataSourceVultr, self).__init__(sys_cfg, distro, paths)
|
||||
@@ -54,13 +59,8 @@ class DataSourceVultr(sources.DataSource
|
||||
self.get_datasource_data(self.metadata)
|
||||
|
||||
# Dump some data so diagnosing failures is manageable
|
||||
- LOG.debug("Vultr Vendor Config:")
|
||||
- LOG.debug(util.json_dumps(self.metadata["vendor-data"]))
|
||||
LOG.debug("SUBID: %s", self.metadata["instance-id"])
|
||||
LOG.debug("Hostname: %s", self.metadata["local-hostname"])
|
||||
- if self.userdata_raw is not None:
|
||||
- LOG.debug("User-Data:")
|
||||
- LOG.debug(self.userdata_raw)
|
||||
|
||||
return True
|
||||
|
||||
@@ -146,7 +146,4 @@ if __name__ == "__main__":
|
||||
config = md["vendor-data"]
|
||||
sysinfo = vultr.get_sysinfo()
|
||||
|
||||
- print(util.json_dumps(sysinfo))
|
||||
- print(util.json_dumps(config))
|
||||
-
|
||||
# vi: ts=4 expandtab
|
||||
--- cloudinit/sources/__init__.py.orig
|
||||
+++ cloudinit/sources/__init__.py
|
||||
@@ -132,6 +132,12 @@ def redact_sensitive_keys(metadata, reda
|
||||
|
||||
Replace any keys values listed in 'sensitive_keys' with redact_value.
|
||||
"""
|
||||
+ # While 'sensitive_keys' should already sanitized to only include what
|
||||
+ # is in metadata, it is possible keys will overlap. For example, if
|
||||
+ # "merged_cfg" and "merged_cfg/ds/userdata" both match, it's possible that
|
||||
+ # "merged_cfg" will get replaced first, meaning "merged_cfg/ds/userdata"
|
||||
+ # no longer represents a valid key.
|
||||
+ # Thus, we still need to do membership checks in this function.
|
||||
if not metadata.get("sensitive_keys", []):
|
||||
return metadata
|
||||
md_copy = copy.deepcopy(metadata)
|
||||
@@ -139,9 +145,14 @@ def redact_sensitive_keys(metadata, reda
|
||||
path_parts = key_path.split("/")
|
||||
obj = md_copy
|
||||
for path in path_parts:
|
||||
- if isinstance(obj[path], dict) and path != path_parts[-1]:
|
||||
+ if (
|
||||
+ path in obj
|
||||
+ and isinstance(obj[path], dict)
|
||||
+ and path != path_parts[-1]
|
||||
+ ):
|
||||
obj = obj[path]
|
||||
- obj[path] = redact_value
|
||||
+ if path in obj:
|
||||
+ obj[path] = redact_value
|
||||
return md_copy
|
||||
|
||||
|
||||
@@ -249,6 +260,14 @@ class DataSource(CloudInitPickleMixin, m
|
||||
sensitive_metadata_keys: Tuple[str, ...] = (
|
||||
"merged_cfg",
|
||||
"security-credentials",
|
||||
+ "userdata",
|
||||
+ "user-data",
|
||||
+ "user_data",
|
||||
+ "vendordata",
|
||||
+ "vendor-data",
|
||||
+ # Provide ds/vendor_data to avoid redacting top-level
|
||||
+ # "vendor_data": {enabled: True}
|
||||
+ "ds/vendor_data",
|
||||
)
|
||||
|
||||
# True on datasources that may not see hotplugged devices reflected
|
||||
--- cloudinit/stages.py.orig
|
||||
+++ cloudinit/stages.py
|
||||
@@ -203,7 +203,9 @@ class Init:
|
||||
util.ensure_dirs(self._initial_subdirs())
|
||||
log_file = util.get_cfg_option_str(self.cfg, "def_log_file")
|
||||
if log_file:
|
||||
- util.ensure_file(log_file, mode=0o640, preserve_mode=True)
|
||||
+ # At this point the log file should have already been created
|
||||
+ # in the setupLogging function of log.py
|
||||
+ util.ensure_file(log_file, mode=0o640, preserve_mode=False)
|
||||
perms = self.cfg.get("syslog_fix_perms")
|
||||
if not perms:
|
||||
perms = {}
|
||||
--- tests/unittests/sources/test_init.py.orig
|
||||
+++ tests/unittests/sources/test_init.py
|
||||
@@ -464,6 +464,12 @@ class TestDataSource(CiTestCase):
|
||||
(
|
||||
"merged_cfg",
|
||||
"security-credentials",
|
||||
+ "userdata",
|
||||
+ "user-data",
|
||||
+ "user_data",
|
||||
+ "vendordata",
|
||||
+ "vendor-data",
|
||||
+ "ds/vendor_data",
|
||||
),
|
||||
datasource.sensitive_metadata_keys,
|
||||
)
|
||||
@@ -574,6 +580,12 @@ class TestDataSource(CiTestCase):
|
||||
(
|
||||
"merged_cfg",
|
||||
"security-credentials",
|
||||
+ "userdata",
|
||||
+ "user-data",
|
||||
+ "user_data",
|
||||
+ "vendordata",
|
||||
+ "vendor-data",
|
||||
+ "ds/vendor_data",
|
||||
),
|
||||
datasource.sensitive_metadata_keys,
|
||||
)
|
||||
--- tests/unittests/test_stages.py.orig
|
||||
+++ tests/unittests/test_stages.py
|
||||
@@ -606,19 +606,23 @@ class TestInit_InitializeFilesystem:
|
||||
# Assert we create it 0o640 by default if it doesn't already exist
|
||||
assert 0o640 == stat.S_IMODE(log_file.stat().mode)
|
||||
|
||||
- def test_existing_file_permissions_are_not_modified(self, init, tmpdir):
|
||||
- """If the log file already exists, we should not modify its permissions
|
||||
+ def test_existing_file_permissions(self, init, tmpdir):
|
||||
+ """Test file permissions are set as expected.
|
||||
+
|
||||
+ CIS Hardening requires 640 permissions. These permissions are
|
||||
+ currently hardcoded on every boot, but if there's ever a reason
|
||||
+ to change this, we need to then ensure that they
|
||||
+ are *not* set every boot.
|
||||
|
||||
See https://bugs.launchpad.net/cloud-init/+bug/1900837.
|
||||
"""
|
||||
- # Use a mode that will never be made the default so this test will
|
||||
- # always be valid
|
||||
- mode = 0o606
|
||||
log_file = tmpdir.join("cloud-init.log")
|
||||
log_file.ensure()
|
||||
- log_file.chmod(mode)
|
||||
+ # Use a mode that will never be made the default so this test will
|
||||
+ # always be valid
|
||||
+ log_file.chmod(0o606)
|
||||
init._cfg = {"def_log_file": str(log_file)}
|
||||
|
||||
init._initialize_filesystem()
|
||||
|
||||
- assert mode == stat.S_IMODE(log_file.stat().mode)
|
||||
+ assert 0o640 == stat.S_IMODE(log_file.stat().mode)
|
@ -5,6 +5,14 @@ Thu Apr 27 12:22:11 UTC 2023 - Robert Schweikert <rjschwei@suse.com>
|
||||
+ Config module cc_refresh_rmc_and_interface is implemented such that
|
||||
it will only work on RH distros. Set the module availability accordingly.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Apr 11 18:48:30 UTC 2023 - Robert Schweikert <rjschwei@suse.com>
|
||||
|
||||
- Sensitive data exposure (bsc#1210277, CVE-2023-1786)
|
||||
+ Add hidesensitivedata
|
||||
+ Add cloud-init-cve-2023-1786-redact-inst-data.patch
|
||||
+ Do not expose sensitive data gathered from the CSP
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Feb 23 13:38:43 UTC 2023 - Robert Schweikert <rjschwei@suse.com>
|
||||
|
||||
|
@ -26,6 +26,7 @@ Url: https://github.com/canonical/cloud-init
|
||||
Group: System/Management
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
Source1: rsyslog-cloud-init.cfg
|
||||
Source2: hidesensitivedata
|
||||
Patch1: datasourceLocalDisk.patch
|
||||
# FIXME (lp#1849296)
|
||||
Patch2: cloud-init-break-resolv-symlink.patch
|
||||
@ -37,8 +38,9 @@ Patch4: cloud-init-no-tempnet-oci.patch
|
||||
Patch5: cloud-init-fix-ca-test.patch
|
||||
# FIXME (lp#1812117)
|
||||
Patch6: cloud-init-write-routes.patch
|
||||
Patch7: cloud-init-cve-2023-1786-redact-instance-data-json-main.patch
|
||||
# FIXME https://github.com/canonical/cloud-init/pull/2148
|
||||
Patch7: cloud-init-power-rhel-only.patch
|
||||
Patch8: cloud-init-power-rhel-only.patch
|
||||
BuildRequires: fdupes
|
||||
BuildRequires: filesystem
|
||||
# pkg-config is needed to find correct systemd unit dir
|
||||
@ -144,6 +146,7 @@ Documentation and examples for cloud-init tools
|
||||
%patch5
|
||||
%patch6
|
||||
%patch7
|
||||
%patch8
|
||||
|
||||
# patch in the full version to version.py
|
||||
version_pys=$(find . -name version.py -type f)
|
||||
@ -187,6 +190,8 @@ mkdir -p %{buildroot}/%{_sysconfdir}/rsyslog.d
|
||||
mkdir -p %{buildroot}/usr/lib/udev/rules.d/
|
||||
cp -a %{SOURCE1} %{buildroot}/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf
|
||||
mv %{buildroot}/lib/udev/rules.d/66-azure-ephemeral.rules %{buildroot}/usr/lib/udev/rules.d/
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
install -m 755 %{SOURCE2} %{buildroot}%{_sbindir}
|
||||
|
||||
# remove debian/ubuntu specific profile.d file (bnc#779553)
|
||||
rm -f %{buildroot}%{_sysconfdir}/profile.d/Z99-cloud-locale-test.sh
|
||||
@ -196,6 +201,9 @@ rm %{buildroot}/%{_sysconfdir}/cloud/templates/*.debian.*
|
||||
rm %{buildroot}/%{_sysconfdir}/cloud/templates/*.redhat.*
|
||||
rm %{buildroot}/%{_sysconfdir}/cloud/templates/*.ubuntu.*
|
||||
|
||||
%post
|
||||
/usr/sbin/hidesensitivedata
|
||||
|
||||
# remove duplicate files
|
||||
%if 0%{?suse_version}
|
||||
%fdupes %{buildroot}%{python3_sitelib}
|
||||
@ -207,6 +215,7 @@ rm %{buildroot}/%{_sysconfdir}/cloud/templates/*.ubuntu.*
|
||||
%{_bindir}/cloud-id
|
||||
%{_bindir}/cloud-init
|
||||
%{_bindir}/cloud-init-per
|
||||
%{_sbindir}/hidesensitivedata
|
||||
%dir %{_sysconfdir}/cloud
|
||||
%dir %{_sysconfdir}/cloud/clean.d
|
||||
%{_sysconfdir}/cloud/clean.d/README
|
||||
|
36
hidesensitivedata
Normal file
36
hidesensitivedata
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from cloudinit.atomic_helper import write_json
|
||||
from cloudinit.sources import (
|
||||
DataSource,
|
||||
process_instance_metadata,
|
||||
redact_sensitive_keys,
|
||||
)
|
||||
|
||||
from cloudinit.stages import Init
|
||||
|
||||
init = Init()
|
||||
log_file = init.cfg["def_log_file"]
|
||||
if os.path.exists(log_file):
|
||||
os.chmod(log_file, 0o640)
|
||||
|
||||
rundir = init.paths.run_dir
|
||||
instance_data_path = Path(rundir, "instance-data.json")
|
||||
if not os.path.exists(str(instance_data_path)):
|
||||
sys.exit(0)
|
||||
instance_json = json.load(instance_data_path.open(encoding="utf-8"))
|
||||
|
||||
sensitive_keys = DataSource.sensitive_metadata_keys
|
||||
|
||||
processed_json = process_instance_metadata(
|
||||
instance_json, sensitive_keys=sensitive_keys
|
||||
)
|
||||
redacted_json = redact_sensitive_keys(processed_json)
|
||||
|
||||
write_json(str(instance_data_path), redacted_json)
|
Loading…
Reference in New Issue
Block a user