...

Source file src/cloud.google.com/go/auth/grpctransport/directpath.go

Documentation: cloud.google.com/go/auth/grpctransport

     1  // Copyright 2023 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package grpctransport
    16  
    17  import (
    18  	"context"
    19  	"net"
    20  	"os"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"cloud.google.com/go/auth"
    25  	"cloud.google.com/go/compute/metadata"
    26  	"google.golang.org/grpc"
    27  	grpcgoogle "google.golang.org/grpc/credentials/google"
    28  )
    29  
    30  func isDirectPathEnabled(endpoint string, opts *Options) bool {
    31  	if opts.InternalOptions != nil && !opts.InternalOptions.EnableDirectPath {
    32  		return false
    33  	}
    34  	if !checkDirectPathEndPoint(endpoint) {
    35  		return false
    36  	}
    37  	if b, _ := strconv.ParseBool(os.Getenv(disableDirectPathEnvVar)); b {
    38  		return false
    39  	}
    40  	return true
    41  }
    42  
    43  func checkDirectPathEndPoint(endpoint string) bool {
    44  	// Only [dns:///]host[:port] is supported, not other schemes (e.g., "tcp://" or "unix://").
    45  	// Also don't try direct path if the user has chosen an alternate name resolver
    46  	// (i.e., via ":///" prefix).
    47  	if strings.Contains(endpoint, "://") && !strings.HasPrefix(endpoint, "dns:///") {
    48  		return false
    49  	}
    50  
    51  	if endpoint == "" {
    52  		return false
    53  	}
    54  
    55  	return true
    56  }
    57  
    58  func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, _ *Options) bool {
    59  	if tp == nil {
    60  		return false
    61  	}
    62  	tok, err := tp.Token(context.Background())
    63  	if err != nil {
    64  		return false
    65  	}
    66  	if tok == nil {
    67  		return false
    68  	}
    69  	if source, _ := tok.Metadata["auth.google.tokenSource"].(string); source != "compute-metadata" {
    70  		return false
    71  	}
    72  	if acct, _ := tok.Metadata["auth.google.serviceAccount"].(string); acct != "default" {
    73  		return false
    74  	}
    75  	return true
    76  }
    77  
    78  func isDirectPathXdsUsed(o *Options) bool {
    79  	// Method 1: Enable DirectPath xDS by env;
    80  	if b, _ := strconv.ParseBool(os.Getenv(enableDirectPathXdsEnvVar)); b {
    81  		return true
    82  	}
    83  	// Method 2: Enable DirectPath xDS by option;
    84  	if o.InternalOptions != nil && o.InternalOptions.EnableDirectPathXds {
    85  		return true
    86  	}
    87  	return false
    88  }
    89  
    90  // configureDirectPath returns some dial options and an endpoint to use if the
    91  // configuration allows the use of direct path. If it does not the provided
    92  // grpcOpts and endpoint are returned.
    93  func configureDirectPath(grpcOpts []grpc.DialOption, opts *Options, endpoint string, creds *auth.Credentials) ([]grpc.DialOption, string) {
    94  	if isDirectPathEnabled(endpoint, opts) && metadata.OnGCE() && isTokenProviderDirectPathCompatible(creds, opts) {
    95  		// Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates.
    96  		grpcOpts = []grpc.DialOption{
    97  			grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(grpcgoogle.DefaultCredentialsOptions{PerRPCCreds: &grpcCredentialsProvider{creds: creds}}))}
    98  		if timeoutDialerOption != nil {
    99  			grpcOpts = append(grpcOpts, timeoutDialerOption)
   100  		}
   101  		// Check if google-c2p resolver is enabled for DirectPath
   102  		if isDirectPathXdsUsed(opts) {
   103  			// google-c2p resolver target must not have a port number
   104  			if addr, _, err := net.SplitHostPort(endpoint); err == nil {
   105  				endpoint = "google-c2p:///" + addr
   106  			} else {
   107  				endpoint = "google-c2p:///" + endpoint
   108  			}
   109  		} else {
   110  			if !strings.HasPrefix(endpoint, "dns:///") {
   111  				endpoint = "dns:///" + endpoint
   112  			}
   113  			grpcOpts = append(grpcOpts,
   114  				// For now all DirectPath go clients will be using the following lb config, but in future
   115  				// when different services need different configs, then we should change this to a
   116  				// per-service config.
   117  				grpc.WithDisableServiceConfig(),
   118  				grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"grpclb":{"childPolicy":[{"pick_first":{}}]}}]}`))
   119  		}
   120  		// TODO: add support for system parameters (quota project, request reason) via chained interceptor.
   121  	}
   122  	return grpcOpts, endpoint
   123  }
   124  

View as plain text