github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/internal/credproviders/ecs_provider.go (about) 1 // Copyright (C) MongoDB, Inc. 2023-present. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7 package credproviders 8 9 import ( 10 "context" 11 "encoding/json" 12 "errors" 13 "fmt" 14 "net/http" 15 "time" 16 17 "go.mongodb.org/mongo-driver/internal/aws/credentials" 18 ) 19 20 const ( 21 // ecsProviderName provides a name of ECS provider 22 ecsProviderName = "ECSProvider" 23 24 awsRelativeURI = "http://169.254.170.2/" 25 ) 26 27 // An ECSProvider retrieves credentials from ECS metadata. 28 type ECSProvider struct { 29 AwsContainerCredentialsRelativeURIEnv EnvVar 30 31 httpClient *http.Client 32 expiration time.Time 33 34 // expiryWindow will allow the credentials to trigger refreshing prior to the credentials actually expiring. 35 // This is beneficial so expiring credentials do not cause request to fail unexpectedly due to exceptions. 36 // 37 // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true 38 // 10 seconds before the credentials are actually expired. 39 expiryWindow time.Duration 40 } 41 42 // NewECSProvider returns a pointer to an ECS credential provider. 43 func NewECSProvider(httpClient *http.Client, expiryWindow time.Duration) *ECSProvider { 44 return &ECSProvider{ 45 // AwsContainerCredentialsRelativeURIEnv is the environment variable for AWS_CONTAINER_CREDENTIALS_RELATIVE_URI 46 AwsContainerCredentialsRelativeURIEnv: EnvVar("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"), 47 httpClient: httpClient, 48 expiryWindow: expiryWindow, 49 } 50 } 51 52 // RetrieveWithContext retrieves the keys from the AWS service. 53 func (e *ECSProvider) RetrieveWithContext(ctx context.Context) (credentials.Value, error) { 54 const defaultHTTPTimeout = 10 * time.Second 55 56 v := credentials.Value{ProviderName: ecsProviderName} 57 58 relativeEcsURI := e.AwsContainerCredentialsRelativeURIEnv.Get() 59 if len(relativeEcsURI) == 0 { 60 return v, errors.New("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI is missing") 61 } 62 fullURI := awsRelativeURI + relativeEcsURI 63 64 req, err := http.NewRequest(http.MethodGet, fullURI, nil) 65 if err != nil { 66 return v, err 67 } 68 req.Header.Set("Accept", "application/json") 69 70 ctx, cancel := context.WithTimeout(ctx, defaultHTTPTimeout) 71 defer cancel() 72 resp, err := e.httpClient.Do(req.WithContext(ctx)) 73 if err != nil { 74 return v, err 75 } 76 defer resp.Body.Close() 77 if resp.StatusCode != http.StatusOK { 78 return v, fmt.Errorf("response failure: %s", resp.Status) 79 } 80 81 var ecsResp struct { 82 AccessKeyID string `json:"AccessKeyId"` 83 SecretAccessKey string `json:"SecretAccessKey"` 84 Token string `json:"Token"` 85 Expiration time.Time `json:"Expiration"` 86 } 87 88 err = json.NewDecoder(resp.Body).Decode(&ecsResp) 89 if err != nil { 90 return v, err 91 } 92 93 v.AccessKeyID = ecsResp.AccessKeyID 94 v.SecretAccessKey = ecsResp.SecretAccessKey 95 v.SessionToken = ecsResp.Token 96 if !v.HasKeys() { 97 return v, errors.New("failed to retrieve ECS keys") 98 } 99 e.expiration = ecsResp.Expiration.Add(-e.expiryWindow) 100 101 return v, nil 102 } 103 104 // Retrieve retrieves the keys from the AWS service. 105 func (e *ECSProvider) Retrieve() (credentials.Value, error) { 106 return e.RetrieveWithContext(context.Background()) 107 } 108 109 // IsExpired returns true if the credentials are expired. 110 func (e *ECSProvider) IsExpired() bool { 111 return e.expiration.Before(time.Now()) 112 }