1
#include "source/common/grpc/google_grpc_creds_impl.h"
2

            
3
#include "envoy/config/core/v3/grpc_service.pb.h"
4
#include "envoy/grpc/google_grpc_creds.h"
5

            
6
#include "source/common/config/datasource.h"
7
#include "source/common/runtime/runtime_features.h"
8

            
9
#include "grpcpp/security/tls_certificate_provider.h"
10

            
11
namespace Envoy {
12
namespace Grpc {
13

            
14
std::shared_ptr<grpc::ChannelCredentials> CredsUtility::getChannelCredentials(
15
1100
    const envoy::config::core::v3::GrpcService::GoogleGrpc& google_grpc, Api::Api& api) {
16
1100
  if (google_grpc.has_channel_credentials()) {
17
182
    switch (google_grpc.channel_credentials().credential_specifier_case()) {
18
178
    case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelCredentials::
19
178
        CredentialSpecifierCase::kSslCredentials: {
20
178
      const auto& ssl_credentials = google_grpc.channel_credentials().ssl_credentials();
21
178
      const auto root_certs = THROW_OR_RETURN_VALUE(
22
178
          Config::DataSource::read(ssl_credentials.root_certs(), true, api), std::string);
23
178
      const auto private_key = THROW_OR_RETURN_VALUE(
24
178
          Config::DataSource::read(ssl_credentials.private_key(), true, api), std::string);
25
178
      const auto cert_chain = THROW_OR_RETURN_VALUE(
26
178
          Config::DataSource::read(ssl_credentials.cert_chain(), true, api), std::string);
27
178
      grpc::experimental::TlsChannelCredentialsOptions options;
28
178
      if (!private_key.empty() || !cert_chain.empty()) {
29
4
        options.set_certificate_provider(
30
4
            std::make_shared<grpc::experimental::StaticDataCertificateProvider>(
31
4
                root_certs,
32
4
                std::vector<grpc::experimental::IdentityKeyCertPair>{{private_key, cert_chain}}));
33
175
      } else if (!root_certs.empty()) {
34
172
        options.set_certificate_provider(
35
172
            std::make_shared<grpc::experimental::StaticDataCertificateProvider>(root_certs));
36
172
      }
37
178
      if (!root_certs.empty()) {
38
176
        options.watch_root_certs();
39
176
      }
40
178
      if (!private_key.empty() || !cert_chain.empty()) {
41
4
        options.watch_identity_key_cert_pairs();
42
4
      }
43
178
      if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.google_grpc_disable_tls_13")) {
44
1
        options.set_max_tls_version(grpc_tls_version::TLS1_2);
45
1
      }
46
178
      return grpc::experimental::TlsCredentials(options);
47
    }
48
1
    case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelCredentials::
49
1
        CredentialSpecifierCase::kLocalCredentials: {
50
1
      return grpc::experimental::LocalCredentials(UDS);
51
    }
52
1
    case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelCredentials::
53
1
        CredentialSpecifierCase::kGoogleDefault: {
54
1
      return grpc::GoogleDefaultCredentials();
55
    }
56
2
    default:
57
2
      return nullptr;
58
182
    }
59
182
  }
60
918
  return nullptr;
61
1100
}
62

            
63
std::shared_ptr<grpc::ChannelCredentials> CredsUtility::defaultSslChannelCredentials(
64
12
    const envoy::config::core::v3::GrpcService& grpc_service_config, Api::Api& api) {
65
12
  auto creds = getChannelCredentials(grpc_service_config.google_grpc(), api);
66
12
  if (creds != nullptr) {
67
10
    return creds;
68
10
  }
69
2
  grpc::experimental::TlsChannelCredentialsOptions options;
70
2
  if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.google_grpc_disable_tls_13")) {
71
    options.set_max_tls_version(grpc_tls_version::TLS1_2);
72
  }
73
2
  return grpc::experimental::TlsCredentials(options);
74
12
}
75

            
76
std::vector<std::shared_ptr<grpc::CallCredentials>>
77
1087
CredsUtility::callCredentials(const envoy::config::core::v3::GrpcService::GoogleGrpc& google_grpc) {
78
1087
  std::vector<std::shared_ptr<grpc::CallCredentials>> creds;
79
1090
  for (const auto& credential : google_grpc.call_credentials()) {
80
11
    std::shared_ptr<grpc::CallCredentials> new_call_creds;
81
11
    switch (credential.credential_specifier_case()) {
82
3
    case envoy::config::core::v3::GrpcService::GoogleGrpc::CallCredentials::
83
3
        CredentialSpecifierCase::kAccessToken: {
84
3
      new_call_creds = grpc::AccessTokenCredentials(credential.access_token());
85
3
      break;
86
    }
87
2
    case envoy::config::core::v3::GrpcService::GoogleGrpc::CallCredentials::
88
2
        CredentialSpecifierCase::kGoogleComputeEngine: {
89
2
      new_call_creds = grpc::GoogleComputeEngineCredentials();
90
2
      break;
91
    }
92
2
    case envoy::config::core::v3::GrpcService::GoogleGrpc::CallCredentials::
93
2
        CredentialSpecifierCase::kGoogleRefreshToken: {
94
2
      new_call_creds = grpc::GoogleRefreshTokenCredentials(credential.google_refresh_token());
95
2
      break;
96
    }
97
1
    case envoy::config::core::v3::GrpcService::GoogleGrpc::CallCredentials::
98
1
        CredentialSpecifierCase::kServiceAccountJwtAccess: {
99
1
      new_call_creds = grpc::ServiceAccountJWTAccessCredentials(
100
1
          credential.service_account_jwt_access().json_key(),
101
1
          credential.service_account_jwt_access().token_lifetime_seconds());
102
1
      break;
103
    }
104
1
    case envoy::config::core::v3::GrpcService::GoogleGrpc::CallCredentials::
105
1
        CredentialSpecifierCase::kGoogleIam: {
106
1
      new_call_creds = grpc::GoogleIAMCredentials(credential.google_iam().authorization_token(),
107
1
                                                  credential.google_iam().authority_selector());
108
1
      break;
109
    }
110
1
    case envoy::config::core::v3::GrpcService::GoogleGrpc::CallCredentials::
111
1
        CredentialSpecifierCase::kStsService: {
112
1
      grpc::experimental::StsCredentialsOptions options = {
113
1
          credential.sts_service().token_exchange_service_uri(),
114
1
          credential.sts_service().resource(),
115
1
          credential.sts_service().audience(),
116
1
          credential.sts_service().scope(),
117
1
          credential.sts_service().requested_token_type(),
118
1
          credential.sts_service().subject_token_path(),
119
1
          credential.sts_service().subject_token_type(),
120
1
          credential.sts_service().actor_token_path(),
121
1
          credential.sts_service().actor_token_type(),
122
1
      };
123
1
      new_call_creds = grpc::experimental::StsCredentials(options);
124
1
      break;
125
    }
126
1
    default:
127
      // We don't handle plugin credentials here, callers can do so instead if they want.
128
1
      continue;
129
11
    }
130
    // Any of the above creds creation can fail, if they do they return nullptr
131
    // and we ignore them.
132
10
    if (new_call_creds != nullptr) {
133
9
      creds.emplace_back(new_call_creds);
134
9
    }
135
10
  }
136
1087
  return creds;
137
1087
}
138

            
139
std::shared_ptr<grpc::ChannelCredentials> CredsUtility::defaultChannelCredentials(
140
1083
    const envoy::config::core::v3::GrpcService& grpc_service_config, Api::Api& api) {
141
1083
  std::shared_ptr<grpc::ChannelCredentials> channel_creds =
142
1083
      getChannelCredentials(grpc_service_config.google_grpc(), api);
143
1083
  if (channel_creds == nullptr) {
144
916
    channel_creds = grpc::InsecureChannelCredentials();
145
916
  }
146
1083
  auto call_creds_vec = callCredentials(grpc_service_config.google_grpc());
147
1083
  if (call_creds_vec.empty()) {
148
1081
    return channel_creds;
149
1081
  }
150
2
  std::shared_ptr<grpc::CallCredentials> call_creds = call_creds_vec[0];
151
6
  for (uint32_t i = 1; i < call_creds_vec.size(); ++i) {
152
4
    call_creds = grpc::CompositeCallCredentials(call_creds, call_creds_vec[i]);
153
4
  }
154
2
  return grpc::CompositeChannelCredentials(channel_creds, call_creds);
155
1083
}
156

            
157
/**
158
 * Default implementation of Google Grpc Credentials Factory
159
 * Uses ssl creds if available, or defaults to insecure channel.
160
 *
161
 * This is not the same as google_default credentials. This is the default implementation that is
162
 * loaded if no other implementation is configured.
163
 */
164
class DefaultGoogleGrpcCredentialsFactory : public GoogleGrpcCredentialsFactory {
165

            
166
public:
167
  std::shared_ptr<grpc::ChannelCredentials>
168
  getChannelCredentials(const envoy::config::core::v3::GrpcService& grpc_service_config,
169
1079
                        Server::Configuration::CommonFactoryContext& context) override {
170
1079
    return CredsUtility::defaultChannelCredentials(grpc_service_config, context.api());
171
1079
  }
172

            
173
501
  std::string name() const override { return "envoy.grpc_credentials.default"; }
174
};
175

            
176
/**
177
 * Static registration for the default Google gRPC credentials factory. @see RegisterFactory.
178
 */
179
REGISTER_FACTORY(DefaultGoogleGrpcCredentialsFactory, GoogleGrpcCredentialsFactory);
180

            
181
} // namespace Grpc
182
} // namespace Envoy