From f0a801161bf883c10e9cbbb5437c1cfe7964da68 Mon Sep 17 00:00:00 2001 From: Kevin Park Date: Mon, 11 Dec 2023 15:56:45 +0900 Subject: [PATCH] Update client & server configuration --- admin/client.go | 30 ++++++++------------- client/client.go | 64 ++++++++++++++++++++++++-------------------- server/rpc/server.go | 44 +++++++++++++++++++++--------- 3 files changed, 78 insertions(+), 60 deletions(-) diff --git a/admin/client.go b/admin/client.go index e9b2ea48f..e107e5dcc 100644 --- a/admin/client.go +++ b/admin/client.go @@ -19,6 +19,7 @@ package admin import ( "context" + "crypto/tls" "fmt" "net/http" "strings" @@ -66,9 +67,8 @@ type Options struct { // Client is a client for admin service. type Client struct { - conn *http.Client - client v1connect.AdminServiceClient - //dialOptions []grpc.DialOption + conn *http.Client + client v1connect.AdminServiceClient authInterceptor *AuthInterceptor logger *zap.Logger } @@ -80,16 +80,11 @@ func New(opts ...Option) (*Client, error) { opt(&options) } - //tlsConfig := credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12}) - //credentialOptions := grpc.WithTransportCredentials(tlsConfig) - //if options.IsInsecure { - // credentialOptions = grpc.WithTransportCredentials(insecure.NewCredentials()) - //} - //dialOptions := []grpc.DialOption{credentialOptions} - // - //authInterceptor := NewAuthInterceptor(options.Token) - //dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(authInterceptor.Unary())) - //dialOptions = append(dialOptions, grpc.WithStreamInterceptor(authInterceptor.Stream())) + conn := &http.Client{} + if !options.IsInsecure { + tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12} + conn.Transport = &http.Transport{TLSClientConfig: tlsConfig} + } logger := options.Logger if logger == nil { @@ -101,8 +96,8 @@ func New(opts ...Option) (*Client, error) { } return &Client{ - logger: logger, - //dialOptions: dialOptions, + conn: conn, + logger: logger, authInterceptor: NewAuthInterceptor(options.Token), }, nil } @@ -127,7 +122,6 @@ func (c *Client) Dial(rpcAddr string) error { rpcAddr = "http://" + rpcAddr } - c.conn = http.DefaultClient c.client = v1connect.NewAdminServiceClient(c.conn, rpcAddr, connect.WithInterceptors(c.authInterceptor)) return nil @@ -135,9 +129,7 @@ func (c *Client) Dial(rpcAddr string) error { // Close closes the connection to the admin service. func (c *Client) Close() error { - //if err := c.conn.Close(); err != nil { - // return fmt.Errorf("close connection: %w", err) - //} + c.conn.CloseIdleConnections() return nil } diff --git a/client/client.go b/client/client.go index f6e5846db..3217be68e 100644 --- a/client/client.go +++ b/client/client.go @@ -20,9 +20,12 @@ package client import ( "context" + "crypto/tls" + "crypto/x509" "errors" "fmt" "net/http" + "os" "strings" "connectrpc.com/connect" @@ -80,8 +83,7 @@ type Client struct { client v1connect.YorkieServiceClient options Options clientOptions []connect.ClientOption - // dialOptions []grpc.DialOption - logger *zap.Logger + logger *zap.Logger id *time.ActorID key string @@ -120,29 +122,22 @@ func New(opts ...Option) (*Client, error) { k = xid.New().String() } + conn := &http.Client{} + if options.CertFile != "" { + tlsConfig, err := newTLSConfigFromFile(options.CertFile, options.ServerNameOverride) + if err != nil { + return nil, fmt.Errorf("create client tls from file: %w", err) + } + + conn.Transport = &http.Transport{TLSClientConfig: tlsConfig} + } + var clientOptions []connect.ClientOption clientOptions = append(clientOptions, connect.WithInterceptors(NewAuthInterceptor(options.APIKey, options.Token))) - - //var dialOptions []grpc.DialOption - // - //transportCreds := grpc.WithTransportCredentials(insecure.NewCredentials()) - //if options.CertFile != "" { - // creds, err := credentials.NewClientTLSFromFile(options.CertFile, options.ServerNameOverride) - // if err != nil { - // return nil, fmt.Errorf("create client tls from file: %w", err) - // } - // transportCreds = grpc.WithTransportCredentials(creds) - //} - //dialOptions = append(dialOptions, transportCreds) - // - //authInterceptor := NewAuthInterceptor(options.APIKey, options.Token) - //dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(authInterceptor.Unary())) - //dialOptions = append(dialOptions, grpc.WithStreamInterceptor(authInterceptor.Stream())) - // - //if options.MaxCallRecvMsgSize != 0 { - // dialOptions = append(dialOptions, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(options.MaxCallRecvMsgSize))) - //} + if options.MaxCallRecvMsgSize != 0 { + clientOptions = append(clientOptions, connect.WithReadMaxBytes(options.MaxCallRecvMsgSize)) + } logger := options.Logger if logger == nil { @@ -154,10 +149,10 @@ func New(opts ...Option) (*Client, error) { } return &Client{ + conn: conn, clientOptions: clientOptions, - //dialOptions: dialOptions, - options: options, - logger: logger, + options: options, + logger: logger, key: k, status: deactivated, @@ -185,7 +180,6 @@ func (c *Client) Dial(rpcAddr string) error { rpcAddr = "http://" + rpcAddr } - c.conn = http.DefaultClient c.client = v1connect.NewYorkieServiceClient(c.conn, rpcAddr, c.clientOptions...) return nil @@ -197,9 +191,7 @@ func (c *Client) Close() error { return err } - //if err := c.conn.Close(); err != nil { - // return fmt.Errorf("close connection: %w", err) - //} + c.conn.CloseIdleConnections() return nil } @@ -726,6 +718,20 @@ func (c *Client) broadcast(ctx context.Context, doc *document.Document, topic st return nil } +// NewClientTLSFromFile +func newTLSConfigFromFile(certFile, serverNameOverride string) (*tls.Config, error) { + b, err := os.ReadFile(certFile) + if err != nil { + return nil, err + } + cp := x509.NewCertPool() + if !cp.AppendCertsFromPEM(b) { + return nil, fmt.Errorf("credentials: failed to append certificates") + } + + return &tls.Config{ServerName: serverNameOverride, RootCAs: cp}, nil +} + /** * withShardKey returns a context with the given shard key in metadata. */ diff --git a/server/rpc/server.go b/server/rpc/server.go index 62c77883f..e9930ab95 100644 --- a/server/rpc/server.go +++ b/server/rpc/server.go @@ -118,8 +118,16 @@ func (s *Server) listenAndServe() error { newCORS().Handler(s.serverMux), &http2.Server{}, ) - if err := s.httpServer.ListenAndServe(); err != http.ErrServerClosed { - logging.DefaultLogger().Errorf("HTTP server ListenAndServe: %v", err) + if s.conf.CertFile != "" && s.conf.KeyFile != "" { + if err := s.httpServer.ListenAndServeTLS(s.conf.CertFile, s.conf.KeyFile); err != http.ErrServerClosed { + logging.DefaultLogger().Errorf("HTTP server ListenAndServeTLS: %v", err) + } + return + } else { + if err := s.httpServer.ListenAndServe(); err != http.ErrServerClosed { + logging.DefaultLogger().Errorf("HTTP server ListenAndServe: %v", err) + } + return } }() return nil @@ -128,20 +136,35 @@ func (s *Server) listenAndServe() error { func newCORS() *cors.Cors { return cors.New(cors.Options{ AllowedMethods: []string{ - http.MethodHead, + http.MethodOptions, http.MethodGet, http.MethodPost, http.MethodPut, - http.MethodPatch, http.MethodDelete, }, AllowOriginFunc: func(origin string) bool { - // Allow all origins, which effectively disables CORS. return true }, - AllowedHeaders: []string{"*"}, + AllowedHeaders: []string{ + "Grpc-Timeout", + "Content-Type", + "Keep-Alive", + "User-Agent", + "Cache-Control", + "Content-Type", + "Content-Transfer-Encoding", + "Custom-Header-1", + "X-Accept-Content-Transfer-Encoding", + "X-Accept-Response-Streaming", + "X-User-Agent", + "X-Yorkie-User-Agent", + "X-Grpc-Web", + "Authorization", + "X-API-Key", + "X-Shard-Key", + }, + MaxAge: int(1728 * time.Second), ExposedHeaders: []string{ - // Content-Type is in the default safelist. "Accept", "Accept-Encoding", "Accept-Post", @@ -155,11 +178,8 @@ func newCORS() *cors.Cors { "Grpc-Status-Details-Bin", "X-Custom-Header", "Connect-Protocol-Version", + "Custom-Header-1", }, - // Let browsers cache CORS information for longer, which reduces the number - // of preflight requests. Any changes to ExposedHeaders won't take effect - // until the cached data expires. FF caps this value at 24h, and modern - // Chrome caps it at 2h. - MaxAge: int(2 * time.Hour / time.Second), + AllowCredentials: true, }) }