Better ssh and x509 keys extraction
For ssh keys, try gathering all values found under both "public_keys" and "keys" fields under metadata. For x509 certificate keys, try looking into metadata under both "meta" and "keys" fields and finally userdata if no such information is retrieved earlier. Change-Id: I43345344aa008187787e97d6296abfc181416cf3
This commit is contained in:
parent
effb94ca0e
commit
30bab776b2
@ -62,9 +62,18 @@ class BaseOpenStackService(base.BaseMetadataService):
|
||||
return self._get_meta_data().get('hostname')
|
||||
|
||||
def get_public_keys(self):
|
||||
public_keys = self._get_meta_data().get('public_keys')
|
||||
if public_keys:
|
||||
return public_keys.values()
|
||||
"""Get a list of all unique public keys found among the metadata."""
|
||||
public_keys = []
|
||||
meta_data = self._get_meta_data()
|
||||
public_keys_dict = meta_data.get('public_keys')
|
||||
if public_keys_dict:
|
||||
public_keys = list(public_keys_dict.values())
|
||||
keys = meta_data.get("keys")
|
||||
if keys:
|
||||
for key_dict in keys:
|
||||
if key_dict["type"] == "ssh":
|
||||
public_keys.append(key_dict["data"])
|
||||
return list(set(public_keys))
|
||||
|
||||
def get_network_details(self):
|
||||
network_config = self._get_meta_data().get('network_config')
|
||||
@ -94,35 +103,44 @@ class BaseOpenStackService(base.BaseMetadataService):
|
||||
return password
|
||||
|
||||
def get_client_auth_certs(self):
|
||||
cert_data = None
|
||||
"""Gather all unique certificates found among the metadata.
|
||||
|
||||
If there are no certificates under "meta" or "keys" field,
|
||||
then try looking into user-data for this kind of information.
|
||||
"""
|
||||
certs = []
|
||||
meta_data = self._get_meta_data()
|
||||
meta = meta_data.get('meta')
|
||||
|
||||
meta = meta_data.get("meta")
|
||||
if meta:
|
||||
i = 0
|
||||
cert_data_list = []
|
||||
idx = 0
|
||||
while True:
|
||||
# Chunking is necessary as metadata items can be
|
||||
# max. 255 chars long
|
||||
cert_chunk = meta.get('admin_cert%d' % i)
|
||||
# max. 255 chars long.
|
||||
cert_chunk = meta.get("admin_cert%d" % idx)
|
||||
if not cert_chunk:
|
||||
break
|
||||
if not cert_data:
|
||||
cert_data = cert_chunk
|
||||
else:
|
||||
cert_data += cert_chunk
|
||||
i += 1
|
||||
cert_data_list.append(cert_chunk)
|
||||
idx += 1
|
||||
if cert_data_list:
|
||||
# It's a list of strings for sure.
|
||||
certs.append("".join(cert_data_list))
|
||||
|
||||
if not cert_data:
|
||||
keys = meta_data.get("keys")
|
||||
if keys:
|
||||
for key_dict in keys:
|
||||
if key_dict["type"] == "x509":
|
||||
certs.append(key_dict["data"])
|
||||
|
||||
if not certs:
|
||||
# Look if the user_data contains a PEM certificate
|
||||
try:
|
||||
user_data = self.get_user_data()
|
||||
if user_data.startswith(
|
||||
x509constants.PEM_HEADER.encode()):
|
||||
cert_data = user_data
|
||||
certs.append(user_data)
|
||||
except base.NotExistingMetadataException:
|
||||
LOG.debug("user_data metadata not present")
|
||||
|
||||
if cert_data:
|
||||
return [cert_data]
|
||||
return list(set((cert.strip() for cert in certs)))
|
||||
|
@ -68,9 +68,64 @@ def get_fake_metadata_json(version):
|
||||
"FV3og4Wyz5zipPVh8YpVev6dlg0tRWUrCtZF9"
|
||||
"IODpCTrT3vsPRG3xz7CppR+vGi/1gLXHtJCRj"
|
||||
"frHwkY6cXyhypNmkU99K/wMqSv30vsDwdnsQ1"
|
||||
"q3YhLarMHB Generated by Nova\n",
|
||||
0: "windows"
|
||||
"q3YhLarMHB Generated by Nova\n"
|
||||
},
|
||||
"keys": [
|
||||
{
|
||||
"data":
|
||||
"ssh-rsa "
|
||||
"AAAAB3NzaC1yc2EAAAADAQABAAABA"
|
||||
"QDf7kQHq7zvBod3yIZs0tB/AOOZz5pab7qt/h"
|
||||
"78VF7yi6qTsFdUnQxRue43R/75wa9EEyokgYR"
|
||||
"LKIN+Jq2A5tXNMcK+rNOCzLJFtioAwEl+S6VL"
|
||||
"G9jfkbUv++7zoSMOsanNmEDvG0B79MpyECFCl"
|
||||
"th2DsdE4MQypify35U5ri5Qi7E6PEYAsU65LF"
|
||||
"MG2boeCIB29BEooE6AgPr2DuJeJ+2uw+YScF9"
|
||||
"FV3og4Wyz5zipPVh8YpVev6dlg0tRWUrCtZF9"
|
||||
"IODpCTrT3vsPRG3xz7CppR+vGi/1gLXHtJCRj"
|
||||
"frHwkY6cXyhypNmkU99K/wMqSv30vsDwdnsQ1"
|
||||
"q3YhLarMHB Generated by Nova\n",
|
||||
"type": "ssh",
|
||||
"name": "key"
|
||||
},
|
||||
{
|
||||
"data":
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDNzCCAh+gAwIBAgIJAODgoAY83AxRMA0GCS"
|
||||
"qGSIb3DQEBCwUAMCsxKTAnBgNV\nBAMTIGE3ZD"
|
||||
"g3YTM1NzE1MDQzYzI4NDUwYTMzZGFiYWQwMDk2"
|
||||
"MB4XDTE1MDUxMjE5\nNDEwNVoXDTI1MDUwOTE5"
|
||||
"NDEwNVowKzEpMCcGA1UEAxMgYTdkODdhMzU3MT"
|
||||
"UwNDNj\nMjg0NTBhMzNkYWJhZDAwOTYwggEiMA"
|
||||
"0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\nAQ"
|
||||
"DAbRN9IRO0vEj6lgh5ZBAdpMR8mDymcP5M8uLT"
|
||||
"CqvrFSuv2yB+rei3fJ7Rw4Tv\nHX/aKCMVjqAO"
|
||||
"T3CwsO9UA+Q2BmbkCi/e8VpzHN8m8VwkyBLXNn"
|
||||
"4ed6e+G5WOPVXH\n76RajfRkDq+WCo330SiBWt"
|
||||
"QBsC0AP8l1M57XYxtowh/EweJDZ5bYIogPOnrP"
|
||||
"XRSl\nylDKiJuAs74fOiDITdeXCGeiPTy2VFCi"
|
||||
"LUV7DLpCRUV89tEpFlNVlD6yTmnE/Mrh\nA49s"
|
||||
"m9PUMY1cI8Bl5f5B/CBQa+5lEQT72HMOuumFrX"
|
||||
"MOD4jQIcNyRl4LKdam1wwA\nESu0s7Cz5LxvJc"
|
||||
"d4EgUxwYrHAgMBAAGjXjBcMBMGA1UdJQQMMAoG"
|
||||
"CCsGAQUFBwMC\nMEUGA1UdEQQ+MDygOgYKKwYB"
|
||||
"BAGCNxQCA6AsDCphN2Q4N2EzNTcxNTA0M2MyOD"
|
||||
"Q1\nMGEzM2RhYmFkMDA5NkBsb2NhbGhvc3QwDQ"
|
||||
"YJKoZIhvcNAQELBQADggEBABpTP8mg\nOHl+Jp"
|
||||
"3wcBVz5sdFUmPRCGJgPaG/rUgAHuC1UNNP3Oy0"
|
||||
"VlDOIc3Yv0Wt3kLa081N\nUy7NIQjQAN29Pq3c"
|
||||
"1Jsq0ucpzEroIBdwacCkB51lZ5CtzwlztK2KZ3"
|
||||
"gWJVpraQwn\nt9ZZ2w+eKKt332+uXFVqNgkBjN"
|
||||
"3LHeehFv1Vd0HQYPkuwWIrf7O0gpZP9MD3+GnZ"
|
||||
"\nEMvBxOV5yFPbPFQSWX50YHijtEkKbXb/liEA"
|
||||
"RccxZwl1aC2+IfaSrMh3JqWF/AQf\nlVtJYgGw"
|
||||
"ixt/OUsA+oA5u6LuPSJhwFnrAN8UWrrOLlswcl"
|
||||
"jQ2mfTambZp43AomqJ\n6N07zSahNAf/UqI=\n"
|
||||
"-----END CERTIFICATE-----\n",
|
||||
"type": "x509",
|
||||
"name": "cert"
|
||||
}
|
||||
],
|
||||
"network_config": {
|
||||
"content_path": "network",
|
||||
# This is not actually in the metadata json file,
|
||||
|
@ -43,6 +43,8 @@ class TestBaseOpenStackService(unittest.TestCase):
|
||||
fake_metadata = fake_json_response.get_fake_metadata_json(date)
|
||||
self._fake_network_config = fake_metadata["network_config"]
|
||||
self._fake_content = self._fake_network_config["debian_config"]
|
||||
self._fake_public_keys = fake_metadata["public_keys"]
|
||||
self._fake_keys = fake_metadata["keys"]
|
||||
self._partial_test_get_network_details = functools.partial(
|
||||
self._test_get_network_details,
|
||||
network_config=self._fake_network_config,
|
||||
@ -96,10 +98,16 @@ class TestBaseOpenStackService(unittest.TestCase):
|
||||
@mock.patch(MODPATH +
|
||||
".BaseOpenStackService._get_meta_data")
|
||||
def test_get_public_keys(self, mock_get_meta_data):
|
||||
mock_get_meta_data.return_value.get.side_effect = \
|
||||
[self._fake_public_keys, self._fake_keys]
|
||||
response = self._service.get_public_keys()
|
||||
mock_get_meta_data.assert_called_once_with()
|
||||
mock_get_meta_data().get.assert_called_once_with('public_keys')
|
||||
self.assertEqual(mock_get_meta_data().get().values(), response)
|
||||
mock_get_meta_data.return_value.get.assert_any_call("public_keys")
|
||||
mock_get_meta_data.return_value.get.assert_any_call("keys")
|
||||
values = (list(self._fake_public_keys.values()) +
|
||||
[key["data"] for key in self._fake_keys
|
||||
if key["type"] == "ssh"])
|
||||
self.assertEqual(sorted(list(set(values))), sorted(response))
|
||||
|
||||
@mock.patch(MODPATH +
|
||||
".BaseOpenStackService._get_meta_data")
|
||||
@ -135,18 +143,30 @@ class TestBaseOpenStackService(unittest.TestCase):
|
||||
mock_get_user_data.side_effect = [ret_value]
|
||||
response = self._service.get_client_auth_certs()
|
||||
mock_get_meta_data.assert_called_once_with()
|
||||
if 'meta' in meta_data:
|
||||
self.assertEqual([b'fake cert'], response)
|
||||
elif type(ret_value) is str and ret_value.startswith(
|
||||
x509constants.PEM_HEADER):
|
||||
if isinstance(ret_value, bytes) and ret_value.startswith(
|
||||
x509constants.PEM_HEADER.encode()):
|
||||
mock_get_user_data.assert_called_once_with()
|
||||
self.assertEqual([ret_value], response)
|
||||
elif ret_value is base.NotExistingMetadataException:
|
||||
self.assertIsNone(response)
|
||||
self.assertFalse(response)
|
||||
else:
|
||||
expected = []
|
||||
expectation = {
|
||||
"meta": 'fake cert',
|
||||
"keys": [key["data"].strip() for key in self._fake_keys
|
||||
if key["type"] == "x509"]
|
||||
}
|
||||
for field, value in expectation.items():
|
||||
if field in meta_data:
|
||||
expected.extend(value if isinstance(value, list)
|
||||
else [value])
|
||||
self.assertEqual(sorted(list(set(expected))), sorted(response))
|
||||
|
||||
def test_get_client_auth_certs(self):
|
||||
self._test_get_client_auth_certs(
|
||||
meta_data={'meta': {'admin_cert0': b'fake cert'}})
|
||||
meta_data={'meta': {'admin_cert0': 'fake ',
|
||||
'admin_cert1': 'cert'},
|
||||
"keys": self._fake_keys})
|
||||
|
||||
def test_get_client_auth_certs_no_cert_data(self):
|
||||
self._test_get_client_auth_certs(
|
||||
|
Loading…
x
Reference in New Issue
Block a user