LCOV - code coverage report
Current view: top level - source/extensions/grpc_credentials/aws_iam - config.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 89 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 6 0.0 %

          Line data    Source code
       1             : #include "source/extensions/grpc_credentials/aws_iam/config.h"
       2             : 
       3             : #include "envoy/common/exception.h"
       4             : #include "envoy/config/core/v3/grpc_service.pb.h"
       5             : #include "envoy/config/grpc_credential/v3/aws_iam.pb.h"
       6             : #include "envoy/config/grpc_credential/v3/aws_iam.pb.validate.h"
       7             : #include "envoy/grpc/google_grpc_creds.h"
       8             : #include "envoy/registry/registry.h"
       9             : 
      10             : #include "source/common/config/utility.h"
      11             : #include "source/common/grpc/google_grpc_creds_impl.h"
      12             : #include "source/common/http/utility.h"
      13             : #include "source/common/protobuf/message_validator_impl.h"
      14             : #include "source/extensions/common/aws/credentials_provider_impl.h"
      15             : #include "source/extensions/common/aws/region_provider_impl.h"
      16             : #include "source/extensions/common/aws/sigv4_signer_impl.h"
      17             : #include "source/extensions/common/aws/utility.h"
      18             : 
      19             : namespace Envoy {
      20             : namespace Extensions {
      21             : namespace GrpcCredentials {
      22             : namespace AwsIam {
      23             : 
      24             : std::shared_ptr<grpc::ChannelCredentials> AwsIamGrpcCredentialsFactory::getChannelCredentials(
      25           0 :     const envoy::config::core::v3::GrpcService& grpc_service_config, Api::Api& api) {
      26             : 
      27           0 :   const auto& google_grpc = grpc_service_config.google_grpc();
      28           0 :   std::shared_ptr<grpc::ChannelCredentials> creds =
      29           0 :       Grpc::CredsUtility::defaultSslChannelCredentials(grpc_service_config, api);
      30             : 
      31           0 :   std::shared_ptr<grpc::CallCredentials> call_creds;
      32           0 :   for (const auto& credential : google_grpc.call_credentials()) {
      33           0 :     switch (credential.credential_specifier_case()) {
      34           0 :     case envoy::config::core::v3::GrpcService::GoogleGrpc::CallCredentials::
      35           0 :         CredentialSpecifierCase::kFromPlugin: {
      36           0 :       if (credential.from_plugin().name() == "envoy.grpc_credentials.aws_iam") {
      37           0 :         AwsIamGrpcCredentialsFactory credentials_factory;
      38             :         // We don't deal with validation failures here at runtime today, see
      39             :         // https://github.com/envoyproxy/envoy/issues/8010.
      40           0 :         const Envoy::ProtobufTypes::MessagePtr config_message =
      41           0 :             Envoy::Config::Utility::translateToFactoryConfig(
      42           0 :                 credential.from_plugin(), ProtobufMessage::getNullValidationVisitor(),
      43           0 :                 credentials_factory);
      44           0 :         const auto& config = Envoy::MessageUtil::downcastAndValidate<
      45           0 :             const envoy::config::grpc_credential::v3::AwsIamConfig&>(
      46           0 :             *config_message, ProtobufMessage::getNullValidationVisitor());
      47           0 :         const auto region = getRegion(config);
      48             :         // TODO(suniltheta): Due to the reasons explained in
      49             :         // https://github.com/envoyproxy/envoy/issues/27586 this aws iam plugin is not able to
      50             :         // utilize http async client to fetch AWS credentials. For time being this is still using
      51             :         // libcurl to fetch the credentials. To fully get rid of curl, need to address the below
      52             :         // usage of AWS credentials common utils. Until then we are setting nullopt for server
      53             :         // factory context.
      54           0 :         auto credentials_provider = std::make_shared<Common::Aws::DefaultCredentialsProviderChain>(
      55           0 :             api, absl::nullopt /*Empty factory context*/, region,
      56           0 :             Common::Aws::Utility::fetchMetadata);
      57           0 :         auto signer = std::make_unique<Common::Aws::SigV4SignerImpl>(
      58           0 :             config.service_name(), region, credentials_provider, api.timeSource(),
      59             :             // TODO: extend API to allow specifying header exclusion. ref:
      60             :             // https://github.com/envoyproxy/envoy/pull/18998
      61           0 :             Common::Aws::AwsSigningHeaderExclusionVector{});
      62           0 :         std::shared_ptr<grpc::CallCredentials> new_call_creds = grpc::MetadataCredentialsFromPlugin(
      63           0 :             std::make_unique<AwsIamHeaderAuthenticator>(std::move(signer)));
      64           0 :         if (call_creds == nullptr) {
      65           0 :           call_creds = new_call_creds;
      66           0 :         } else {
      67           0 :           call_creds = grpc::CompositeCallCredentials(call_creds, new_call_creds);
      68           0 :         }
      69           0 :       }
      70           0 :       break;
      71           0 :     }
      72           0 :     default:
      73             :       // unused credential types
      74           0 :       continue;
      75           0 :     }
      76           0 :   }
      77             : 
      78           0 :   if (call_creds != nullptr) {
      79           0 :     return grpc::CompositeChannelCredentials(creds, call_creds);
      80           0 :   }
      81             : 
      82           0 :   return creds;
      83           0 : }
      84             : 
      85             : std::string AwsIamGrpcCredentialsFactory::getRegion(
      86           0 :     const envoy::config::grpc_credential::v3::AwsIamConfig& config) {
      87           0 :   Common::Aws::RegionProviderPtr region_provider;
      88           0 :   if (!config.region().empty()) {
      89           0 :     region_provider = std::make_unique<Common::Aws::StaticRegionProvider>(config.region());
      90           0 :   } else {
      91           0 :     region_provider = std::make_unique<Common::Aws::EnvironmentRegionProvider>();
      92           0 :   }
      93             : 
      94           0 :   if (!region_provider->getRegion().has_value()) {
      95           0 :     throw EnvoyException("Could not determine AWS region. "
      96           0 :                          "If you are not running Envoy in EC2 or ECS, "
      97           0 :                          "provide the region in the plugin configuration.");
      98           0 :   }
      99             : 
     100           0 :   return *region_provider->getRegion();
     101           0 : }
     102             : 
     103             : grpc::Status
     104             : AwsIamHeaderAuthenticator::GetMetadata(grpc::string_ref service_url, grpc::string_ref method_name,
     105             :                                        const grpc::AuthContext&,
     106           0 :                                        std::multimap<grpc::string, grpc::string>* metadata) {
     107             : 
     108           0 :   auto message = buildMessageToSign(absl::string_view(service_url.data(), service_url.length()),
     109           0 :                                     absl::string_view(method_name.data(), method_name.length()));
     110             : 
     111           0 :   TRY_NEEDS_AUDIT { signer_->sign(message, false); }
     112           0 :   END_TRY catch (const EnvoyException& e) {
     113           0 :     return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
     114           0 :   }
     115             : 
     116           0 :   signedHeadersToMetadata(message.headers(), *metadata);
     117             : 
     118           0 :   return grpc::Status::OK;
     119           0 : }
     120             : 
     121             : Http::RequestMessageImpl
     122             : AwsIamHeaderAuthenticator::buildMessageToSign(absl::string_view service_url,
     123           0 :                                               absl::string_view method_name) {
     124             : 
     125           0 :   const auto uri = fmt::format("{}/{}", service_url, method_name);
     126           0 :   absl::string_view host;
     127           0 :   absl::string_view path;
     128           0 :   Http::Utility::extractHostPathFromUri(uri, host, path);
     129             : 
     130           0 :   Http::RequestMessageImpl message;
     131           0 :   message.headers().setReferenceMethod(Http::Headers::get().MethodValues.Post);
     132           0 :   message.headers().setHost(host);
     133           0 :   message.headers().setPath(path);
     134             : 
     135           0 :   return message;
     136           0 : }
     137             : 
     138             : void AwsIamHeaderAuthenticator::signedHeadersToMetadata(
     139           0 :     const Http::HeaderMap& headers, std::multimap<grpc::string, grpc::string>& metadata) {
     140             : 
     141           0 :   headers.iterate([&metadata](const Http::HeaderEntry& entry) -> Http::HeaderMap::Iterate {
     142           0 :     const auto& key = entry.key().getStringView();
     143             :     // Skip pseudo-headers
     144           0 :     if (key.empty() || key[0] == ':') {
     145           0 :       return Http::HeaderMap::Iterate::Continue;
     146           0 :     }
     147           0 :     metadata.emplace(key, entry.value().getStringView());
     148           0 :     return Http::HeaderMap::Iterate::Continue;
     149           0 :   });
     150           0 : }
     151             : 
     152             : REGISTER_FACTORY(AwsIamGrpcCredentialsFactory, Grpc::GoogleGrpcCredentialsFactory);
     153             : 
     154             : } // namespace AwsIam
     155             : } // namespace GrpcCredentials
     156             : } // namespace Extensions
     157             : } // namespace Envoy

Generated by: LCOV version 1.15