mirror of
https://github.com/gravitational/teleport.git
synced 2026-11-02 23:31:08 +08:00
172 lines
4.2 KiB
Go
172 lines
4.2 KiB
Go
// Copyright 2022 Gravitational, Inc
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package proxy
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"errors"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/gravitational/trace"
|
|
"github.com/sirupsen/logrus"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/keepalive"
|
|
|
|
"github.com/gravitational/teleport"
|
|
"github.com/gravitational/teleport/api/client/proto"
|
|
"github.com/gravitational/teleport/api/metadata"
|
|
"github.com/gravitational/teleport/lib/auth"
|
|
"github.com/gravitational/teleport/lib/utils"
|
|
)
|
|
|
|
const (
|
|
peerKeepAlive = time.Second * 10
|
|
peerTimeout = time.Second * 20
|
|
)
|
|
|
|
// ServerConfig configures a Server instance.
|
|
type ServerConfig struct {
|
|
AccessCache auth.AccessCache
|
|
Listener net.Listener
|
|
TLSConfig *tls.Config
|
|
ClusterDialer ClusterDialer
|
|
Log logrus.FieldLogger
|
|
|
|
// getConfigForClient gets the client tls config.
|
|
// configurable for testing purposes.
|
|
getConfigForClient func(*tls.ClientHelloInfo) (*tls.Config, error)
|
|
|
|
// service is a custom ProxyServiceServer
|
|
// configurable for testing purposes.
|
|
service proto.ProxyServiceServer
|
|
}
|
|
|
|
// checkAndSetDefaults checks and sets default values
|
|
func (c *ServerConfig) checkAndSetDefaults() error {
|
|
if c.Log == nil {
|
|
c.Log = logrus.New()
|
|
}
|
|
c.Log = c.Log.WithField(
|
|
trace.Component,
|
|
teleport.Component(teleport.ComponentProxy, "peer"),
|
|
)
|
|
|
|
if c.AccessCache == nil {
|
|
return trace.BadParameter("missing access cache")
|
|
}
|
|
|
|
if c.Listener == nil {
|
|
return trace.BadParameter("missing listener")
|
|
}
|
|
|
|
if c.ClusterDialer == nil {
|
|
return trace.BadParameter("missing cluster dialer server")
|
|
}
|
|
|
|
if c.TLSConfig == nil {
|
|
return trace.BadParameter("missing tls config")
|
|
}
|
|
|
|
if len(c.TLSConfig.Certificates) == 0 {
|
|
return trace.BadParameter("missing tls certificate")
|
|
}
|
|
|
|
c.TLSConfig = c.TLSConfig.Clone()
|
|
c.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
|
|
|
if c.getConfigForClient == nil {
|
|
c.getConfigForClient = getConfigForClient(c.TLSConfig, c.AccessCache, c.Log)
|
|
}
|
|
c.TLSConfig.GetConfigForClient = c.getConfigForClient
|
|
|
|
if c.service == nil {
|
|
c.service = &proxyService{
|
|
c.ClusterDialer,
|
|
c.Log,
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Server is a proxy service server using grpc and tls.
|
|
type Server struct {
|
|
config ServerConfig
|
|
server *grpc.Server
|
|
}
|
|
|
|
// NewServer creates a new proxy server instance.
|
|
func NewServer(config ServerConfig) (*Server, error) {
|
|
err := config.checkAndSetDefaults()
|
|
if err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
|
|
metrics, err := newServerMetrics()
|
|
if err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
|
|
reporter := newReporter(metrics)
|
|
|
|
transportCreds := newProxyCredentials(credentials.NewTLS(config.TLSConfig))
|
|
server := grpc.NewServer(
|
|
grpc.Creds(transportCreds),
|
|
grpc.StatsHandler(newStatsHandler(reporter)),
|
|
grpc.ChainStreamInterceptor(metadata.StreamServerInterceptor, utils.GRPCServerStreamErrorInterceptor),
|
|
grpc.KeepaliveParams(keepalive.ServerParameters{
|
|
Time: peerKeepAlive,
|
|
Timeout: peerTimeout,
|
|
}),
|
|
grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
|
|
MinTime: peerKeepAlive,
|
|
PermitWithoutStream: true,
|
|
}),
|
|
)
|
|
|
|
proto.RegisterProxyServiceServer(server, config.service)
|
|
|
|
return &Server{
|
|
config: config,
|
|
server: server,
|
|
}, nil
|
|
}
|
|
|
|
// Serve starts the proxy server.
|
|
func (s *Server) Serve() error {
|
|
if err := s.server.Serve(s.config.Listener); err != nil {
|
|
if errors.Is(err, grpc.ErrServerStopped) ||
|
|
utils.IsUseOfClosedNetworkError(err) {
|
|
return nil
|
|
}
|
|
return trace.Wrap(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Close closes the proxy server immediately.
|
|
func (s *Server) Close() error {
|
|
s.server.Stop()
|
|
return nil
|
|
}
|
|
|
|
// Shutdown does a graceful shutdown of the proxy server.
|
|
func (s *Server) Shutdown() error {
|
|
s.server.GracefulStop()
|
|
return nil
|
|
}
|