-
Notifications
You must be signed in to change notification settings - Fork 295
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
Implement Amazon's IMDSv2 #249
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -12,9 +12,12 @@ import ( | |||||||
) | ||||||||
|
||||||||
const ( | ||||||||
awsHostname = "169.254.169.254" | ||||||||
awsEndpointPath = "/2016-09-02/dynamic/instance-identity/document" | ||||||||
awsEndpoint = "http://" + awsHostname + awsEndpointPath | ||||||||
awsHostname = "169.254.169.254" | ||||||||
awsEndpointPath = "/2016-09-02/dynamic/instance-identity/document" | ||||||||
awsTokenEndpointPath = "/latest/api/token" | ||||||||
awsEndpoint = "http://" + awsHostname + awsEndpointPath | ||||||||
awsTokenEndpoint = "http://" + awsHostname + awsTokenEndpointPath | ||||||||
awsTokenTTL = "60" // seconds this AWS utiliation session will last | ||||||||
) | ||||||||
|
||||||||
type aws struct { | ||||||||
|
@@ -44,6 +47,24 @@ func (e unexpectedAWSErr) Error() string { | |||||||
return fmt.Sprintf("unexpected AWS error: %v", e.e) | ||||||||
} | ||||||||
|
||||||||
// getAWSToken attempts to get the IMDSv2 token within the providerTimeout set | ||||||||
// provider.go. | ||||||||
func getAWSToken(client *http.Client) (token string, err error) { | ||||||||
request, err := http.NewRequest("PUT", awsTokenEndpoint, nil) | ||||||||
request.Header.Add("X-aws-ec2-metadata-token-ttl-seconds", awsTokenTTL) | ||||||||
response, err := client.Do(request) | ||||||||
if err != nil { | ||||||||
return "", err | ||||||||
} | ||||||||
defer response.Body.Close() | ||||||||
body, err := ioutil.ReadAll(response.Body) | ||||||||
if err != nil { | ||||||||
return "", err | ||||||||
} | ||||||||
|
||||||||
return string(body), nil | ||||||||
} | ||||||||
|
||||||||
func getAWS(client *http.Client) (ret *aws, err error) { | ||||||||
// In some cases, 3rd party providers might block requests to metadata | ||||||||
// endpoints in such a way that causes a panic in the underlying | ||||||||
|
@@ -56,7 +77,18 @@ func getAWS(client *http.Client) (ret *aws, err error) { | |||||||
} | ||||||||
}() | ||||||||
|
||||||||
response, err := client.Get(awsEndpoint) | ||||||||
// AWS' IMDSv2 requires us to get a token before requesting metadata. | ||||||||
awsToken, err := getAWSToken(client) | ||||||||
if err != nil { | ||||||||
ret = nil | ||||||||
err = unexpectedAWSErr{e: fmt.Errorf("error contacting AWS IMDSv2 token endpoint, %v", err)} | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should return here, if an error happened, right?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or, maybe you could create a request to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for noticing this! After thinking harder about it, we shouldn't throw an unExpectedAWSErr at all, we're expecting a timeout unless they're in AWS. Fixing this and the test. A more thorough implementation would raise errors on other HTTP errors, but I'm deferring that work in the interest of time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding the extra request to awsEndpoint, I'd rather avoid making three calls to AWS and increasing the overhead by another 0.5 second on startup. As of now, IMDSv2 endpoints are always available -- the only control the customer has is to turn IMDSv1 off to help their security posture. |
||||||||
} | ||||||||
|
||||||||
//Add the header to the outbound request. | ||||||||
request, err := http.NewRequest("GET", awsEndpoint, nil) | ||||||||
request.Header.Add("X-aws-ec2-metadata-token", awsToken) | ||||||||
|
||||||||
response, err := client.Do(request) | ||||||||
if err != nil { | ||||||||
// No unexpectedAWSErr here: A timeout is usually going to | ||||||||
// happen. | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.