Unverified Commit b3a95af6 authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

feat(aws-config): Add IMDSv2 Credentials Provider (#709)



* feat(aws-config): Add IMDSv2 Credentials Provider

This follows up on #701 to use IMDS to act as a credentials provider. IMDS sits in the chain in two places:

1. IMDS may be used as a `credential_source` in `~/.aws/config`
2. IMDS is the last provider in the default chain of credential providers.

The IMDS credential provider may also be used directly.

* fix doc links

* Update aws/rust-runtime/aws-config/src/imds/credentials.rs

Co-authored-by: default avatarJohn DiSanti <jdisanti@amazon.com>

* Update aws/rust-runtime/aws-config/src/imds/credentials.rs

Co-authored-by: default avatarJohn DiSanti <jdisanti@amazon.com>

* CR feedback

Co-authored-by: default avatarJohn DiSanti <jdisanti@amazon.com>
parent 8e115e1d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
vNext (Month Day, Year)
=======================
**New This Week**
- Add IMDS credential provider to `aws-config` (#709)
- Add IMDS client to `aws-config` (#701)
- Add `TimeSource` to `aws_types::os_shim_internal` (#701)
- User agent construction is now `const fn` (#701)
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ vNext (Month Day, Year)
=======================
**New This Week**
- Add IMDS client to `aws-config`
- Add IMDS credential provider to `aws-config` (smithy-rs#709)
- Update event stream `Receiver`s to be `Send` (aws-sdk-rust#224)
- Add `sts::AssumeRoleProvider` to `aws-config` (#703, aws-sdk-rust#3)

+3 −2
Original line number Diff line number Diff line
@@ -8,9 +8,9 @@ exclude = ["test-data/*"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default-provider = ["profile", "imds", "meta", "sts", "environment"]
profile = ["sts", "web-identity-token", "meta", "environment"]
profile = ["sts", "web-identity-token", "meta", "environment", "imds"]
meta = ["tokio/sync"]
imds = ["profile", "smithy-http", "smithy-types", "smithy-http-tower", "tower", "aws-http", "meta"]
imds = ["profile", "smithy-http", "smithy-types", "smithy-http-tower", "smithy-json", "tower", "aws-http", "meta"]
environment = ["meta"]
sts = ["aws-sdk-sts", "aws-hyper"]
web-identity-token = ["sts", "profile"]
@@ -43,6 +43,7 @@ tower = { version = "0.4.8", optional = true }
aws-http = { path = "../../sdk/build/aws-sdk/aws-http", optional = true }
bytes = "1.1.0"
http = "0.2.4"
smithy-json = { path = "../../sdk/build/aws-sdk/smithy-json", optional = true }


[dev-dependencies]
+41 −19
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ pub mod credentials {
    pub struct Builder {
        profile_file_builder: crate::profile::credentials::Builder,
        web_identity_builder: crate::web_identity_token::Builder,
        imds_builder: crate::imds::credentials::Builder,
        credential_cache: crate::meta::credentials::lazy_caching::Builder,
        region_override: Option<Box<dyn ProvideRegion>>,
        region_chain: crate::default_provider::region::Builder,
@@ -240,10 +241,12 @@ pub mod credentials {
            let profile_provider = self.profile_file_builder.configure(&conf).build();
            let env_provider = EnvironmentVariableCredentialsProvider::new_with_env(conf.env());
            let web_identity_token_provider = self.web_identity_builder.configure(&conf).build();
            let imds_provider = self.imds_builder.configure(&conf).build();

            let provider_chain = CredentialsProviderChain::first_try("Environment", env_provider)
                .or_else("Profile", profile_provider)
                .or_else("WebIdentityToken", web_identity_token_provider);
                .or_else("WebIdentityToken", web_identity_token_provider)
                .or_else("Ec2InstanceMetadata", imds_provider);
            let cached_provider = self.credential_cache.configure(&conf).load(provider_chain);
            DefaultCredentialsChain(cached_provider.build())
        }
@@ -252,8 +255,36 @@ pub mod credentials {
    #[cfg(test)]
    mod test {

        /// Test generation macro
        ///
        /// # Examples
        /// **Run the test case in `test-data/default-provider-chain/test_name`
        /// ```rust
        /// make_test!(test_name);
        /// ```
        ///
        /// **Update (responses are replayed but new requests are recorded) the test case**:
        /// ```rust
        /// make_test!(update: test_name)
        /// ```
        ///
        /// **Run the test case against a real HTTPS connection:**
        /// > Note: Be careful to remove sensitive information before commiting. Always use a temporary
        /// > AWS account when recording live traffic.
        /// ```rust
        /// make_test!(live: test_name)
        /// ```
        macro_rules! make_test {
            ($name: ident) => {
                make_test!($name, execute);
            };
            (update: $name:ident) => {
                make_test!($name, execute_and_update);
            };
            (live: $name:ident) => {
                make_test!($name, execute_from_live_traffic);
            };
            ($name: ident, $func: ident) => {
                #[traced_test]
                #[tokio::test]
                async fn $name() {
@@ -262,7 +293,7 @@ pub mod credentials {
                        stringify!($name)
                    ))
                    .unwrap()
                    .execute(|conf| async {
                    .$func(|conf| async {
                        crate::default_provider::credentials::Builder::default()
                            .configure(conf)
                            .build()
@@ -286,6 +317,14 @@ pub mod credentials {
        make_test!(web_identity_token_source_profile);
        make_test!(web_identity_token_profile);
        make_test!(profile_overrides_web_identity);
        make_test!(imds_token_fail);

        make_test!(imds_no_iam_role);
        make_test!(imds_default_chain_error);
        make_test!(imds_default_chain_success);
        make_test!(imds_assume_role);
        make_test!(imds_disabled);
        make_test!(imds_default_chain_retries);

        #[tokio::test]
        async fn profile_name_override() {
@@ -305,22 +344,5 @@ pub mod credentials {
                .expect("creds should load");
            assert_eq!(creds.access_key_id(), "correct_key_secondary");
        }

        /// Helper that uses `execute_and_update` instead of execute
        ///
        /// If you run this, it will add another HTTP traffic log which re-records the request
        /// data
        #[tokio::test]
        #[ignore]
        async fn update_test() {
            crate::test_case::TestEnvironment::from_dir(concat!(
                "./test-data/default-provider-chain/web_identity_token_source_profile",
            ))
            .unwrap()
            .execute_and_update(|conf| async {
                super::Builder::default().configure(conf).build().await
            })
            .await
        }
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ const DEFAULT_RETRIES: u32 = 3;
///
/// 7. The default value of `http://169.254.169.254` will be used.
///
///
#[derive(Debug)]
pub struct Client {
    endpoint: Endpoint,
    inner: smithy_client::Client<DynConnector, ImdsMiddleware>,
@@ -224,7 +224,7 @@ impl Error for ImdsError {
/// IMDS Middleware
///
/// The IMDS middleware includes a token-loader & a UserAgent stage
#[derive(Clone)]
#[derive(Clone, Debug)]
struct ImdsMiddleware {
    token_loader: TokenMiddleware,
}
Loading