in src/aws-cpp-sdk-identity-management/source/auth/STSProfileCredentialsProvider.cpp [165:310]
void STSProfileCredentialsProvider::Reload()
{
// make a copy of the profiles map to be able to set credentials on the individual profiles when assuming role
auto loadedProfiles = Aws::Config::GetCachedConfigProfiles();
auto profileIt = loadedProfiles.find(m_profileName);
if(profileIt == loadedProfiles.end())
{
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << m_profileName <<" was not found in the shared configuration file.");
m_credentials = {};
return;
}
ProfileState profileState = CheckProfile(profileIt->second, true/*topLevelProfile*/);
if (profileState == ProfileState::Static)
{
m_credentials = profileIt->second.GetCredentials();
AWSCredentialsProvider::Reload();
return;
}
if (profileState == ProfileState::Process)
{
const auto& creds = GetCredentialsFromProcess(profileIt->second.GetCredentialProcess());
if (!creds.IsExpiredOrEmpty())
{
m_credentials = creds;
AWSCredentialsProvider::Reload();
}
return;
}
if (profileState == ProfileState::Invalid)
{
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << profileIt->second.GetName() << " is invalid. Check its configuration.");
m_credentials = {};
return;
}
if (profileState == ProfileState::SourceProfile)
{
// A top level profile with a 'SourceProfile' state (determined by CheckProfile rules) means that its static
// credentials will be ignored. So, it's ok to clear them out here to simplify the logic in the chaining loop
// below.
profileIt->second.SetCredentials({});
}
AWS_LOGSTREAM_INFO(CLASS_TAG, "Profile " << profileIt->second.GetName()
<< " has a role ARN. Attempting to load its source credentials from profile "
<< profileIt->second.GetSourceProfile());
Aws::Vector<Config::AWSProfileConfigLoader::ProfilesContainer::iterator> sourceProfiles;
Aws::Set<Aws::String> visitedProfiles;
auto currentProfile = profileIt;
sourceProfiles.push_back(currentProfile);
// build the chain (DAG)
while(!currentProfile->second.GetSourceProfile().empty())
{
ProfileState currentProfileState = CheckProfile(currentProfile->second, false /*topLevelProfile*/);
auto currentProfileName = currentProfile->second.GetName();
if (currentProfileState == ProfileState::Invalid)
{
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << profileIt->second.GetName() << " is invalid. Check its configuration.");
m_credentials = {};
return;
}
// terminate the chain as soon as we hit a profile with either static credentials or credential process
if (currentProfileState == ProfileState::Static || currentProfileState == ProfileState::Process)
{
break;
}
if (currentProfileState == ProfileState::SelfReferencing)
{
sourceProfiles.push_back(currentProfile);
break;
}
// check if we have a circular reference in the graph.
if (visitedProfiles.find(currentProfileName) != visitedProfiles.end())
{
// TODO: print the whole DAG for better debugging
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << currentProfileName << " has a circular reference. Aborting.");
m_credentials = {};
return;
}
visitedProfiles.emplace(currentProfileName);
const auto it = loadedProfiles.find(currentProfile->second.GetSourceProfile());
if(it == loadedProfiles.end())
{
// TODO: print the whole DAG for better debugging
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << currentProfileName << " has an invalid source profile " << currentProfile->second.GetSourceProfile());
m_credentials = {};
return;
}
currentProfile = it;
sourceProfiles.push_back(currentProfile);
}
// The last profile added to the stack is not checked. Check it now.
if (!sourceProfiles.empty())
{
if (CheckProfile(sourceProfiles.back()->second, false /*topLevelProfile*/) == ProfileState::Invalid)
{
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << sourceProfiles.back()->second.GetName() << " is invalid. Check its configuration.");
m_credentials = {};
return;
}
}
while (sourceProfiles.size() > 1)
{
const auto profile = sourceProfiles.back()->second;
sourceProfiles.pop_back();
AWSCredentials stsCreds;
if (profile.GetCredentialProcess().empty())
{
assert(!profile.GetCredentials().IsEmpty());
stsCreds = profile.GetCredentials();
}
else
{
stsCreds = GetCredentialsFromProcess(profile.GetCredentialProcess());
}
// get the role arn from the profile at the top of the stack (which hasn't been popped out yet)
const auto arn = sourceProfiles.back()->second.GetRoleArn();
const auto& assumedCreds = GetCredentialsFromSTS(stsCreds, arn);
sourceProfiles.back()->second.SetCredentials(assumedCreds);
}
if (!sourceProfiles.empty())
{
assert(profileIt == sourceProfiles.back());
assert(!profileIt->second.GetCredentials().IsEmpty());
}
m_credentials = profileIt->second.GetCredentials();
AWSCredentialsProvider::Reload();
}