github.com/aavshr/aws-sdk-go@v1.41.3/aws/credentials/plugincreds/provider.go (about)

     1  //go:build go1.8
     2  // +build go1.8
     3  
     4  // Package plugincreds implements a credentials provider sourced from a Go
     5  // plugin. This package allows you to use a Go plugin to retrieve AWS credentials
     6  // for the SDK to use for service API calls.
     7  //
     8  // As of Go 1.8 plugins are only supported on the Linux platform.
     9  //
    10  // Plugin Symbol Name
    11  //
    12  // The "GetAWSSDKCredentialProvider" is the symbol name that will be used to
    13  // lookup the credentials provider getter from the plugin. If you want to use a
    14  // custom symbol name you should use GetPluginProviderFnsByName to lookup the
    15  // symbol by a custom name.
    16  //
    17  // This symbol is a function that returns two additional functions. One to
    18  // retrieve the credentials, and another to determine if the credentials have
    19  // expired.
    20  //
    21  // Plugin Symbol Signature
    22  //
    23  // The plugin credential provider requires the symbol to match the
    24  // following signature.
    25  //
    26  //   func() (RetrieveFn func() (key, secret, token string, err error), IsExpiredFn func() bool)
    27  //
    28  // Plugin Implementation Example
    29  //
    30  // The following is an example implementation of a SDK credential provider using
    31  // the plugin provider in this package. See the SDK's example/aws/credential/plugincreds/plugin
    32  // folder for a runnable example of this.
    33  //
    34  //   package main
    35  //
    36  //   func main() {}
    37  //
    38  //   var myCredProvider provider
    39  //
    40  //   // Build: go build -o plugin.so -buildmode=plugin plugin.go
    41  //   func init() {
    42  //   	// Initialize a mock credential provider with stubs
    43  //   	myCredProvider = provider{"a","b","c"}
    44  //   }
    45  //
    46  //   // GetAWSSDKCredentialProvider is the symbol SDK will lookup and use to
    47  //   // get the credential provider's retrieve and isExpired functions.
    48  //   func GetAWSSDKCredentialProvider() (func() (key, secret, token string, err error), func() bool) {
    49  //   	return myCredProvider.Retrieve,	myCredProvider.IsExpired
    50  //   }
    51  //
    52  //   // mock implementation of a type that returns retrieves credentials and
    53  //   // returns if they have expired.
    54  //   type provider struct {
    55  //   	key, secret, token string
    56  //   }
    57  //
    58  //   func (p provider) Retrieve() (key, secret, token string, err error) {
    59  //   	return p.key, p.secret, p.token, nil
    60  //   }
    61  //
    62  //   func (p *provider) IsExpired() bool {
    63  //   	return false;
    64  //   }
    65  //
    66  // Configuring SDK for Plugin Credentials
    67  //
    68  // To configure the SDK to use a plugin's credential provider you'll need to first
    69  // open the plugin file using the plugin standard library package. Once you have
    70  // a handle to the plugin you can use the NewCredentials function of this package
    71  // to create a new credentials.Credentials value that can be set as the
    72  // credentials loader of a Session or Config. See the SDK's example/aws/credential/plugincreds
    73  // folder for a runnable example of this.
    74  //
    75  //   // Open plugin, and load it into the process.
    76  //   p, err := plugin.Open("somefile.so")
    77  //   if err != nil {
    78  //   	return nil, err
    79  //   }
    80  //
    81  //   // Create a new Credentials value which will source the provider's Retrieve
    82  //   // and IsExpired functions from the plugin.
    83  //   creds, err := plugincreds.NewCredentials(p)
    84  //   if err != nil {
    85  //   	return nil, err
    86  //   }
    87  //
    88  //   // Example to configure a Session with the newly created credentials that
    89  //   // will be sourced using the plugin's functionality.
    90  //   sess := session.Must(session.NewSession(&aws.Config{
    91  //   	Credentials:  creds,
    92  //   }))
    93  package plugincreds
    94  
    95  import (
    96  	"fmt"
    97  	"plugin"
    98  
    99  	"github.com/aavshr/aws-sdk-go/aws/awserr"
   100  	"github.com/aavshr/aws-sdk-go/aws/credentials"
   101  )
   102  
   103  // ProviderSymbolName the symbol name the SDK will use to lookup the plugin
   104  // provider value from.
   105  const ProviderSymbolName = `GetAWSSDKCredentialProvider`
   106  
   107  // ProviderName is the name this credentials provider will label any returned
   108  // credentials Value with.
   109  const ProviderName = `PluginCredentialsProvider`
   110  
   111  const (
   112  	// ErrCodeLookupSymbolError failed to lookup symbol
   113  	ErrCodeLookupSymbolError = "LookupSymbolError"
   114  
   115  	// ErrCodeInvalidSymbolError symbol invalid
   116  	ErrCodeInvalidSymbolError = "InvalidSymbolError"
   117  
   118  	// ErrCodePluginRetrieveNil Retrieve function was nil
   119  	ErrCodePluginRetrieveNil = "PluginRetrieveNilError"
   120  
   121  	// ErrCodePluginIsExpiredNil IsExpired Function was nil
   122  	ErrCodePluginIsExpiredNil = "PluginIsExpiredNilError"
   123  
   124  	// ErrCodePluginProviderRetrieve plugin provider's retrieve returned error
   125  	ErrCodePluginProviderRetrieve = "PluginProviderRetrieveError"
   126  )
   127  
   128  // Provider is the credentials provider that will use the plugin provided
   129  // Retrieve and IsExpired functions to retrieve credentials.
   130  type Provider struct {
   131  	RetrieveFn  func() (key, secret, token string, err error)
   132  	IsExpiredFn func() bool
   133  }
   134  
   135  // NewCredentials returns a new Credentials loader using the plugin provider.
   136  // If the symbol isn't found or is invalid in the plugin an error will be
   137  // returned.
   138  func NewCredentials(p *plugin.Plugin) (*credentials.Credentials, error) {
   139  	retrieve, isExpired, err := GetPluginProviderFns(p)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	return credentials.NewCredentials(Provider{
   145  		RetrieveFn:  retrieve,
   146  		IsExpiredFn: isExpired,
   147  	}), nil
   148  }
   149  
   150  // Retrieve will return the credentials Value if they were successfully retrieved
   151  // from the underlying plugin provider. An error will be returned otherwise.
   152  func (p Provider) Retrieve() (credentials.Value, error) {
   153  	creds := credentials.Value{
   154  		ProviderName: ProviderName,
   155  	}
   156  
   157  	k, s, t, err := p.RetrieveFn()
   158  	if err != nil {
   159  		return creds, awserr.New(ErrCodePluginProviderRetrieve,
   160  			"failed to retrieve credentials with plugin provider", err)
   161  	}
   162  
   163  	creds.AccessKeyID = k
   164  	creds.SecretAccessKey = s
   165  	creds.SessionToken = t
   166  
   167  	return creds, nil
   168  }
   169  
   170  // IsExpired will return the expired state of the underlying plugin provider.
   171  func (p Provider) IsExpired() bool {
   172  	return p.IsExpiredFn()
   173  }
   174  
   175  // GetPluginProviderFns returns the plugin's Retrieve and IsExpired functions
   176  // returned by the plugin's credential provider getter.
   177  //
   178  // Uses ProviderSymbolName as the symbol name when lookup up the symbol. If you
   179  // want to use a different symbol name, use GetPluginProviderFnsByName.
   180  func GetPluginProviderFns(p *plugin.Plugin) (func() (key, secret, token string, err error), func() bool, error) {
   181  	return GetPluginProviderFnsByName(p, ProviderSymbolName)
   182  }
   183  
   184  // GetPluginProviderFnsByName returns the plugin's Retrieve and IsExpired functions
   185  // returned by the plugin's credential provider getter.
   186  //
   187  // Same as GetPluginProviderFns, but takes a custom symbolName to lookup with.
   188  func GetPluginProviderFnsByName(p *plugin.Plugin, symbolName string) (func() (key, secret, token string, err error), func() bool, error) {
   189  	sym, err := p.Lookup(symbolName)
   190  	if err != nil {
   191  		return nil, nil, awserr.New(ErrCodeLookupSymbolError,
   192  			fmt.Sprintf("failed to lookup %s plugin provider symbol", symbolName), err)
   193  	}
   194  
   195  	fn, ok := sym.(func() (func() (key, secret, token string, err error), func() bool))
   196  	if !ok {
   197  		return nil, nil, awserr.New(ErrCodeInvalidSymbolError,
   198  			fmt.Sprintf("symbol %T, does not match the 'func() (func() (key, secret, token string, err error), func() bool)'  type", sym), nil)
   199  	}
   200  
   201  	retrieveFn, isExpiredFn := fn()
   202  	if retrieveFn == nil {
   203  		return nil, nil, awserr.New(ErrCodePluginRetrieveNil,
   204  			"the plugin provider retrieve function cannot be nil", nil)
   205  	}
   206  	if isExpiredFn == nil {
   207  		return nil, nil, awserr.New(ErrCodePluginIsExpiredNil,
   208  			"the plugin provider isExpired function cannot be nil", nil)
   209  	}
   210  
   211  	return retrieveFn, isExpiredFn, nil
   212  }