summaryrefslogtreecommitdiff
path: root/cloudinit
diff options
context:
space:
mode:
authorChad Smith <chad.smith@canonical.com>2020-03-04 15:19:43 -0700
committerGitHub <noreply@github.com>2020-03-04 15:19:43 -0700
commitfa639704f67539d9c1d8668383f755cb0213fd4a (patch)
tree04dfb98f4a5132b5ba84f7d96836e584aa03f5a6 /cloudinit
parent1d2dfc5d879dc905f440697c2b805c9485dda821 (diff)
downloadvyos-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__.py8
-rw-r--r--cloudinit/sources/tests/test_init.py57
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))