Skip to content

Commit f4ef98a

Browse files
committed
Support Web Identity in STSProfileCredentialsProvider.
1 parent 592b3df commit f4ef98a

File tree

2 files changed

+96
-18
lines changed

2 files changed

+96
-18
lines changed

src/aws-cpp-sdk-identity-management/include/aws/identity-management/auth/STSProfileCredentialsProvider.h

+2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,10 @@ namespace Aws
106106
* Returns the assumed role credentials or empty credentials on error.
107107
*/
108108
AWSCredentials GetCredentialsFromSTS(const AWSCredentials& credentials, const Aws::String& roleARN);
109+
AWSCredentials GetCredentialsFromWebIdentity(const Config::Profile& profile);
109110
private:
110111
AWSCredentials GetCredentialsFromSTSInternal(const Aws::String& roleArn, Aws::STS::STSClient* client);
112+
AWSCredentials GetCredentialsFromWebIdentityInternal(const Config::Profile& profile, Aws::STS::STSClient* client);
111113

112114
Aws::String m_profileName;
113115
AWSCredentials m_credentials;

src/aws-cpp-sdk-identity-management/source/auth/STSProfileCredentialsProvider.cpp

+94-18
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55

66
#include <aws/identity-management/auth/STSProfileCredentialsProvider.h>
77
#include <aws/sts/model/AssumeRoleRequest.h>
8+
#include <aws/sts/model/AssumeRoleWithWebIdentityRequest.h>
89
#include <aws/sts/STSClient.h>
910
#include <aws/core/utils/logging/LogMacros.h>
1011
#include <aws/core/utils/Outcome.h>
1112
#include <aws/core/utils/UUID.h>
1213

14+
#include <fstream>
1315
#include <utility>
1416

1517
using namespace Aws;
@@ -88,25 +90,27 @@ enum class ProfileState
8890
Process,
8991
SourceProfile,
9092
SelfReferencing, // special case of SourceProfile.
93+
RoleARNWebIdentity
9194
};
9295

9396
/*
9497
* A valid profile can be in one of the following states. Any other state is considered invalid.
95-
+---------+-----------+-----------+--------------+
96-
| | | | |
97-
| Role | Source | Process | Static |
98-
| ARN | Profile | | Credentials |
99-
+------------------------------------------------+
100-
| | | | |
101-
| false | false | false | TRUE |
102-
| | | | |
103-
| false | false | TRUE | false |
104-
| | | | |
105-
| TRUE | TRUE | false | false |
106-
| | | | |
107-
| TRUE | TRUE | false | TRUE |
108-
| | | | |
109-
+---------+-----------+-----------+--------------+
98+
+---------+-----------+-----------+--------------+------------+
99+
| | | | | |
100+
| Role | Source | Process | Static | Web |
101+
| ARN | Profile | | Credentials | Identity |
102+
+------------------------------------------------+------------+
103+
| | | | | |
104+
| false | false | false | TRUE | false |
105+
| | | | | |
106+
| false | false | TRUE | false | false |
107+
| | | | | |
108+
| TRUE | TRUE | false | false | false |
109+
| | | | | |
110+
| TRUE | TRUE | false | TRUE | false |
111+
| | | | | |
112+
| TRUE | false | false | false | TRUE |
113+
+---------+-----------+-----------+--------------+------------+
110114
111115
*/
112116
static ProfileState CheckProfile(const Aws::Config::Profile& profile, bool topLevelProfile)
@@ -115,6 +119,7 @@ static ProfileState CheckProfile(const Aws::Config::Profile& profile, bool topLe
115119
constexpr int PROCESS_CREDENTIALS = 2;
116120
constexpr int SOURCE_PROFILE = 4;
117121
constexpr int ROLE_ARN = 8;
122+
constexpr int WEB_IDENTITY_TOKEN_FILE = 16;
118123

119124
int state = 0;
120125

@@ -138,6 +143,11 @@ static ProfileState CheckProfile(const Aws::Config::Profile& profile, bool topLe
138143
state += ROLE_ARN;
139144
}
140145

146+
if (!profile.GetValue("web_identity_token_file").empty())
147+
{
148+
state += WEB_IDENTITY_TOKEN_FILE;
149+
}
150+
141151
if (topLevelProfile)
142152
{
143153
switch(state)
@@ -155,6 +165,8 @@ static ProfileState CheckProfile(const Aws::Config::Profile& profile, bool topLe
155165
}
156166
// source-profile over-rule static credentials in top-level profiles (except when self-referencing)
157167
return ProfileState::SourceProfile;
168+
case 24: // role arn && web identity
169+
return ProfileState::RoleARNWebIdentity;
158170
default:
159171
// All other cases are considered malformed configuration.
160172
return ProfileState::Invalid;
@@ -176,6 +188,8 @@ static ProfileState CheckProfile(const Aws::Config::Profile& profile, bool topLe
176188
return ProfileState::SelfReferencing;
177189
}
178190
return ProfileState::Static; // static credentials over-rule source-profile (except when self-referencing)
191+
case 24: // role arn && web identity
192+
return ProfileState::RoleARNWebIdentity;
179193
default:
180194
// All other cases are considered malformed configuration.
181195
return ProfileState::Invalid;
@@ -302,10 +316,14 @@ void STSProfileCredentialsProvider::Reload()
302316

303317
while (sourceProfiles.size() > 1)
304318
{
305-
const auto profile = sourceProfiles.back()->second;
319+
const auto& profile = sourceProfiles.back()->second;
306320
sourceProfiles.pop_back();
307321
AWSCredentials stsCreds;
308-
if (profile.GetCredentialProcess().empty())
322+
if (CheckProfile(profile, false /*topLevelProfile*/) == ProfileState::RoleARNWebIdentity)
323+
{
324+
stsCreds = GetCredentialsFromWebIdentity(profile);
325+
}
326+
else if (profile.GetCredentialProcess().empty())
309327
{
310328
assert(!profile.GetCredentials().IsEmpty());
311329
stsCreds = profile.GetCredentials();
@@ -316,7 +334,7 @@ void STSProfileCredentialsProvider::Reload()
316334
}
317335

318336
// get the role arn from the profile at the top of the stack (which hasn't been popped out yet)
319-
const auto arn = sourceProfiles.back()->second.GetRoleArn();
337+
const auto& arn = sourceProfiles.back()->second.GetRoleArn();
320338
const auto& assumedCreds = GetCredentialsFromSTS(stsCreds, arn);
321339
sourceProfiles.back()->second.SetCredentials(assumedCreds);
322340
}
@@ -366,3 +384,61 @@ AWSCredentials STSProfileCredentialsProvider::GetCredentialsFromSTS(const AWSCre
366384
Aws::STS::STSClient stsClient {credentials};
367385
return GetCredentialsFromSTSInternal(roleArn, &stsClient);
368386
}
387+
388+
AWSCredentials STSProfileCredentialsProvider::GetCredentialsFromWebIdentityInternal(const Config::Profile& profile, Aws::STS::STSClient* client)
389+
{
390+
Aws::String roleSessionName = profile.GetValue("role_session_name");
391+
if (roleSessionName.empty())
392+
{
393+
roleSessionName = Aws::Utils::UUID::PseudoRandomUUID();
394+
}
395+
396+
Aws::String token;
397+
{
398+
auto& tokenPath = profile.GetValue("web_identity_token_file");
399+
Aws::IFStream tokenFile(tokenPath);
400+
if (tokenFile) {
401+
token = Aws::String(
402+
(std::istreambuf_iterator<char>(tokenFile)),
403+
std::istreambuf_iterator<char>());
404+
}
405+
else {
406+
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Can't open token file: " << tokenPath);
407+
return {};
408+
}
409+
}
410+
411+
using namespace Aws::STS::Model;
412+
AssumeRoleWithWebIdentityRequest assumeRoleRequest;
413+
assumeRoleRequest
414+
.WithRoleArn(profile.GetRoleArn())
415+
.WithRoleSessionName(roleSessionName)
416+
.WithWebIdentityToken(token)
417+
.WithDurationSeconds(static_cast<int>(std::chrono::seconds(m_duration).count()));
418+
auto outcome = client->AssumeRoleWithWebIdentity(assumeRoleRequest);
419+
if (outcome.IsSuccess())
420+
{
421+
const auto& modelCredentials = outcome.GetResult().GetCredentials();
422+
return {modelCredentials.GetAccessKeyId(),
423+
modelCredentials.GetSecretAccessKey(),
424+
modelCredentials.GetSessionToken(),
425+
modelCredentials.GetExpiration()};
426+
}
427+
else
428+
{
429+
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Failed to assume role " << profile.GetRoleArn());
430+
}
431+
return {};
432+
}
433+
434+
AWSCredentials STSProfileCredentialsProvider::GetCredentialsFromWebIdentity(const Config::Profile& profile)
435+
{
436+
using namespace Aws::STS::Model;
437+
if (m_stsClientFactory) {
438+
auto client = m_stsClientFactory({});
439+
return GetCredentialsFromWebIdentityInternal(profile, client.get());
440+
}
441+
442+
Aws::STS::STSClient stsClient{AWSCredentials{}};
443+
return GetCredentialsFromWebIdentityInternal(profile, &stsClient);
444+
}

0 commit comments

Comments
 (0)