...

Source file src/google.golang.org/grpc/credentials/google/xds.go

Documentation: google.golang.org/grpc/credentials/google

     1  /*
     2   *
     3   * Copyright 2021 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  package google
    20  
    21  import (
    22  	"context"
    23  	"net"
    24  	"net/url"
    25  	"strings"
    26  
    27  	"google.golang.org/grpc/credentials"
    28  	"google.golang.org/grpc/internal/xds"
    29  )
    30  
    31  const cfeClusterNamePrefix = "google_cfe_"
    32  const cfeClusterResourceNamePrefix = "/envoy.config.cluster.v3.Cluster/google_cfe_"
    33  const cfeClusterAuthorityName = "traffic-director-c2p.xds.googleapis.com"
    34  
    35  // clusterTransportCreds is a combo of TLS + ALTS.
    36  //
    37  // On the client, ClientHandshake picks TLS or ALTS based on address attributes.
    38  // - if attributes has cluster name
    39  //   - if cluster name has prefix "google_cfe_", or
    40  //     "xdstp://traffic-director-c2p.xds.googleapis.com/envoy.config.cluster.v3.Cluster/google_cfe_",
    41  //     use TLS
    42  //   - otherwise, use ALTS
    43  //
    44  // - else, do TLS
    45  //
    46  // On the server, ServerHandshake always does TLS.
    47  type clusterTransportCreds struct {
    48  	tls  credentials.TransportCredentials
    49  	alts credentials.TransportCredentials
    50  }
    51  
    52  func newClusterTransportCreds(tls, alts credentials.TransportCredentials) *clusterTransportCreds {
    53  	return &clusterTransportCreds{
    54  		tls:  tls,
    55  		alts: alts,
    56  	}
    57  }
    58  
    59  // clusterName returns the xDS cluster name stored in the attributes in the
    60  // context.
    61  func clusterName(ctx context.Context) string {
    62  	chi := credentials.ClientHandshakeInfoFromContext(ctx)
    63  	if chi.Attributes == nil {
    64  		return ""
    65  	}
    66  	cluster, _ := xds.GetXDSHandshakeClusterName(chi.Attributes)
    67  	return cluster
    68  }
    69  
    70  // isDirectPathCluster returns true if the cluster in the context is a
    71  // directpath cluster, meaning ALTS should be used.
    72  func isDirectPathCluster(ctx context.Context) bool {
    73  	cluster := clusterName(ctx)
    74  	if cluster == "" {
    75  		// No cluster; not xDS; use TLS.
    76  		return false
    77  	}
    78  	if strings.HasPrefix(cluster, cfeClusterNamePrefix) {
    79  		// xDS cluster prefixed by "google_cfe_"; use TLS.
    80  		return false
    81  	}
    82  	if !strings.HasPrefix(cluster, "xdstp:") {
    83  		// Other xDS cluster name; use ALTS.
    84  		return true
    85  	}
    86  	u, err := url.Parse(cluster)
    87  	if err != nil {
    88  		// Shouldn't happen, but assume ALTS.
    89  		return true
    90  	}
    91  	// If authority AND path match our CFE checks, use TLS; otherwise use ALTS.
    92  	return u.Host != cfeClusterAuthorityName || !strings.HasPrefix(u.Path, cfeClusterResourceNamePrefix)
    93  }
    94  
    95  func (c *clusterTransportCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
    96  	if isDirectPathCluster(ctx) {
    97  		// If attributes have cluster name, and cluster name is not cfe, it's a
    98  		// backend address, use ALTS.
    99  		return c.alts.ClientHandshake(ctx, authority, rawConn)
   100  	}
   101  	return c.tls.ClientHandshake(ctx, authority, rawConn)
   102  }
   103  
   104  func (c *clusterTransportCreds) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
   105  	return c.tls.ServerHandshake(conn)
   106  }
   107  
   108  func (c *clusterTransportCreds) Info() credentials.ProtocolInfo {
   109  	// TODO: this always returns tls.Info now, because we don't have a cluster
   110  	// name to check when this method is called. This method doesn't affect
   111  	// anything important now. We may want to revisit this if it becomes more
   112  	// important later.
   113  	return c.tls.Info()
   114  }
   115  
   116  func (c *clusterTransportCreds) Clone() credentials.TransportCredentials {
   117  	return &clusterTransportCreds{
   118  		tls:  c.tls.Clone(),
   119  		alts: c.alts.Clone(),
   120  	}
   121  }
   122  
   123  func (c *clusterTransportCreds) OverrideServerName(s string) error {
   124  	if err := c.tls.OverrideServerName(s); err != nil {
   125  		return err
   126  	}
   127  	return c.alts.OverrideServerName(s)
   128  }
   129  

View as plain text