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