provider.go (4000B)
1 // Package endpointcreds provides support for retrieving credentials from an 2 // arbitrary HTTP endpoint. 3 // 4 // The credentials endpoint Provider can receive both static and refreshable 5 // credentials that will expire. Credentials are static when an "Expiration" 6 // value is not provided in the endpoint's response. 7 // 8 // Static credentials will never expire once they have been retrieved. The format 9 // of the static credentials response: 10 // 11 // { 12 // "AccessKeyId" : "MUA...", 13 // "SecretAccessKey" : "/7PC5om....", 14 // } 15 // 16 // Refreshable credentials will expire within the "ExpiryWindow" of the Expiration 17 // value in the response. The format of the refreshable credentials response: 18 // 19 // { 20 // "AccessKeyId" : "MUA...", 21 // "SecretAccessKey" : "/7PC5om....", 22 // "Token" : "AQoDY....=", 23 // "Expiration" : "2016-02-25T06:03:31Z" 24 // } 25 // 26 // Errors should be returned in the following format and only returned with 400 27 // or 500 HTTP status codes. 28 // 29 // { 30 // "code": "ErrorCode", 31 // "message": "Helpful error message." 32 // } 33 package endpointcreds 34 35 import ( 36 "context" 37 "fmt" 38 "net/http" 39 40 "github.com/aws/aws-sdk-go-v2/aws" 41 "github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client" 42 "github.com/aws/smithy-go/middleware" 43 ) 44 45 // ProviderName is the name of the credentials provider. 46 const ProviderName = `CredentialsEndpointProvider` 47 48 type getCredentialsAPIClient interface { 49 GetCredentials(context.Context, *client.GetCredentialsInput, ...func(*client.Options)) (*client.GetCredentialsOutput, error) 50 } 51 52 // Provider satisfies the aws.CredentialsProvider interface, and is a client to 53 // retrieve credentials from an arbitrary endpoint. 54 type Provider struct { 55 // The AWS Client to make HTTP requests to the endpoint with. The endpoint 56 // the request will be made to is provided by the aws.Config's 57 // EndpointResolver. 58 client getCredentialsAPIClient 59 60 options Options 61 } 62 63 // HTTPClient is a client for sending HTTP requests 64 type HTTPClient interface { 65 Do(*http.Request) (*http.Response, error) 66 } 67 68 // Options is structure of configurable options for Provider 69 type Options struct { 70 // Endpoint to retrieve credentials from. Required 71 Endpoint string 72 73 // HTTPClient to handle sending HTTP requests to the target endpoint. 74 HTTPClient HTTPClient 75 76 // Set of options to modify how the credentials operation is invoked. 77 APIOptions []func(*middleware.Stack) error 78 79 // The Retryer to be used for determining whether a failed requested should be retried 80 Retryer aws.Retryer 81 82 // Optional authorization token value if set will be used as the value of 83 // the Authorization header of the endpoint credential request. 84 AuthorizationToken string 85 } 86 87 // New returns a credentials Provider for retrieving AWS credentials 88 // from arbitrary endpoint. 89 func New(endpoint string, optFns ...func(*Options)) *Provider { 90 o := Options{ 91 Endpoint: endpoint, 92 } 93 94 for _, fn := range optFns { 95 fn(&o) 96 } 97 98 p := &Provider{ 99 client: client.New(client.Options{ 100 HTTPClient: o.HTTPClient, 101 Endpoint: o.Endpoint, 102 APIOptions: o.APIOptions, 103 Retryer: o.Retryer, 104 }), 105 options: o, 106 } 107 108 return p 109 } 110 111 // Retrieve will attempt to request the credentials from the endpoint the Provider 112 // was configured for. And error will be returned if the retrieval fails. 113 func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) { 114 resp, err := p.getCredentials(ctx) 115 if err != nil { 116 return aws.Credentials{}, fmt.Errorf("failed to load credentials, %w", err) 117 } 118 119 creds := aws.Credentials{ 120 AccessKeyID: resp.AccessKeyID, 121 SecretAccessKey: resp.SecretAccessKey, 122 SessionToken: resp.Token, 123 Source: ProviderName, 124 } 125 126 if resp.Expiration != nil { 127 creds.CanExpire = true 128 creds.Expires = *resp.Expiration 129 } 130 131 return creds, nil 132 } 133 134 func (p *Provider) getCredentials(ctx context.Context) (*client.GetCredentialsOutput, error) { 135 return p.client.GetCredentials(ctx, &client.GetCredentialsInput{AuthorizationToken: p.options.AuthorizationToken}) 136 }