provider.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. import (
  35. "context"
  36. "fmt"
  37. "net/http"
  38. "github.com/aws/aws-sdk-go-v2/aws"
  39. "github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client"
  40. "github.com/aws/smithy-go/middleware"
  41. )
  42. // ProviderName is the name of the credentials provider.
  43. const ProviderName = `CredentialsEndpointProvider`
  44. type getCredentialsAPIClient interface {
  45. GetCredentials(context.Context, *client.GetCredentialsInput, ...func(*client.Options)) (*client.GetCredentialsOutput, error)
  46. }
  47. // Provider satisfies the aws.CredentialsProvider interface, and is a client to
  48. // retrieve credentials from an arbitrary endpoint.
  49. type Provider struct {
  50. // The AWS Client to make HTTP requests to the endpoint with. The endpoint
  51. // the request will be made to is provided by the aws.Config's
  52. // EndpointResolver.
  53. client getCredentialsAPIClient
  54. options Options
  55. }
  56. // HTTPClient is a client for sending HTTP requests
  57. type HTTPClient interface {
  58. Do(*http.Request) (*http.Response, error)
  59. }
  60. // Options is structure of configurable options for Provider
  61. type Options struct {
  62. // Endpoint to retrieve credentials from. Required
  63. Endpoint string
  64. // HTTPClient to handle sending HTTP requests to the target endpoint.
  65. HTTPClient HTTPClient
  66. // Set of options to modify how the credentials operation is invoked.
  67. APIOptions []func(*middleware.Stack) error
  68. // The Retryer to be used for determining whether a failed requested should be retried
  69. Retryer aws.Retryer
  70. // Optional authorization token value if set will be used as the value of
  71. // the Authorization header of the endpoint credential request.
  72. AuthorizationToken string
  73. }
  74. // New returns a credentials Provider for retrieving AWS credentials
  75. // from arbitrary endpoint.
  76. func New(endpoint string, optFns ...func(*Options)) *Provider {
  77. o := Options{
  78. Endpoint: endpoint,
  79. }
  80. for _, fn := range optFns {
  81. fn(&o)
  82. }
  83. p := &Provider{
  84. client: client.New(client.Options{
  85. HTTPClient: o.HTTPClient,
  86. Endpoint: o.Endpoint,
  87. APIOptions: o.APIOptions,
  88. Retryer: o.Retryer,
  89. }),
  90. options: o,
  91. }
  92. return p
  93. }
  94. // Retrieve will attempt to request the credentials from the endpoint the Provider
  95. // was configured for. And error will be returned if the retrieval fails.
  96. func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) {
  97. resp, err := p.getCredentials(ctx)
  98. if err != nil {
  99. return aws.Credentials{}, fmt.Errorf("failed to load credentials, %w", err)
  100. }
  101. creds := aws.Credentials{
  102. AccessKeyID: resp.AccessKeyID,
  103. SecretAccessKey: resp.SecretAccessKey,
  104. SessionToken: resp.Token,
  105. Source: ProviderName,
  106. }
  107. if resp.Expiration != nil {
  108. creds.CanExpire = true
  109. creds.Expires = *resp.Expiration
  110. }
  111. return creds, nil
  112. }
  113. func (p *Provider) getCredentials(ctx context.Context) (*client.GetCredentialsOutput, error) {
  114. return p.client.GetCredentials(ctx, &client.GetCredentialsInput{AuthorizationToken: p.options.AuthorizationToken})
  115. }