fix(providers): refresh GCP metadata server token on expiration (#8929)
Signed-off-by: Tom Birch <tom@neara.com> Co-authored-by: Tom Birch <tom@neara.com>
This commit is contained in:
@@ -58,7 +58,8 @@ enum AdcCredentials {
|
|||||||
/// Credentials for a service account
|
/// Credentials for a service account
|
||||||
ServiceAccount(ServiceAccountCredentials),
|
ServiceAccount(ServiceAccountCredentials),
|
||||||
/// Credentials for the GCP native default account
|
/// Credentials for the GCP native default account
|
||||||
DefaultAccount(TokenResponse),
|
#[serde(skip)]
|
||||||
|
DefaultAccount(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Credentials for an authorized user account.
|
/// Credentials for an authorized user account.
|
||||||
@@ -258,19 +259,11 @@ impl AdcCredentials {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the identity token and credentials from metadata server
|
|
||||||
let token_response = response
|
|
||||||
.json::<TokenResponse>()
|
|
||||||
.await
|
|
||||||
.map_err(|e| AuthError::Credentials(format!("Invalid metadata response: {}", e)))?;
|
|
||||||
|
|
||||||
// Note: When using metadata server, we have access to the OAuth2 access token
|
// Note: When using metadata server, we have access to the OAuth2 access token
|
||||||
// that can be used to authenticate applications.
|
// that can be used to authenticate applications.
|
||||||
Ok(AdcCredentials::DefaultAccount(TokenResponse {
|
// However, this token expires. Better to keep the base_url, and fetch a new token
|
||||||
token_type: token_response.token_type,
|
// when needed
|
||||||
access_token: token_response.access_token,
|
Ok(AdcCredentials::DefaultAccount(base_url.to_string()))
|
||||||
expires_in: token_response.expires_in,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,15 +532,36 @@ impl GcpAuth {
|
|||||||
/// Gets a token directly from the GCP metadata endpoint.
|
/// Gets a token directly from the GCP metadata endpoint.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `creds` - Default Access Token Response
|
/// * `base_url` - Default Access Token base url
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// * `Result<TokenResponse>` - The token response
|
/// * `Result<TokenResponse>` - The token response
|
||||||
async fn get_default_access_token(
|
async fn get_default_access_token(&self, base_url: &str) -> Result<TokenResponse, AuthError> {
|
||||||
&self,
|
let metadata_path = "/computeMetadata/v1/instance/service-accounts/default/token";
|
||||||
creds: &TokenResponse,
|
let response = self
|
||||||
) -> Result<TokenResponse, AuthError> {
|
.client
|
||||||
Ok(creds.clone())
|
.get(format!("{}{}", base_url, metadata_path))
|
||||||
|
.header("Metadata-Flavor", "Google")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| AuthError::TokenExchange(e.to_string()))?;
|
||||||
|
|
||||||
|
let status = response.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
let error_text = response
|
||||||
|
.text()
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|_| "Unknown error".to_string());
|
||||||
|
return Err(AuthError::TokenExchange(format!(
|
||||||
|
"Status {}: {}",
|
||||||
|
status, error_text
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
response
|
||||||
|
.json::<TokenResponse>()
|
||||||
|
.await
|
||||||
|
.map_err(|e| AuthError::TokenExchange(format!("Invalid response: {}", e)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1019,10 +1033,8 @@ iXVBc2YmAuU8hiOFUPxtyQfNzG5fQ0rhJSewdtyWxIadJSLj6fsK+AEsNQ==
|
|||||||
result
|
result
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok(AdcCredentials::DefaultAccount(token_response)) = result {
|
if let Ok(AdcCredentials::DefaultAccount(base_url)) = result {
|
||||||
assert_eq!(token_response.access_token, expected_token);
|
assert_eq!(base_url, mock_server.uri());
|
||||||
assert_eq!(token_response.token_type, expected_type);
|
|
||||||
assert_eq!(token_response.expires_in, expected_expires);
|
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected DefaultAccount credentials, got {:?}", result);
|
panic!("Expected DefaultAccount credentials, got {:?}", result);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user