Home | History | Annotate | Download | only in google_default
      1 /*
      2  *
      3  * Copyright 2015 gRPC authors.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  */
     18 
     19 #include <grpc/support/port_platform.h>
     20 
     21 #include "src/core/lib/security/credentials/credentials.h"
     22 
     23 #include <string.h>
     24 
     25 #include <grpc/support/alloc.h>
     26 #include <grpc/support/log.h>
     27 #include <grpc/support/sync.h>
     28 
     29 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h"
     30 #include "src/core/lib/channel/channel_args.h"
     31 #include "src/core/lib/gpr/env.h"
     32 #include "src/core/lib/gpr/string.h"
     33 #include "src/core/lib/http/httpcli.h"
     34 #include "src/core/lib/http/parser.h"
     35 #include "src/core/lib/iomgr/load_file.h"
     36 #include "src/core/lib/iomgr/polling_entity.h"
     37 #include "src/core/lib/security/credentials/alts/alts_credentials.h"
     38 #include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
     39 #include "src/core/lib/security/credentials/google_default/google_default_credentials.h"
     40 #include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
     41 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
     42 #include "src/core/lib/slice/slice_internal.h"
     43 #include "src/core/lib/slice/slice_string_helpers.h"
     44 #include "src/core/lib/surface/api_trace.h"
     45 
     46 /* -- Constants. -- */
     47 
     48 #define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
     49 
     50 /* -- Default credentials. -- */
     51 
     52 static grpc_channel_credentials* g_default_credentials = nullptr;
     53 static int g_compute_engine_detection_done = 0;
     54 static gpr_mu g_state_mu;
     55 static gpr_once g_once = GPR_ONCE_INIT;
     56 static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker =
     57     grpc_alts_is_running_on_gcp;
     58 
     59 static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); }
     60 
     61 typedef struct {
     62   grpc_polling_entity pollent;
     63   int is_done;
     64   int success;
     65   grpc_http_response response;
     66 } compute_engine_detector;
     67 
     68 static void google_default_credentials_destruct(
     69     grpc_channel_credentials* creds) {
     70   grpc_google_default_channel_credentials* c =
     71       reinterpret_cast<grpc_google_default_channel_credentials*>(creds);
     72   grpc_channel_credentials_unref(c->alts_creds);
     73   grpc_channel_credentials_unref(c->ssl_creds);
     74 }
     75 
     76 static grpc_security_status google_default_create_security_connector(
     77     grpc_channel_credentials* creds, grpc_call_credentials* call_creds,
     78     const char* target, const grpc_channel_args* args,
     79     grpc_channel_security_connector** sc, grpc_channel_args** new_args) {
     80   grpc_google_default_channel_credentials* c =
     81       reinterpret_cast<grpc_google_default_channel_credentials*>(creds);
     82   bool is_grpclb_load_balancer = grpc_channel_arg_get_bool(
     83       grpc_channel_args_find(args, GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER),
     84       false);
     85   bool is_backend_from_grpclb_load_balancer = grpc_channel_arg_get_bool(
     86       grpc_channel_args_find(
     87           args, GRPC_ARG_ADDRESS_IS_BACKEND_FROM_GRPCLB_LOAD_BALANCER),
     88       false);
     89   bool use_alts =
     90       is_grpclb_load_balancer || is_backend_from_grpclb_load_balancer;
     91   grpc_security_status status = GRPC_SECURITY_ERROR;
     92   status = use_alts ? c->alts_creds->vtable->create_security_connector(
     93                           c->alts_creds, call_creds, target, args, sc, new_args)
     94                     : c->ssl_creds->vtable->create_security_connector(
     95                           c->ssl_creds, call_creds, target, args, sc, new_args);
     96   /* grpclb-specific channel args are removed from the channel args set
     97    * to ensure backends and fallback adresses will have the same set of channel
     98    * args. By doing that, it guarantees the connections to backends will not be
     99    * torn down and re-connected when switching in and out of fallback mode.
    100    */
    101   if (use_alts) {
    102     static const char* args_to_remove[] = {
    103         GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER,
    104         GRPC_ARG_ADDRESS_IS_BACKEND_FROM_GRPCLB_LOAD_BALANCER,
    105     };
    106     *new_args = grpc_channel_args_copy_and_add_and_remove(
    107         args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), nullptr, 0);
    108   }
    109   return status;
    110 }
    111 
    112 static grpc_channel_credentials_vtable google_default_credentials_vtable = {
    113     google_default_credentials_destruct,
    114     google_default_create_security_connector, nullptr};
    115 
    116 /* Takes ownership of creds_path if not NULL. */
    117 static grpc_error* create_default_creds_from_path(
    118     char* creds_path, grpc_call_credentials** creds) {
    119   grpc_json* json = nullptr;
    120   grpc_auth_json_key key;
    121   grpc_auth_refresh_token token;
    122   grpc_call_credentials* result = nullptr;
    123   grpc_slice creds_data = grpc_empty_slice();
    124   grpc_error* error = GRPC_ERROR_NONE;
    125   if (creds_path == nullptr) {
    126     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("creds_path unset");
    127     goto end;
    128   }
    129   error = grpc_load_file(creds_path, 0, &creds_data);
    130   if (error != GRPC_ERROR_NONE) {
    131     goto end;
    132   }
    133   json = grpc_json_parse_string_with_len(
    134       reinterpret_cast<char*> GRPC_SLICE_START_PTR(creds_data),
    135       GRPC_SLICE_LENGTH(creds_data));
    136   if (json == nullptr) {
    137     error = grpc_error_set_str(
    138         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to parse JSON"),
    139         GRPC_ERROR_STR_RAW_BYTES, grpc_slice_ref_internal(creds_data));
    140     goto end;
    141   }
    142 
    143   /* First, try an auth json key. */
    144   key = grpc_auth_json_key_create_from_json(json);
    145   if (grpc_auth_json_key_is_valid(&key)) {
    146     result =
    147         grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
    148             key, grpc_max_auth_token_lifetime());
    149     if (result == nullptr) {
    150       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    151           "grpc_service_account_jwt_access_credentials_create_from_auth_json_"
    152           "key failed");
    153     }
    154     goto end;
    155   }
    156 
    157   /* Then try a refresh token if the auth json key was invalid. */
    158   token = grpc_auth_refresh_token_create_from_json(json);
    159   if (grpc_auth_refresh_token_is_valid(&token)) {
    160     result =
    161         grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
    162     if (result == nullptr) {
    163       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    164           "grpc_refresh_token_credentials_create_from_auth_refresh_token "
    165           "failed");
    166     }
    167     goto end;
    168   }
    169 
    170 end:
    171   GPR_ASSERT((result == nullptr) + (error == GRPC_ERROR_NONE) == 1);
    172   if (creds_path != nullptr) gpr_free(creds_path);
    173   grpc_slice_unref_internal(creds_data);
    174   if (json != nullptr) grpc_json_destroy(json);
    175   *creds = result;
    176   return error;
    177 }
    178 
    179 grpc_channel_credentials* grpc_google_default_credentials_create(void) {
    180   grpc_channel_credentials* result = nullptr;
    181   grpc_call_credentials* call_creds = nullptr;
    182   grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    183       "Failed to create Google credentials");
    184   grpc_error* err;
    185   grpc_core::ExecCtx exec_ctx;
    186 
    187   GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ());
    188 
    189   gpr_once_init(&g_once, init_default_credentials);
    190 
    191   gpr_mu_lock(&g_state_mu);
    192 
    193   if (g_default_credentials != nullptr) {
    194     result = grpc_channel_credentials_ref(g_default_credentials);
    195     goto end;
    196   }
    197 
    198   /* First, try the environment variable. */
    199   err = create_default_creds_from_path(
    200       gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds);
    201   if (err == GRPC_ERROR_NONE) goto end;
    202   error = grpc_error_add_child(error, err);
    203 
    204   /* Then the well-known file. */
    205   err = create_default_creds_from_path(
    206       grpc_get_well_known_google_credentials_file_path(), &call_creds);
    207   if (err == GRPC_ERROR_NONE) goto end;
    208   error = grpc_error_add_child(error, err);
    209 
    210   /* At last try to see if we're on compute engine (do the detection only once
    211      since it requires a network test). */
    212   if (!g_compute_engine_detection_done) {
    213     int need_compute_engine_creds = g_gce_tenancy_checker();
    214     g_compute_engine_detection_done = 1;
    215     if (need_compute_engine_creds) {
    216       call_creds = grpc_google_compute_engine_credentials_create(nullptr);
    217       if (call_creds == nullptr) {
    218         error = grpc_error_add_child(
    219             error, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    220                        "Failed to get credentials from network"));
    221       }
    222     }
    223   }
    224 
    225 end:
    226   if (result == nullptr) {
    227     if (call_creds != nullptr) {
    228       /* Create google default credentials. */
    229       auto creds = static_cast<grpc_google_default_channel_credentials*>(
    230           gpr_zalloc(sizeof(grpc_google_default_channel_credentials)));
    231       creds->base.vtable = &google_default_credentials_vtable;
    232       creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
    233       gpr_ref_init(&creds->base.refcount, 1);
    234       creds->ssl_creds =
    235           grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
    236       GPR_ASSERT(creds->ssl_creds != nullptr);
    237       grpc_alts_credentials_options* options =
    238           grpc_alts_credentials_client_options_create();
    239       creds->alts_creds = grpc_alts_credentials_create(options);
    240       grpc_alts_credentials_options_destroy(options);
    241       /* Add a global reference so that it can be cached and re-served. */
    242       g_default_credentials = grpc_composite_channel_credentials_create(
    243           &creds->base, call_creds, nullptr);
    244       GPR_ASSERT(g_default_credentials != nullptr);
    245       grpc_channel_credentials_unref(&creds->base);
    246       grpc_call_credentials_unref(call_creds);
    247       result = grpc_channel_credentials_ref(g_default_credentials);
    248     } else {
    249       gpr_log(GPR_ERROR, "Could not create google default credentials.");
    250     }
    251   }
    252   gpr_mu_unlock(&g_state_mu);
    253   if (result == nullptr) {
    254     GRPC_LOG_IF_ERROR("grpc_google_default_credentials_create", error);
    255   } else {
    256     GRPC_ERROR_UNREF(error);
    257   }
    258 
    259   return result;
    260 }
    261 
    262 namespace grpc_core {
    263 namespace internal {
    264 
    265 void set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker) {
    266   g_gce_tenancy_checker = checker;
    267 }
    268 
    269 }  // namespace internal
    270 }  // namespace grpc_core
    271 
    272 void grpc_flush_cached_google_default_credentials(void) {
    273   grpc_core::ExecCtx exec_ctx;
    274   gpr_once_init(&g_once, init_default_credentials);
    275   gpr_mu_lock(&g_state_mu);
    276   if (g_default_credentials != nullptr) {
    277     grpc_channel_credentials_unref(g_default_credentials);
    278     g_default_credentials = nullptr;
    279   }
    280   g_compute_engine_detection_done = 0;
    281   gpr_mu_unlock(&g_state_mu);
    282 }
    283 
    284 /* -- Well known credentials path. -- */
    285 
    286 static grpc_well_known_credentials_path_getter creds_path_getter = nullptr;
    287 
    288 char* grpc_get_well_known_google_credentials_file_path(void) {
    289   if (creds_path_getter != nullptr) return creds_path_getter();
    290   return grpc_get_well_known_google_credentials_file_path_impl();
    291 }
    292 
    293 void grpc_override_well_known_credentials_path_getter(
    294     grpc_well_known_credentials_path_getter getter) {
    295   creds_path_getter = getter;
    296 }
    297