@@ -150,12 +150,60 @@ function _credentialsTempFile() {
150
150
}
151
151
152
152
/**
153
- * Read the contents of the credentials file into memory. If it is not
154
- * found, then return undefined.
153
+ * Write the instance profile credentials to a caching backend.
155
154
*
156
- * @returns {undefined|object } AWS instance profile credentials or undefined
155
+ * @param r {Request} HTTP request object (not used, but required for NGINX configuration)
156
+ * @param credentials {{accessKeyId: (string), secretAccessKey: (string), sessionToken: (string), expiration: (string)}} AWS instance profile credentials
157
157
*/
158
- function readCredentials ( ) {
158
+ function writeCredentials ( r , credentials ) {
159
+ // Do not bother writing credentials if we are running in a mode where we
160
+ // do not need instance credentials.
161
+ if ( process . env [ 'S3_ACCESS_KEY_ID' ] && process . env [ 'S3_SECRET_KEY' ] ) {
162
+ return ;
163
+ }
164
+
165
+ if ( ! credentials ) {
166
+ throw `Cannot write invalid credentials: ${ JSON . stringify ( credentials ) } ` ;
167
+ }
168
+
169
+ if ( "variables" in r && r . variables . cache_instance_credentials_enabled == 1 ) {
170
+ _writeCredentialsToKeyValStore ( r , credentials ) ;
171
+ } else {
172
+ _writeCredentialsToFile ( credentials ) ;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Write the instance profile credentials to the NGINX Keyval store.
178
+ *
179
+ * @param r {Request} HTTP request object (not used, but required for NGINX configuration)
180
+ * @param credentials {{accessKeyId: (string), secretAccessKey: (string), sessionToken: (string), expiration: (string)}} AWS instance profile credentials
181
+ * @private
182
+ */
183
+ function _writeCredentialsToKeyValStore ( r , credentials ) {
184
+ r . variables . instance_credential_json = JSON . stringify ( credentials ) ;
185
+ }
186
+
187
+ /**
188
+ * Write the instance profile credentials to a file on the file system. This
189
+ * file will be quite small and should end up in the file cache relatively
190
+ * quickly if it is repeatedly read.
191
+ *
192
+ * @param r {Request} HTTP request object (not used, but required for NGINX configuration)
193
+ * @param credentials {{accessKeyId: (string), secretAccessKey: (string), sessionToken: (string), expiration: (string)}} AWS instance profile credentials
194
+ * @private
195
+ */
196
+ function _writeCredentialsToFile ( credentials ) {
197
+ fs . writeFileSync ( _credentialsTempFile ( ) , JSON . stringify ( credentials ) ) ;
198
+ }
199
+
200
+ /**
201
+ * Get the instance profile credentials needed to authenticated against S3 from
202
+ * a backend cache. If the credentials cannot be found, then return undefined.
203
+ * @param r {Request} HTTP request object (not used, but required for NGINX configuration)
204
+ * @returns {undefined|{accessKeyId: (string), secretAccessKey: (string), sessionToken: (string), expiration: (string)} } AWS instance profile credentials or undefined
205
+ */
206
+ function readCredentials ( r ) {
159
207
if ( process . env [ 'S3_ACCESS_KEY_ID' ] && process . env [ 'S3_SECRET_KEY' ] ) {
160
208
return {
161
209
accessKeyId : process . env [ 'S3_ACCESS_KEY_ID' ] ,
@@ -165,6 +213,44 @@ function readCredentials() {
165
213
} ;
166
214
}
167
215
216
+ if ( "variables" in r && r . variables . cache_instance_credentials_enabled == 1 ) {
217
+ return _readCredentialsFromKeyValStore ( r ) ;
218
+ } else {
219
+ return _readCredentialsFromFile ( ) ;
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Read credentials from the NGINX Keyval store. If it is not found, then
225
+ * return undefined.
226
+ *
227
+ * @param r {Request} HTTP request object (not used, but required for NGINX configuration)
228
+ * @returns {undefined|{accessKeyId: (string), secretAccessKey: (string), sessionToken: (string), expiration: (string)} } AWS instance profile credentials or undefined
229
+ * @private
230
+ */
231
+ function _readCredentialsFromKeyValStore ( r ) {
232
+ var cached = r . variables . instance_credential_json ;
233
+
234
+ if ( ! cached ) {
235
+ return undefined ;
236
+ }
237
+
238
+ try {
239
+ return JSON . parse ( cached ) ;
240
+ } catch ( e ) {
241
+ _debug_log ( r , `Error parsing JSON value from r.variables.instance_credential_json: ${ e } ` ) ;
242
+ return undefined ;
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Read the contents of the credentials file into memory. If it is not
248
+ * found, then return undefined.
249
+ *
250
+ * @returns {undefined|{accessKeyId: (string), secretAccessKey: (string), sessionToken: (string), expiration: (string)} } AWS instance profile credentials or undefined
251
+ * @private
252
+ */
253
+ function _readCredentialsFromFile ( ) {
168
254
var credsFilePath = _credentialsTempFile ( ) ;
169
255
170
256
try {
@@ -201,7 +287,7 @@ function s3auth(r) {
201
287
202
288
var signature ;
203
289
204
- var credentials = readCredentials ( ) ;
290
+ var credentials = readCredentials ( r ) ;
205
291
if ( sigver == '2' ) {
206
292
signature = signatureV2 ( r , bucket , credentials ) ;
207
293
} else {
@@ -211,8 +297,14 @@ function s3auth(r) {
211
297
return signature ;
212
298
}
213
299
214
- function s3SecurityToken ( ) {
215
- var credentials = readCredentials ( ) ;
300
+ /**
301
+ * Get the current session token from the instance profile credential cache.
302
+ *
303
+ * @param r {Request} HTTP request object (not used, but required for NGINX configuration)
304
+ * @returns {string } current session token or empty string
305
+ */
306
+ function s3SecurityToken ( r ) {
307
+ var credentials = readCredentials ( r ) ;
216
308
if ( credentials . sessionToken ) {
217
309
return credentials . sessionToken ;
218
310
}
@@ -782,7 +874,21 @@ var maxValidityOffsetMs = 4.5 * 60 * 100;
782
874
* @returns {Promise<void> }
783
875
*/
784
876
async function fetchCredentials ( r ) {
785
- var current = readCredentials ( ) ;
877
+ // If we are not using an AWS instance profile to set our credentials we
878
+ // exit quickly and don't write a credentials file.
879
+ if ( process . env [ 'S3_ACCESS_KEY_ID' ] && process . env [ 'S3_SECRET_KEY' ] ) {
880
+ r . return ( 200 ) ;
881
+ return ;
882
+ }
883
+
884
+ try {
885
+ var current = readCredentials ( r ) ;
886
+ } catch ( e ) {
887
+ _debug_log ( r , `Could not read credentials: ${ e } ` ) ;
888
+ r . return ( 500 ) ;
889
+ return ;
890
+ }
891
+
786
892
if ( current ) {
787
893
var exp = new Date ( current . expiration ) . getTime ( ) - maxValidityOffsetMs ;
788
894
if ( now . getTime ( ) < exp ) {
@@ -793,13 +899,6 @@ async function fetchCredentials(r) {
793
899
794
900
var credentials ;
795
901
796
- // If we are not using an AWS instance profile to set our credentials we
797
- // exit quickly and don't write a credentials file.
798
- if ( process . env [ 'S3_ACCESS_KEY_ID' ] && process . env [ 'S3_SECRET_KEY' ] ) {
799
- r . return ( 200 ) ;
800
- return ;
801
- }
802
-
803
902
_debug_log ( r , 'Cached credentials are expired or not present, requesting new ones' ) ;
804
903
805
904
if ( process . env [ 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' ] ) {
@@ -821,9 +920,9 @@ async function fetchCredentials(r) {
821
920
}
822
921
}
823
922
try {
824
- fs . writeFileSync ( _credentialsTempFile ( ) , JSON . stringify ( credentials ) ) ;
923
+ writeCredentials ( r , credentials ) ;
825
924
} catch ( e ) {
826
- _debug_log ( r , ' Could not write credentials file: ' + JSON . stringify ( e ) ) ;
925
+ _debug_log ( r , ` Could not write credentials: ${ e } ` ) ;
827
926
r . return ( 500 ) ;
828
927
return ;
829
928
}
@@ -899,6 +998,7 @@ export default {
899
998
awsHeaderDate,
900
999
fetchCredentials,
901
1000
readCredentials,
1001
+ writeCredentials,
902
1002
s3date,
903
1003
s3auth,
904
1004
s3SecurityToken,
0 commit comments