How could I fallback to use credentials from a parsed file (config.yml
) if no environment variables were found? For testing, I am using this example:
extern crate rusoto_core;
extern crate rusoto_s3;
use rusoto_core::credential::ChainProvider;
use rusoto_core::request::HttpClient;
use rusoto_core::Region;
use rusoto_s3::{S3, S3Client};
use std::time::{Duration, Instant};
fn main() {
let mut chain = ChainProvider::new();
chain.set_timeout(Duration::from_millis(200));
let s3client = S3Client::new_with(
HttpClient::new().expect("failed to create request dispatcher"),
chain,
Region::UsEast1,
);
let start = Instant::now();
println!("Starting up at {:?}", start);
match s3client.list_buckets().sync() {
Err(e) => println!("Error listing buckets: {}", e),
Ok(buckets) => println!("Buckets found: {:?}", buckets),
};
println!("Took {:?}", Instant::now().duration_since(start));
}
It works but requires the environment variables AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
. I would like to extend it so that If there are no defined environment variables, I could use the keys found in a parsed file:
// parse config file
let file = std::fs::File::open("config.yml").expect("Unable to open file");
let yml: Config = match serde_yaml::from_reader(file) {
Err(err) => {
println!("Error: {}", err);
return;
}
Ok(yml) => yml,
};
The config.yml
for example could be something like:
---
endpoint: s3.provider
access_key: ACCESS_KEY_ID
secret_key: SECRET_ACCESS_KEY
What could I add to the chain
to use the credentials found in the config.yml
, something probably like:
let config_provider = StaticProvider::new_minimal(yml.access_key, yml.secret_key);
How to give preference to the environment and if not found then use the credentials provided by the StaticProvider
?
The ChainProvider
actually has four sources to check for AWS credentials. The third one is the AWS configuration file located in user's home directory. But its format is predetermined.
If you insist on using your own YAML file, you can chain EnvironmentProvider
and StaticProvider
together like so:
//# futures01 = { package = "futures", version = "0.1.28" }
//# rusoto_core = "0.41.0"
//# rusoto_s3 = "0.41.0"
//# rusoto_credential = "0.41.1"
use futures01::future::Future;
use rusoto_core::request::HttpClient;
use rusoto_core::Region;
use rusoto_credential::{
AwsCredentials,
CredentialsError,
EnvironmentProvider,
ProvideAwsCredentials,
StaticProvider,
};
use rusoto_s3::{S3, S3Client};
use std::time::Instant;
struct MyChainProvider<'a> {
access_key: &'a str,
secret_key: &'a str,
}
impl<'a> ProvideAwsCredentials for MyChainProvider<'a> {
type Future = Box<dyn Future<Item=AwsCredentials, Error=CredentialsError> + Send>;
fn credentials(&self) -> Self::Future {
let future = EnvironmentProvider::default().credentials()
.or_else({
let access_key = self.access_key.to_string();
let secret_key = self.secret_key.to_string();
move |_| -> Self::Future {
Box::new(StaticProvider::new_minimal(access_key, secret_key).credentials())
}
});
Box::new(future)
}
}
fn main() {
let chain = MyChainProvider {
access_key: ...,
secret_key: ...,
};
...
}