Add aws-sourced external credentials

pull/24733/head
Chuan Ren 4 years ago
parent 6046624c42
commit 1faf030cc4
  1. 2
      BUILD
  2. 2
      BUILD.gn
  3. 1
      CMakeLists.txt
  4. 2
      Makefile
  5. 2
      build_autogenerated.yaml
  6. 1
      config.m4
  7. 1
      config.w32
  8. 2
      gRPC-C++.podspec
  9. 3
      gRPC-Core.podspec
  10. 2
      grpc.gemspec
  11. 1
      grpc.gyp
  12. 2
      package.xml
  13. 415
      src/core/lib/security/credentials/external/aws_external_account_credentials.cc
  14. 79
      src/core/lib/security/credentials/external/aws_external_account_credentials.h
  15. 1
      src/python/grpcio/grpc_core_dependencies.py
  16. 487
      test/core/security/credentials_test.cc
  17. 2
      tools/doxygen/Doxyfile.c++.internal
  18. 2
      tools/doxygen/Doxyfile.core.internal

@ -1812,6 +1812,7 @@ grpc_cc_library(
"src/core/lib/security/credentials/composite/composite_credentials.cc",
"src/core/lib/security/credentials/credentials.cc",
"src/core/lib/security/credentials/credentials_metadata.cc",
"src/core/lib/security/credentials/external/aws_external_account_credentials.cc",
"src/core/lib/security/credentials/external/aws_request_signer.cc",
"src/core/lib/security/credentials/external/external_account_credentials.cc",
"src/core/lib/security/credentials/external/file_external_account_credentials.cc",
@ -1858,6 +1859,7 @@ grpc_cc_library(
"src/core/lib/security/credentials/alts/alts_credentials.h",
"src/core/lib/security/credentials/composite/composite_credentials.h",
"src/core/lib/security/credentials/credentials.h",
"src/core/lib/security/credentials/external/aws_external_account_credentials.h",
"src/core/lib/security/credentials/external/aws_request_signer.h",
"src/core/lib/security/credentials/external/external_account_credentials.h",
"src/core/lib/security/credentials/external/file_external_account_credentials.h",

@ -1009,6 +1009,8 @@ config("grpc_config") {
"src/core/lib/security/credentials/credentials.cc",
"src/core/lib/security/credentials/credentials.h",
"src/core/lib/security/credentials/credentials_metadata.cc",
"src/core/lib/security/credentials/external/aws_external_account_credentials.cc",
"src/core/lib/security/credentials/external/aws_external_account_credentials.h",
"src/core/lib/security/credentials/external/aws_request_signer.cc",
"src/core/lib/security/credentials/external/aws_request_signer.h",
"src/core/lib/security/credentials/external/external_account_credentials.cc",

@ -1851,6 +1851,7 @@ add_library(grpc
src/core/lib/security/credentials/composite/composite_credentials.cc
src/core/lib/security/credentials/credentials.cc
src/core/lib/security/credentials/credentials_metadata.cc
src/core/lib/security/credentials/external/aws_external_account_credentials.cc
src/core/lib/security/credentials/external/aws_request_signer.cc
src/core/lib/security/credentials/external/external_account_credentials.cc
src/core/lib/security/credentials/external/file_external_account_credentials.cc

@ -2255,6 +2255,7 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/composite/composite_credentials.cc \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/credentials_metadata.cc \
src/core/lib/security/credentials/external/aws_external_account_credentials.cc \
src/core/lib/security/credentials/external/aws_request_signer.cc \
src/core/lib/security/credentials/external/external_account_credentials.cc \
src/core/lib/security/credentials/external/file_external_account_credentials.cc \
@ -4800,6 +4801,7 @@ src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc:
src/core/lib/security/credentials/composite/composite_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/credentials_metadata.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/aws_external_account_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/aws_request_signer.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/external_account_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/file_external_account_credentials.cc: $(OPENSSL_DEP)

@ -767,6 +767,7 @@ libs:
- src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
- src/core/lib/security/credentials/composite/composite_credentials.h
- src/core/lib/security/credentials/credentials.h
- src/core/lib/security/credentials/external/aws_external_account_credentials.h
- src/core/lib/security/credentials/external/aws_request_signer.h
- src/core/lib/security/credentials/external/external_account_credentials.h
- src/core/lib/security/credentials/external/file_external_account_credentials.h
@ -1282,6 +1283,7 @@ libs:
- src/core/lib/security/credentials/composite/composite_credentials.cc
- src/core/lib/security/credentials/credentials.cc
- src/core/lib/security/credentials/credentials_metadata.cc
- src/core/lib/security/credentials/external/aws_external_account_credentials.cc
- src/core/lib/security/credentials/external/aws_request_signer.cc
- src/core/lib/security/credentials/external/external_account_credentials.cc
- src/core/lib/security/credentials/external/file_external_account_credentials.cc

@ -502,6 +502,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/composite/composite_credentials.cc \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/credentials_metadata.cc \
src/core/lib/security/credentials/external/aws_external_account_credentials.cc \
src/core/lib/security/credentials/external/aws_request_signer.cc \
src/core/lib/security/credentials/external/external_account_credentials.cc \
src/core/lib/security/credentials/external/file_external_account_credentials.cc \

@ -469,6 +469,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\credentials\\composite\\composite_credentials.cc " +
"src\\core\\lib\\security\\credentials\\credentials.cc " +
"src\\core\\lib\\security\\credentials\\credentials_metadata.cc " +
"src\\core\\lib\\security\\credentials\\external\\aws_external_account_credentials.cc " +
"src\\core\\lib\\security\\credentials\\external\\aws_request_signer.cc " +
"src\\core\\lib\\security\\credentials\\external\\external_account_credentials.cc " +
"src\\core\\lib\\security\\credentials\\external\\file_external_account_credentials.cc " +

@ -612,6 +612,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/external/aws_external_account_credentials.h',
'src/core/lib/security/credentials/external/aws_request_signer.h',
'src/core/lib/security/credentials/external/external_account_credentials.h',
'src/core/lib/security/credentials/external/file_external_account_credentials.h',
@ -1222,6 +1223,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/external/aws_external_account_credentials.h',
'src/core/lib/security/credentials/external/aws_request_signer.h',
'src/core/lib/security/credentials/external/external_account_credentials.h',
'src/core/lib/security/credentials/external/file_external_account_credentials.h',

@ -1065,6 +1065,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/credentials.cc',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/credentials_metadata.cc',
'src/core/lib/security/credentials/external/aws_external_account_credentials.cc',
'src/core/lib/security/credentials/external/aws_external_account_credentials.h',
'src/core/lib/security/credentials/external/aws_request_signer.cc',
'src/core/lib/security/credentials/external/aws_request_signer.h',
'src/core/lib/security/credentials/external/external_account_credentials.cc',
@ -1753,6 +1755,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/external/aws_external_account_credentials.h',
'src/core/lib/security/credentials/external/aws_request_signer.h',
'src/core/lib/security/credentials/external/external_account_credentials.h',
'src/core/lib/security/credentials/external/file_external_account_credentials.h',

@ -982,6 +982,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/credentials.cc )
s.files += %w( src/core/lib/security/credentials/credentials.h )
s.files += %w( src/core/lib/security/credentials/credentials_metadata.cc )
s.files += %w( src/core/lib/security/credentials/external/aws_external_account_credentials.cc )
s.files += %w( src/core/lib/security/credentials/external/aws_external_account_credentials.h )
s.files += %w( src/core/lib/security/credentials/external/aws_request_signer.cc )
s.files += %w( src/core/lib/security/credentials/external/aws_request_signer.h )
s.files += %w( src/core/lib/security/credentials/external/external_account_credentials.cc )

@ -868,6 +868,7 @@
'src/core/lib/security/credentials/composite/composite_credentials.cc',
'src/core/lib/security/credentials/credentials.cc',
'src/core/lib/security/credentials/credentials_metadata.cc',
'src/core/lib/security/credentials/external/aws_external_account_credentials.cc',
'src/core/lib/security/credentials/external/aws_request_signer.cc',
'src/core/lib/security/credentials/external/external_account_credentials.cc',
'src/core/lib/security/credentials/external/file_external_account_credentials.cc',

@ -962,6 +962,8 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/credentials_metadata.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/aws_external_account_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/aws_external_account_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/aws_request_signer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/aws_request_signer.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/external_account_credentials.cc" role="src" />

@ -0,0 +1,415 @@
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/credentials/external/aws_external_account_credentials.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_replace.h"
#include "src/core/lib/gpr/env.h"
namespace grpc_core {
namespace {
const char* kExpectedEnvironmentId = "aws1";
const char* kRegionEnvVar = "AWS_REGION";
const char* kAccessKeyIdEnvVar = "AWS_ACCESS_KEY_ID";
const char* kSecretAccessKeyEnvVar = "AWS_SECRET_ACCESS_KEY";
const char* kSessionTokenEnvVar = "AWS_SESSION_TOKEN";
std::string UrlEncode(const absl::string_view& s) {
const char* hex = "0123456789ABCDEF";
std::string result;
result.reserve(s.length());
for (auto c : s) {
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') || c == '-' || c == '_' || c == '!' ||
c == '\'' || c == '(' || c == ')' || c == '*' || c == '~' || c == '.') {
result.push_back(c);
} else {
result.push_back('%');
result.push_back(hex[static_cast<unsigned char>(c) >> 4]);
result.push_back(hex[static_cast<unsigned char>(c) & 15]);
}
}
return result;
}
} // namespace
RefCountedPtr<AwsExternalAccountCredentials>
AwsExternalAccountCredentials::Create(ExternalAccountCredentialsOptions options,
std::vector<std::string> scopes,
grpc_error** error) {
auto creds = MakeRefCounted<AwsExternalAccountCredentials>(
std::move(options), std::move(scopes), error);
if (*error == GRPC_ERROR_NONE) {
return creds;
} else {
return nullptr;
}
}
AwsExternalAccountCredentials::AwsExternalAccountCredentials(
ExternalAccountCredentialsOptions options, std::vector<std::string> scopes,
grpc_error** error)
: ExternalAccountCredentials(options, std::move(scopes)) {
auto it = options.credential_source.object_value().find("environment_id");
if (it == options.credential_source.object_value().end()) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"environment_id field not present.");
return;
}
if (it->second.type() != Json::Type::STRING) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"environment_id field must be a string.");
return;
}
if (it->second.string_value() != kExpectedEnvironmentId) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("environment_id does not match.");
return;
}
it = options.credential_source.object_value().find("region_url");
if (it == options.credential_source.object_value().end()) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("region_url field not present.");
return;
}
if (it->second.type() != Json::Type::STRING) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"region_url field must be a string.");
return;
}
region_url_ = it->second.string_value();
it = options.credential_source.object_value().find("url");
if (it != options.credential_source.object_value().end() &&
it->second.type() == Json::Type::STRING) {
url_ = it->second.string_value();
}
it = options.credential_source.object_value().find(
"regional_cred_verification_url");
if (it == options.credential_source.object_value().end()) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"regional_cred_verification_url field not present.");
return;
}
if (it->second.type() != Json::Type::STRING) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"regional_cred_verification_url field must be a string.");
return;
}
regional_cred_verification_url_ = it->second.string_value();
}
void AwsExternalAccountCredentials::RetrieveSubjectToken(
HTTPRequestContext* ctx, const ExternalAccountCredentialsOptions& options,
std::function<void(std::string, grpc_error*)> cb) {
if (ctx == nullptr) {
FinishRetrieveSubjectToken(
"",
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Missing HTTPRequestContext to start subject token retrieval."));
return;
}
ctx_ = ctx;
cb_ = cb;
if (signer_ != nullptr) {
BuildSubjectToken();
} else {
RetrieveRegion();
}
}
void AwsExternalAccountCredentials::RetrieveRegion() {
UniquePtr<char> region_from_env(gpr_getenv(kRegionEnvVar));
if (region_from_env != nullptr) {
region_ = std::string(region_from_env.get());
if (url_.empty()) {
RetrieveSigningKeys();
} else {
RetrieveRoleName();
}
return;
}
grpc_uri* uri = grpc_uri_parse(region_url_, false);
if (uri == nullptr) {
FinishRetrieveSubjectToken(
"",
GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrFormat("Invalid region url: %s.", region_url_).c_str()));
return;
}
grpc_httpcli_request request;
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = const_cast<char*>(uri->authority);
request.http.path = gpr_strdup(uri->path);
request.handshaker = (strcmp(uri->scheme, "https") == 0)
? &grpc_httpcli_ssl
: &grpc_httpcli_plaintext;
grpc_resource_quota* resource_quota =
grpc_resource_quota_create("external_account_credentials");
grpc_http_response_destroy(&ctx_->response);
ctx_->response = {};
GRPC_CLOSURE_INIT(&ctx_->closure, OnRetrieveRegion, this, nullptr);
grpc_httpcli_get(ctx_->httpcli_context, ctx_->pollent, resource_quota,
&request, ctx_->deadline, &ctx_->closure, &ctx_->response);
grpc_resource_quota_unref_internal(resource_quota);
grpc_http_request_destroy(&request.http);
grpc_uri_destroy(uri);
}
void AwsExternalAccountCredentials::OnRetrieveRegion(void* arg,
grpc_error* error) {
AwsExternalAccountCredentials* self =
static_cast<AwsExternalAccountCredentials*>(arg);
self->OnRetrieveRegionInternal(GRPC_ERROR_REF(error));
}
void AwsExternalAccountCredentials::OnRetrieveRegionInternal(
grpc_error* error) {
if (error != GRPC_ERROR_NONE) {
FinishRetrieveSubjectToken("", error);
return;
}
// Remove the last letter of availability zone to get pure region
absl::string_view response_body(ctx_->response.body,
ctx_->response.body_length);
region_ = std::string(response_body.substr(0, response_body.size() - 1));
if (url_.empty()) {
RetrieveSigningKeys();
} else {
RetrieveRoleName();
}
}
void AwsExternalAccountCredentials::RetrieveRoleName() {
grpc_uri* uri = grpc_uri_parse(url_, false);
if (uri == nullptr) {
FinishRetrieveSubjectToken(
"", GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrFormat("Invalid url: %s.", url_).c_str()));
return;
}
grpc_httpcli_request request;
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = const_cast<char*>(uri->authority);
request.http.path = gpr_strdup(uri->path);
request.handshaker = (strcmp(uri->scheme, "https") == 0)
? &grpc_httpcli_ssl
: &grpc_httpcli_plaintext;
grpc_resource_quota* resource_quota =
grpc_resource_quota_create("external_account_credentials");
grpc_http_response_destroy(&ctx_->response);
ctx_->response = {};
GRPC_CLOSURE_INIT(&ctx_->closure, OnRetrieveRoleName, this, nullptr);
grpc_httpcli_get(ctx_->httpcli_context, ctx_->pollent, resource_quota,
&request, ctx_->deadline, &ctx_->closure, &ctx_->response);
grpc_resource_quota_unref_internal(resource_quota);
grpc_http_request_destroy(&request.http);
grpc_uri_destroy(uri);
}
void AwsExternalAccountCredentials::OnRetrieveRoleName(void* arg,
grpc_error* error) {
AwsExternalAccountCredentials* self =
static_cast<AwsExternalAccountCredentials*>(arg);
self->OnRetrieveRoleNameInternal(GRPC_ERROR_REF(error));
}
void AwsExternalAccountCredentials::OnRetrieveRoleNameInternal(
grpc_error* error) {
if (error != GRPC_ERROR_NONE) {
FinishRetrieveSubjectToken("", error);
return;
}
role_name_ = std::string(ctx_->response.body);
RetrieveSigningKeys();
}
void AwsExternalAccountCredentials::RetrieveSigningKeys() {
UniquePtr<char> access_key_id_from_env(gpr_getenv(kAccessKeyIdEnvVar));
UniquePtr<char> secret_access_key_from_env(
gpr_getenv(kSecretAccessKeyEnvVar));
UniquePtr<char> token_from_env(gpr_getenv(kSessionTokenEnvVar));
if (access_key_id_from_env != nullptr &&
secret_access_key_from_env != nullptr && token_from_env != nullptr) {
access_key_id_ = std::string(access_key_id_from_env.get());
secret_access_key_ = std::string(secret_access_key_from_env.get());
token_ = std::string(token_from_env.get());
BuildSubjectToken();
return;
}
if (role_name_.empty()) {
FinishRetrieveSubjectToken(
"", GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Missing role name when retrieving signing keys."));
return;
}
std::string url_with_role_name = absl::StrCat(url_, "/", role_name_);
grpc_uri* uri = grpc_uri_parse(url_with_role_name, false);
if (uri == nullptr) {
FinishRetrieveSubjectToken(
"", GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrFormat("Invalid url with role name: %s.",
url_with_role_name)
.c_str()));
return;
}
grpc_httpcli_request request;
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = const_cast<char*>(uri->authority);
request.http.path = gpr_strdup(uri->path);
request.handshaker = (strcmp(uri->scheme, "https") == 0)
? &grpc_httpcli_ssl
: &grpc_httpcli_plaintext;
grpc_resource_quota* resource_quota =
grpc_resource_quota_create("external_account_credentials");
grpc_http_response_destroy(&ctx_->response);
ctx_->response = {};
GRPC_CLOSURE_INIT(&ctx_->closure, OnRetrieveSigningKeys, this, nullptr);
grpc_httpcli_get(ctx_->httpcli_context, ctx_->pollent, resource_quota,
&request, ctx_->deadline, &ctx_->closure, &ctx_->response);
grpc_resource_quota_unref_internal(resource_quota);
grpc_http_request_destroy(&request.http);
grpc_uri_destroy(uri);
}
void AwsExternalAccountCredentials::OnRetrieveSigningKeys(void* arg,
grpc_error* error) {
AwsExternalAccountCredentials* self =
static_cast<AwsExternalAccountCredentials*>(arg);
self->OnRetrieveSigningKeysInternal(GRPC_ERROR_REF(error));
}
void AwsExternalAccountCredentials::OnRetrieveSigningKeysInternal(
grpc_error* error) {
if (error != GRPC_ERROR_NONE) {
FinishRetrieveSubjectToken("", error);
return;
}
absl::string_view response_body(ctx_->response.body,
ctx_->response.body_length);
Json json = Json::Parse(response_body, &error);
if (error != GRPC_ERROR_NONE || json.type() != Json::Type::OBJECT) {
FinishRetrieveSubjectToken(
"", GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Invalid retrieve signing keys response.", &error, 1));
GRPC_ERROR_UNREF(error);
return;
}
auto it = json.object_value().find("access_key_id");
if (it != json.object_value().end() &&
it->second.type() == Json::Type::STRING) {
access_key_id_ = it->second.string_value();
} else {
FinishRetrieveSubjectToken(
"", GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrFormat("Missing or invalid access_key_id in %s.",
response_body)
.c_str()));
return;
}
it = json.object_value().find("secret_access_key");
if (it != json.object_value().end() &&
it->second.type() == Json::Type::STRING) {
secret_access_key_ = it->second.string_value();
} else {
FinishRetrieveSubjectToken(
"", GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrFormat("Missing or invalid secret_access_key in %s.",
response_body)
.c_str()));
return;
}
it = json.object_value().find("token");
if (it != json.object_value().end() &&
it->second.type() == Json::Type::STRING) {
token_ = it->second.string_value();
} else {
FinishRetrieveSubjectToken(
"",
GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrFormat("Missing or invalid token in %s.", response_body)
.c_str()));
return;
}
BuildSubjectToken();
}
void AwsExternalAccountCredentials::BuildSubjectToken() {
grpc_error* error = GRPC_ERROR_NONE;
if (signer_ == nullptr) {
cred_verification_url_ = absl::StrReplaceAll(
regional_cred_verification_url_, {{"{region}", region_}});
signer_ = absl::make_unique<AwsRequestSigner>(
access_key_id_, secret_access_key_, token_, "POST",
cred_verification_url_, region_, "",
std::map<std::string, std::string>(), &error);
if (error != GRPC_ERROR_NONE) {
FinishRetrieveSubjectToken(
"", GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Creating aws request signer failed.", &error, 1));
GRPC_ERROR_UNREF(error);
return;
}
}
auto signed_headers = signer_->GetSignedRequestHeaders();
if (error != GRPC_ERROR_NONE) {
FinishRetrieveSubjectToken("",
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Invalid getting signed request"
"headers.",
&error, 1));
GRPC_ERROR_UNREF(error);
return;
}
// Construct subject token
Json::Array headers;
headers.push_back(Json(
{{"key", "Authorization"}, {"value", signed_headers["Authorization"]}}));
headers.push_back(Json({{"key", "host"}, {"value", signed_headers["host"]}}));
headers.push_back(
Json({{"key", "x-amz-date"}, {"value", signed_headers["x-amz-date"]}}));
Json::Object object{{"url", Json(cred_verification_url_)},
{"method", Json("POST")},
{"body", Json("")},
{"headers", Json(headers)}};
Json subject_token_json(object);
std::string subject_token = UrlEncode(subject_token_json.Dump());
FinishRetrieveSubjectToken(subject_token, GRPC_ERROR_NONE);
}
void AwsExternalAccountCredentials::FinishRetrieveSubjectToken(
std::string subject_token, grpc_error* error) {
// Reset context
ctx_ = nullptr;
// Move object state into local variables.
auto cb = cb_;
cb_ = nullptr;
// Invoke the callback.
if (error != GRPC_ERROR_NONE) {
cb("", error);
} else {
cb(subject_token, GRPC_ERROR_NONE);
}
}
} // namespace grpc_core

@ -0,0 +1,79 @@
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_AWS_EXTERNAL_ACCOUNT_CREDENTIALS_H
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_AWS_EXTERNAL_ACCOUNT_CREDENTIALS_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/credentials/external/external_account_credentials.h"
#include "src/core/lib/security/credentials/external/aws_request_signer.h"
namespace grpc_core {
class AwsExternalAccountCredentials final : public ExternalAccountCredentials {
public:
static RefCountedPtr<AwsExternalAccountCredentials> Create(
ExternalAccountCredentialsOptions options,
std::vector<std::string> scopes, grpc_error** error);
AwsExternalAccountCredentials(ExternalAccountCredentialsOptions options,
std::vector<std::string> scopes,
grpc_error** error);
private:
void RetrieveSubjectToken(
HTTPRequestContext* ctx, const ExternalAccountCredentialsOptions& options,
std::function<void(std::string, grpc_error*)> cb) override;
void RetrieveRegion();
static void OnRetrieveRegion(void* arg, grpc_error* error);
void OnRetrieveRegionInternal(grpc_error* error);
void RetrieveRoleName();
static void OnRetrieveRoleName(void* arg, grpc_error* error);
void OnRetrieveRoleNameInternal(grpc_error* error);
void RetrieveSigningKeys();
static void OnRetrieveSigningKeys(void* arg, grpc_error* error);
void OnRetrieveSigningKeysInternal(grpc_error* error);
void BuildSubjectToken();
void FinishRetrieveSubjectToken(std::string subject_token, grpc_error* error);
// Fields of credential source
std::string region_url_;
std::string url_;
std::string regional_cred_verification_url_;
// Information required by request signer
std::string region_;
std::string role_name_;
std::string access_key_id_;
std::string secret_access_key_;
std::string token_;
std::unique_ptr<AwsRequestSigner> signer_;
std::string cred_verification_url_;
HTTPRequestContext* ctx_ = nullptr;
std::function<void(std::string, grpc_error*)> cb_ = nullptr;
};
} // namespace grpc_core
#endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_AWS_EXTERNAL_ACCOUNT_CREDENTIALS_H

@ -478,6 +478,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/composite/composite_credentials.cc',
'src/core/lib/security/credentials/credentials.cc',
'src/core/lib/security/credentials/credentials_metadata.cc',
'src/core/lib/security/credentials/external/aws_external_account_credentials.cc',
'src/core/lib/security/credentials/external/aws_request_signer.cc',
'src/core/lib/security/credentials/external/external_account_credentials.cc',
'src/core/lib/security/credentials/external/file_external_account_credentials.cc',

@ -44,6 +44,7 @@
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/security/credentials/composite/composite_credentials.h"
#include "src/core/lib/security/credentials/external/aws_external_account_credentials.h"
#include "src/core/lib/security/credentials/external/external_account_credentials.h"
#include "src/core/lib/security/credentials/external/file_external_account_credentials.h"
#include "src/core/lib/security/credentials/external/url_external_account_credentials.h"
@ -174,6 +175,58 @@ static const char
"{\"url\":\"invalid_credential_source_url\","
"\"headers\":{\"Metadata-Flavor\":\"Google\"}}";
static const char
valid_aws_external_account_creds_retrieve_signing_keys_response[] =
"{\"access_key_id\":\"test_access_key_id\",\"secret_access_key\":"
"\"test_secret_access_key\",\"token\":\"test_token\"}";
static const char valid_aws_external_account_creds_options_credential_source[] =
"{\"environment_id\":\"aws1\","
"\"region_url\":\"https://foo.com:5555/region_url\","
"\"url\":\"https://foo.com:5555/url\","
"\"regional_cred_verification_url\":\"https://foo.com:5555/"
"regional_cred_verification_url_{region}\"}";
static const char
invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id
[] = "{\"environment_id\":\"unsupported_aws_version\","
"\"region_url\":\"https://foo.com:5555/region_url\","
"\"url\":\"https://foo.com:5555/url\","
"\"regional_cred_verification_url\":\"https://foo.com:5555/"
"regional_cred_verification_url_{region}\"}";
static const char
invalid_aws_external_account_creds_options_credential_source_invalid_region_url
[] = "{\"environment_id\":\"aws1\","
"\"region_url\":\"invalid_region_url\","
"\"url\":\"https://foo.com:5555/url\","
"\"regional_cred_verification_url\":\"https://foo.com:5555/"
"regional_cred_verification_url_{region}\"}";
static const char
invalid_aws_external_account_creds_options_credential_source_invalid_url[] =
"{\"environment_id\":\"aws1\","
"\"region_url\":\"https://foo.com:5555/region_url\","
"\"url\":\"invalid_url\","
"\"regional_cred_verification_url\":\"https://foo.com:5555/"
"regional_cred_verification_url_{region}\"}";
static const char
invalid_aws_external_account_creds_options_credential_source_missing_role_name
[] = "{\"environment_id\":\"aws1\","
"\"region_url\":\"https://foo.com:5555/region_url\","
"\"url\":\"https://foo.com:5555/url_no_role_name\","
"\"regional_cred_verification_url\":\"https://foo.com:5555/"
"regional_cred_verification_url_{region}\"}";
static const char
invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url
[] = "{\"environment_id\":\"aws1\","
"\"region_url\":\"https://foo.com:5555/region_url\","
"\"url\":\"https://foo.com:5555/url_no_role_name\","
"\"regional_cred_verification_url\":\"invalid_regional_cred_"
"verification_url\"}";
/* -- Global state flags. -- */
static bool g_test_is_on_gce = false;
@ -1942,7 +1995,6 @@ static void validate_external_account_creds_token_exchage_request(
GPR_ASSERT(strcmp(grpc_uri_get_query_arg(uri, "scope"),
"https://www.googleapis.com/auth/cloud-platform") == 0);
grpc_uri_destroy(uri);
// Check the rest of the request.
GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
GPR_ASSERT(strcmp(request->http.path, "/token") == 0);
@ -1964,7 +2016,6 @@ validate_external_account_creds_service_account_impersonation_request(
GPR_ASSERT(body_size != 0);
GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
GPR_ASSERT(strcmp(body, "scope=scope_1 scope_2") == 0);
// Check the rest of the request.
GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
GPR_ASSERT(strcmp(request->http.path, "/service_account_impersonation") == 0);
@ -2035,6 +2086,69 @@ static int url_external_account_creds_httpcli_get_success(
return 1;
}
static void validate_aws_external_account_creds_token_exchage_request(
const grpc_httpcli_request* request, const char* body, size_t body_size,
bool expect_actor_token) {
// Check that the body is constructed properly.
GPR_ASSERT(body != nullptr);
GPR_ASSERT(body_size != 0);
GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
std::string get_url_equivalent =
absl::StrFormat("%s?%s", "https://foo.com:5555/token", body);
grpc_uri* uri = grpc_uri_parse(get_url_equivalent.c_str(), false);
GPR_ASSERT(strcmp(grpc_uri_get_query_arg(uri, "audience"), "audience") == 0);
GPR_ASSERT(strcmp(grpc_uri_get_query_arg(uri, "grant_type"),
"urn:ietf:params:oauth:grant-type:token-exchange") == 0);
GPR_ASSERT(strcmp(grpc_uri_get_query_arg(uri, "requested_token_type"),
"urn:ietf:params:oauth:token-type:access_token") == 0);
GPR_ASSERT(strcmp(grpc_uri_get_query_arg(uri, "subject_token_type"),
"subject_token_type") == 0);
GPR_ASSERT(strcmp(grpc_uri_get_query_arg(uri, "scope"),
"https://www.googleapis.com/auth/cloud-platform") == 0);
grpc_uri_destroy(uri);
// Check the rest of the request.
GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
GPR_ASSERT(strcmp(request->http.path, "/token") == 0);
GPR_ASSERT(request->http.hdr_count == 2);
GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
GPR_ASSERT(strcmp(request->http.hdrs[0].value,
"application/x-www-form-urlencoded") == 0);
GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0);
GPR_ASSERT(strcmp(request->http.hdrs[1].value,
"Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
}
static int aws_external_account_creds_httpcli_get_success(
const grpc_httpcli_request* request, grpc_millis /*deadline*/,
grpc_closure* on_done, grpc_httpcli_response* response) {
if (strcmp(request->http.path, "/region_url") == 0) {
*response = http_response(200, "test_regionz");
} else if (strcmp(request->http.path, "/url") == 0) {
*response = http_response(200, "test_role_name");
} else if (strcmp(request->http.path, "/url_no_role_name") == 0) {
*response = http_response(200, "");
} else if (strcmp(request->http.path, "/url/test_role_name") == 0) {
*response = http_response(
200, valid_aws_external_account_creds_retrieve_signing_keys_response);
}
grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
return 1;
}
static int aws_external_account_creds_httpcli_post_success(
const grpc_httpcli_request* request, const char* body, size_t body_size,
grpc_millis /*deadline*/, grpc_closure* on_done,
grpc_httpcli_response* response) {
if (strcmp(request->http.path, "/token") == 0) {
validate_aws_external_account_creds_token_exchage_request(request, body,
body_size, true);
*response = http_response(
200, valid_external_account_creds_token_exchange_response);
}
grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
return 1;
}
// The subclass of ExternalAccountCredentials for testing.
// ExternalAccountCredentials is an abstract class so we can't directly test
// against it.
@ -2515,6 +2629,366 @@ static void test_file_external_account_creds_failure_invalid_json_content(
gpr_free(subject_token_path);
}
static void test_aws_external_account_creds_success(void) {
expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
grpc_core::ExecCtx exec_ctx;
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
valid_aws_external_account_creds_options_credential_source, &error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
request_metadata_state* state =
make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
aws_external_account_creds_httpcli_post_success);
run_request_metadata_test(creds.get(), auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
grpc_httpcli_set_override(nullptr, nullptr);
}
static void test_aws_external_account_creds_success_path_region_env_keys_url(
void) {
expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
grpc_core::ExecCtx exec_ctx;
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
gpr_setenv("AWS_REGION", "test_regionz");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
valid_aws_external_account_creds_options_credential_source, &error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
request_metadata_state* state =
make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
aws_external_account_creds_httpcli_post_success);
run_request_metadata_test(creds.get(), auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
grpc_httpcli_set_override(nullptr, nullptr);
gpr_unsetenv("AWS_REGION");
}
static void test_aws_external_account_creds_success_path_region_url_keys_env(
void) {
expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
grpc_core::ExecCtx exec_ctx;
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
gpr_setenv("AWS_SESSION_TOKEN", "test_token");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
valid_aws_external_account_creds_options_credential_source, &error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
request_metadata_state* state =
make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
aws_external_account_creds_httpcli_post_success);
run_request_metadata_test(creds.get(), auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
grpc_httpcli_set_override(nullptr, nullptr);
gpr_unsetenv("AWS_ACCESS_KEY_ID");
gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
gpr_unsetenv("AWS_SESSION_TOKEN");
}
static void test_aws_external_account_creds_success_path_region_env_keys_env(
void) {
expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
grpc_core::ExecCtx exec_ctx;
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
gpr_setenv("AWS_REGION", "test_regionz");
gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
gpr_setenv("AWS_SESSION_TOKEN", "test_token");
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
valid_aws_external_account_creds_options_credential_source, &error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
request_metadata_state* state =
make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
aws_external_account_creds_httpcli_post_success);
run_request_metadata_test(creds.get(), auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
grpc_httpcli_set_override(nullptr, nullptr);
gpr_unsetenv("AWS_REGION");
gpr_unsetenv("AWS_ACCESS_KEY_ID");
gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
gpr_unsetenv("AWS_SESSION_TOKEN");
}
static void test_aws_external_account_creds_failure_unmatched_environment_id(
void) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id,
&error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds == nullptr);
grpc_slice expected_error_slice =
grpc_slice_from_static_string("environment_id does not match.");
grpc_slice actual_error_slice;
GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
&actual_error_slice));
GPR_ASSERT(grpc_slice_cmp(expected_error_slice, actual_error_slice) == 0);
GRPC_ERROR_UNREF(error);
}
static void test_aws_external_account_creds_failure_invalid_region_url(void) {
grpc_core::ExecCtx exec_ctx;
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
invalid_aws_external_account_creds_options_credential_source_invalid_region_url,
&error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Invalid region url: invalid_region_url.");
grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Error occurred when fetching oauth2 token.", &error, 1);
request_metadata_state* state =
make_request_metadata_state(expected_error, nullptr, 0);
grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
aws_external_account_creds_httpcli_post_success);
run_request_metadata_test(creds.get(), auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
grpc_httpcli_set_override(nullptr, nullptr);
GRPC_ERROR_UNREF(error);
}
static void test_aws_external_account_creds_failure_invalid_url(void) {
grpc_core::ExecCtx exec_ctx;
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
invalid_aws_external_account_creds_options_credential_source_invalid_url,
&error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid url: invalid_url.");
grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Error occurred when fetching oauth2 token.", &error, 1);
request_metadata_state* state =
make_request_metadata_state(expected_error, nullptr, 0);
grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
aws_external_account_creds_httpcli_post_success);
run_request_metadata_test(creds.get(), auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
grpc_httpcli_set_override(nullptr, nullptr);
GRPC_ERROR_UNREF(error);
}
static void test_aws_external_account_creds_failure_missing_role_name(void) {
grpc_core::ExecCtx exec_ctx;
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
invalid_aws_external_account_creds_options_credential_source_missing_role_name,
&error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Missing role name when retrieving signing keys.");
grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Error occurred when fetching oauth2 token.", &error, 1);
request_metadata_state* state =
make_request_metadata_state(expected_error, nullptr, 0);
grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
aws_external_account_creds_httpcli_post_success);
run_request_metadata_test(creds.get(), auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
grpc_httpcli_set_override(nullptr, nullptr);
GRPC_ERROR_UNREF(error);
}
static void
test_aws_external_account_creds_failure_invalid_regional_cred_verification_url(
void) {
grpc_core::ExecCtx exec_ctx;
grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
nullptr, nullptr};
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::Json credential_source = grpc_core::Json::Parse(
invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url,
&error);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_core::ExternalAccountCredentials::ExternalAccountCredentialsOptions
options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
"https://foo.com:5555/token", // token_url;
"https://foo.com:5555/token_info", // token_info_url;
credential_source, // credential_source;
"quota_project_id", // quota_project_id;
"client_id", // client_id;
"client_secret", // client_secret;
};
auto creds =
grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Creating aws request signer failed.");
grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Error occurred when fetching oauth2 token.", &error, 1);
request_metadata_state* state =
make_request_metadata_state(expected_error, nullptr, 0);
grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
aws_external_account_creds_httpcli_post_success);
run_request_metadata_test(creds.get(), auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
grpc_httpcli_set_override(nullptr, nullptr);
GRPC_ERROR_UNREF(error);
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
@ -2571,6 +3045,15 @@ int main(int argc, char** argv) {
test_file_external_account_creds_success_format_json();
test_file_external_account_creds_failure_file_not_found();
test_file_external_account_creds_failure_invalid_json_content();
test_aws_external_account_creds_success();
test_aws_external_account_creds_success_path_region_env_keys_url();
test_aws_external_account_creds_success_path_region_url_keys_env();
test_aws_external_account_creds_success_path_region_env_keys_env();
test_aws_external_account_creds_failure_unmatched_environment_id();
test_aws_external_account_creds_failure_invalid_region_url();
test_aws_external_account_creds_failure_invalid_url();
test_aws_external_account_creds_failure_missing_role_name();
test_aws_external_account_creds_failure_invalid_regional_cred_verification_url();
grpc_shutdown();
return 0;
}

@ -1914,6 +1914,8 @@ src/core/lib/security/credentials/composite/composite_credentials.h \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/credentials.h \
src/core/lib/security/credentials/credentials_metadata.cc \
src/core/lib/security/credentials/external/aws_external_account_credentials.cc \
src/core/lib/security/credentials/external/aws_external_account_credentials.h \
src/core/lib/security/credentials/external/aws_request_signer.cc \
src/core/lib/security/credentials/external/aws_request_signer.h \
src/core/lib/security/credentials/external/external_account_credentials.cc \

@ -1756,6 +1756,8 @@ src/core/lib/security/credentials/composite/composite_credentials.h \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/credentials.h \
src/core/lib/security/credentials/credentials_metadata.cc \
src/core/lib/security/credentials/external/aws_external_account_credentials.cc \
src/core/lib/security/credentials/external/aws_external_account_credentials.h \
src/core/lib/security/credentials/external/aws_request_signer.cc \
src/core/lib/security/credentials/external/aws_request_signer.h \
src/core/lib/security/credentials/external/external_account_credentials.cc \

Loading…
Cancel
Save