Unverified Commit 4563849d authored by John DiSanti's avatar John DiSanti Committed by GitHub
Browse files

Revamp errors in `aws-config` (#1934)

parent 543cac37
Loading
Loading
Loading
Loading
+81 −45
Original line number Diff line number Diff line
@@ -100,7 +100,7 @@ impl EcsCredentialsProvider {
        let auth = match self.env.get(ENV_AUTHORIZATION).ok() {
            Some(auth) => Some(HeaderValue::from_str(&auth).map_err(|err| {
                tracing::warn!(token = %auth, "invalid auth token");
                CredentialsError::invalid_configuration(EcsConfigurationErr::InvalidAuthToken {
                CredentialsError::invalid_configuration(EcsConfigurationError::InvalidAuthToken {
                    err,
                    value: auth,
                })
@@ -140,11 +140,11 @@ impl ProvideCredentials for EcsCredentialsProvider {
enum Provider {
    Configured(HttpCredentialProvider),
    NotConfigured,
    InvalidConfiguration(EcsConfigurationErr),
    InvalidConfiguration(EcsConfigurationError),
}

impl Provider {
    async fn uri(env: Env, dns: Option<DnsService>) -> Result<Uri, EcsConfigurationErr> {
    async fn uri(env: Env, dns: Option<DnsService>) -> Result<Uri, EcsConfigurationError> {
        let relative_uri = env.get(ENV_RELATIVE_URI).ok();
        let full_uri = env.get(ENV_FULL_URI).ok();
        if let Some(relative_uri) = relative_uri {
@@ -153,9 +153,9 @@ impl Provider {
            let mut dns = dns.or_else(tokio_dns);
            validate_full_uri(&full_uri, dns.as_mut())
                .await
                .map_err(|err| EcsConfigurationErr::InvalidFullUri { err, uri: full_uri })
                .map_err(|err| EcsConfigurationError::InvalidFullUri { err, uri: full_uri })
        } else {
            Err(EcsConfigurationErr::NotConfigured)
            Err(EcsConfigurationError::NotConfigured)
        }
    }

@@ -164,7 +164,7 @@ impl Provider {
        let env = provider_config.env();
        let uri = match Self::uri(env, builder.dns).await {
            Ok(uri) => uri,
            Err(EcsConfigurationErr::NotConfigured) => return Provider::NotConfigured,
            Err(EcsConfigurationError::NotConfigured) => return Provider::NotConfigured,
            Err(err) => return Provider::InvalidConfiguration(err),
        };
        let http_provider = HttpCredentialProvider::builder()
@@ -179,12 +179,12 @@ impl Provider {
        Provider::Configured(http_provider)
    }

    fn build_full_uri(relative_uri: String) -> Result<Uri, EcsConfigurationErr> {
    fn build_full_uri(relative_uri: String) -> Result<Uri, EcsConfigurationError> {
        let mut relative_uri = match relative_uri.parse::<Uri>() {
            Ok(uri) => uri,
            Err(invalid_uri) => {
                tracing::warn!(uri = %DisplayErrorContext(&invalid_uri), "invalid URI loaded from environment");
                return Err(EcsConfigurationErr::InvalidRelativeUri {
                return Err(EcsConfigurationError::InvalidRelativeUri {
                    err: invalid_uri,
                    uri: relative_uri,
                });
@@ -197,7 +197,7 @@ impl Provider {
}

#[derive(Debug)]
enum EcsConfigurationErr {
enum EcsConfigurationError {
    InvalidRelativeUri {
        err: InvalidUri,
        uri: String,
@@ -213,22 +213,22 @@ enum EcsConfigurationErr {
    NotConfigured,
}

impl Display for EcsConfigurationErr {
impl Display for EcsConfigurationError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            EcsConfigurationErr::InvalidRelativeUri { err, uri } => write!(
            EcsConfigurationError::InvalidRelativeUri { err, uri } => write!(
                f,
                "invalid relative URI for ECS provider ({}): {}",
                err, uri
            ),
            EcsConfigurationErr::InvalidFullUri { err, uri } => {
            EcsConfigurationError::InvalidFullUri { err, uri } => {
                write!(f, "invalid full URI for ECS provider ({}): {}", err, uri)
            }
            EcsConfigurationErr::NotConfigured => write!(
            EcsConfigurationError::NotConfigured => write!(
                f,
                "No environment variables were set to configure ECS provider"
            ),
            EcsConfigurationErr::InvalidAuthToken { err, value } => write!(
            EcsConfigurationError::InvalidAuthToken { err, value } => write!(
                f,
                "`{}` could not be used as a header value for the auth token. {}",
                value, err
@@ -237,12 +237,13 @@ impl Display for EcsConfigurationErr {
    }
}

impl Error for EcsConfigurationErr {
impl Error for EcsConfigurationError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match &self {
            EcsConfigurationErr::InvalidRelativeUri { err, .. } => Some(err),
            EcsConfigurationErr::InvalidFullUri { err, .. } => Some(err),
            _ => None,
            EcsConfigurationError::InvalidRelativeUri { err, .. } => Some(err),
            EcsConfigurationError::InvalidFullUri { err, .. } => Some(err),
            EcsConfigurationError::InvalidAuthToken { err, .. } => Some(err),
            EcsConfigurationError::NotConfigured => None,
        }
    }
}
@@ -303,12 +304,8 @@ impl Builder {
    }
}

/// Invalid Full URI
///
/// When the full URI setting is used, the URI must either be HTTPS or point to a loopback interface.
#[derive(Debug)]
#[non_exhaustive]
pub enum InvalidFullUriError {
enum InvalidFullUriErrorKind {
    /// The provided URI could not be parsed as a URI
    #[non_exhaustive]
    InvalidUri(InvalidUri),
@@ -329,36 +326,51 @@ pub enum InvalidFullUriError {
    DnsLookupFailed(io::Error),
}

/// Invalid Full URI
///
/// When the full URI setting is used, the URI must either be HTTPS or point to a loopback interface.
#[derive(Debug)]
pub struct InvalidFullUriError {
    kind: InvalidFullUriErrorKind,
}

impl Display for InvalidFullUriError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            InvalidFullUriError::InvalidUri(err) => write!(f, "URI was invalid: {}", err),
            InvalidFullUriError::MissingHost => write!(f, "URI did not specify a host"),
            InvalidFullUriError::NotLoopback => {
        use InvalidFullUriErrorKind::*;
        match self.kind {
            InvalidUri(_) => write!(f, "URI was invalid"),
            MissingHost => write!(f, "URI did not specify a host"),
            NotLoopback => {
                write!(f, "URI did not refer to the loopback interface")
            }
            InvalidFullUriError::DnsLookupFailed(err) => {
            DnsLookupFailed(_) => {
                write!(
                    f,
                    "failed to perform DNS lookup while validating URI: {}",
                    err
                    "failed to perform DNS lookup while validating URI"
                )
            }
            InvalidFullUriError::NoDnsService => write!(f, "No DNS service was provided. Enable `rt-tokio` or provide a `dns` service to the builder.")
            NoDnsService => write!(f, "no DNS service was provided. Enable `rt-tokio` or provide a `dns` service to the builder.")
        }
    }
}

impl Error for InvalidFullUriError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            InvalidFullUriError::InvalidUri(err) => Some(err),
            InvalidFullUriError::DnsLookupFailed(err) => Some(err),
        use InvalidFullUriErrorKind::*;
        match &self.kind {
            InvalidUri(err) => Some(err),
            DnsLookupFailed(err) => Some(err),
            _ => None,
        }
    }
}

impl From<InvalidFullUriErrorKind> for InvalidFullUriError {
    fn from(kind: InvalidFullUriErrorKind) -> Self {
        Self { kind }
    }
}

/// Dns resolver interface
pub type DnsService = BoxCloneService<String, Vec<IpAddr>, io::Error>;

@@ -374,20 +386,20 @@ async fn validate_full_uri(
) -> Result<Uri, InvalidFullUriError> {
    let uri = uri
        .parse::<Uri>()
        .map_err(InvalidFullUriError::InvalidUri)?;
        .map_err(InvalidFullUriErrorKind::InvalidUri)?;
    if uri.scheme() == Some(&Scheme::HTTPS) {
        return Ok(uri);
    }
    // For HTTP URIs, we need to validate that it points to a loopback address
    let host = uri.host().ok_or(InvalidFullUriError::MissingHost)?;
    let host = uri.host().ok_or(InvalidFullUriErrorKind::MissingHost)?;
    let is_loopback = match host.parse::<IpAddr>() {
        Ok(addr) => addr.is_loopback(),
        Err(_domain_name) => {
            let dns = dns.ok_or(InvalidFullUriError::NoDnsService)?;
            dns.ready().await.map_err(InvalidFullUriError::DnsLookupFailed)?
            let dns = dns.ok_or(InvalidFullUriErrorKind::NoDnsService)?;
            dns.ready().await.map_err(InvalidFullUriErrorKind::DnsLookupFailed)?
                    .call(host.to_owned())
                    .await
                    .map_err(InvalidFullUriError::DnsLookupFailed)?
                    .map_err(InvalidFullUriErrorKind::DnsLookupFailed)?
                    .iter()
                    .all(|addr| {
                        if !addr.is_loopback() {
@@ -402,7 +414,7 @@ async fn validate_full_uri(
    };
    match is_loopback {
        true => Ok(uri),
        false => Err(InvalidFullUriError::NotLoopback),
        false => Err(InvalidFullUriErrorKind::NotLoopback.into()),
    }
}

@@ -459,7 +471,7 @@ mod test {

    use crate::ecs::{
        tokio_dns, validate_full_uri, Builder, EcsCredentialsProvider, InvalidFullUriError,
        Provider,
        InvalidFullUriErrorKind, Provider,
    };
    use crate::provider_config::ProviderConfig;
    use crate::test_case::GenericTestResult;
@@ -547,7 +559,12 @@ mod test {
            .unwrap()
            .expect_err("DNS service is required");
        assert!(
            matches!(no_dns_error, InvalidFullUriError::NoDnsService),
            matches!(
                no_dns_error,
                InvalidFullUriError {
                    kind: InvalidFullUriErrorKind::NoDnsService
                }
            ),
            "expected no dns service, got: {}",
            no_dns_error
        );
@@ -567,7 +584,12 @@ mod test {
            .now_or_never()
            .unwrap()
            .expect_err("not a loopback");
        assert!(matches!(err, InvalidFullUriError::NotLoopback));
        assert!(matches!(
            err,
            InvalidFullUriError {
                kind: InvalidFullUriErrorKind::NotLoopback
            }
        ));
    }

    #[test]
@@ -594,7 +616,12 @@ mod test {
            .now_or_never()
            .unwrap();
        assert!(
            matches!(resp, Err(InvalidFullUriError::NotLoopback)),
            matches!(
                resp,
                Err(InvalidFullUriError {
                    kind: InvalidFullUriErrorKind::NotLoopback
                })
            ),
            "Should be invalid: {:?}",
            resp
        );
@@ -703,7 +730,16 @@ mod test {
        let err = validate_full_uri("http://www.amazon.com/creds", dns.as_mut())
            .await
            .expect_err("not a loopback");
        assert!(matches!(err, InvalidFullUriError::NotLoopback), "{:?}", err);
        assert!(
            matches!(
                err,
                InvalidFullUriError {
                    kind: InvalidFullUriErrorKind::NotLoopback
                }
            ),
            "{:?}",
            err
        );
        assert!(logs_contain(
            "Address does not resolve to the loopback interface"
        ));
+36 −218
Original line number Diff line number Diff line
@@ -7,15 +7,16 @@
//!
//! Client for direct access to IMDSv2.

use std::borrow::Cow;
use std::convert::TryFrom;
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;

use crate::connector::expect_connector;
use crate::imds::client::error::{
    BuildError, BuildErrorKind, ImdsError, InnerImdsError, InvalidEndpointMode,
};
use crate::imds::client::token::TokenMiddleware;
use crate::provider_config::ProviderConfig;
use crate::{profile, PKG_VERSION};
use aws_http::user_agent::{ApiMetadata, AwsUserAgent, UserAgentStage};
use aws_sdk_sso::config::timeout::TimeoutConfig;
use aws_smithy_client::http_connector::ConnectorSettings;
use aws_smithy_client::{erase::DynConnector, SdkSuccess};
use aws_smithy_client::{retry, SdkError};
use aws_smithy_http::body::SdkBody;
@@ -30,20 +31,16 @@ use aws_smithy_http_tower::map_request::{
use aws_smithy_types::error::display::DisplayErrorContext;
use aws_smithy_types::retry::{ErrorKind, RetryKind};
use aws_types::os_shim_internal::{Env, Fs};

use bytes::Bytes;
use http::uri::InvalidUri;
use http::{Response, Uri};
use std::borrow::Cow;
use std::error::Error;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::OnceCell;

use crate::connector::expect_connector;
use crate::imds::client::token::TokenMiddleware;
use crate::profile::credentials::ProfileFileError;
use crate::provider_config::ProviderConfig;
use crate::{profile, PKG_VERSION};
use aws_sdk_sso::config::timeout::TimeoutConfig;
use aws_smithy_client::http_connector::ConnectorSettings;

pub mod error;
mod token;

// 6 hours
@@ -209,23 +206,23 @@ impl Client {
                SdkError::ConstructionFailure(_) if err.source().is_some() => {
                    match err.into_source().map(|e| e.downcast::<ImdsError>()) {
                        Ok(Ok(token_failure)) => *token_failure,
                        Ok(Err(err)) => ImdsError::Unexpected(err),
                        Err(err) => ImdsError::Unexpected(err.into()),
                        Ok(Err(err)) => ImdsError::unexpected(err),
                        Err(err) => ImdsError::unexpected(err),
                    }
                }
                SdkError::ConstructionFailure(_) => ImdsError::Unexpected(err.into()),
                SdkError::ConstructionFailure(_) => ImdsError::unexpected(err),
                SdkError::ServiceError(context) => match context.err() {
                    InnerImdsError::InvalidUtf8 => {
                        ImdsError::Unexpected("IMDS returned invalid UTF-8".into())
                        ImdsError::unexpected("IMDS returned invalid UTF-8")
                    }
                    InnerImdsError::BadStatus => {
                        ImdsError::error_response(context.into_raw().into_parts().0)
                    }
                    InnerImdsError::BadStatus => ImdsError::ErrorResponse {
                        response: context.into_raw().into_parts().0,
                    },
                },
                SdkError::TimeoutError(_)
                | SdkError::DispatchFailure(_)
                | SdkError::ResponseError(_) => ImdsError::IoError(err.into()),
                _ => ImdsError::Unexpected(err.into()),
                | SdkError::ResponseError(_) => ImdsError::io_error(err),
                _ => ImdsError::unexpected(err),
            })
    }

@@ -237,7 +234,9 @@ impl Client {
        &self,
        path: &str,
    ) -> Result<Operation<ImdsGetResponseHandler, ImdsResponseRetryClassifier>, ImdsError> {
        let mut base_uri: Uri = path.parse().map_err(|_| ImdsError::InvalidPath)?;
        let mut base_uri: Uri = path.parse().map_err(|_| {
            ImdsError::unexpected("IMDS path was not a valid URI. Hint: does it begin with `/`?")
        })?;
        self.inner.endpoint.set_endpoint(&mut base_uri, None);
        let request = http::Request::builder()
            .uri(base_uri)
@@ -251,74 +250,6 @@ impl Client {
    }
}

/// An error retrieving metadata from IMDS
#[derive(Debug)]
#[non_exhaustive]
pub enum ImdsError {
    /// An IMDSv2 Token could not be loaded
    ///
    /// Requests to IMDS must be accompanied by a token obtained via a `PUT` request. This is handled
    /// transparently by the [`Client`].
    FailedToLoadToken(SdkError<TokenError>),

    /// The `path` was invalid for an IMDS request
    ///
    /// The `path` parameter must be a valid URI path segment, and it must begin with `/`.
    InvalidPath,

    /// An error response was returned from IMDS
    #[non_exhaustive]
    ErrorResponse {
        /// The returned raw response
        response: http::Response<SdkBody>,
    },

    /// IO Error
    ///
    /// An error occurred communication with IMDS
    IoError(Box<dyn Error + Send + Sync + 'static>),

    /// An unexpected error occurred communicating with IMDS
    Unexpected(Box<dyn Error + Send + Sync + 'static>),
}

impl Display for ImdsError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            ImdsError::FailedToLoadToken(inner) => {
                write!(f, "Failed to load session token: {}", inner)
            }
            ImdsError::InvalidPath => write!(
                f,
                "IMDS path was not a valid URI. Hint: Does it begin with `/`?"
            ),
            ImdsError::ErrorResponse { response } => write!(
                f,
                "Error response from IMDS (code: {}). {:?}",
                response.status().as_u16(),
                response
            ),
            ImdsError::IoError(err) => {
                write!(f, "An IO error occurred communicating with IMDS: {}", err)
            }
            ImdsError::Unexpected(err) => write!(
                f,
                "An unexpected error occurred communicating with IMDS: {}",
                err
            ),
        }
    }
}

impl Error for ImdsError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match &self {
            ImdsError::FailedToLoadToken(inner) => Some(inner),
            _ => None,
        }
    }
}

/// IMDS Middleware
///
/// The IMDS middleware includes a token-loader & a UserAgent stage
@@ -339,23 +270,6 @@ impl<S> tower::Layer<S> for ImdsMiddleware {
#[derive(Copy, Clone)]
struct ImdsGetResponseHandler;

#[derive(Debug)]
enum InnerImdsError {
    BadStatus,
    InvalidUtf8,
}

impl Display for InnerImdsError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            InnerImdsError::BadStatus => write!(f, "failing status code returned from IMDS"),
            InnerImdsError::InvalidUtf8 => write!(f, "IMDS did not return valid UTF-8"),
        }
    }
}

impl Error for InnerImdsError {}

impl ParseStrictResponse for ImdsGetResponseHandler {
    type Output = Result<String, InnerImdsError>;

@@ -386,22 +300,6 @@ pub enum EndpointMode {
    IpV6,
}

/// Invalid Endpoint Mode
#[derive(Debug, Clone)]
pub struct InvalidEndpointMode(String);

impl Display for InvalidEndpointMode {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "`{}` is not a valid endpoint mode. Valid values are [`IPv4`, `IPv6`]",
            &self.0
        )
    }
}

impl Error for InvalidEndpointMode {}

impl FromStr for EndpointMode {
    type Err = InvalidEndpointMode;

@@ -409,7 +307,7 @@ impl FromStr for EndpointMode {
        match value {
            _ if value.eq_ignore_ascii_case("ipv4") => Ok(EndpointMode::IpV4),
            _ if value.eq_ignore_ascii_case("ipv6") => Ok(EndpointMode::IpV6),
            other => Err(InvalidEndpointMode(other.to_owned())),
            other => Err(InvalidEndpointMode::new(other.to_owned())),
        }
    }
}
@@ -436,40 +334,6 @@ pub struct Builder {
    config: Option<ProviderConfig>,
}

/// Error constructing IMDSv2 Client
#[derive(Debug)]
pub enum BuildError {
    /// The endpoint mode was invalid
    InvalidEndpointMode(InvalidEndpointMode),

    /// The AWS Profile (e.g. `~/.aws/config`) was invalid
    InvalidProfile(ProfileFileError),

    /// The specified endpoint was not a valid URI
    InvalidEndpointUri(InvalidUri),
}

impl Display for BuildError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "failed to build IMDS client: ")?;
        match self {
            BuildError::InvalidEndpointMode(e) => write!(f, "{}", e),
            BuildError::InvalidProfile(e) => write!(f, "{}", e),
            BuildError::InvalidEndpointUri(e) => write!(f, "{}", e),
        }
    }
}

impl Error for BuildError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            BuildError::InvalidEndpointMode(e) => Some(e),
            BuildError::InvalidProfile(e) => Some(e),
            BuildError::InvalidEndpointUri(e) => Some(e),
        }
    }
}

impl Builder {
    /// Override the number of retries for fetching tokens & metadata
    ///
@@ -632,14 +496,16 @@ impl EndpointSource {
                // load an endpoint override from the environment
                let profile = profile::load(fs, env, &Default::default())
                    .await
                    .map_err(BuildError::InvalidProfile)?;
                    .map_err(BuildErrorKind::InvalidProfile)?;
                let uri_override = if let Ok(uri) = env.get(env::ENDPOINT) {
                    Some(Cow::Owned(uri))
                } else {
                    profile.get(profile_keys::ENDPOINT).map(Cow::Borrowed)
                };
                if let Some(uri) = uri_override {
                    return Uri::try_from(uri.as_ref()).map_err(BuildError::InvalidEndpointUri);
                    return Ok(
                        Uri::try_from(uri.as_ref()).map_err(BuildErrorKind::InvalidEndpointUri)?
                    );
                }

                // if not, load a endpoint mode from the environment
@@ -647,10 +513,10 @@ impl EndpointSource {
                    mode
                } else if let Ok(mode) = env.get(env::ENDPOINT_MODE) {
                    mode.parse::<EndpointMode>()
                        .map_err(BuildError::InvalidEndpointMode)?
                        .map_err(BuildErrorKind::InvalidEndpointMode)?
                } else if let Some(mode) = profile.get(profile_keys::ENDPOINT_MODE) {
                    mode.parse::<EndpointMode>()
                        .map_err(BuildError::InvalidEndpointMode)?
                        .map_err(BuildErrorKind::InvalidEndpointMode)?
                } else {
                    EndpointMode::IpV4
                };
@@ -661,54 +527,6 @@ impl EndpointSource {
    }
}

/// Error retrieving token from IMDS
#[derive(Debug)]
pub enum TokenError {
    /// The token was invalid
    ///
    /// Because tokens must be eventually sent as a header, the token must be a valid header value.
    InvalidToken,

    /// No TTL was sent
    ///
    /// The token response must include a time-to-live indicating the lifespan of the token.
    NoTtl,

    /// The TTL was invalid
    ///
    /// The TTL must be a valid positive integer.
    InvalidTtl,

    /// Invalid Parameters
    ///
    /// The request to load a token was malformed. This indicates an SDK bug.
    InvalidParameters,

    /// Forbidden
    ///
    /// IMDS is disabled or has been disallowed via permissions.
    Forbidden,
}

impl Display for TokenError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            TokenError::InvalidToken => write!(f, "Invalid Token"),
            TokenError::NoTtl => write!(f, "Token response did not contain a TTL header"),
            TokenError::InvalidTtl => write!(f, "The returned TTL was invalid"),
            TokenError::InvalidParameters => {
                write!(f, "Invalid request parameters. This indicates an SDK bug.")
            }
            TokenError::Forbidden => write!(
                f,
                "Request forbidden: IMDS is disabled or the caller has insufficient permissions."
            ),
        }
    }
}

impl Error for TokenError {}

#[derive(Clone)]
struct ImdsResponseRetryClassifier;

@@ -1086,7 +904,7 @@ pub(crate) mod test {
        )]);
        let client = make_client(&connection).await;
        let err = client.get("/latest/metadata").await.expect_err("no token");
        assert_full_error_contains!(err, "Invalid Token");
        assert_full_error_contains!(err, "invalid token");
        connection.assert_requests_match(&[]);
    }

@@ -1142,7 +960,7 @@ pub(crate) mod test {
            time_elapsed
        );
        match resp {
            ImdsError::FailedToLoadToken(err)
            err @ ImdsError::FailedToLoadToken(_)
                if format!("{}", DisplayErrorContext(&err)).contains("timeout") => {} // ok,
            other => panic!(
                "wrong error, expected construction failure with TimedOutError inside: {}",
+281 −0

File added.

Preview size limit exceeded, changes collapsed.

+16 −18

File changed.

Preview size limit exceeded, changes collapsed.

+7 −5
Original line number Diff line number Diff line
@@ -8,11 +8,11 @@
//! # Important
//! This credential provider will NOT fallback to IMDSv1. Ensure that IMDSv2 is enabled on your instances.

use super::client::error::ImdsError;
use crate::imds;
use crate::imds::client::{ImdsError, LazyClient};
use crate::imds::client::LazyClient;
use crate::json_credentials::{parse_json_credentials, JsonCredentials, RefreshableCredentials};
use crate::provider_config::ProviderConfig;
use aws_smithy_client::SdkError;
use aws_types::credentials::{future, CredentialsError, ProvideCredentials};
use aws_types::os_shim_internal::Env;
use aws_types::{credentials, Credentials};
@@ -149,16 +149,18 @@ impl ImdsCredentialsProvider {
            .await
        {
            Ok(profile) => Ok(profile),
            Err(ImdsError::ErrorResponse { response, .. }) if response.status().as_u16() == 404 => {
            Err(ImdsError::ErrorResponse(context))
                if context.response().status().as_u16() == 404 =>
            {
                tracing::info!(
                    "received 404 from IMDS when loading profile information. \
                    Hint: This instance may not have an IAM role associated."
                );
                Err(CredentialsError::not_loaded("received 404 from IMDS"))
            }
            Err(ImdsError::FailedToLoadToken(err @ SdkError::DispatchFailure(_))) => {
            Err(ImdsError::FailedToLoadToken(context)) if context.is_dispatch_failure() => {
                Err(CredentialsError::not_loaded(ImdsCommunicationError {
                    source: err.into(),
                    source: context.into_source().into(),
                }))
            }
            Err(other) => Err(CredentialsError::provider_error(other)),
Loading