ec2_metadata_credentials.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. var AWS = require('../core');
  2. require('../metadata_service');
  3. /**
  4. * Represents credentials received from the metadata service on an EC2 instance.
  5. *
  6. * By default, this class will connect to the metadata service using
  7. * {AWS.MetadataService} and attempt to load any available credentials. If it
  8. * can connect, and credentials are available, these will be used with zero
  9. * 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 EC2 metadata service are timing out, you can increase
  14. * these values by configuring them directly:
  15. *
  16. * ```javascript
  17. * AWS.config.credentials = new AWS.EC2MetadataCredentials({
  18. * httpOptions: { timeout: 5000 }, // 5 second timeout
  19. * maxRetries: 10, // retry 10 times
  20. * retryDelayOptions: { base: 200 }, // see AWS.Config for information
  21. * logger: console // see AWS.Config for information
  22. * ec2MetadataV1Disabled: false // whether to block IMDS v1 fallback.
  23. * });
  24. * ```
  25. *
  26. * If your requests are timing out in connecting to the metadata service, such
  27. * as when testing on a development machine, you can use the connectTimeout
  28. * option, specified in milliseconds, which also defaults to 1 second.
  29. *
  30. * If the requests failed or returns expired credentials, it will
  31. * extend the expiration of current credential, with a warning message. For more
  32. * information, please go to:
  33. * https://docs.aws.amazon.com/sdkref/latest/guide/feature-static-credentials.html
  34. *
  35. * @!attribute originalExpiration
  36. * @return [Date] The optional original expiration of the current credential.
  37. * In case of AWS outage, the EC2 metadata will extend expiration of the
  38. * existing credential.
  39. *
  40. * @see AWS.Config.retryDelayOptions
  41. * @see AWS.Config.logger
  42. *
  43. * @!macro nobrowser
  44. */
  45. AWS.EC2MetadataCredentials = AWS.util.inherit(AWS.Credentials, {
  46. constructor: function EC2MetadataCredentials(options) {
  47. AWS.Credentials.call(this);
  48. options = options ? AWS.util.copy(options) : {};
  49. options = AWS.util.merge(
  50. {maxRetries: this.defaultMaxRetries}, options);
  51. if (!options.httpOptions) options.httpOptions = {};
  52. options.httpOptions = AWS.util.merge(
  53. {timeout: this.defaultTimeout,
  54. connectTimeout: this.defaultConnectTimeout},
  55. options.httpOptions);
  56. this.metadataService = new AWS.MetadataService(options);
  57. this.logger = options.logger || AWS.config && AWS.config.logger;
  58. },
  59. /**
  60. * @api private
  61. */
  62. defaultTimeout: 1000,
  63. /**
  64. * @api private
  65. */
  66. defaultConnectTimeout: 1000,
  67. /**
  68. * @api private
  69. */
  70. defaultMaxRetries: 3,
  71. /**
  72. * The original expiration of the current credential. In case of AWS
  73. * outage, the EC2 metadata will extend expiration of the existing
  74. * credential.
  75. */
  76. originalExpiration: undefined,
  77. /**
  78. * Loads the credentials from the instance metadata service
  79. *
  80. * @callback callback function(err)
  81. * Called when the instance metadata service responds (or fails). When
  82. * this callback is called with no error, it means that the credentials
  83. * information has been loaded into the object (as the `accessKeyId`,
  84. * `secretAccessKey`, and `sessionToken` properties).
  85. * @param err [Error] if an error occurred, this value will be filled
  86. * @see get
  87. */
  88. refresh: function refresh(callback) {
  89. this.coalesceRefresh(callback || AWS.util.fn.callback);
  90. },
  91. /**
  92. * @api private
  93. * @param callback
  94. */
  95. load: function load(callback) {
  96. var self = this;
  97. self.metadataService.loadCredentials(function(err, creds) {
  98. if (err) {
  99. if (self.hasLoadedCredentials()) {
  100. self.extendExpirationIfExpired();
  101. callback();
  102. } else {
  103. callback(err);
  104. }
  105. } else {
  106. self.setCredentials(creds);
  107. self.extendExpirationIfExpired();
  108. callback();
  109. }
  110. });
  111. },
  112. /**
  113. * Whether this credential has been loaded.
  114. * @api private
  115. */
  116. hasLoadedCredentials: function hasLoadedCredentials() {
  117. return this.AccessKeyId && this.secretAccessKey;
  118. },
  119. /**
  120. * if expired, extend the expiration by 15 minutes base plus a jitter of 5
  121. * minutes range.
  122. * @api private
  123. */
  124. extendExpirationIfExpired: function extendExpirationIfExpired() {
  125. if (this.needsRefresh()) {
  126. this.originalExpiration = this.originalExpiration || this.expireTime;
  127. this.expired = false;
  128. var nextTimeout = 15 * 60 + Math.floor(Math.random() * 5 * 60);
  129. var currentTime = AWS.util.date.getDate().getTime();
  130. this.expireTime = new Date(currentTime + nextTimeout * 1000);
  131. // TODO: add doc link;
  132. this.logger.warn('Attempting credential expiration extension due to a '
  133. + 'credential service availability issue. A refresh of these '
  134. + 'credentials will be attempted again at ' + this.expireTime
  135. + '\nFor more information, please visit: https://docs.aws.amazon.com/sdkref/latest/guide/feature-static-credentials.html');
  136. }
  137. },
  138. /**
  139. * Update the credential with new credential responded from EC2 metadata
  140. * service.
  141. * @api private
  142. */
  143. setCredentials: function setCredentials(creds) {
  144. var currentTime = AWS.util.date.getDate().getTime();
  145. var expireTime = new Date(creds.Expiration);
  146. this.expired = currentTime >= expireTime ? true : false;
  147. this.metadata = creds;
  148. this.accessKeyId = creds.AccessKeyId;
  149. this.secretAccessKey = creds.SecretAccessKey;
  150. this.sessionToken = creds.Token;
  151. this.expireTime = expireTime;
  152. }
  153. });