diff options
author | Chad Smith <chad.smith@canonical.com> | 2020-03-04 15:19:43 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-04 15:19:43 -0700 |
commit | fa639704f67539d9c1d8668383f755cb0213fd4a (patch) | |
tree | 04dfb98f4a5132b5ba84f7d96836e584aa03f5a6 /cloudinit | |
parent | 1d2dfc5d879dc905f440697c2b805c9485dda821 (diff) | |
download | vyos-cloud-init-fa639704f67539d9c1d8668383f755cb0213fd4a.tar.gz vyos-cloud-init-fa639704f67539d9c1d8668383f755cb0213fd4a.zip |
instance-data: write redacted cfg to instance-data.json (#233)
When cloud-init persisted instance metadata to instance-data.json
if failed to redact the sensitive value. Currently, the only sensitive
key 'security-credentials' is omitted as cloud-init does not fetch
this value from IMDS.
Fix this by properly redacting the content from the public
instance-metadata.json file while retaining the value in the root-only
instance-data-sensitive.json file.
LP: #1865947
Diffstat (limited to 'cloudinit')
-rw-r--r-- | cloudinit/sources/__init__.py | 8 | ||||
-rw-r--r-- | cloudinit/sources/tests/test_init.py | 57 |
2 files changed, 54 insertions, 11 deletions
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py index dd93cfd8..805d803d 100644 --- a/cloudinit/sources/__init__.py +++ b/cloudinit/sources/__init__.py @@ -315,12 +315,12 @@ class DataSource(metaclass=abc.ABCMeta): except UnicodeDecodeError as e: LOG.warning('Error persisting instance-data.json: %s', str(e)) return False - json_file = os.path.join(self.paths.run_dir, INSTANCE_JSON_FILE) - write_json(json_file, processed_data) # World readable json_sensitive_file = os.path.join(self.paths.run_dir, INSTANCE_JSON_SENSITIVE_FILE) - write_json(json_sensitive_file, - redact_sensitive_keys(processed_data), mode=0o600) + write_json(json_sensitive_file, processed_data, mode=0o600) + json_file = os.path.join(self.paths.run_dir, INSTANCE_JSON_FILE) + # World readable + write_json(json_file, redact_sensitive_keys(processed_data)) return True def _get_data(self): diff --git a/cloudinit/sources/tests/test_init.py b/cloudinit/sources/tests/test_init.py index f73b37ed..6db127e7 100644 --- a/cloudinit/sources/tests/test_init.py +++ b/cloudinit/sources/tests/test_init.py @@ -318,8 +318,8 @@ class TestDataSource(CiTestCase): self.assertEqual(0o644, stat.S_IMODE(file_stat.st_mode)) self.assertEqual(expected, util.load_json(content)) - def test_get_data_writes_json_instance_data_sensitive(self): - """get_data writes INSTANCE_JSON_SENSITIVE_FILE as readonly root.""" + def test_get_data_writes_redacted_public_json_instance_data(self): + """get_data writes redacted content to public INSTANCE_JSON_FILE.""" tmp = self.tmp_dir() datasource = DataSourceTestSubclassNet( self.sys_cfg, self.distro, Paths({'run_dir': tmp}), @@ -333,11 +333,53 @@ class TestDataSource(CiTestCase): ('security-credentials',), datasource.sensitive_metadata_keys) datasource.get_data() json_file = self.tmp_path(INSTANCE_JSON_FILE, tmp) - sensitive_json_file = self.tmp_path(INSTANCE_JSON_SENSITIVE_FILE, tmp) redacted = util.load_json(util.load_file(json_file)) + expected = { + 'base64_encoded_keys': [], + 'sensitive_keys': ['ds/meta_data/some/security-credentials'], + 'v1': { + '_beta_keys': ['subplatform'], + 'availability-zone': 'myaz', + 'availability_zone': 'myaz', + 'cloud-name': 'subclasscloudname', + 'cloud_name': 'subclasscloudname', + 'instance-id': 'iid-datasource', + 'instance_id': 'iid-datasource', + 'local-hostname': 'test-subclass-hostname', + 'local_hostname': 'test-subclass-hostname', + 'platform': 'mytestsubclass', + 'public_ssh_keys': [], + 'region': 'myregion', + 'subplatform': 'unknown'}, + 'ds': { + '_doc': EXPERIMENTAL_TEXT, + 'meta_data': { + 'availability_zone': 'myaz', + 'local-hostname': 'test-subclass-hostname', + 'region': 'myregion', + 'some': {'security-credentials': REDACT_SENSITIVE_VALUE}}} + } + self.assertEqual(expected, redacted) + file_stat = os.stat(json_file) + self.assertEqual(0o644, stat.S_IMODE(file_stat.st_mode)) + + def test_get_data_writes_json_instance_data_sensitive(self): + """ + get_data writes unmodified data to sensitive file as root-readonly. + """ + tmp = self.tmp_dir() + datasource = DataSourceTestSubclassNet( + self.sys_cfg, self.distro, Paths({'run_dir': tmp}), + custom_metadata={ + 'availability_zone': 'myaz', + 'local-hostname': 'test-subclass-hostname', + 'region': 'myregion', + 'some': {'security-credentials': { + 'cred1': 'sekret', 'cred2': 'othersekret'}}}) self.assertEqual( - {'cred1': 'sekret', 'cred2': 'othersekret'}, - redacted['ds']['meta_data']['some']['security-credentials']) + ('security-credentials',), datasource.sensitive_metadata_keys) + datasource.get_data() + sensitive_json_file = self.tmp_path(INSTANCE_JSON_SENSITIVE_FILE, tmp) content = util.load_file(sensitive_json_file) expected = { 'base64_encoded_keys': [], @@ -362,9 +404,10 @@ class TestDataSource(CiTestCase): 'availability_zone': 'myaz', 'local-hostname': 'test-subclass-hostname', 'region': 'myregion', - 'some': {'security-credentials': REDACT_SENSITIVE_VALUE}}} + 'some': { + 'security-credentials': + {'cred1': 'sekret', 'cred2': 'othersekret'}}}} } - self.maxDiff = None self.assertEqual(expected, util.load_json(content)) file_stat = os.stat(sensitive_json_file) self.assertEqual(0o600, stat.S_IMODE(file_stat.st_mode)) |