Merge ~jasonzio/cloud-init:fingerprint into cloud-init:master
- Git
- lp:~jasonzio/cloud-init
- fingerprint
- Merge into master
Status: | Merged |
---|---|
Approved by: | Chad Smith |
Approved revision: | 2009ec145e03122794756406b3944665a1c643bf |
Merge reported by: | Server Team CI bot |
Merged at revision: | not available |
Proposed branch: | ~jasonzio/cloud-init:fingerprint |
Merge into: | cloud-init:master |
Diff against target: |
516 lines (+322/-41) 7 files modified
cloudinit/sources/DataSourceAzure.py (+9/-4) cloudinit/sources/helpers/azure.py (+78/-31) tests/data/azure/parse_certificates_fingerprints (+4/-0) tests/data/azure/parse_certificates_pem (+152/-0) tests/data/azure/pubkey_extract_cert (+13/-0) tests/data/azure/pubkey_extract_ssh_key (+1/-0) tests/unittests/test_datasource/test_azure_helper.py (+65/-6) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chad Smith | Approve | ||
Server Team CI bot | continuous-integration | Approve | |
Ryan Harper | Needs Fixing | ||
Review via email:
|
Commit message
azure: Filter list of ssh keys pulled from fabric
The Azure data source is expected to expose a list of
ssh keys for the user-to-
metadata. When configured to use the __builtin__ agent
this list is built by the WALinuxAgentShim. The shim
retrieves the full set of certificates and public keys
exposed to the VM from the wireserver, extracts any
ssh keys it can, and returns that list.
This fix reduces that list of ssh keys to just the
ones whose fingerprints appear in the "administrative
user" section of the ovf-env.xml file. The Azure
control plane exposes other ssh keys to the VM for
other reasons, but those should not be added to the
authorized_keys file for the provisioned user.
Description of the change
This addresses a bug filed on 2019-01-10 titled
"additional key added to ssh authorized_keys on azure"
All I have is a fuzzy screen shot of the
marked-as-private bug so I can't read the bug number.
Steps to reproduce the problem (and thus how to test
this fix works) are given in that bug.

Server Team CI bot (server-team-bot) wrote : | # |
- 8170777... by "Jason Zions (MSFT)" <email address hidden>
-
Fix pycodestyle issues

Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:8170777c3a3
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
- d2cf5ab... by "Jason Zions (MSFT)" <email address hidden>
-
Redact sample Certificates data
- 03f8214... by "Jason Zions (MSFT)" <email address hidden>
-
Address pycodestyle again

Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:d2cf5ab9ef8
https:/
Executed test runs:
SUCCESS: Checkout
SUCCESS: Unit & Style Tests
FAILED: Ubuntu LTS: Build
Click here to trigger a rebuild:
https:/

Jason Zions (jasonzio) wrote : | # |
> FAILED: Continuous integration, rev:d2cf5ab9ef8
> https:/
> Executed test runs:
> SUCCESS: Checkout
> SUCCESS: Unit & Style Tests
> FAILED: Ubuntu LTS: Build
>
> Click here to trigger a rebuild:
> https:/
This appears to be a deficiency in the container within which the "Ubuntu LTS: Build" phase is performed; the ssh-keygen command is missing. The Azure data source in cloud-init has relied on this command for quite some time; there were just no tests that actually ran the command. This merge adds several tests that confirm the code uses that command correctly to get the desired results.

Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:03f821421e6
https:/
Executed test runs:
SUCCESS: Checkout
SUCCESS: Unit & Style Tests
FAILED: Ubuntu LTS: Build
Click here to trigger a rebuild:
https:/

Ryan Harper (raharper) wrote : | # |
I've added a few comments in-line.

Chad Smith (chad.smith) wrote : | # |
Thanks for the branch Jason,
I was starting to take a cut at that mock to try to lift some of that work off your shoulders but only got a bit through the branch. Wanted to send this your way by way of informing what we could to to avoid leaking calls onto the underlying test system.
See what you think. Thanks
https:/

Jason Zions (jasonzio) wrote : | # |
Thanks for the general technique you like to see; I'll add that to the mental toolkit.
I wrote raharper separately about this issue; he suggested that cloud_test was the right environment for these specific tests. My goal with these unit tests was to validate the action of taking a certificate generated by the Azure control plane and extract from it a public key and fingerprint, and then use that public key to generate a matching SSH key. That validation requires using a real cert and comparing the actual results to the expected fingerprint and ssh key. Mocking the results that come back from the openssl tools doesn't achieve the goal.
Do the tests intended for cloud_test live in a separate location from the unittests, or are they marked or flagged so as to run only in that environment?
To move forward expeditiously with this merge, though, the fastest approach is for me to either disable the tests or delete them. There's no point in mocking out the subp call; there are other tests that do that.
Jason
_______
From: <email address hidden> <email address hidden> on behalf of Chad Smith <email address hidden>
Sent: Thursday, February 21, 2019 10:03
To: <email address hidden>
Subject: Re: [Merge] ~jasonzio/
Thanks for the branch Jason,
I was starting to take a cut at that mock to try to lift some of that work off your shoulders but only got a bit through the branch. Wanted to send this your way by way of informing what we could to to avoid leaking calls onto the underlying test system.
See what you think. Thanks
https:/
--
https:/
You are the owner of ~jasonzio/

Chad Smith (chad.smith) wrote : | # |
Thanks for the response Jason,
> Do the tests intended for cloud_test live in a separate location from the unittests, or are they marked or flagged so as to run only in that environment?
cloud-init/
It feels like you might be able to create an integration test that exercises some of this logic directly by adding an integration test under tests/cloud_
You'd need a yaml file which can feed #cloud-config and collect_scripts directives into an instance under test and use collect_scripts to grab any response content you expected to see when processing certs with azure_helper.
Additionally you could limit that integration test to only run on a specific platform by raising a SkipTest from the python test module for your specific test case.
if self.platform != 'lxd':
raise SkipTest(
> To move forward expeditiously with this merge, though, the fastest approach is for me to either disable the tests or delete them. There's no point in mocking out the subp call; there are other tests that do that.
I'd agree that integration tests probably have more value here than the mocked subp calls, but there is still value in exercising some of the interfaces called between your methods and to validate the contained logic. I'm all for simplifying or reducing what your unittests are asserting. If you are able to put an integration test together, I'd wouldn't also be less concerned your unittest coverage.
Cloud-init's unittests are run not just for continuous integration, but also during package builds in restricted environments which do not come with some runtime dependencies like openssl etc. On the other hand, our integration tests are run on "complete" systems across a variety of platforms (instead of just our build/CI environment) and exercise those external dependencies directly on a variety of platforms and distros.

Jason Zions (jasonzio) wrote : | # |
I added other tests that exercise the interfaces between the methods; the tests that actually try to use openssl go beyond them. I'll disable these tests for now and, in a future merge, move them into cloud_test where they can do their thing. I have an objective for the first half of 2019 to improve the cloud-meets-distro testing of cloud-init, so it'll be easy to get the time I need to do it right.
Thanks for all the explanation. I don't suppose there's a doc anyplace that I was supposed to read that explained this stuff; although I'd be embarrassed at jumping in without doing the reading, I'd certainly go back and read it now.
On a related thought: would it be acceptable to pivot to using pyOpenSSL or even pyca/cryptography as a replacement for subp() invocation of command line tools? Not in this merge, but some time in the next few months?
Jason
-----Original Message-----
From: <email address hidden> <email address hidden> On Behalf Of Chad Smith
Sent: Thursday, February 21, 2019 1:42 PM
To: <email address hidden>
Subject: Re: [Merge] ~jasonzio/
Thanks for the response Jason,
> Do the tests intended for cloud_test live in a separate location from the unittests, or are they marked or flagged so as to run only in that environment?
cloud-init/
It feels like you might be able to create an integration test that exercises some of this logic directly by adding an integration test under tests/cloud_
You'd need a yaml file which can feed #cloud-config and collect_scripts directives into an instance under test and use collect_scripts to grab any response content you expected to see when processing certs with azure_helper.
Additionally you could limit that integration test to only run on a specific platform by raising a SkipTest from the python test module for your specific test case.
if self.platform != 'lxd':
raise SkipTest(
> To move forward expeditiously with this merge, though, the fastest approach is for me to either disable the tests or delete them. There's no point in mocking out the subp call; there are other tests that do that.
I'd agree that integration tests probably have more value here than the mocked subp calls, but there is still value in exercising some of the interfaces called between your methods and to...
- 8bf9c9c... by "Jason Zions (MSFT)" <email address hidden>
-
Disable tests that validate openssl cmds

Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:8bf9c9c9bef
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
- b2a0e63... by "Jason Zions (MSFT)" <email address hidden>
-
Extract test data into raw data files
- cea6c04... by "Jason Zions (MSFT)" <email address hidden>
-
Don't annotate to skip tests, use raise instead

Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:b2a0e6312de
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/

Jason Zions (jasonzio) wrote : | # |
I think this addresses your feedback.

Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:cea6c04fcd9
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
- 0c13e35... by "Jason Zions (MSFT)" <email address hidden>
-
Use proper decorator to skip tests

Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:0c13e353ff1
https:/
Executed test runs:
SUCCESS: Checkout
SUCCESS: Unit & Style Tests
SUCCESS: Ubuntu LTS: Build
SUCCESS: Ubuntu LTS: Integration
IN_PROGRESS: Declarative: Post Actions
Click here to trigger a rebuild:
https:/
- 2009ec1... by "Jason Zions (MSFT)" <email address hidden>
-
Make get_metadata_
from_fabric mock return dict with array

Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:2009ec145e0
https:/
Executed test runs:
SUCCESS: Checkout
SUCCESS: Unit & Style Tests
SUCCESS: Ubuntu LTS: Build
SUCCESS: Ubuntu LTS: Integration
IN_PROGRESS: Declarative: Post Actions
Click here to trigger a rebuild:
https:/

Chad Smith (chad.smith) wrote : | # |
Thanks so much for this rework Jason. From the looks of things it looks like you are properly filtering keys for the user. Let's look more at the integration tests in the future.
I ran a couple of upgrade tests on azure to validate instances that have been deployed without regression or adding unexpected keys.

Jason Zions (jasonzio) wrote : | # |
Greatly appreciate the additional testing in Azure. We beat it up pretty thoroughly before I submitted, but every extra set of eyes is a big plus.
I'll definitely work with you on integration testing in the coming weeks.
_______
From: <email address hidden> <email address hidden> on behalf of Chad Smith <email address hidden>
Sent: Friday, February 22, 2019 02:01
To: <email address hidden>
Subject: Re: [Merge] ~jasonzio/
Review: Approve
Thanks so much for this rework Jason. From the looks of things it looks like you are properly filtering keys for the user. Let's look more at the integration tests in the future.
I ran a couple of upgrade tests on azure to validate instances that have been deployed without regression or adding unexpected keys.
--
https:/
You are the owner of ~jasonzio/
Preview Diff
1 | diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py |
2 | index a4f998b..eccbee5 100644 |
3 | --- a/cloudinit/sources/DataSourceAzure.py |
4 | +++ b/cloudinit/sources/DataSourceAzure.py |
5 | @@ -627,9 +627,11 @@ class DataSourceAzure(sources.DataSource): |
6 | if self.ds_cfg['agent_command'] == AGENT_START_BUILTIN: |
7 | self.bounce_network_with_azure_hostname() |
8 | |
9 | + pubkey_info = self.cfg.get('_pubkeys', None) |
10 | metadata_func = partial(get_metadata_from_fabric, |
11 | fallback_lease_file=self. |
12 | - dhclient_lease_file) |
13 | + dhclient_lease_file, |
14 | + pubkey_info=pubkey_info) |
15 | else: |
16 | metadata_func = self.get_metadata_from_agent |
17 | |
18 | @@ -642,6 +644,7 @@ class DataSourceAzure(sources.DataSource): |
19 | "Error communicating with Azure fabric; You may experience." |
20 | "connectivity issues.", exc_info=True) |
21 | return False |
22 | + |
23 | util.del_file(REPORTED_READY_MARKER_FILE) |
24 | util.del_file(REPROVISION_MARKER_FILE) |
25 | return fabric_data |
26 | @@ -909,13 +912,15 @@ def find_child(node, filter_func): |
27 | def load_azure_ovf_pubkeys(sshnode): |
28 | # This parses a 'SSH' node formatted like below, and returns |
29 | # an array of dicts. |
30 | - # [{'fp': '6BE7A7C3C8A8F4B123CCA5D0C2F1BE4CA7B63ED7', |
31 | - # 'path': 'where/to/go'}] |
32 | + # [{'fingerprint': '6BE7A7C3C8A8F4B123CCA5D0C2F1BE4CA7B63ED7', |
33 | + # 'path': '/where/to/go'}] |
34 | # |
35 | # <SSH><PublicKeys> |
36 | - # <PublicKey><Fingerprint>ABC</FingerPrint><Path>/ABC</Path> |
37 | + # <PublicKey><Fingerprint>ABC</FingerPrint><Path>/x/y/z</Path> |
38 | # ... |
39 | # </PublicKeys></SSH> |
40 | + # Under some circumstances, there may be a <Value> element along with the |
41 | + # Fingerprint and Path. Pass those along if they appear. |
42 | results = find_child(sshnode, lambda n: n.localName == "PublicKeys") |
43 | if len(results) == 0: |
44 | return [] |
45 | diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py |
46 | index e5696b1..2829dd2 100644 |
47 | --- a/cloudinit/sources/helpers/azure.py |
48 | +++ b/cloudinit/sources/helpers/azure.py |
49 | @@ -138,9 +138,36 @@ class OpenSSLManager(object): |
50 | self.certificate = certificate |
51 | LOG.debug('New certificate generated.') |
52 | |
53 | - def parse_certificates(self, certificates_xml): |
54 | - tag = ElementTree.fromstring(certificates_xml).find( |
55 | - './/Data') |
56 | + @staticmethod |
57 | + def _run_x509_action(action, cert): |
58 | + cmd = ['openssl', 'x509', '-noout', action] |
59 | + result, _ = util.subp(cmd, data=cert) |
60 | + return result |
61 | + |
62 | + def _get_ssh_key_from_cert(self, certificate): |
63 | + pub_key = self._run_x509_action('-pubkey', certificate) |
64 | + keygen_cmd = ['ssh-keygen', '-i', '-m', 'PKCS8', '-f', '/dev/stdin'] |
65 | + ssh_key, _ = util.subp(keygen_cmd, data=pub_key) |
66 | + return ssh_key |
67 | + |
68 | + def _get_fingerprint_from_cert(self, certificate): |
69 | + """openssl x509 formats fingerprints as so: |
70 | + 'SHA1 Fingerprint=07:3E:19:D1:4D:1C:79:92:24:C6:A0:FD:8D:DA:\ |
71 | + B6:A8:BF:27:D4:73\n' |
72 | + |
73 | + Azure control plane passes that fingerprint as so: |
74 | + '073E19D14D1C799224C6A0FD8DDAB6A8BF27D473' |
75 | + """ |
76 | + raw_fp = self._run_x509_action('-fingerprint', certificate) |
77 | + eq = raw_fp.find('=') |
78 | + octets = raw_fp[eq+1:-1].split(':') |
79 | + return ''.join(octets) |
80 | + |
81 | + def _decrypt_certs_from_xml(self, certificates_xml): |
82 | + """Decrypt the certificates XML document using the our private key; |
83 | + return the list of certs and private keys contained in the doc. |
84 | + """ |
85 | + tag = ElementTree.fromstring(certificates_xml).find('.//Data') |
86 | certificates_content = tag.text |
87 | lines = [ |
88 | b'MIME-Version: 1.0', |
89 | @@ -151,32 +178,30 @@ class OpenSSLManager(object): |
90 | certificates_content.encode('utf-8'), |
91 | ] |
92 | with cd(self.tmpdir): |
93 | - with open('Certificates.p7m', 'wb') as f: |
94 | - f.write(b'\n'.join(lines)) |
95 | out, _ = util.subp( |
96 | - 'openssl cms -decrypt -in Certificates.p7m -inkey' |
97 | + 'openssl cms -decrypt -in /dev/stdin -inkey' |
98 | ' {private_key} -recip {certificate} | openssl pkcs12 -nodes' |
99 | ' -password pass:'.format(**self.certificate_names), |
100 | - shell=True) |
101 | - private_keys, certificates = [], [] |
102 | + shell=True, data=b'\n'.join(lines)) |
103 | + return out |
104 | + |
105 | + def parse_certificates(self, certificates_xml): |
106 | + """Given the Certificates XML document, return a dictionary of |
107 | + fingerprints and associated SSH keys derived from the certs.""" |
108 | + out = self._decrypt_certs_from_xml(certificates_xml) |
109 | current = [] |
110 | + keys = {} |
111 | for line in out.splitlines(): |
112 | current.append(line) |
113 | if re.match(r'[-]+END .*?KEY[-]+$', line): |
114 | - private_keys.append('\n'.join(current)) |
115 | + # ignore private_keys |
116 | current = [] |
117 | elif re.match(r'[-]+END .*?CERTIFICATE[-]+$', line): |
118 | - certificates.append('\n'.join(current)) |
119 | + certificate = '\n'.join(current) |
120 | + ssh_key = self._get_ssh_key_from_cert(certificate) |
121 | + fingerprint = self._get_fingerprint_from_cert(certificate) |
122 | + keys[fingerprint] = ssh_key |
123 | current = [] |
124 | - keys = [] |
125 | - for certificate in certificates: |
126 | - with cd(self.tmpdir): |
127 | - public_key, _ = util.subp( |
128 | - 'openssl x509 -noout -pubkey |' |
129 | - 'ssh-keygen -i -m PKCS8 -f /dev/stdin', |
130 | - data=certificate, |
131 | - shell=True) |
132 | - keys.append(public_key) |
133 | return keys |
134 | |
135 | |
136 | @@ -206,7 +231,6 @@ class WALinuxAgentShim(object): |
137 | self.dhcpoptions = dhcp_options |
138 | self._endpoint = None |
139 | self.openssl_manager = None |
140 | - self.values = {} |
141 | self.lease_file = fallback_lease_file |
142 | |
143 | def clean_up(self): |
144 | @@ -328,8 +352,9 @@ class WALinuxAgentShim(object): |
145 | LOG.debug('Azure endpoint found at %s', endpoint_ip_address) |
146 | return endpoint_ip_address |
147 | |
148 | - def register_with_azure_and_fetch_data(self): |
149 | - self.openssl_manager = OpenSSLManager() |
150 | + def register_with_azure_and_fetch_data(self, pubkey_info=None): |
151 | + if self.openssl_manager is None: |
152 | + self.openssl_manager = OpenSSLManager() |
153 | http_client = AzureEndpointHttpClient(self.openssl_manager.certificate) |
154 | LOG.info('Registering with Azure...') |
155 | attempts = 0 |
156 | @@ -347,16 +372,37 @@ class WALinuxAgentShim(object): |
157 | attempts += 1 |
158 | LOG.debug('Successfully fetched GoalState XML.') |
159 | goal_state = GoalState(response.contents, http_client) |
160 | - public_keys = [] |
161 | - if goal_state.certificates_xml is not None: |
162 | + ssh_keys = [] |
163 | + if goal_state.certificates_xml is not None and pubkey_info is not None: |
164 | LOG.debug('Certificate XML found; parsing out public keys.') |
165 | - public_keys = self.openssl_manager.parse_certificates( |
166 | + keys_by_fingerprint = self.openssl_manager.parse_certificates( |
167 | goal_state.certificates_xml) |
168 | - data = { |
169 | - 'public-keys': public_keys, |
170 | - } |
171 | + ssh_keys = self._filter_pubkeys(keys_by_fingerprint, pubkey_info) |
172 | self._report_ready(goal_state, http_client) |
173 | - return data |
174 | + return {'public-keys': ssh_keys} |
175 | + |
176 | + def _filter_pubkeys(self, keys_by_fingerprint, pubkey_info): |
177 | + """cloud-init expects a straightforward array of keys to be dropped |
178 | + into the user's authorized_keys file. Azure control plane exposes |
179 | + multiple public keys to the VM via wireserver. Select just the |
180 | + user's key(s) and return them, ignoring any other certs. |
181 | + """ |
182 | + keys = [] |
183 | + for pubkey in pubkey_info: |
184 | + if 'value' in pubkey and pubkey['value']: |
185 | + keys.append(pubkey['value']) |
186 | + elif 'fingerprint' in pubkey and pubkey['fingerprint']: |
187 | + fingerprint = pubkey['fingerprint'] |
188 | + if fingerprint in keys_by_fingerprint: |
189 | + keys.append(keys_by_fingerprint[fingerprint]) |
190 | + else: |
191 | + LOG.warning("ovf-env.xml specified PublicKey fingerprint " |
192 | + "%s not found in goalstate XML", fingerprint) |
193 | + else: |
194 | + LOG.warning("ovf-env.xml specified PublicKey with neither " |
195 | + "value nor fingerprint: %s", pubkey) |
196 | + |
197 | + return keys |
198 | |
199 | def _report_ready(self, goal_state, http_client): |
200 | LOG.debug('Reporting ready to Azure fabric.') |
201 | @@ -373,11 +419,12 @@ class WALinuxAgentShim(object): |
202 | LOG.info('Reported ready to Azure fabric.') |
203 | |
204 | |
205 | -def get_metadata_from_fabric(fallback_lease_file=None, dhcp_opts=None): |
206 | +def get_metadata_from_fabric(fallback_lease_file=None, dhcp_opts=None, |
207 | + pubkey_info=None): |
208 | shim = WALinuxAgentShim(fallback_lease_file=fallback_lease_file, |
209 | dhcp_options=dhcp_opts) |
210 | try: |
211 | - return shim.register_with_azure_and_fetch_data() |
212 | + return shim.register_with_azure_and_fetch_data(pubkey_info=pubkey_info) |
213 | finally: |
214 | shim.clean_up() |
215 | |
216 | diff --git a/tests/data/azure/parse_certificates_fingerprints b/tests/data/azure/parse_certificates_fingerprints |
217 | new file mode 100644 |
218 | index 0000000..f7293c5 |
219 | --- /dev/null |
220 | +++ b/tests/data/azure/parse_certificates_fingerprints |
221 | @@ -0,0 +1,4 @@ |
222 | +ECEDEB3B8488D31AF3BC4CCED493F64B7D27D7B1 |
223 | +073E19D14D1C799224C6A0FD8DDAB6A8BF27D473 |
224 | +4C16E7FAD6297D74A9B25EB8F0A12808CEBE293E |
225 | +929130695289B450FE45DCD5F6EF0CDE69865867 |
226 | diff --git a/tests/data/azure/parse_certificates_pem b/tests/data/azure/parse_certificates_pem |
227 | new file mode 100644 |
228 | index 0000000..3521ea3 |
229 | --- /dev/null |
230 | +++ b/tests/data/azure/parse_certificates_pem |
231 | @@ -0,0 +1,152 @@ |
232 | +Bag Attributes |
233 | + localKeyID: 01 00 00 00 |
234 | + Microsoft CSP Name: Microsoft Enhanced Cryptographic Provider v1.0 |
235 | +Key Attributes |
236 | + X509v3 Key Usage: 10 |
237 | +-----BEGIN PRIVATE KEY----- |
238 | +MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDlEe5fUqwdrQTP |
239 | +W2oVlGK2f31q/8ULT8KmOTyUvL0RPdJQ69vvHOc5Q2CKg2eviHC2LWhF8WmpnZj6 |
240 | +61RL0GeFGizwvU8Moebw5p3oqdcgoGpHVtxf+mr4QcWF58/Fwez0dA4hcsimVNBz |
241 | +eNpBBUIKNBMTBG+4d6hcQBUAGKUdGRcCGEyTqXLU0MgHjxC9JgVqWJl+X2LcAGj5 |
242 | +7J+tGYGTLzKJmeCeGVNN5ZtJ0T85MYHCKQk1/FElK+Kq5akovXffQHjlnCPcx0NJ |
243 | +47NBjlPaFp2gjnAChn79bT4iCjOFZ9avWpqRpeU517UCnY7djOr3fuod/MSQyh3L |
244 | +Wuem1tWBAgMBAAECggEBAM4ZXQRs6Kjmo95BHGiAEnSqrlgX+dycjcBq3QPh8KZT |
245 | +nifqnf48XhnackENy7tWIjr3DctoUq4mOp8AHt77ijhqfaa4XSg7fwKeK9NLBGC5 |
246 | +lAXNtAey0o2894/sKrd+LMkgphoYIUnuI4LRaGV56potkj/ZDP/GwTcG/R4SDnTn |
247 | +C1Nb05PNTAPQtPZrgPo7TdM6gGsTnFbVrYHQLyg2Sq/osHfF15YohB01esRLCAwb |
248 | +EF8JkRC4hWIZoV7BsyQ39232zAJQGGla7+wKFs3kObwh3VnFkQpT94KZnNiZuEfG |
249 | +x5pW4Pn3gXgNsftscXsaNe/M9mYZqo//Qw7NvUIvAvECgYEA9AVveyK0HOA06fhh |
250 | ++3hUWdvw7Pbrl+e06jO9+bT1RjQMbHKyI60DZyVGuAySN86iChJRoJr5c6xj+iXU |
251 | +cR6BVJDjGH5t1tyiK2aYf6hEpK9/j8Z54UiVQ486zPP0PGfT2TO4lBLK+8AUmoaH |
252 | +gk21ul8QeVCeCJa/o+xEoRFvzcUCgYEA8FCbbvInrUtNY+9eKaUYoNodsgBVjm5X |
253 | +I0YPUL9D4d+1nvupHSV2NVmQl0w1RaJwrNTafrl5LkqjhQbmuWNta6QgfZzSA3LB |
254 | +lWXo1Mm0azKdcD3qMGbvn0Q3zU+yGNEgmB/Yju3/NtgYRG6tc+FCWRbPbiCnZWT8 |
255 | +v3C2Y0XggI0CgYEA2/jCZBgGkTkzue5kNVJlh5OS/aog+pCvL6hxCtarfBuTT3ed |
256 | +Sje+p46cz3DVpmUpATc+Si8py7KNdYQAm/BJ2be6X+woi9Xcgo87zWgcaPCjZzId |
257 | +0I2jsIE/Gl6XvpRCDrxnGWRPgt3GNP4szbPLrDPiH9oie8+Y9eYYf7G+PZkCgYEA |
258 | +nRSzZOPYV4f/QDF4pVQLMykfe/iH9B/fyWjEHg3He19VQmRReIHCMMEoqBziPXAe |
259 | +onpHj8oAkeer1wpZyhhZr6CKtFDLXgGm09bXSC/IRMHC81klORovyzU2HHfZfCtG |
260 | +WOmIDnU2+0xpIGIP8sztJ3qnf97MTJSkOSadsWo9gwkCgYEAh5AQmJQmck88Dff2 |
261 | +qIfJIX8d+BDw47BFJ89OmMFjGV8TNB+JO+AV4Vkodg4hxKpLqTFZTTUFgoYfy5u1 |
262 | +1/BhAjpmCDCrzubCFhx+8VEoM2+2+MmnuQoMAm9+/mD/IidwRaARgXgvEmp7sfdt |
263 | +RyWd+p2lYvFkC/jORQtDMY4uW1o= |
264 | +-----END PRIVATE KEY----- |
265 | +Bag Attributes |
266 | + localKeyID: 02 00 00 00 |
267 | + Microsoft CSP Name: Microsoft Strong Cryptographic Provider |
268 | +Key Attributes |
269 | + X509v3 Key Usage: 10 |
270 | +-----BEGIN PRIVATE KEY----- |
271 | +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDlQhPrZwVQYFV4 |
272 | +FBc0H1iTXYaznMpwZvEITKtXWACzTdguUderEVOkXW3HTi5HvC2rMayt0nqo3zcd |
273 | +x1eGiqdjpZQ/wMrkz9wNEM/nNMsXntEwxk0jCVNKB/jz6vf+BOtrSI01SritAGZW |
274 | +dpKoTUyztT8C2mA3X6D8g3m4Dd07ltnzxaDqAQIU5jBHh3f/Q14tlPNZWUIiqVTC |
275 | +gDxgAe7MDmfs9h3CInTBX1XM5J4UsLTL23/padgeSvP5YF5qr1+0c7Tdftxr2lwA |
276 | +N3rLkisf5EiLAToVyJJlgP/exo2I8DaIKe7DZzD3Y1CrurOpkcMKYu5kM1Htlbua |
277 | +tDkAa2oDAgMBAAECggEAOvdueS9DyiMlCKAeQb1IQosdQOh0l0ma+FgEABC2CWhd |
278 | +0LgjQTBRM6cGO+urcq7/jhdWQ1UuUG4tVn71z7itCi/F/Enhxc2C22d2GhFVpWsn |
279 | +giSXJYpZ/mIjkdVfWNo6FRuRmmHwMys1p0qTOS+8qUJWhSzW75csqJZGgeUrAI61 |
280 | +LBV5F0SGR7dR2xZfy7PeDs9xpD0QivDt5DpsZWPaPvw4QlhdLgw6/YU1h9vtm6ci |
281 | +xLjnPRLZ7JMpcQHO8dUDl6FiEI7yQ11BDm253VQAVMddYRPQABn7SpEF8kD/aZVh |
282 | +2Clvz61Rz80SKjPUthMPLWMCRp7zB0xDMzt3/1i+tQKBgQD6Ar1/oD3eFnRnpi4u |
283 | +n/hdHJtMuXWNfUA4dspNjP6WGOid9sgIeUUdif1XyVJ+afITzvgpWc7nUWIqG2bQ |
284 | +WxJ/4q2rjUdvjNXTy1voVungR2jD5WLQ9DKeaTR0yCliWlx4JgdPG7qGI5MMwsr+ |
285 | +R/PUoUUhGeEX+o/sCSieO3iUrQKBgQDqwBEMvIdhAv/CK2sG3fsKYX8rFT55ZNX3 |
286 | +Tix9DbUGY3wQColNuI8U1nDlxE9U6VOfT9RPqKelBLCgbzB23kdEJnjSlnqlTxrx |
287 | +E+Hkndyf2ckdJAR3XNxoQ6SRLJNBsgoBj/z5tlfZE9/Jc+uh0mYy3e6g6XCVPBcz |
288 | +MgoIc+ofbwKBgQCGQhZ1hR30N+bHCozeaPW9OvGDIE0qcEqeh9xYDRFilXnF6pK9 |
289 | +SjJ9jG7KR8jPLiHb1VebDSl5O1EV/6UU2vNyTc6pw7LLCryBgkGW4aWy1WZDXNnW |
290 | +EG1meGS9GghvUss5kmJ2bxOZmV0Mi0brisQ8OWagQf+JGvtS7BAt+Q3l+QKBgAb9 |
291 | +8YQPmXiqPjPqVyW9Ntz4SnFeEJ5NApJ7IZgX8GxgSjGwHqbR+HEGchZl4ncE/Bii |
292 | +qBA3Vcb0fM5KgYcI19aPzsl28fA6ivLjRLcqfIfGVNcpW3iyq13vpdctHLW4N9QU |
293 | +FdTaOYOds+ysJziKq8CYG6NvUIshXw+HTgUybqbBAoGBAIIOqcmmtgOClAwipA17 |
294 | +dAHsI9Sjk+J0+d4JU6o+5TsmhUfUKIjXf5+xqJkJcQZMEe5GhxcCuYkgFicvh4Hz |
295 | +kv2H/EU35LcJTqC6KTKZOWIbGcn1cqsvwm3GQJffYDiO8fRZSwCaif2J3F2lfH4Y |
296 | +R/fA67HXFSTT+OncdRpY1NOn |
297 | +-----END PRIVATE KEY----- |
298 | +Bag Attributes: <Empty Attributes> |
299 | +subject=/CN=CRP/OU=AzureRT/O=Microsoft Corporation/L=Redmond/ST=WA/C=US |
300 | +issuer=/CN=Root Agency |
301 | +-----BEGIN CERTIFICATE----- |
302 | +MIIB+TCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQDDAtSb290 |
303 | +IEFnZW5jeTAeFw0xOTAyMTUxOTA0MDRaFw0yOTAyMTUxOTE0MDRaMGwxDDAKBgNV |
304 | +BAMMA0NSUDEQMA4GA1UECwwHQXp1cmVSVDEeMBwGA1UECgwVTWljcm9zb2Z0IENv |
305 | +cnBvcmF0aW9uMRAwDgYDVQQHDAdSZWRtb25kMQswCQYDVQQIDAJXQTELMAkGA1UE |
306 | +BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIlPjJXzrRih4C |
307 | +k/XsoI01oqo7IUxH3dA2F7vHGXQoIpKCp8Qe6Z6cFfdD8Uj+s+B1BX6hngwzIwjN |
308 | +jE/23X3SALVzJVWzX4Y/IEjbgsuao6sOyNyB18wIU9YzZkVGj68fmMlUw3LnhPbe |
309 | +eWkufZaJCaLyhQOwlRMbOcn48D6Ys8fccOyXNzpq3rH1OzeQpxS2M8zaJYP4/VZ/ |
310 | +sf6KRpI7bP+QwyFvNKfhcaO9/gj4kMo9lVGjvDU20FW6g8UVNJCV9N4GO6mOcyqo |
311 | +OhuhVfjCNGgW7N1qi0TIVn0/MQM4l4dcT2R7Z/bV9fhMJLjGsy5A4TLAdRrhKUHT |
312 | +bzi9HyDvAgMBAAEwDQYJKoZIhvcNAQEFBQADAQA= |
313 | +-----END CERTIFICATE----- |
314 | +Bag Attributes |
315 | + localKeyID: 01 00 00 00 |
316 | +subject=/C=US/ST=WASHINGTON/L=Seattle/O=Microsoft/OU=Azure/CN=AnhVo/emailAddress=redacted@microsoft.com |
317 | +issuer=/C=US/ST=WASHINGTON/L=Seattle/O=Microsoft/OU=Azure/CN=AnhVo/emailAddress=redacted@microsoft.com |
318 | +-----BEGIN CERTIFICATE----- |
319 | +MIID7TCCAtWgAwIBAgIJALQS3yMg3R41MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD |
320 | +VQQGEwJVUzETMBEGA1UECAwKV0FTSElOR1RPTjEQMA4GA1UEBwwHU2VhdHRsZTES |
321 | +MBAGA1UECgwJTWljcm9zb2Z0MQ4wDAYDVQQLDAVBenVyZTEOMAwGA1UEAwwFQW5o |
322 | +Vm8xIjAgBgkqhkiG9w0BCQEWE2FuaHZvQG1pY3Jvc29mdC5jb20wHhcNMTkwMjE0 |
323 | +MjMxMjQwWhcNMjExMTEwMjMxMjQwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgM |
324 | +CldBU0hJTkdUT04xEDAOBgNVBAcMB1NlYXR0bGUxEjAQBgNVBAoMCU1pY3Jvc29m |
325 | +dDEOMAwGA1UECwwFQXp1cmUxDjAMBgNVBAMMBUFuaFZvMSIwIAYJKoZIhvcNAQkB |
326 | +FhNhbmh2b0BtaWNyb3NvZnQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB |
327 | +CgKCAQEA5RHuX1KsHa0Ez1tqFZRitn99av/FC0/Cpjk8lLy9ET3SUOvb7xznOUNg |
328 | +ioNnr4hwti1oRfFpqZ2Y+utUS9BnhRos8L1PDKHm8Oad6KnXIKBqR1bcX/pq+EHF |
329 | +hefPxcHs9HQOIXLIplTQc3jaQQVCCjQTEwRvuHeoXEAVABilHRkXAhhMk6ly1NDI |
330 | +B48QvSYFaliZfl9i3ABo+eyfrRmBky8yiZngnhlTTeWbSdE/OTGBwikJNfxRJSvi |
331 | +quWpKL1330B45Zwj3MdDSeOzQY5T2hadoI5wAoZ+/W0+IgozhWfWr1qakaXlOde1 |
332 | +Ap2O3Yzq937qHfzEkMody1rnptbVgQIDAQABo1AwTjAdBgNVHQ4EFgQUPvdgLiv3 |
333 | +pAk4r0QTPZU3PFOZJvgwHwYDVR0jBBgwFoAUPvdgLiv3pAk4r0QTPZU3PFOZJvgw |
334 | +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVUHZT+h9+uCPLTEl5IDg |
335 | +kqd9WpzXA7PJd/V+7DeDDTkEd06FIKTWZLfxLVVDjQJnQqubQb//e0zGu1qKbXnX |
336 | +R7xqWabGU4eyPeUFWddmt1OHhxKLU3HbJNJJdL6XKiQtpGGUQt/mqNQ/DEr6hhNF |
337 | +im5I79iA8H/dXA2gyZrj5Rxea4mtsaYO0mfp1NrFtJpAh2Djy4B1lBXBIv4DWG9e |
338 | +mMEwzcLCOZj2cOMA6+mdLMUjYCvIRtnn5MKUHyZX5EmX79wsqMTvVpddlVLB9Kgz |
339 | +Qnvft9+SBWh9+F3ip7BsL6Q4Q9v8eHRbnP0ya7ddlgh64uwf9VOfZZdKCnwqudJP |
340 | +3g== |
341 | +-----END CERTIFICATE----- |
342 | +Bag Attributes |
343 | + localKeyID: 02 00 00 00 |
344 | +subject=/CN=/subscriptions/redacted/resourcegroups/redacted/providers/Microsoft.Compute/virtualMachines/redacted |
345 | +issuer=/CN=Microsoft.ManagedIdentity |
346 | +-----BEGIN CERTIFICATE----- |
347 | +MIIDnTCCAoWgAwIBAgIUB2lauSRccvFkoJybUfIwOUqBN7MwDQYJKoZIhvcNAQEL |
348 | +BQAwJDEiMCAGA1UEAxMZTWljcm9zb2Z0Lk1hbmFnZWRJZGVudGl0eTAeFw0xOTAy |
349 | +MTUxOTA5MDBaFw0xOTA4MTQxOTA5MDBaMIGUMYGRMIGOBgNVBAMTgYYvc3Vic2Ny |
350 | +aXB0aW9ucy8yN2I3NTBjZC1lZDQzLTQyZmQtOTA0NC04ZDc1ZTEyNGFlNTUvcmVz |
351 | +b3VyY2Vncm91cHMvYW5oZXh0cmFzc2gvcHJvdmlkZXJzL01pY3Jvc29mdC5Db21w |
352 | +dXRlL3ZpcnR1YWxNYWNoaW5lcy9hbmh0ZXN0Y2VydDCCASIwDQYJKoZIhvcNAQEB |
353 | +BQADggEPADCCAQoCggEBAOVCE+tnBVBgVXgUFzQfWJNdhrOcynBm8QhMq1dYALNN |
354 | +2C5R16sRU6RdbcdOLke8LasxrK3SeqjfNx3HV4aKp2OllD/AyuTP3A0Qz+c0yxee |
355 | +0TDGTSMJU0oH+PPq9/4E62tIjTVKuK0AZlZ2kqhNTLO1PwLaYDdfoPyDebgN3TuW |
356 | +2fPFoOoBAhTmMEeHd/9DXi2U81lZQiKpVMKAPGAB7swOZ+z2HcIidMFfVczknhSw |
357 | +tMvbf+lp2B5K8/lgXmqvX7RztN1+3GvaXAA3esuSKx/kSIsBOhXIkmWA/97GjYjw |
358 | +Nogp7sNnMPdjUKu6s6mRwwpi7mQzUe2Vu5q0OQBragMCAwEAAaNWMFQwDgYDVR0P |
359 | +AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYD |
360 | +VR0jBBgwFoAUOJvzEsriQWdJBndPrK+Me1bCPjYwDQYJKoZIhvcNAQELBQADggEB |
361 | +AFGP/g8o7Hv/to11M0UqfzJuW/AyH9RZtSRcNQFLZUndwweQ6fap8lFsA4REUdqe |
362 | +7Quqp5JNNY1XzKLWXMPoheIDH1A8FFXdsAroArzlNs9tO3TlIHE8A7HxEVZEmR4b |
363 | +7ZiixmkQPS2RkjEoV/GM6fheBrzuFn7X5kVZyE6cC5sfcebn8xhk3ZcXI0VmpdT0 |
364 | +jFBsf5IvFCIXXLLhJI4KXc8VMoKFU1jT9na/jyaoGmfwovKj4ib8s2aiXGAp7Y38 |
365 | +UCmY+bJapWom6Piy5Jzi/p/kzMVdJcSa+GqpuFxBoQYEVs2XYVl7cGu/wPM+NToC |
366 | +pkSoWwF1QAnHn0eokR9E1rU= |
367 | +-----END CERTIFICATE----- |
368 | +Bag Attributes: <Empty Attributes> |
369 | +subject=/CN=CRP/OU=AzureRT/O=Microsoft Corporation/L=Redmond/ST=WA/C=US |
370 | +issuer=/CN=Root Agency |
371 | +-----BEGIN CERTIFICATE----- |
372 | +MIIB+TCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQDDAtSb290 |
373 | +IEFnZW5jeTAeFw0xOTAyMTUxOTA0MDRaFw0yOTAyMTUxOTE0MDRaMGwxDDAKBgNV |
374 | +BAMMA0NSUDEQMA4GA1UECwwHQXp1cmVSVDEeMBwGA1UECgwVTWljcm9zb2Z0IENv |
375 | +cnBvcmF0aW9uMRAwDgYDVQQHDAdSZWRtb25kMQswCQYDVQQIDAJXQTELMAkGA1UE |
376 | +BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHU9IDclbKVYVb |
377 | +Yuv0+zViX+wTwlKspslmy/uf3hkWLh7pyzyrq70S7qtSW2EGixUPxZS/R8pOLHoi |
378 | +nlKF9ILgj0gVTCJsSwnWpXRg3rhZwIVoYMHN50BHS1SqVD0lsWNMXmo76LoJcjmW |
379 | +vwIznvj5C/gnhU+K7+c3m7AlCyU2wjwpBAEYj7PQs6l/wTqpEiaqC5NytNBd7qp+ |
380 | +lYYysVrpa1PFL0Nj4MMZARIfjkiJtL9qDhy9YZeJRQ6q/Fhz0kjvkZnfxixfKF4y |
381 | +WzOfhBrAtpF6oOnuYKk3hxjh9KjTTX4/U8zdLojalX09iyHyEjwJKGlGEpzh1aY7 |
382 | +t5btUyvpAgMBAAEwDQYJKoZIhvcNAQEFBQADAQA= |
383 | +-----END CERTIFICATE----- |
384 | diff --git a/tests/data/azure/pubkey_extract_cert b/tests/data/azure/pubkey_extract_cert |
385 | new file mode 100644 |
386 | index 0000000..ce9b852 |
387 | --- /dev/null |
388 | +++ b/tests/data/azure/pubkey_extract_cert |
389 | @@ -0,0 +1,13 @@ |
390 | +-----BEGIN CERTIFICATE----- |
391 | +MIIB+TCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQDDAtSb290 |
392 | +IEFnZW5jeTAeFw0xOTAyMTUxOTA0MDRaFw0yOTAyMTUxOTE0MDRaMGwxDDAKBgNV |
393 | +BAMMA0NSUDEQMA4GA1UECwwHQXp1cmVSVDEeMBwGA1UECgwVTWljcm9zb2Z0IENv |
394 | +cnBvcmF0aW9uMRAwDgYDVQQHDAdSZWRtb25kMQswCQYDVQQIDAJXQTELMAkGA1UE |
395 | +BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHU9IDclbKVYVb |
396 | +Yuv0+zViX+wTwlKspslmy/uf3hkWLh7pyzyrq70S7qtSW2EGixUPxZS/R8pOLHoi |
397 | +nlKF9ILgj0gVTCJsSwnWpXRg3rhZwIVoYMHN50BHS1SqVD0lsWNMXmo76LoJcjmW |
398 | +vwIznvj5C/gnhU+K7+c3m7AlCyU2wjwpBAEYj7PQs6l/wTqpEiaqC5NytNBd7qp+ |
399 | +lYYysVrpa1PFL0Nj4MMZARIfjkiJtL9qDhy9YZeJRQ6q/Fhz0kjvkZnfxixfKF4y |
400 | +WzOfhBrAtpF6oOnuYKk3hxjh9KjTTX4/U8zdLojalX09iyHyEjwJKGlGEpzh1aY7 |
401 | +t5btUyvpAgMBAAEwDQYJKoZIhvcNAQEFBQADAQA= |
402 | +-----END CERTIFICATE----- |
403 | diff --git a/tests/data/azure/pubkey_extract_ssh_key b/tests/data/azure/pubkey_extract_ssh_key |
404 | new file mode 100644 |
405 | index 0000000..54d749e |
406 | --- /dev/null |
407 | +++ b/tests/data/azure/pubkey_extract_ssh_key |
408 | @@ -0,0 +1 @@ |
409 | +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHU9IDclbKVYVbYuv0+zViX+wTwlKspslmy/uf3hkWLh7pyzyrq70S7qtSW2EGixUPxZS/R8pOLHoinlKF9ILgj0gVTCJsSwnWpXRg3rhZwIVoYMHN50BHS1SqVD0lsWNMXmo76LoJcjmWvwIznvj5C/gnhU+K7+c3m7AlCyU2wjwpBAEYj7PQs6l/wTqpEiaqC5NytNBd7qp+lYYysVrpa1PFL0Nj4MMZARIfjkiJtL9qDhy9YZeJRQ6q/Fhz0kjvkZnfxixfKF4yWzOfhBrAtpF6oOnuYKk3hxjh9KjTTX4/U8zdLojalX09iyHyEjwJKGlGEpzh1aY7t5btUyvp |
410 | diff --git a/tests/unittests/test_datasource/test_azure_helper.py b/tests/unittests/test_datasource/test_azure_helper.py |
411 | index 26b2b93..0255616 100644 |
412 | --- a/tests/unittests/test_datasource/test_azure_helper.py |
413 | +++ b/tests/unittests/test_datasource/test_azure_helper.py |
414 | @@ -1,11 +1,13 @@ |
415 | # This file is part of cloud-init. See LICENSE file for license information. |
416 | |
417 | import os |
418 | +import unittest2 |
419 | from textwrap import dedent |
420 | |
421 | from cloudinit.sources.helpers import azure as azure_helper |
422 | from cloudinit.tests.helpers import CiTestCase, ExitStack, mock, populate_dir |
423 | |
424 | +from cloudinit.util import load_file |
425 | from cloudinit.sources.helpers.azure import WALinuxAgentShim as wa_shim |
426 | |
427 | GOAL_STATE_TEMPLATE = """\ |
428 | @@ -289,6 +291,50 @@ class TestOpenSSLManager(CiTestCase): |
429 | self.assertEqual([mock.call(manager.tmpdir)], del_dir.call_args_list) |
430 | |
431 | |
432 | +class TestOpenSSLManagerActions(CiTestCase): |
433 | + |
434 | + def setUp(self): |
435 | + super(TestOpenSSLManagerActions, self).setUp() |
436 | + |
437 | + self.allowed_subp = True |
438 | + |
439 | + def _data_file(self, name): |
440 | + path = 'tests/data/azure' |
441 | + return os.path.join(path, name) |
442 | + |
443 | + @unittest2.skip("todo move to cloud_test") |
444 | + def test_pubkey_extract(self): |
445 | + cert = load_file(self._data_file('pubkey_extract_cert')) |
446 | + good_key = load_file(self._data_file('pubkey_extract_ssh_key')) |
447 | + sslmgr = azure_helper.OpenSSLManager() |
448 | + key = sslmgr._get_ssh_key_from_cert(cert) |
449 | + self.assertEqual(good_key, key) |
450 | + |
451 | + good_fingerprint = '073E19D14D1C799224C6A0FD8DDAB6A8BF27D473' |
452 | + fingerprint = sslmgr._get_fingerprint_from_cert(cert) |
453 | + self.assertEqual(good_fingerprint, fingerprint) |
454 | + |
455 | + @unittest2.skip("todo move to cloud_test") |
456 | + @mock.patch.object(azure_helper.OpenSSLManager, '_decrypt_certs_from_xml') |
457 | + def test_parse_certificates(self, mock_decrypt_certs): |
458 | + """Azure control plane puts private keys as well as certificates |
459 | + into the Certificates XML object. Make sure only the public keys |
460 | + from certs are extracted and that fingerprints are converted to |
461 | + the form specified in the ovf-env.xml file. |
462 | + """ |
463 | + cert_contents = load_file(self._data_file('parse_certificates_pem')) |
464 | + fingerprints = load_file(self._data_file( |
465 | + 'parse_certificates_fingerprints') |
466 | + ).splitlines() |
467 | + mock_decrypt_certs.return_value = cert_contents |
468 | + sslmgr = azure_helper.OpenSSLManager() |
469 | + keys_by_fp = sslmgr.parse_certificates('') |
470 | + for fp in keys_by_fp.keys(): |
471 | + self.assertIn(fp, fingerprints) |
472 | + for fp in fingerprints: |
473 | + self.assertIn(fp, keys_by_fp) |
474 | + |
475 | + |
476 | class TestWALinuxAgentShim(CiTestCase): |
477 | |
478 | def setUp(self): |
479 | @@ -329,18 +375,31 @@ class TestWALinuxAgentShim(CiTestCase): |
480 | |
481 | def test_certificates_used_to_determine_public_keys(self): |
482 | shim = wa_shim() |
483 | - data = shim.register_with_azure_and_fetch_data() |
484 | + """if register_with_azure_and_fetch_data() isn't passed some info about |
485 | + the user's public keys, there's no point in even trying to parse |
486 | + the certificates |
487 | + """ |
488 | + mypk = [{'fingerprint': 'fp1', 'path': 'path1'}, |
489 | + {'fingerprint': 'fp3', 'path': 'path3', 'value': ''}] |
490 | + certs = {'fp1': 'expected-key', |
491 | + 'fp2': 'should-not-be-found', |
492 | + 'fp3': 'expected-no-value-key', |
493 | + } |
494 | + sslmgr = self.OpenSSLManager.return_value |
495 | + sslmgr.parse_certificates.return_value = certs |
496 | + data = shim.register_with_azure_and_fetch_data(pubkey_info=mypk) |
497 | self.assertEqual( |
498 | [mock.call(self.GoalState.return_value.certificates_xml)], |
499 | - self.OpenSSLManager.return_value.parse_certificates.call_args_list) |
500 | - self.assertEqual( |
501 | - self.OpenSSLManager.return_value.parse_certificates.return_value, |
502 | - data['public-keys']) |
503 | + sslmgr.parse_certificates.call_args_list) |
504 | + self.assertIn('expected-key', data['public-keys']) |
505 | + self.assertIn('expected-no-value-key', data['public-keys']) |
506 | + self.assertNotIn('should-not-be-found', data['public-keys']) |
507 | |
508 | def test_absent_certificates_produces_empty_public_keys(self): |
509 | + mypk = [{'fingerprint': 'fp1', 'path': 'path1'}] |
510 | self.GoalState.return_value.certificates_xml = None |
511 | shim = wa_shim() |
512 | - data = shim.register_with_azure_and_fetch_data() |
513 | + data = shim.register_with_azure_and_fetch_data(pubkey_info=mypk) |
514 | self.assertEqual([], data['public-keys']) |
515 | |
516 | def test_correct_url_used_for_report_ready(self): |
FAILED: Continuous integration, rev:c3721d01651 eed9e9be921c52f 003056b34c2530 /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 569/
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild: /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 569/rebuild
https:/