Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions crates/attestation/src/azure/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Microsoft Azure vTPM attestation evidence generation and verification
mod ak_certificate;
mod nv_index;
use std::time::Duration;

use ak_certificate::{read_ak_certificate_from_tpm, verify_ak_cert_with_azure_roots};
use az_tdx_vtpm::{hcl, imds, vtpm};
use base64::{Engine as _, engine::general_purpose::URL_SAFE as BASE64_URL_SAFE};
Expand All @@ -13,6 +15,9 @@ use x509_parser::prelude::*;

use crate::{dcap::verify_dcap_attestation_with_given_timestamp, measurements::MultiMeasurements};

/// Used in attestation type detection to check if we are on Azure
const AZURE_METADATA_API: &str = "http://169.254.169.254/metadata/instance";

/// The attestation evidence payload that gets sent over the channel
#[derive(Debug, Serialize, Deserialize)]
struct AttestationDocument {
Expand Down Expand Up @@ -266,6 +271,24 @@ impl RsaPubKey {
}
}

/// Detect whether we are on Azure and can make an Azure vTPM attestation
pub async fn detect_azure_cvm() -> Result<bool, reqwest::Error> {
let client = reqwest::Client::builder().no_proxy().timeout(Duration::from_secs(2)).build()?;

let resp = client.get(AZURE_METADATA_API).header("Metadata", "true").send().await;

if let Ok(r) = resp &&
r.status().is_success() &&
r.headers()
.get(reqwest::header::CONTENT_TYPE)
.and_then(|value| value.to_str().ok())
.is_some_and(|value| value.starts_with("application/json"))
{
return Ok(az_tdx_vtpm::is_tdx_cvm().unwrap_or(false));
}
Ok(false)
}
Comment on lines +275 to +290
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question:

there's quite a bunch of stuff happening here, at any point of which things could go off the happy-path.

should we perhaps log that? even if at debug/trace level?

(for the operator it could be important to be able to tell if the check has "decided" not-azure b/c of timeout, or b/c of missing header, or whatever else).

alternatively, this could be enriched Error type instead of the one from reqwest.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. Probably it should only return false if we appear to be not on azure because the metadata api is not available. Unusual cases like that the metadata API is available but no response header should be treated as an error with an explicit type.


/// An error when generating or verifying a Microsoft Azure vTPM attestation
#[derive(Error, Debug)]
pub enum MaaError {
Expand Down
2 changes: 1 addition & 1 deletion crates/attestation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl AttestationType {
// First attempt azure, if the feature is present
#[cfg(feature = "azure")]
{
if azure::create_azure_attestation([0; 64]).is_ok() {
if azure::detect_azure_cvm().await? {
return Ok(AttestationType::AzureTdx);
}
}
Expand Down
Loading