code.dwrz.net

Go monorepo.
Log | Files | Refs

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 }