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 }