|
|
936480 |
From 2428320b2157a0fcc0f35bea12584286ebd02aab Mon Sep 17 00:00:00 2001
|
|
|
936480 |
From: Eduardo Otubo <otubo@redhat.com>
|
|
|
936480 |
Date: Wed, 15 May 2019 12:15:25 +0200
|
|
|
936480 |
Subject: [PATCH 1/5] Azure: Ensure platform random_seed is always serializable
|
|
|
936480 |
as JSON.
|
|
|
936480 |
|
|
|
936480 |
RH-Author: Eduardo Otubo <otubo@redhat.com>
|
|
|
936480 |
Message-id: <20190515121529.11191-2-otubo@redhat.com>
|
|
|
936480 |
Patchwork-id: 87881
|
|
|
936480 |
O-Subject: [rhel-7 cloud-init PATCHv2 1/5] Azure: Ensure platform random_seed is always serializable as JSON.
|
|
|
936480 |
Bugzilla: 1687565
|
|
|
936480 |
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
|
|
936480 |
RH-Acked-by: Mohammed Gamal <mgamal@redhat.com>
|
|
|
936480 |
|
|
|
936480 |
From: "Jason Zions (MSFT)" <jasonzio@microsoft.com>
|
|
|
936480 |
|
|
|
936480 |
BZ: 1687565
|
|
|
936480 |
BRANCH: rhel7/master-18.5
|
|
|
936480 |
UPSTREAM: 0dc3a77f
|
|
|
936480 |
BREW: 21696239
|
|
|
936480 |
|
|
|
936480 |
commit 0dc3a77f41f4544e4cb5a41637af7693410d4cdf
|
|
|
936480 |
Author: Jason Zions (MSFT) <jasonzio@microsoft.com>
|
|
|
936480 |
Date: Tue Mar 26 18:53:50 2019 +0000
|
|
|
936480 |
|
|
|
936480 |
Azure: Ensure platform random_seed is always serializable as JSON.
|
|
|
936480 |
|
|
|
936480 |
The Azure platform surfaces random bytes into /sys via Hyper-V.
|
|
|
936480 |
Python 2.7 json.dump() raises an exception if asked to convert
|
|
|
936480 |
a str with non-character content, and python 3.0 json.dump()
|
|
|
936480 |
won't serialize a "bytes" value. As a result, c-i instance
|
|
|
936480 |
data is often not written by Azure, making reboots slower (c-i
|
|
|
936480 |
has to repeat work).
|
|
|
936480 |
|
|
|
936480 |
The random data is base64-encoded and then decoded into a string
|
|
|
936480 |
(str or unicode depending on the version of Python in use). The
|
|
|
936480 |
base64 string has just as many bits of entropy, so we're not
|
|
|
936480 |
throwing away useful "information", but we can be certain
|
|
|
936480 |
json.dump() will correctly serialize the bits.
|
|
|
936480 |
|
|
|
936480 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
936480 |
|
|
|
936480 |
Conflicts:
|
|
|
936480 |
tests/unittests/test_datasource/test_azure.py
|
|
|
936480 |
Skipped the commit edf052c as it removes support for python-2.6
|
|
|
936480 |
|
|
|
936480 |
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
|
|
936480 |
---
|
|
|
936480 |
cloudinit/sources/DataSourceAzure.py | 24 +++++++++++++++++++-----
|
|
|
936480 |
tests/data/azure/non_unicode_random_string | 1 +
|
|
|
936480 |
tests/unittests/test_datasource/test_azure.py | 24 ++++++++++++++++++++++--
|
|
|
936480 |
3 files changed, 42 insertions(+), 7 deletions(-)
|
|
|
936480 |
create mode 100644 tests/data/azure/non_unicode_random_string
|
|
|
936480 |
|
|
|
936480 |
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
|
|
|
936480 |
index 2062ca5..a768b2c 100644
|
|
|
936480 |
--- a/cloudinit/sources/DataSourceAzure.py
|
|
|
936480 |
+++ b/cloudinit/sources/DataSourceAzure.py
|
|
|
936480 |
@@ -54,6 +54,7 @@ REPROVISION_MARKER_FILE = "/var/lib/cloud/data/poll_imds"
|
|
|
936480 |
REPORTED_READY_MARKER_FILE = "/var/lib/cloud/data/reported_ready"
|
|
|
936480 |
AGENT_SEED_DIR = '/var/lib/waagent'
|
|
|
936480 |
IMDS_URL = "http://169.254.169.254/metadata/"
|
|
|
936480 |
+PLATFORM_ENTROPY_SOURCE = "/sys/firmware/acpi/tables/OEM0"
|
|
|
936480 |
|
|
|
936480 |
# List of static scripts and network config artifacts created by
|
|
|
936480 |
# stock ubuntu suported images.
|
|
|
936480 |
@@ -195,6 +196,8 @@ if util.is_FreeBSD():
|
|
|
936480 |
RESOURCE_DISK_PATH = "/dev/" + res_disk
|
|
|
936480 |
else:
|
|
|
936480 |
LOG.debug("resource disk is None")
|
|
|
936480 |
+ # TODO Find where platform entropy data is surfaced
|
|
|
936480 |
+ PLATFORM_ENTROPY_SOURCE = None
|
|
|
936480 |
|
|
|
936480 |
BUILTIN_DS_CONFIG = {
|
|
|
936480 |
'agent_command': AGENT_START_BUILTIN,
|
|
|
936480 |
@@ -1100,16 +1103,27 @@ def _check_freebsd_cdrom(cdrom_dev):
|
|
|
936480 |
return False
|
|
|
936480 |
|
|
|
936480 |
|
|
|
936480 |
-def _get_random_seed():
|
|
|
936480 |
+def _get_random_seed(source=PLATFORM_ENTROPY_SOURCE):
|
|
|
936480 |
"""Return content random seed file if available, otherwise,
|
|
|
936480 |
return None."""
|
|
|
936480 |
# azure / hyper-v provides random data here
|
|
|
936480 |
- # TODO. find the seed on FreeBSD platform
|
|
|
936480 |
# now update ds_cfg to reflect contents pass in config
|
|
|
936480 |
- if util.is_FreeBSD():
|
|
|
936480 |
+ if source is None:
|
|
|
936480 |
return None
|
|
|
936480 |
- return util.load_file("/sys/firmware/acpi/tables/OEM0",
|
|
|
936480 |
- quiet=True, decode=False)
|
|
|
936480 |
+ seed = util.load_file(source, quiet=True, decode=False)
|
|
|
936480 |
+
|
|
|
936480 |
+ # The seed generally contains non-Unicode characters. load_file puts
|
|
|
936480 |
+ # them into a str (in python 2) or bytes (in python 3). In python 2,
|
|
|
936480 |
+ # bad octets in a str cause util.json_dumps() to throw an exception. In
|
|
|
936480 |
+ # python 3, bytes is a non-serializable type, and the handler load_file
|
|
|
936480 |
+ # uses applies b64 encoding *again* to handle it. The simplest solution
|
|
|
936480 |
+ # is to just b64encode the data and then decode it to a serializable
|
|
|
936480 |
+ # string. Same number of bits of entropy, just with 25% more zeroes.
|
|
|
936480 |
+ # There's no need to undo this base64-encoding when the random seed is
|
|
|
936480 |
+ # actually used in cc_seed_random.py.
|
|
|
936480 |
+ seed = base64.b64encode(seed).decode()
|
|
|
936480 |
+
|
|
|
936480 |
+ return seed
|
|
|
936480 |
|
|
|
936480 |
|
|
|
936480 |
def list_possible_azure_ds_devs():
|
|
|
936480 |
diff --git a/tests/data/azure/non_unicode_random_string b/tests/data/azure/non_unicode_random_string
|
|
|
936480 |
new file mode 100644
|
|
|
936480 |
index 0000000..b9ecefb
|
|
|
936480 |
--- /dev/null
|
|
|
936480 |
+++ b/tests/data/azure/non_unicode_random_string
|
|
|
936480 |
@@ -0,0 +1 @@
|
|
|
936480 |
+OEM0d\x00\x00\x00\x01\x80VRTUALMICROSFT\x02\x17\x00\x06MSFT\x97\x00\x00\x00C\xb4{V\xf4X%\x061x\x90\x1c\xfen\x86\xbf~\xf5\x8c\x94&\x88\xed\x84\xf9B\xbd\xd3\xf1\xdb\xee:\xd9\x0fc\x0e\x83(\xbd\xe3'\xfc\x85,\xdf\xf4\x13\x99N\xc5\xf3Y\x1e\xe3\x0b\xa4H\x08J\xb9\xdcdb$
|
|
|
936480 |
\ No newline at end of file
|
|
|
936480 |
diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py
|
|
|
936480 |
index 417d86a..eacf225 100644
|
|
|
936480 |
--- a/tests/unittests/test_datasource/test_azure.py
|
|
|
936480 |
+++ b/tests/unittests/test_datasource/test_azure.py
|
|
|
936480 |
@@ -7,11 +7,11 @@ from cloudinit.sources import (
|
|
|
936480 |
UNSET, DataSourceAzure as dsaz, InvalidMetaDataException)
|
|
|
936480 |
from cloudinit.util import (b64e, decode_binary, load_file, write_file,
|
|
|
936480 |
find_freebsd_part, get_path_dev_freebsd,
|
|
|
936480 |
- MountFailedError)
|
|
|
936480 |
+ MountFailedError, json_dumps, load_json)
|
|
|
936480 |
from cloudinit.version import version_string as vs
|
|
|
936480 |
from cloudinit.tests.helpers import (
|
|
|
936480 |
HttprettyTestCase, CiTestCase, populate_dir, mock, wrap_and_call,
|
|
|
936480 |
- ExitStack, PY26, SkipTest)
|
|
|
936480 |
+ ExitStack, PY26, SkipTest, resourceLocation)
|
|
|
936480 |
|
|
|
936480 |
import crypt
|
|
|
936480 |
import httpretty
|
|
|
936480 |
@@ -1924,4 +1924,24 @@ class TestWBIsPlatformViable(CiTestCase):
|
|
|
936480 |
self.logs.getvalue())
|
|
|
936480 |
|
|
|
936480 |
|
|
|
936480 |
+class TestRandomSeed(CiTestCase):
|
|
|
936480 |
+ """Test proper handling of random_seed"""
|
|
|
936480 |
+
|
|
|
936480 |
+ def test_non_ascii_seed_is_serializable(self):
|
|
|
936480 |
+ """Pass if a random string from the Azure infrastructure which
|
|
|
936480 |
+ contains at least one non-Unicode character can be converted to/from
|
|
|
936480 |
+ JSON without alteration and without throwing an exception.
|
|
|
936480 |
+ """
|
|
|
936480 |
+ path = resourceLocation("azure/non_unicode_random_string")
|
|
|
936480 |
+ result = dsaz._get_random_seed(path)
|
|
|
936480 |
+
|
|
|
936480 |
+ obj = {'seed': result}
|
|
|
936480 |
+ try:
|
|
|
936480 |
+ serialized = json_dumps(obj)
|
|
|
936480 |
+ deserialized = load_json(serialized)
|
|
|
936480 |
+ except UnicodeDecodeError:
|
|
|
936480 |
+ self.fail("Non-serializable random seed returned")
|
|
|
936480 |
+
|
|
|
936480 |
+ self.assertEqual(deserialized['seed'], result)
|
|
|
936480 |
+
|
|
|
936480 |
# vi: ts=4 expandtab
|
|
|
936480 |
--
|
|
|
936480 |
1.8.3.1
|
|
|
936480 |
|