Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mismatched and Unclear Doc on How to use InstanceProfile's Credential #4623

Closed
michaelmnguyen opened this issue Nov 14, 2022 · 8 comments
Closed
Assignees
Labels
bug This issue is a bug.

Comments

@michaelmnguyen
Copy link

Describe the bug

The use case for this issue is

  1. An IAM role is mapped to InstanceProfile, which is associated with an EC2 instance.
  2. The application that runs on this EC2 instance needs to retrieve the credentials of the InstanceProfile, so it can call AWS services such as SQS.

The AWS SDK Go doc at
https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds

talks about retrieving AWS credentials from Amazon EC2 Instance Roles via Amazon EC2 IMDS. However, there are several issues:

  1. The Go version of its APIs and therefore its usage paradigm are completely different from the Java version as described at https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/InstanceProfileCredentialsProvider.html

For instance, AWS SDK has InstanceProfileCredentialsProvider in Java. But in Golang, AWS SDK somehow uses imds.New(imds.Options{})

  1. Even for AWS SDK Go, its documentation is not clear

For instance,

provider := imds.New(imds.Options{})

What is imds ? And how does imds.Options{} indicate that it uses EC2 Instance role ?

Expected Behavior

Long-term Fix: The AWS SDK APIs and usage paradigm should be consistent across programming languages. The only difference should be syntax differences in the programming languages.

Short-term Fix: provide clear explanation of what IMDS means and how imds.Options{} indicate that it uses EC2 Instance role.

Current Behavior

Please see description.

Reproduction Steps

Please see description.

Possible Solution

Long-term Fix: The AWS SDK APIs and usage paradigm should be consistent across programming languages. The only difference should be syntax differences in the programming languages.

Short-term Fix: provide clear explanation of what IMDS means and how imds.Options{} indicate that it uses EC2 Instance role.

Additional Information/Context

No response

SDK version used

1.44.137

Environment details (Version of Go (go version)? OS name and version, etc.)

1.19

@michaelmnguyen michaelmnguyen added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Nov 14, 2022
@RanVaknin RanVaknin self-assigned this Nov 14, 2022
@RanVaknin
Copy link
Contributor

Hi @michaelmnguyen ,

Thanks for opening this issue, I'll take a look and get back to you as soon as possible.

Ran~

@RanVaknin RanVaknin added investigating This issue is being investigated and/or work is in progress to resolve the issue. and removed needs-triage This issue or PR still needs to be triaged. labels Nov 14, 2022
@RanVaknin
Copy link
Contributor

RanVaknin commented Nov 14, 2022

Hi @michaelmnguyen ,

Just to give you some background The EC2 Instance Metadata Service (IMDS) is data about an instance that can be used to configure or manage the running instance.

Regarding our documentation, I can confirm that this is broken and I apologize for that. I will add a backlog item to fix this with a working example.

Here is my setup and how I got it to work:

1. IAM Role setup:

  • Created an IAM role following this workflow.
  • Gave the role permissions to call the desired service (in my case it was s3)
  • Attached the role to the EC2 instance

2. GO code to be run inside instance:
(Please note the code here is v2, not v1. You should be able to mix and match v1 and v2 imports safely. I was not able to find clear enough resources to make this work in v1. If you are struggling to make this work please let me know and I'll do some more research)

package main

import (
	"context"
	"fmt"
	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds"
	"github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
	
	// Get a credential provider from the configured role attached to the currently running EC2 instance
	provider := ec2rolecreds.New()

	// Construct a client, wrap the provider in a cache, and supply the region for the desired service (in my case buckets live on us-east-2
	client := s3.New(s3.Options{
		Credentials: aws.NewCredentialsCache(provider),
		Region:      "us-east-2",
	})
	
	out, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})
	if err != nil {
		panic(err)
	}

	fmt.Println(len(out.Buckets))
}

3. Run on EC2 host:

  • For us to run this first we need to cross compile it for the intended operating system and processor. In my case Im using a Linux OS with an AMD64 processor. To build my binary I will run GOOS=linux GOARCH=amd64 go build main.go
  • Copy the binary file into our remote EC2 host:
    scp -i path/to/my/pemfile.pem main ec2-user@ec2-x-xxx-xxx-xxx.us-east-2.compute.amazonaws.com:~/.
  • Preferably in a new terminal ssh into the host and run the binary we copied over:
    ./main

Output:

17 // I have 17 buckets in us-east-2

Additionally, I'd like to address these two remarks:

Long-term Fix: The AWS SDK APIs and usage paradigm should be consistent across programming languages. The only difference should be syntax differences in the programming languages.

All the SDK clients are auto-generated from the service models that service team publishes. Other utilities like IMDS are hand written and aside from the guidelines we receive each SDK team implements it based on the merit of the respective language. Why there are big differences - I cannot tell but this is a good point.

Short-term Fix: provide clear explanation of what IMDS means and how imds.Options{} indicate that it uses EC2 Instance role.

To reinforce what I've written in the above point, 99% of the SDK is code generated including documentation. IMDS is different in that It was up to the team to write and document everything and this clearly fell between the cracks. I apologize for that.

Please let me know if this helps.
All the best,
Ran~

@RanVaknin RanVaknin added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed investigating This issue is being investigated and/or work is in progress to resolve the issue. labels Nov 14, 2022
@michaelmnguyen
Copy link
Author

Hi @RanVaknin,

Thank you for the quick and detailed response. The role set up and sample working code are very helpful. I will try them out on my side and let you know.

Michael,

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Nov 16, 2022
@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

@michaelmnguyen
Copy link
Author

Hi @RanVaknin Sorry for the delayed response on this thread. It was due to some production issues on my side in addition to being sick over the Thanksgiving week.

I was able to get the security for InstanceProfile in golang to work with the sample code you provided for S3 bucket. I also tested it with different VPCs to make sure it works consistently with different network settings.

My follow-up questions are

  1. For SQS, Golang version of AWS SDK has sqs.ReceiveMessageWithContext API
    to retrieve messages from the SQS queue. However, if the queue does not have any messages, this API just returns an empty result. So the client code has to continuously call this API until the queue has a message.

    On the other hand, the Java version of AWS SDK has an API that is synchronous where it blocks and returns to the client apps only when the queue has a message. Does the Golang version of AWS SDK has the equivalent API ? If not, does AWS SDK expect the client apps to continuously call ReceiveMessageWithContext in a loop ?

  2. The broader aspect is as a Best Practice, any SDK should provide the same APIs, regardless of the programming languages. The only difference should be the syntax among the programming languages. Could AWS do that for its SDK ? As is, AWS APIs and their paradigms at least between Java and Golang are totally different.

Thanks.

Michael Nguyen,

@RanVaknin RanVaknin reopened this Nov 29, 2022
@RanVaknin
Copy link
Contributor

RanVaknin commented Nov 29, 2022

Hi @michaelmnguyen ,

Thanks for following up. Sorry to hear about you being sick, but I'm glad the solution provided works for you.

I'll address your new concerns here, but in the future if any more issues arise please open a separate ticket.

Both Java's and Go's operations are acting the same way. The SDK client will attempt to make a call to retrieve messages from the queue, if the queue is empty it will return an empty result.
I've confirmed with @debora-ito from the Java SDK team that this behavior is the same.

What you are describing is a Waiter, and SQS does not have any waiters defined for their API - so this behavior of waiting until there's a response, does not exist for this particular service.

regarding this:

The broader aspect is as a Best Practice, any SDK should provide the same APIs, regardless of the programming languages. The only difference should be the syntax among the programming languages. Could AWS do that for its SDK ? As is, AWS APIs and their paradigms at least between Java and Golang are totally different.

Aside from language specific differences, 99% of the SDK's clients are auto-generated from the models of their respective service APIs. So the behavior should, and is the same across all SDKs.
This was not the case for IMDS since this is not an auto-generated utility.

Let me know if you have any other questions.
Thanks,
Ran~

@michaelmnguyen
Copy link
Author

Thanks @RanVaknin for the quick response. My posts for the new issues about the blocking call for SQS and SDK across languages at #4642 and #4643 were crossed with your response in this thread.

I will follow up with you in those threads as needed.

Michael,

@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug.
Projects
None yet
Development

No branches or pull requests

2 participants