Search code examples
amazon-web-servicesrustamazon-ec2

AWS EC2 | using Rusoto SDK: Couldn't find AWS credentials


I am trying to work with the new Instance Metadata Service Version 2 (IMDSv2) API.

It works as expected when I try to query the metadata manually as described on Retrieve instance metadata - Amazon Elastic Compute Cloud.

However, if I try to query for the instance tags it fails with error message:

Couldn't find AWS credentials in environment, credentials file, or IAM role

The tags query is done by the Rusoto SDK that I am using, that works when I set --http-tokens optional as described on Configure the instance metadata options - Amazon Elastic Compute Cloud.

I don't fully understand why setting the machine to work with IMDSv2 would effect the DescribeTags request, as I believe it's not using the same API - so I am guessing that's a side effect.

If I try and do a manual query using curl (instead of using the SDK):

https://ec2.amazonaws.com/?Action=DescribeTags&Filter.1.Name=resource-id&Filter.1.Value.1=ami-1a2b3c4d

I get:

The action DescribeTags is not valid for this web service


Solution

  • The library that I was using (Rusoto SDK 0.47.0) doesn't support fetching the credentials needed when the host is set to work with the IMDSv2.

    The workaround was to manually query for the IAM role credentials. First, you get the token:

    GET /latest/api/token
    

    Next, use the token header "X-aws-ec2-metadata-token" with the value from the previous:

    GET /meta-data/iam/security-credentials
    

    Afterwards, use the result from the previous query (and don't forget to set the token header), and query:

    GET /meta-data/iam/security-credentials/<query 2 result>
    

    This will provide with the following data:

    struct SecurityCredentials {
    #[serde(rename = "AccessKeyId")]
    access_key_id: String,
    #[serde(rename = "SecretAccessKey")]
    secret_access_key: String,
    #[serde(rename = "Token")]
    token: String,
    }
    

    Then what I needed to do was to build a custom credentials provider using that data (but this part is already lib specific).