EC2InstanceProfileConfigLoader.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/core/config/AWSProfileConfigLoader.h>
  6. #include <aws/core/internal/AWSHttpResourceClient.h>
  7. #include <aws/core/auth/AWSCredentialsProvider.h>
  8. #include <aws/core/utils/memory/stl/AWSList.h>
  9. #include <aws/core/utils/logging/LogMacros.h>
  10. #include <aws/core/utils/json/JsonSerializer.h>
  11. #include <fstream>
  12. #include <random>
  13. namespace Aws
  14. {
  15. namespace Config
  16. {
  17. using namespace Aws::Utils;
  18. using namespace Aws::Auth;
  19. static const char* const INTERNAL_EXCEPTION_PHRASE = "InternalServiceException";
  20. static const int64_t FIVE_MINUTE_MILLIS = 60000 * 5;
  21. static const int64_t TEN_MINUTE_MILLIS = 60000 * 10;
  22. static const char* const EC2_INSTANCE_PROFILE_LOG_TAG = "Aws::Config::EC2InstanceProfileConfigLoader";
  23. EC2InstanceProfileConfigLoader::EC2InstanceProfileConfigLoader(const std::shared_ptr<Aws::Internal::EC2MetadataClient>& client)
  24. {
  25. if(client == nullptr)
  26. {
  27. Aws::Internal::InitEC2MetadataClient();
  28. m_ec2metadataClient = Aws::Internal::GetEC2MetadataClient();
  29. }
  30. else
  31. {
  32. m_ec2metadataClient = client;
  33. }
  34. }
  35. bool EC2InstanceProfileConfigLoader::LoadInternal()
  36. {
  37. // re-use old credentials until we need to call IMDS again.
  38. if (DateTime::Now().Millis() < this->credentialsValidUntilMillis) {
  39. AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG,
  40. "Skipping IMDS call until " << this->credentialsValidUntilMillis);
  41. return true;
  42. }
  43. this->credentialsValidUntilMillis = DateTime::Now().Millis();
  44. if (!m_ec2metadataClient) {
  45. AWS_LOGSTREAM_FATAL(EC2_INSTANCE_PROFILE_LOG_TAG, "EC2MetadataClient is a nullptr!")
  46. return false;
  47. }
  48. auto credentialsStr = m_ec2metadataClient->GetDefaultCredentialsSecurely();
  49. if(credentialsStr.empty()) return false;
  50. Json::JsonValue credentialsDoc(credentialsStr);
  51. if (!credentialsDoc.WasParseSuccessful())
  52. {
  53. AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG,
  54. "Failed to parse output from EC2MetadataService.");
  55. return false;
  56. }
  57. const char* accessKeyId = "AccessKeyId";
  58. const char* secretAccessKey = "SecretAccessKey";
  59. const char* expiration = "Expiration";
  60. const char* code = "Code";
  61. Aws::String accessKey, secretKey, token;
  62. auto credentialsView = credentialsDoc.View();
  63. DateTime expirationTime(credentialsView.GetString(expiration), Aws::Utils::DateFormat::ISO_8601);
  64. // re-use old credentials and not block if the IMDS call failed or if the latest credential is in the past
  65. if (expirationTime.WasParseSuccessful() && DateTime::Now() > expirationTime) {
  66. AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG,
  67. "Expiration Time of Credentials in the past, refusing to update credentials");
  68. this->credentialsValidUntilMillis = DateTime::Now().Millis() + calculateRetryTime();
  69. return true;
  70. } else if (credentialsView.GetString(code) == INTERNAL_EXCEPTION_PHRASE) {
  71. AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG,
  72. "IMDS call failed, refusing to update credentials");
  73. this->credentialsValidUntilMillis = DateTime::Now().Millis() + calculateRetryTime();
  74. return true;
  75. }
  76. accessKey = credentialsView.GetString(accessKeyId);
  77. AWS_LOGSTREAM_INFO(EC2_INSTANCE_PROFILE_LOG_TAG,
  78. "Successfully pulled credentials from metadata service with access key " << accessKey);
  79. secretKey = credentialsView.GetString(secretAccessKey);
  80. token = credentialsView.GetString("Token");
  81. auto region = m_ec2metadataClient->GetCurrentRegion();
  82. Profile profile;
  83. profile.SetCredentials(AWSCredentials(accessKey, secretKey, token));
  84. profile.SetRegion(region);
  85. profile.SetName(INSTANCE_PROFILE_KEY);
  86. m_profiles[INSTANCE_PROFILE_KEY] = profile;
  87. return true;
  88. }
  89. int64_t EC2InstanceProfileConfigLoader::calculateRetryTime() const {
  90. std::random_device rd;
  91. std::mt19937_64 gen(rd());
  92. std::uniform_int_distribution<int64_t> dist(FIVE_MINUTE_MILLIS, TEN_MINUTE_MILLIS);
  93. return dist(gen);
  94. }
  95. } // Config namespace
  96. } // Aws namespace