From cbdb2a03430b883f4996d94ef0843fcc097a31d7 Mon Sep 17 00:00:00 2001 From: Michael Armijo Date: Wed, 8 May 2024 13:26:07 -0600 Subject: [PATCH] microsoft/azure: allow empty certificate chain in PKCS12 file Azure is populating the certs endpoint even when an SSH key is not provided. The certificate chain in the PKCS12 file is empty in this case causing afterburn to fail with the current logic. Check if the certificate chain is empty before retrieving the SSH public key and warn that a key was not provisioned if it is indeed empty. --- docs/release-notes.md | 2 ++ src/providers/microsoft/azure/mod.rs | 17 ++++++++++++++++- src/providers/microsoft/crypto/mod.rs | 9 ++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index 2c09e9b2..74e41cf1 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,6 +12,8 @@ Major changes: Minor changes: +- Fix Azure SSH key fetching when no key provisioned. + Packaging changes: diff --git a/src/providers/microsoft/azure/mod.rs b/src/providers/microsoft/azure/mod.rs index 6c7ba8b5..69512880 100644 --- a/src/providers/microsoft/azure/mod.rs +++ b/src/providers/microsoft/azure/mod.rs @@ -412,7 +412,22 @@ impl MetadataProvider for Azure { bail!("unexpected empty certificates endpoint"); } - let key = self.get_ssh_pubkey(certs_endpoint)?; + // The certs endpoint is being populated even when the user does not supply + // an SSH key when created a VM. In this case the certificate chain is empty + // causing a failure when trying to access it. Check if the certificate chain + // is empty, meaning that an SSH key hasn't been provided, and only warn + // instead of fail. + let key = match self.get_ssh_pubkey(certs_endpoint) { + Ok(k) => k, + Err(e) => match e.root_cause().to_string().as_ref() { + "SSH public key not found in chain" => { + warn!("SSH pubkeys requested, but not provisioned for this instance"); + return Ok(vec![]); + } + _ => return Err(e), + }, + }; + Ok(vec![key]) } diff --git a/src/providers/microsoft/crypto/mod.rs b/src/providers/microsoft/crypto/mod.rs index d009baef..38c6601f 100644 --- a/src/providers/microsoft/crypto/mod.rs +++ b/src/providers/microsoft/crypto/mod.rs @@ -65,7 +65,14 @@ pub fn p12_to_ssh_pubkey(p12_der: &[u8]) -> Result { // ParsedPKCS12_2 has three parts: a pkey, a main x509 cert, and a list of other // x509 certs. The list of other x509 certs are called the `certificate chain` // currently denoted as `ca`; there is only one cert in this `certificate chain`, - // which is the ssh public key. + // which is the ssh public key. The certs endpoint may still be populated even if + // an SSH public key hasn't been provided, which would lead to this code being + // executed. The certificate chain will be empty in this case, so error out and + // handle it further up the stack. + if p12.ca.is_none() { + return Err(anyhow!("SSH public key not found in chain")); + } + let ca = p12 .ca .ok_or_else(|| anyhow!("failed to get chain from pkcs12"))?;