[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
This commit is contained in:
parent
667def7505
commit
79c9a67dee
|
|
@ -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*>(
|
||||
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");
|
||||
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…
Reference in New Issue