ecs_credentials.js (4843B)
1 var AWS = require('../core'); 2 3 /** 4 * Represents credentials received from relative URI specified in the ECS container. 5 * 6 * This class will request refreshable credentials from the relative URI 7 * specified by the AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variable 8 * in the container. If valid credentials are returned in the response, these 9 * will be used with zero configuration. 10 * 11 * This credentials class will by default timeout after 1 second of inactivity 12 * and retry 3 times. 13 * If your requests to the relative URI are timing out, you can increase 14 * the value by configuring them directly: 15 * 16 * ```javascript 17 * AWS.config.credentials = new AWS.ECSCredentials({ 18 * httpOptions: { timeout: 5000 }, // 5 second timeout 19 * maxRetries: 10, // retry 10 times 20 * retryDelayOptions: { base: 200 } // see AWS.Config for information 21 * }); 22 * ``` 23 * 24 * @see AWS.Config.retryDelayOptions 25 * 26 * @!macro nobrowser 27 */ 28 AWS.ECSCredentials = AWS.util.inherit(AWS.Credentials, { 29 constructor: function ECSCredentials(options) { 30 AWS.Credentials.call(this); 31 options = options ? AWS.util.copy(options) : {}; 32 if (!options.httpOptions) options.httpOptions = {}; 33 options.httpOptions = AWS.util.merge( 34 this.httpOptions, options.httpOptions); 35 AWS.util.update(this, options); 36 }, 37 38 /** 39 * @api private 40 */ 41 httpOptions: { timeout: 1000 }, 42 43 /** 44 * @api private 45 */ 46 host: '169.254.170.2', 47 48 /** 49 * @api private 50 */ 51 maxRetries: 3, 52 53 /** 54 * Sets the name of the ECS environment variable to check for relative URI 55 * If changed, please change the name in the documentation for defaultProvider 56 * in credential_provider_chain.js and in all tests in test/credentials.spec.coffee 57 * 58 * @api private 59 */ 60 environmentVar: 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI', 61 62 /** 63 * @api private 64 */ 65 getECSRelativeUri: function getECSRelativeUri() { 66 if (process && process.env) return process.env[this.environmentVar]; 67 }, 68 69 /** 70 * @api private 71 */ 72 credsFormatIsValid: function credsFormatIsValid(credData) { 73 return (!!credData.AccessKeyId && !!credData.SecretAccessKey && 74 !!credData.Token && !!credData.Expiration); 75 }, 76 77 /** 78 * @api private 79 */ 80 request: function request(path, callback) { 81 path = path || '/'; 82 var httpRequest = new AWS.HttpRequest('http://' + this.host + path); 83 httpRequest.method = 'GET'; 84 httpRequest.headers.Accept = 'application/json'; 85 AWS.util.handleRequestWithRetries(httpRequest, this, callback); 86 }, 87 88 /** 89 * @api private 90 */ 91 refreshQueue: [], 92 93 /** 94 * Loads the credentials from the relative URI specified by container 95 * 96 * @callback callback function(err) 97 * Called when the request to the relative URI responds (or fails). When 98 * this callback is called with no error, it means that the credentials 99 * information has been loaded into the object (as the `accessKeyId`, 100 * `secretAccessKey`, `sessionToken`, and `expireTime` properties). 101 * @param err [Error] if an error occurred, this value will be filled 102 * @see get 103 */ 104 refresh: function refresh(callback) { 105 var self = this; 106 var refreshQueue = self.refreshQueue; 107 if (!callback) callback = function(err) { if (err) throw err; }; 108 refreshQueue.push({ 109 provider: self, 110 errCallback: callback 111 }); 112 if (refreshQueue.length > 1) { return; } 113 114 function callbacks(err, creds) { 115 var call, cb; 116 while ((call = refreshQueue.shift()) !== undefined) { 117 cb = call.errCallback; 118 if (!err) AWS.util.update(call.provider, creds); 119 cb(err); 120 } 121 } 122 123 if (process === undefined) { 124 callbacks(AWS.util.error( 125 new Error('No process info available'), 126 { code: 'ECSCredentialsProviderFailure' } 127 )); 128 return; 129 } 130 var relativeUri = this.getECSRelativeUri(); 131 if (relativeUri === undefined) { 132 callbacks(AWS.util.error( 133 new Error('Variable ' + this.environmentVar + ' not set.'), 134 { code: 'ECSCredentialsProviderFailure' } 135 )); 136 return; 137 } 138 139 this.request(relativeUri, function(err, data) { 140 if (!err) { 141 try { 142 data = JSON.parse(data); 143 if (self.credsFormatIsValid(data)) { 144 var creds = { 145 expired: false, 146 accessKeyId: data.AccessKeyId, 147 secretAccessKey: data.SecretAccessKey, 148 sessionToken: data.Token, 149 expireTime: new Date(data.Expiration) 150 }; 151 } else { 152 throw AWS.util.error( 153 new Error('Response data is not in valid format'), 154 { code: 'ECSCredentialsProviderFailure' } 155 ); 156 } 157 } catch (dataError) { 158 err = dataError; 159 } 160 } 161 callbacks(err, creds); 162 }); 163 } 164 });