Skip to content

Commit 3663922

Browse files
committed
Add check for running on GCP
1 parent d7fa273 commit 3663922

File tree

1 file changed

+46
-7
lines changed

1 file changed

+46
-7
lines changed

src/attestation/mod.rs

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ use parity_scale_codec::{Decode, Encode};
88
use serde::{Deserialize, Serialize};
99
use std::{
1010
fmt::{self, Display, Formatter},
11-
time::{SystemTime, UNIX_EPOCH},
11+
time::{Duration, SystemTime, UNIX_EPOCH},
1212
};
1313

1414
use thiserror::Error;
1515

1616
use crate::attestation::{dcap::DcapVerificationError, measurements::MeasurementPolicy};
1717

18+
const GCP_METADATA_API: &str =
19+
"http://metadata.google.internal/computeMetadata/v1/project/project-id";
20+
1821
/// This is the type sent over the channel to provide an attestation
1922
#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)]
2023
pub struct AttestationExchangeMessage {
@@ -68,20 +71,23 @@ impl AttestationType {
6871
}
6972

7073
/// Detect what platform we are on by attempting an attestation
71-
pub async fn detect() -> Self {
74+
pub async fn detect() -> Result<Self, AttestationError> {
7275
// First attempt azure, if the feature is present
7376
#[cfg(feature = "azure")]
7477
{
7578
if azure::create_azure_attestation([0; 64]).await.is_ok() {
76-
return AttestationType::AzureTdx;
79+
return Ok(AttestationType::AzureTdx);
7780
}
7881
}
7982
// Otherwise try DCAP quote - this internally checks that the quote provider is `tdx_guest`
8083
if configfs_tsm::create_tdx_quote([0; 64]).is_ok() {
81-
// TODO Possibly also check if it looks like we are on GCP (eg: hit metadata API)
82-
return AttestationType::DcapTdx;
84+
if running_on_gcp().await? {
85+
return Ok(AttestationType::GcpTdx);
86+
} else {
87+
return Ok(AttestationType::DcapTdx);
88+
}
8389
}
84-
AttestationType::None
90+
Ok(AttestationType::None)
8591
}
8692
}
8793

@@ -124,7 +130,7 @@ impl AttestationGenerator {
124130
let attestation_type_string = attestation_type_string.unwrap_or_else(|| "auto".to_string());
125131
let attestaton_type = if attestation_type_string == "auto" {
126132
tracing::info!("Doing attestation type detection...");
127-
AttestationType::detect().await
133+
AttestationType::detect().await?
128134
} else {
129135
serde_json::from_value(serde_json::Value::String(attestation_type_string))?
130136
};
@@ -362,6 +368,32 @@ async fn log_attestation(attestation: &AttestationExchangeMessage) {
362368
}
363369
}
364370

371+
/// Test whether it looks like we are running on GCP by hitting the metadata API
372+
async fn running_on_gcp() -> Result<bool, AttestationError> {
373+
let mut headers = reqwest::header::HeaderMap::new();
374+
headers.insert(
375+
"Metadata-Flavor",
376+
"Google".parse().expect("Cannot parse header"),
377+
);
378+
379+
let client = reqwest::Client::builder()
380+
.timeout(Duration::from_millis(200))
381+
.default_headers(headers)
382+
.build()?;
383+
384+
let resp = client.get(GCP_METADATA_API).send().await;
385+
386+
if let Ok(r) = resp {
387+
return Ok(r.status().is_success()
388+
&& r.headers()
389+
.get("Metadata-Flavor")
390+
.map(|v| v == "Google")
391+
.unwrap_or(false));
392+
}
393+
394+
Ok(false)
395+
}
396+
365397
/// An error when generating or verifying an attestation
366398
#[derive(Error, Debug)]
367399
pub enum AttestationError {
@@ -392,6 +424,8 @@ pub enum AttestationError {
392424
DummyServer(String),
393425
#[error("JSON: {0}")]
394426
SerdeJson(#[from] serde_json::Error),
427+
#[error("HTTP client: {0}")]
428+
Reqwest(#[from] reqwest::Error),
395429
}
396430

397431
#[cfg(test)]
@@ -403,4 +437,9 @@ mod tests {
403437
// We dont enforce what platform the test is run on, only that the function does not panic
404438
let _ = AttestationGenerator::new_with_detection(None, None).await;
405439
}
440+
441+
#[tokio::test]
442+
async fn running_on_gcp_check_does_not_panic() {
443+
let _ = running_on_gcp().await;
444+
}
406445
}

0 commit comments

Comments
 (0)