diff --git a/api/envoy/api/v2/core/grpc_service.proto b/api/envoy/api/v2/core/grpc_service.proto index 8614c86ee30e6..acbce114a5695 100644 --- a/api/envoy/api/v2/core/grpc_service.proto +++ b/api/envoy/api/v2/core/grpc_service.proto @@ -62,7 +62,7 @@ message GrpcService { } } - // [#next-free-field: 7] + // [#next-free-field: 8] message CallCredentials { message ServiceAccountJWTAccessCredentials { string json_key = 1; @@ -86,6 +86,46 @@ message GrpcService { } } + // Security token service configuration that allows Google gRPC to + // fetch security token from an OAuth 2.0 authorization server. + // See https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 and + // https://github.com/grpc/grpc/pull/19587. + // [#next-free-field: 10] + message StsService { + // URI of the token exchange service that handles token exchange requests. + string token_exchange_service_uri = 1 [(validate.rules).string = {uri: true}]; + + // Location of the target service or resource where the client + // intends to use the requested security token. + string resource = 2; + + // Logical name of the target service where the client intends to + // use the requested security token. + string audience = 3; + + // The desired scope of the requested security token in the + // context of the service or resource where the token will be used. + string scope = 4; + + // Type of the requested security token. + string requested_token_type = 5; + + // The path of subject token, a security token that represents the + // identity of the party on behalf of whom the request is being made. + string subject_token_path = 6 [(validate.rules).string = {min_bytes: 1}]; + + // Type of the subject token. + string subject_token_type = 7 [(validate.rules).string = {min_bytes: 1}]; + + // The path of actor token, a security token that represents the identity + // of the acting party. The acting party is authorized to use the + // requested security token and act on behalf of the subject. + string actor_token_path = 8; + + // Type of the actor token. + string actor_token_type = 9; + } + oneof credential_specifier { option (validate.required) = true; @@ -113,6 +153,11 @@ message GrpcService { // https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. // https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. MetadataCredentialsFromPlugin from_plugin = 6; + + // Custom security token service which implements OAuth 2.0 token exchange. + // https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 + // See https://github.com/grpc/grpc/pull/19587. + StsService sts_service = 7; } } diff --git a/api/envoy/api/v3alpha/core/grpc_service.proto b/api/envoy/api/v3alpha/core/grpc_service.proto index 86d950263f675..9f78af9d9fe66 100644 --- a/api/envoy/api/v3alpha/core/grpc_service.proto +++ b/api/envoy/api/v3alpha/core/grpc_service.proto @@ -80,7 +80,7 @@ message GrpcService { } } - // [#next-free-field: 7] + // [#next-free-field: 8] message CallCredentials { option (udpa.api.annotations.versioning).previous_message_type = "envoy.api.v2.core.GrpcService.GoogleGrpc.CallCredentials"; @@ -120,6 +120,49 @@ message GrpcService { } } + // Security token service configuration that allows Google gRPC to + // fetch security token from an OAuth 2.0 authorization server. + // See https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 and + // https://github.com/grpc/grpc/pull/19587. + // [#next-free-field: 10] + message StsService { + option (udpa.api.annotations.versioning).previous_message_type = + "envoy.api.v2.core.GrpcService.GoogleGrpc.CallCredentials.StsService"; + + // URI of the token exchange service that handles token exchange requests. + string token_exchange_service_uri = 1 [(validate.rules).string = {uri: true}]; + + // Location of the target service or resource where the client + // intends to use the requested security token. + string resource = 2; + + // Logical name of the target service where the client intends to + // use the requested security token. + string audience = 3; + + // The desired scope of the requested security token in the + // context of the service or resource where the token will be used. + string scope = 4; + + // Type of the requested security token. + string requested_token_type = 5; + + // The path of subject token, a security token that represents the + // identity of the party on behalf of whom the request is being made. + string subject_token_path = 6 [(validate.rules).string = {min_bytes: 1}]; + + // Type of the subject token. + string subject_token_type = 7 [(validate.rules).string = {min_bytes: 1}]; + + // The path of actor token, a security token that represents the identity + // of the acting party. The acting party is authorized to use the + // requested security token and act on behalf of the subject. + string actor_token_path = 8; + + // Type of the actor token. + string actor_token_type = 9; + } + oneof credential_specifier { option (validate.required) = true; @@ -147,6 +190,11 @@ message GrpcService { // https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. // https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. MetadataCredentialsFromPlugin from_plugin = 6; + + // Custom security token service which implements OAuth 2.0 token exchange. + // https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 + // See https://github.com/grpc/grpc/pull/19587. + StsService sts_service = 7; } } diff --git a/source/common/grpc/google_grpc_creds_impl.cc b/source/common/grpc/google_grpc_creds_impl.cc index 38fc371252193..86187ee3cb4a5 100644 --- a/source/common/grpc/google_grpc_creds_impl.cc +++ b/source/common/grpc/google_grpc_creds_impl.cc @@ -73,6 +73,21 @@ CredsUtility::callCredentials(const envoy::api::v2::core::GrpcService::GoogleGrp credential.google_iam().authority_selector()); break; } + case envoy::api::v2::core::GrpcService::GoogleGrpc::CallCredentials::kStsService: { + grpc::experimental::StsCredentialsOptions options = { + credential.sts_service().token_exchange_service_uri(), + credential.sts_service().resource(), + credential.sts_service().audience(), + credential.sts_service().scope(), + credential.sts_service().requested_token_type(), + credential.sts_service().subject_token_path(), + credential.sts_service().subject_token_type(), + credential.sts_service().actor_token_path(), + credential.sts_service().actor_token_type(), + }; + new_call_creds = grpc::experimental::StsCredentials(options); + break; + } default: // We don't handle plugin credentials here, callers can do so instead if they want. continue; diff --git a/test/common/grpc/google_grpc_creds_test.cc b/test/common/grpc/google_grpc_creds_test.cc index a08fcf1625673..19b6b735dc6dd 100644 --- a/test/common/grpc/google_grpc_creds_test.cc +++ b/test/common/grpc/google_grpc_creds_test.cc @@ -122,6 +122,15 @@ TEST_F(CredsUtilityTest, DefaultChannelCredentials) { google_grpc->add_call_credentials()->mutable_from_plugin()->set_name("foo"); EXPECT_NE(nullptr, CredsUtility::defaultChannelCredentials(config, *api_)); } + { + envoy::api::v2::core::GrpcService config; + TestUtility::setTestSslGoogleGrpcConfig(config, true); + auto* sts_service = config.mutable_google_grpc()->add_call_credentials()->mutable_sts_service(); + sts_service->set_token_exchange_service_uri("http://tokenexchangeservice.com"); + sts_service->set_subject_token_path("/var/run/example_token"); + sts_service->set_subject_token_type("urn:ietf:params:oauth:token-type:access_token"); + EXPECT_NE(nullptr, CredsUtility::defaultChannelCredentials(config, *api_)); + } } } // namespace