...

Source file src/google.golang.org/grpc/xds/internal/server/conn_wrapper.go

Documentation: google.golang.org/grpc/xds/internal/server

     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 server
    20  
    21  import (
    22  	"fmt"
    23  	"net"
    24  	"sync"
    25  	"sync/atomic"
    26  	"time"
    27  
    28  	"google.golang.org/grpc/credentials/tls/certprovider"
    29  	xdsinternal "google.golang.org/grpc/internal/credentials/xds"
    30  	"google.golang.org/grpc/internal/transport"
    31  	"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
    32  )
    33  
    34  // connWrapper is a thin wrapper around a net.Conn returned by Accept(). It
    35  // provides the following additional functionality:
    36  //  1. A way to retrieve the configured deadline. This is required by the
    37  //     ServerHandshake() method of the xdsCredentials when it attempts to read
    38  //     key material from the certificate providers.
    39  //  2. Implements the XDSHandshakeInfo() method used by the xdsCredentials to
    40  //     retrieve the configured certificate providers.
    41  //  3. xDS filter_chain configuration determines security configuration.
    42  //  4. Dynamically reads routing configuration in UsableRouteConfiguration(), called
    43  //     to process incoming RPC's. (LDS + RDS configuration).
    44  type connWrapper struct {
    45  	net.Conn
    46  
    47  	// The specific filter chain picked for handling this connection.
    48  	filterChain *xdsresource.FilterChain
    49  
    50  	// A reference fo the listenerWrapper on which this connection was accepted.
    51  	parent *listenerWrapper
    52  
    53  	// The certificate providers created for this connection.
    54  	rootProvider, identityProvider certprovider.Provider
    55  
    56  	// The connection deadline as configured by the grpc.Server on the rawConn
    57  	// that is returned by a call to Accept(). This is set to the connection
    58  	// timeout value configured by the user (or to a default value) before
    59  	// initiating the transport credential handshake, and set to zero after
    60  	// completing the HTTP2 handshake.
    61  	deadlineMu sync.Mutex
    62  	deadline   time.Time
    63  
    64  	mu       sync.Mutex
    65  	st       transport.ServerTransport
    66  	draining bool
    67  
    68  	// The virtual hosts with matchable routes and instantiated HTTP Filters per
    69  	// route, or an error.
    70  	urc *atomic.Pointer[xdsresource.UsableRouteConfiguration]
    71  }
    72  
    73  // UsableRouteConfiguration returns the UsableRouteConfiguration to be used for
    74  // server side routing.
    75  func (c *connWrapper) UsableRouteConfiguration() xdsresource.UsableRouteConfiguration {
    76  	return *c.urc.Load()
    77  }
    78  
    79  // SetDeadline makes a copy of the passed in deadline and forwards the call to
    80  // the underlying rawConn.
    81  func (c *connWrapper) SetDeadline(t time.Time) error {
    82  	c.deadlineMu.Lock()
    83  	c.deadline = t
    84  	c.deadlineMu.Unlock()
    85  	return c.Conn.SetDeadline(t)
    86  }
    87  
    88  // GetDeadline returns the configured deadline. This will be invoked by the
    89  // ServerHandshake() method of the XdsCredentials, which needs a deadline to
    90  // pass to the certificate provider.
    91  func (c *connWrapper) GetDeadline() time.Time {
    92  	c.deadlineMu.Lock()
    93  	t := c.deadline
    94  	c.deadlineMu.Unlock()
    95  	return t
    96  }
    97  
    98  // XDSHandshakeInfo returns a HandshakeInfo with appropriate security
    99  // configuration for this connection. This method is invoked by the
   100  // ServerHandshake() method of the XdsCredentials.
   101  func (c *connWrapper) XDSHandshakeInfo() (*xdsinternal.HandshakeInfo, error) {
   102  	if c.filterChain.SecurityCfg == nil {
   103  		// If the security config is empty, this means that the control plane
   104  		// did not provide any security configuration and therefore we should
   105  		// return an empty HandshakeInfo here so that the xdsCreds can use the
   106  		// configured fallback credentials.
   107  		return xdsinternal.NewHandshakeInfo(nil, nil, nil, false), nil
   108  	}
   109  
   110  	cpc := c.parent.xdsC.BootstrapConfig().CertProviderConfigs
   111  	// Identity provider name is mandatory on the server-side, and this is
   112  	// enforced when the resource is received at the XDSClient layer.
   113  	secCfg := c.filterChain.SecurityCfg
   114  	ip, err := buildProviderFunc(cpc, secCfg.IdentityInstanceName, secCfg.IdentityCertName, true, false)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	// Root provider name is optional and required only when doing mTLS.
   119  	var rp certprovider.Provider
   120  	if instance, cert := secCfg.RootInstanceName, secCfg.RootCertName; instance != "" {
   121  		rp, err = buildProviderFunc(cpc, instance, cert, false, true)
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  	}
   126  	c.identityProvider = ip
   127  	c.rootProvider = rp
   128  
   129  	return xdsinternal.NewHandshakeInfo(c.rootProvider, c.identityProvider, nil, secCfg.RequireClientCert), nil
   130  }
   131  
   132  // PassServerTransport drains the passed in ServerTransport if draining is set,
   133  // or persists it to be drained once drained is called.
   134  func (c *connWrapper) PassServerTransport(st transport.ServerTransport) {
   135  	c.mu.Lock()
   136  	defer c.mu.Unlock()
   137  	if c.draining {
   138  		st.Drain("draining")
   139  	} else {
   140  		c.st = st
   141  	}
   142  }
   143  
   144  // Drain drains the associated ServerTransport, or sets draining to true so it
   145  // will be drained after it is created.
   146  func (c *connWrapper) Drain() {
   147  	c.mu.Lock()
   148  	defer c.mu.Unlock()
   149  	if c.st == nil {
   150  		c.draining = true
   151  	} else {
   152  		c.st.Drain("draining")
   153  	}
   154  }
   155  
   156  // Close closes the providers and the underlying connection.
   157  func (c *connWrapper) Close() error {
   158  	if c.identityProvider != nil {
   159  		c.identityProvider.Close()
   160  	}
   161  	if c.rootProvider != nil {
   162  		c.rootProvider.Close()
   163  	}
   164  	return c.Conn.Close()
   165  }
   166  
   167  func buildProviderFunc(configs map[string]*certprovider.BuildableConfig, instanceName, certName string, wantIdentity, wantRoot bool) (certprovider.Provider, error) {
   168  	cfg, ok := configs[instanceName]
   169  	if !ok {
   170  		// Defensive programming. If a resource received from the management
   171  		// server contains a certificate provider instance name that is not
   172  		// found in the bootstrap, the resource is NACKed by the xDS client.
   173  		return nil, fmt.Errorf("certificate provider instance %q not found in bootstrap file", instanceName)
   174  	}
   175  	provider, err := cfg.Build(certprovider.BuildOptions{
   176  		CertName:     certName,
   177  		WantIdentity: wantIdentity,
   178  		WantRoot:     wantRoot,
   179  	})
   180  	if err != nil {
   181  		// This error is not expected since the bootstrap process parses the
   182  		// config and makes sure that it is acceptable to the plugin. Still, it
   183  		// is possible that the plugin parses the config successfully, but its
   184  		// Build() method errors out.
   185  		return nil, fmt.Errorf("failed to get security plugin instance (%+v): %v", cfg, err)
   186  	}
   187  	return provider, nil
   188  }
   189  

View as plain text