@@ -4,12 +4,14 @@ import (
44 "context"
55 "errors"
66 "fmt"
7+ "github.com/aws/aws-sdk-go-v2/aws"
8+ "github.com/aws/smithy-go"
9+ "github.com/aws/smithy-go/logging"
710 "net/http"
811 "sync"
912 "sync/atomic"
1013 "time"
1114
12- smithy "github.com/aws/smithy-go"
1315 "github.com/aws/smithy-go/middleware"
1416 smithyhttp "github.com/aws/smithy-go/transport/http"
1517)
@@ -68,7 +70,7 @@ func (t *tokenProvider) HandleFinalize(
6870) (
6971 out middleware.FinalizeOutput , metadata middleware.Metadata , err error ,
7072) {
71- if ! t .enabled () {
73+ if t . fallbackEnabled () && ! t .enabled () {
7274 // short-circuits to insecure data flow if token provider is disabled.
7375 return next .HandleFinalize (ctx , input )
7476 }
@@ -115,23 +117,15 @@ func (t *tokenProvider) HandleDeserialize(
115117 }
116118
117119 if resp .StatusCode == http .StatusUnauthorized { // unauthorized
118- err = & retryableError {Err : err }
119120 t .enable ()
121+ err = & retryableError {Err : err , isRetryable : true }
120122 }
121123
122124 return out , metadata , err
123125}
124126
125- type retryableError struct {
126- Err error
127- }
128-
129- func (* retryableError ) RetryableError () bool { return true }
130-
131- func (e * retryableError ) Error () string { return e .Err .Error () }
132-
133127func (t * tokenProvider ) getToken (ctx context.Context ) (tok * apiToken , err error ) {
134- if ! t .enabled () {
128+ if t . fallbackEnabled () && ! t .enabled () {
135129 return nil , & bypassTokenRetrievalError {
136130 Err : fmt .Errorf ("cannot get API token, provider disabled" ),
137131 }
@@ -147,7 +141,7 @@ func (t *tokenProvider) getToken(ctx context.Context) (tok *apiToken, err error)
147141
148142 tok , err = t .updateToken (ctx )
149143 if err != nil {
150- return nil , fmt . Errorf ( "cannot get API token, %w" , err )
144+ return nil , err
151145 }
152146
153147 return tok , nil
@@ -167,17 +161,19 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
167161 TokenTTL : t .tokenTTL ,
168162 })
169163 if err != nil {
170- // change the disabled flag on token provider to true, when error is request timeout error.
171164 var statusErr interface { HTTPStatusCode () int }
172165 if errors .As (err , & statusErr ) {
173166 switch statusErr .HTTPStatusCode () {
174-
175- // Disable get token if failed because of 403, 404, or 405
167+ // Disable future get token if failed because of 403, 404, or 405
176168 case http .StatusForbidden ,
177169 http .StatusNotFound ,
178170 http .StatusMethodNotAllowed :
179171
180- t .disable ()
172+ if t .fallbackEnabled () {
173+ logger := middleware .GetLogger (ctx )
174+ logger .Logf (logging .Warn , "falling back to IMDSv1: %v" , err )
175+ t .disable ()
176+ }
181177
182178 // 400 errors are terminal, and need to be upstreamed
183179 case http .StatusBadRequest :
@@ -192,8 +188,17 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
192188 atomic .StoreUint32 (& t .disabled , 1 )
193189 }
194190
195- // Token couldn't be retrieved, but bypass this, and allow the
196- // request to continue.
191+ if ! t .fallbackEnabled () {
192+ // NOTE: getToken() is an implementation detail of some outer operation
193+ // (e.g. GetMetadata). It has its own retries that have already been exhausted.
194+ // Mark the underlying error as a terminal error.
195+ err = & retryableError {Err : err , isRetryable : false }
196+ return nil , err
197+ }
198+
199+ // Token couldn't be retrieved, fallback to IMDSv1 insecure flow for this request
200+ // and allow the request to proceed. Future requests _may_ re-attempt fetching a
201+ // token if not disabled.
197202 return nil , & bypassTokenRetrievalError {Err : err }
198203 }
199204
@@ -206,21 +211,21 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
206211 return tok , nil
207212}
208213
209- type bypassTokenRetrievalError struct {
210- Err error
211- }
212-
213- func (e * bypassTokenRetrievalError ) Error () string {
214- return fmt .Sprintf ("bypass token retrieval, %v" , e .Err )
215- }
216-
217- func (e * bypassTokenRetrievalError ) Unwrap () error { return e .Err }
218-
219214// enabled returns if the token provider is current enabled or not.
220215func (t * tokenProvider ) enabled () bool {
221216 return atomic .LoadUint32 (& t .disabled ) == 0
222217}
223218
219+ // fallbackEnabled returns false if EnableFallback is [aws.FalseTernary], true otherwise
220+ func (t * tokenProvider ) fallbackEnabled () bool {
221+ switch t .client .options .EnableFallback {
222+ case aws .FalseTernary :
223+ return false
224+ default :
225+ return true
226+ }
227+ }
228+
224229// disable disables the token provider and it will no longer attempt to inject
225230// the token, nor request updates.
226231func (t * tokenProvider ) disable () {
@@ -235,3 +240,22 @@ func (t *tokenProvider) enable() {
235240 t .tokenMux .Unlock ()
236241 atomic .StoreUint32 (& t .disabled , 0 )
237242}
243+
244+ type bypassTokenRetrievalError struct {
245+ Err error
246+ }
247+
248+ func (e * bypassTokenRetrievalError ) Error () string {
249+ return fmt .Sprintf ("bypass token retrieval, %v" , e .Err )
250+ }
251+
252+ func (e * bypassTokenRetrievalError ) Unwrap () error { return e .Err }
253+
254+ type retryableError struct {
255+ Err error
256+ isRetryable bool
257+ }
258+
259+ func (e * retryableError ) RetryableError () bool { return e .isRetryable }
260+
261+ func (e * retryableError ) Error () string { return e .Err .Error () }
0 commit comments