rusoto_credential/
instance_metadata.rs1use async_trait::async_trait;
4use hyper::Uri;
5use std::time::Duration;
6
7use crate::request::HttpClient;
8use crate::{
9 parse_credentials_from_aws_service, AwsCredentials, CredentialsError, ProvideAwsCredentials,
10};
11
12const AWS_CREDENTIALS_PROVIDER_IP: &str = "169.254.169.254";
13const AWS_CREDENTIALS_PROVIDER_PATH: &str = "latest/meta-data/iam/security-credentials";
14
15#[derive(Clone, Debug)]
44pub struct InstanceMetadataProvider {
45 client: HttpClient,
46 timeout: Duration,
47 metadata_ip_addr: String,
48}
49
50impl InstanceMetadataProvider {
51 pub fn new() -> Self {
53 InstanceMetadataProvider {
54 client: HttpClient::new(),
55 timeout: Duration::from_secs(30),
56 metadata_ip_addr: AWS_CREDENTIALS_PROVIDER_IP.to_string(),
57 }
58 }
59
60 pub fn set_timeout(&mut self, timeout: Duration) {
62 self.timeout = timeout;
63 }
64
65 pub fn set_ip_addr_with_port(&mut self, ip: &str, port: &str) {
67 self.metadata_ip_addr = format!("{}:{}", ip, port);
68 }
69}
70
71impl Default for InstanceMetadataProvider {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77#[async_trait]
78impl ProvideAwsCredentials for InstanceMetadataProvider {
79 async fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
80 let role_name = get_role_name(&self.client, self.timeout, &self.metadata_ip_addr)
81 .await
82 .map_err(|err| CredentialsError {
83 message: format!("Could not get credentials from iam: {}", err.to_string()),
84 })?;
85
86 let cred_str = get_credentials_from_role(
87 &self.client,
88 self.timeout,
89 &role_name,
90 &self.metadata_ip_addr,
91 )
92 .await
93 .map_err(|err| CredentialsError {
94 message: format!("Could not get credentials from iam: {}", err.to_string()),
95 })?;
96
97 parse_credentials_from_aws_service(&cred_str)
98 }
99}
100
101async fn get_role_name(
103 client: &HttpClient,
104 timeout: Duration,
105 ip_addr: &str,
106) -> Result<String, CredentialsError> {
107 let role_name_address = format!("http://{}/{}/", ip_addr, AWS_CREDENTIALS_PROVIDER_PATH);
108 let uri = match role_name_address.parse::<Uri>() {
109 Ok(u) => u,
110 Err(e) => return Err(CredentialsError::new(e)),
111 };
112
113 Ok(client.get(uri, timeout).await?)
114}
115
116async fn get_credentials_from_role(
118 client: &HttpClient,
119 timeout: Duration,
120 role_name: &str,
121 ip_addr: &str,
122) -> Result<String, CredentialsError> {
123 let credentials_provider_url = format!(
124 "http://{}/{}/{}",
125 ip_addr, AWS_CREDENTIALS_PROVIDER_PATH, role_name
126 );
127
128 let uri = match credentials_provider_url.parse::<Uri>() {
129 Ok(u) => u,
130 Err(e) => return Err(CredentialsError::new(e)),
131 };
132
133 Ok(client.get(uri, timeout).await?)
134}