[core/security] Adding metrics header to sts request for external account credentials (#34661)

Closes #34661

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34661 from aeitzman:metrics 9f53992ed4
PiperOrigin-RevId: 585796526
pull/35113/head
aeitzman 1 year ago committed by Copybara-Service
parent 667def7505
commit 79c9a67dee
  1. 4
      src/core/lib/security/credentials/external/aws_external_account_credentials.cc
  2. 4
      src/core/lib/security/credentials/external/aws_external_account_credentials.h
  3. 42
      src/core/lib/security/credentials/external/external_account_credentials.cc
  4. 4
      src/core/lib/security/credentials/external/external_account_credentials.h
  5. 4
      src/core/lib/security/credentials/external/file_external_account_credentials.cc
  6. 4
      src/core/lib/security/credentials/external/file_external_account_credentials.h
  7. 4
      src/core/lib/security/credentials/external/url_external_account_credentials.cc
  8. 4
      src/core/lib/security/credentials/external/url_external_account_credentials.h
  9. 111
      test/core/security/credentials_test.cc

@ -525,4 +525,8 @@ void AwsExternalAccountCredentials::FinishRetrieveSubjectToken(
}
}
absl::string_view AwsExternalAccountCredentials::CredentialSourceType() {
return "aws";
}
} // namespace grpc_core

@ -24,6 +24,8 @@
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/http/httpcli.h"
@ -72,6 +74,8 @@ class AwsExternalAccountCredentials final : public ExternalAccountCredentials {
void AddMetadataRequestHeaders(grpc_http_request* request);
absl::string_view CredentialSourceType() override;
std::string audience_;
OrphanablePtr<HttpRequest> http_request_;

@ -26,6 +26,7 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/escaping.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
@ -53,7 +54,6 @@
#include "src/core/lib/security/credentials/external/file_external_account_credentials.h"
#include "src/core/lib/security/credentials/external/url_external_account_credentials.h"
#include "src/core/lib/security/util/json_util.h"
#include "src/core/lib/slice/b64.h"
#include "src/core/lib/uri/uri_parser.h"
#define EXTERNAL_ACCOUNT_CREDENTIALS_GRANT_TYPE \
@ -271,6 +271,20 @@ std::string ExternalAccountCredentials::debug_string() {
grpc_oauth2_token_fetcher_credentials::debug_string());
}
std::string ExternalAccountCredentials::MetricsHeaderValue() {
return absl::StrFormat(
"gl-cpp/unknown auth/%s google-byoid-sdk source/%s sa-impersonation/%v "
"config-lifetime/%v",
grpc_version_string(), CredentialSourceType(),
!options_.service_account_impersonation_url.empty(),
options_.service_account_impersonation.token_lifetime_seconds !=
IMPERSONATED_CRED_DEFAULT_LIFETIME_IN_SECONDS);
}
absl::string_view ExternalAccountCredentials::CredentialSourceType() {
return "unknown";
}
// The token fetching flow:
// 1. Retrieve subject token - Subclass's RetrieveSubjectToken() gets called
// and the subject token is received in OnRetrieveSubjectTokenInternal().
@ -317,27 +331,21 @@ void ExternalAccountCredentials::ExchangeToken(
}
grpc_http_request request;
memset(&request, 0, sizeof(grpc_http_request));
grpc_http_header* headers = nullptr;
if (!options_.client_id.empty() && !options_.client_secret.empty()) {
request.hdr_count = 2;
headers = static_cast<grpc_http_header*>(
const bool add_authorization_header =
!options_.client_id.empty() && !options_.client_secret.empty();
request.hdr_count = add_authorization_header ? 3 : 2;
auto* headers = static_cast<grpc_http_header*>(
gpr_malloc(sizeof(grpc_http_header) * request.hdr_count));
headers[0].key = gpr_strdup("Content-Type");
headers[0].value = gpr_strdup("application/x-www-form-urlencoded");
headers[1].key = gpr_strdup("x-goog-api-client");
headers[1].value = gpr_strdup(MetricsHeaderValue().c_str());
if (add_authorization_header) {
std::string raw_cred =
absl::StrFormat("%s:%s", options_.client_id, options_.client_secret);
char* encoded_cred =
grpc_base64_encode(raw_cred.c_str(), raw_cred.length(), 0, 0);
std::string str = absl::StrFormat("Basic %s", std::string(encoded_cred));
headers[1].key = gpr_strdup("Authorization");
headers[1].value = gpr_strdup(str.c_str());
gpr_free(encoded_cred);
} else {
request.hdr_count = 1;
headers = static_cast<grpc_http_header*>(
gpr_malloc(sizeof(grpc_http_header) * request.hdr_count));
headers[0].key = gpr_strdup("Content-Type");
headers[0].value = gpr_strdup("application/x-www-form-urlencoded");
std::string str = absl::StrFormat("Basic %s", absl::Base64Escape(raw_cred));
headers[2].key = gpr_strdup("Authorization");
headers[2].value = gpr_strdup(str.c_str());
}
request.hdrs = headers;
std::vector<std::string> body_parts;

@ -101,6 +101,10 @@ class ExternalAccountCredentials
HTTPRequestContext* ctx, const Options& options,
std::function<void(std::string, grpc_error_handle)> cb) = 0;
virtual absl::string_view CredentialSourceType();
std::string MetricsHeaderValue();
private:
// This method implements the common token fetch logic and it will be called
// when grpc_oauth2_token_fetcher_credentials request a new access token.

@ -137,4 +137,8 @@ void FileExternalAccountCredentials::RetrieveSubjectToken(
cb(std::string(content), absl::OkStatus());
}
absl::string_view FileExternalAccountCredentials::CredentialSourceType() {
return "file";
}
} // namespace grpc_core

@ -23,6 +23,8 @@
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/security/credentials/external/external_account_credentials.h"
@ -44,6 +46,8 @@ class FileExternalAccountCredentials final : public ExternalAccountCredentials {
HTTPRequestContext* ctx, const Options& options,
std::function<void(std::string, grpc_error_handle)> cb) override;
absl::string_view CredentialSourceType() override;
// Fields of credential source
std::string file_;
std::string format_type_;

@ -240,4 +240,8 @@ void UrlExternalAccountCredentials::FinishRetrieveSubjectToken(
}
}
absl::string_view UrlExternalAccountCredentials::CredentialSourceType() {
return "url";
}
} // namespace grpc_core

@ -24,6 +24,8 @@
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/http/httpcli.h"
@ -48,6 +50,8 @@ class UrlExternalAccountCredentials final : public ExternalAccountCredentials {
HTTPRequestContext* ctx, const Options& options,
std::function<void(std::string, grpc_error_handle)> cb) override;
absl::string_view CredentialSourceType() override;
static void OnRetrieveSubjectToken(void* arg, grpc_error_handle error);
void OnRetrieveSubjectTokenInternal(grpc_error_handle error);

@ -2127,12 +2127,12 @@ void validate_external_account_creds_token_exchage_request(
// Check the rest of the request.
GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
GPR_ASSERT(strcmp(path, "/token") == 0);
GPR_ASSERT(request->hdr_count == 2);
GPR_ASSERT(request->hdr_count == 3);
GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
GPR_ASSERT(
strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0);
GPR_ASSERT(strcmp(request->hdrs[1].value,
GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0);
GPR_ASSERT(strcmp(request->hdrs[2].value,
"Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
}
@ -2155,12 +2155,12 @@ void validate_external_account_creds_token_exchage_request_with_url_encode(
// Check the rest of the request.
GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
GPR_ASSERT(strcmp(path, "/token_url_encode") == 0);
GPR_ASSERT(request->hdr_count == 2);
GPR_ASSERT(request->hdr_count == 3);
GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
GPR_ASSERT(
strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0);
GPR_ASSERT(strcmp(request->hdrs[1].value,
GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0);
GPR_ASSERT(strcmp(request->hdrs[2].value,
"Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
}
@ -2311,12 +2311,18 @@ void validate_aws_external_account_creds_token_exchage_request(
// Check the rest of the request.
GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
GPR_ASSERT(strcmp(path, "/token") == 0);
GPR_ASSERT(request->hdr_count == 2);
GPR_ASSERT(request->hdr_count == 3);
GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
GPR_ASSERT(
strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0);
GPR_ASSERT(strcmp(request->hdrs[1].value,
GPR_ASSERT(strcmp(request->hdrs[1].key, "x-goog-api-client") == 0);
EXPECT_EQ(
request->hdrs[1].value,
absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/aws "
"sa-impersonation/false config-lifetime/false",
grpc_version_string()));
GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0);
GPR_ASSERT(strcmp(request->hdrs[2].value,
"Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
}
@ -2385,6 +2391,8 @@ class TestExternalAccountCredentials final : public ExternalAccountCredentials {
std::vector<std::string> scopes)
: ExternalAccountCredentials(std::move(options), std::move(scopes)) {}
std::string GetMetricsValue() { return MetricsHeaderValue(); }
protected:
void RetrieveSubjectToken(
HTTPRequestContext* /*ctx*/, const Options& /*options*/,
@ -2393,6 +2401,91 @@ class TestExternalAccountCredentials final : public ExternalAccountCredentials {
}
};
TEST(CredentialsTest, TestExternalAccountCredsMetricsHeader) {
Json credential_source = Json::FromString("");
TestExternalAccountCredentials::ServiceAccountImpersonation
service_account_impersonation;
service_account_impersonation.token_lifetime_seconds = 3600;
TestExternalAccountCredentials::Options options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"", // service_account_impersonation_url;
service_account_impersonation, // service_account_impersonation;
"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;
"", // workforce_pool_user_project;
};
TestExternalAccountCredentials creds(options, {});
EXPECT_EQ(
creds.GetMetricsValue(),
absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown "
"sa-impersonation/false config-lifetime/false",
grpc_version_string()));
}
TEST(CredentialsTest,
TestExternalAccountCredsMetricsHeaderWithServiceAccountImpersonation) {
Json credential_source = Json::FromString("");
TestExternalAccountCredentials::ServiceAccountImpersonation
service_account_impersonation;
service_account_impersonation.token_lifetime_seconds = 3600;
TestExternalAccountCredentials::Options options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"https://foo.com:5555/service_account_impersonation", // service_account_impersonation_url;
service_account_impersonation, // service_account_impersonation;
"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;
"", // workforce_pool_user_project;
};
TestExternalAccountCredentials creds(options, {});
EXPECT_EQ(
creds.GetMetricsValue(),
absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown "
"sa-impersonation/true config-lifetime/false",
grpc_version_string()));
}
TEST(CredentialsTest, TestExternalAccountCredsMetricsHeaderWithConfigLifetime) {
Json credential_source = Json::FromString("");
TestExternalAccountCredentials::ServiceAccountImpersonation
service_account_impersonation;
service_account_impersonation.token_lifetime_seconds = 5000;
TestExternalAccountCredentials::Options options = {
"external_account", // type;
"audience", // audience;
"subject_token_type", // subject_token_type;
"https://foo.com:5555/service_account_impersonation", // service_account_impersonation_url;
service_account_impersonation, // service_account_impersonation;
"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;
"", // workforce_pool_user_project;
};
TestExternalAccountCredentials creds(options, {});
EXPECT_EQ(
creds.GetMetricsValue(),
absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown "
"sa-impersonation/true config-lifetime/true",
grpc_version_string()));
}
TEST(CredentialsTest, TestExternalAccountCredsSuccess) {
ExecCtx exec_ctx;
Json credential_source = Json::FromString("");

Loading…
Cancel
Save