134 lines
3.9 KiB
Go
134 lines
3.9 KiB
Go
// Package endpointcreds provides support for retrieving credentials from an
|
|
// arbitrary HTTP endpoint.
|
|
//
|
|
// The credentials endpoint Provider can receive both static and refreshable
|
|
// credentials that will expire. Credentials are static when an "Expiration"
|
|
// value is not provided in the endpoint's response.
|
|
//
|
|
// Static credentials will never expire once they have been retrieved. The format
|
|
// of the static credentials response:
|
|
// {
|
|
// "AccessKeyId" : "MUA...",
|
|
// "SecretAccessKey" : "/7PC5om....",
|
|
// }
|
|
//
|
|
// Refreshable credentials will expire within the "ExpiryWindow" of the Expiration
|
|
// value in the response. The format of the refreshable credentials response:
|
|
// {
|
|
// "AccessKeyId" : "MUA...",
|
|
// "SecretAccessKey" : "/7PC5om....",
|
|
// "Token" : "AQoDY....=",
|
|
// "Expiration" : "2016-02-25T06:03:31Z"
|
|
// }
|
|
//
|
|
// Errors should be returned in the following format and only returned with 400
|
|
// or 500 HTTP status codes.
|
|
// {
|
|
// "code": "ErrorCode",
|
|
// "message": "Helpful error message."
|
|
// }
|
|
package endpointcreds
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
"github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client"
|
|
"github.com/aws/smithy-go/middleware"
|
|
)
|
|
|
|
// ProviderName is the name of the credentials provider.
|
|
const ProviderName = `CredentialsEndpointProvider`
|
|
|
|
type getCredentialsAPIClient interface {
|
|
GetCredentials(context.Context, *client.GetCredentialsInput, ...func(*client.Options)) (*client.GetCredentialsOutput, error)
|
|
}
|
|
|
|
// Provider satisfies the aws.CredentialsProvider interface, and is a client to
|
|
// retrieve credentials from an arbitrary endpoint.
|
|
type Provider struct {
|
|
// The AWS Client to make HTTP requests to the endpoint with. The endpoint
|
|
// the request will be made to is provided by the aws.Config's
|
|
// EndpointResolver.
|
|
client getCredentialsAPIClient
|
|
|
|
options Options
|
|
}
|
|
|
|
// HTTPClient is a client for sending HTTP requests
|
|
type HTTPClient interface {
|
|
Do(*http.Request) (*http.Response, error)
|
|
}
|
|
|
|
// Options is structure of configurable options for Provider
|
|
type Options struct {
|
|
// Endpoint to retrieve credentials from. Required
|
|
Endpoint string
|
|
|
|
// HTTPClient to handle sending HTTP requests to the target endpoint.
|
|
HTTPClient HTTPClient
|
|
|
|
// Set of options to modify how the credentials operation is invoked.
|
|
APIOptions []func(*middleware.Stack) error
|
|
|
|
// The Retryer to be used for determining whether a failed requested should be retried
|
|
Retryer aws.Retryer
|
|
|
|
// Optional authorization token value if set will be used as the value of
|
|
// the Authorization header of the endpoint credential request.
|
|
AuthorizationToken string
|
|
}
|
|
|
|
// New returns a credentials Provider for retrieving AWS credentials
|
|
// from arbitrary endpoint.
|
|
func New(endpoint string, optFns ...func(*Options)) *Provider {
|
|
o := Options{
|
|
Endpoint: endpoint,
|
|
}
|
|
|
|
for _, fn := range optFns {
|
|
fn(&o)
|
|
}
|
|
|
|
p := &Provider{
|
|
client: client.New(client.Options{
|
|
HTTPClient: o.HTTPClient,
|
|
Endpoint: o.Endpoint,
|
|
APIOptions: o.APIOptions,
|
|
Retryer: o.Retryer,
|
|
}),
|
|
options: o,
|
|
}
|
|
|
|
return p
|
|
}
|
|
|
|
// Retrieve will attempt to request the credentials from the endpoint the Provider
|
|
// was configured for. And error will be returned if the retrieval fails.
|
|
func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) {
|
|
resp, err := p.getCredentials(ctx)
|
|
if err != nil {
|
|
return aws.Credentials{}, fmt.Errorf("failed to load credentials, %w", err)
|
|
}
|
|
|
|
creds := aws.Credentials{
|
|
AccessKeyID: resp.AccessKeyID,
|
|
SecretAccessKey: resp.SecretAccessKey,
|
|
SessionToken: resp.Token,
|
|
Source: ProviderName,
|
|
}
|
|
|
|
if resp.Expiration != nil {
|
|
creds.CanExpire = true
|
|
creds.Expires = *resp.Expiration
|
|
}
|
|
|
|
return creds, nil
|
|
}
|
|
|
|
func (p *Provider) getCredentials(ctx context.Context) (*client.GetCredentialsOutput, error) {
|
|
return p.client.GetCredentials(ctx, &client.GetCredentialsInput{AuthorizationToken: p.options.AuthorizationToken})
|
|
}
|