github.com/cilium/cilium@v1.16.2/api/v1/kvstoremesh/server/server.go (about)

     1  // Code generated by go-swagger; DO NOT EDIT.
     2  
     3  // Copyright Authors of Cilium
     4  // SPDX-License-Identifier: Apache-2.0
     5  
     6  package server
     7  
     8  import (
     9  	"context"
    10  	"crypto/tls"
    11  	"crypto/x509"
    12  	"errors"
    13  	"fmt"
    14  	"log"
    15  	"net"
    16  	"net/http"
    17  	"os"
    18  	"strconv"
    19  	"sync"
    20  	"time"
    21  
    22  	"github.com/go-openapi/loads"
    23  	"github.com/go-openapi/runtime/middleware"
    24  	"github.com/go-openapi/swag"
    25  	"github.com/sirupsen/logrus"
    26  	"github.com/spf13/pflag"
    27  	"golang.org/x/net/netutil"
    28  
    29  	"github.com/cilium/cilium/api/v1/kvstoremesh/server/restapi"
    30  	"github.com/cilium/cilium/api/v1/kvstoremesh/server/restapi/cluster"
    31  	"github.com/cilium/hive/cell"
    32  
    33  	"github.com/cilium/cilium/pkg/api"
    34  	"github.com/cilium/cilium/pkg/hive"
    35  )
    36  
    37  // Cell implements the kvstore mesh REST API server when provided
    38  // the required request handlers.
    39  var Cell = cell.Module(
    40  	"kvstore-mesh-server",
    41  	"kvstore mesh server",
    42  
    43  	cell.Provide(newForCell),
    44  	APICell,
    45  )
    46  
    47  // APICell provides the restapi.KvstoreMeshAPI type, populated
    48  // with the request handlers. This cell is an alternative to 'Cell' when only
    49  // the API type is required and not the full server implementation.
    50  var APICell = cell.Provide(newAPI)
    51  
    52  type apiParams struct {
    53  	cell.In
    54  
    55  	Spec *Spec
    56  
    57  	Middleware middleware.Builder `name:"kvstore-mesh-middleware" optional:"true"`
    58  
    59  	ClusterGetClusterHandler cluster.GetClusterHandler
    60  }
    61  
    62  func newAPI(p apiParams) *restapi.KvstoreMeshAPI {
    63  	api := restapi.NewKvstoreMeshAPI(p.Spec.Document)
    64  
    65  	// Construct the API from the provided handlers
    66  
    67  	api.ClusterGetClusterHandler = p.ClusterGetClusterHandler
    68  
    69  	// Inject custom middleware if provided by Hive
    70  	if p.Middleware != nil {
    71  		api.Middleware = func(builder middleware.Builder) http.Handler {
    72  			return p.Middleware(api.Context().APIHandler(builder))
    73  		}
    74  	}
    75  
    76  	return api
    77  }
    78  
    79  type serverParams struct {
    80  	cell.In
    81  
    82  	Lifecycle  cell.Lifecycle
    83  	Shutdowner hive.Shutdowner
    84  	Logger     logrus.FieldLogger
    85  	Spec       *Spec
    86  	API        *restapi.KvstoreMeshAPI
    87  }
    88  
    89  func newForCell(p serverParams) (*Server, error) {
    90  	s := NewServer(p.API)
    91  	s.shutdowner = p.Shutdowner
    92  	s.logger = p.Logger
    93  	p.Lifecycle.Append(s)
    94  	return s, nil
    95  }
    96  
    97  const (
    98  	schemeHTTP  = "http"
    99  	schemeHTTPS = "https"
   100  	schemeUnix  = "unix"
   101  )
   102  
   103  var defaultSchemes []string
   104  
   105  func init() {
   106  	defaultSchemes = []string{
   107  		schemeHTTP,
   108  		schemeUnix,
   109  	}
   110  }
   111  
   112  var (
   113  	enabledListeners []string
   114  	gracefulTimeout  time.Duration
   115  	maxHeaderSize    int
   116  
   117  	socketPath string
   118  
   119  	host         string
   120  	port         int
   121  	listenLimit  int
   122  	keepAlive    time.Duration
   123  	readTimeout  time.Duration
   124  	writeTimeout time.Duration
   125  
   126  	tlsHost           string
   127  	tlsPort           int
   128  	tlsListenLimit    int
   129  	tlsKeepAlive      time.Duration
   130  	tlsReadTimeout    time.Duration
   131  	tlsWriteTimeout   time.Duration
   132  	tlsCertificate    string
   133  	tlsCertificateKey string
   134  	tlsCACertificate  string
   135  )
   136  
   137  type ServerConfig struct {
   138  	EnableKvstoreMeshServerAccess []string
   139  }
   140  
   141  var (
   142  	defaultServerConfig = ServerConfig{
   143  		EnableKvstoreMeshServerAccess: []string{"*"},
   144  	}
   145  	AdminEnableFlag = "enable-kvstore-mesh-server-access"
   146  )
   147  
   148  func (cfg ServerConfig) Flags(flags *pflag.FlagSet) {
   149  	flags.StringSlice(AdminEnableFlag, cfg.EnableKvstoreMeshServerAccess,
   150  		"List of kvstore mesh APIs which are administratively enabled. Supports '*'.")
   151  }
   152  
   153  var SpecCell = cell.Module(
   154  	"kvstore-mesh-spec",
   155  	"kvstore mesh Specification",
   156  
   157  	cell.Config(defaultServerConfig),
   158  	cell.Provide(newSpec),
   159  )
   160  
   161  type Spec struct {
   162  	*loads.Document
   163  
   164  	// DeniedAPIs is a set of APIs that are administratively disabled.
   165  	DeniedAPIs api.PathSet
   166  }
   167  
   168  func newSpec(cfg ServerConfig) (*Spec, error) {
   169  	swaggerSpec, err := loads.Analyzed(SwaggerJSON, "")
   170  	if err != nil {
   171  		return nil, fmt.Errorf("failed to load swagger spec: %w", err)
   172  	}
   173  
   174  	deniedAPIs, err := api.AllowedFlagsToDeniedPaths(swaggerSpec, cfg.EnableKvstoreMeshServerAccess)
   175  	if err != nil {
   176  		return nil, fmt.Errorf("failed to parse %q flag: %w",
   177  			AdminEnableFlag, err)
   178  	}
   179  
   180  	return &Spec{
   181  		Document:   swaggerSpec,
   182  		DeniedAPIs: deniedAPIs,
   183  	}, nil
   184  }
   185  
   186  // NewServer creates a new api kvstore mesh server but does not configure it
   187  func NewServer(api *restapi.KvstoreMeshAPI) *Server {
   188  	s := new(Server)
   189  	s.api = api
   190  	return s
   191  }
   192  
   193  // ConfigureAPI configures the API and handlers.
   194  func (s *Server) ConfigureAPI() {
   195  	if s.api != nil {
   196  		s.handler = configureAPI(s.api)
   197  	}
   198  }
   199  
   200  // ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse
   201  func (s *Server) ConfigureFlags() {
   202  	if s.api != nil {
   203  		configureFlags(s.api)
   204  	}
   205  }
   206  
   207  // Server for the kvstore mesh API
   208  type Server struct {
   209  	EnabledListeners []string
   210  	CleanupTimeout   time.Duration
   211  	GracefulTimeout  time.Duration
   212  	MaxHeaderSize    int
   213  
   214  	SocketPath    string
   215  	domainSocketL *net.UnixListener
   216  
   217  	Host         string
   218  	Port         int
   219  	ListenLimit  int
   220  	KeepAlive    time.Duration
   221  	ReadTimeout  time.Duration
   222  	WriteTimeout time.Duration
   223  	httpServerL  net.Listener
   224  
   225  	TLSHost           string
   226  	TLSPort           int
   227  	TLSCertificate    string
   228  	TLSCertificateKey string
   229  	TLSCACertificate  string
   230  	TLSListenLimit    int
   231  	TLSKeepAlive      time.Duration
   232  	TLSReadTimeout    time.Duration
   233  	TLSWriteTimeout   time.Duration
   234  	httpsServerL      net.Listener
   235  
   236  	api          *restapi.KvstoreMeshAPI
   237  	handler      http.Handler
   238  	hasListeners bool
   239  	servers      []*http.Server
   240  
   241  	wg         sync.WaitGroup
   242  	shutdowner hive.Shutdowner
   243  	logger     logrus.FieldLogger
   244  }
   245  
   246  // Logf logs message either via defined user logger or via system one if no user logger is defined.
   247  func (s *Server) Logf(f string, args ...interface{}) {
   248  	if s.logger != nil {
   249  		s.logger.Infof(f, args...)
   250  	} else if s.api != nil && s.api.Logger != nil {
   251  		s.api.Logger(f, args...)
   252  	} else {
   253  		log.Printf(f, args...)
   254  	}
   255  }
   256  
   257  // Fatalf logs message either via defined user logger or via system one if no user logger is defined.
   258  // Exits with non-zero status after printing
   259  func (s *Server) Fatalf(f string, args ...interface{}) {
   260  	if s.shutdowner != nil {
   261  		s.shutdowner.Shutdown(hive.ShutdownWithError(fmt.Errorf(f, args...)))
   262  	} else if s.api != nil && s.api.Logger != nil {
   263  		s.api.Logger(f, args...)
   264  		os.Exit(1)
   265  	} else {
   266  		log.Fatalf(f, args...)
   267  	}
   268  }
   269  
   270  // SetAPI configures the server with the specified API. Needs to be called before Serve
   271  func (s *Server) SetAPI(api *restapi.KvstoreMeshAPI) {
   272  	if api == nil {
   273  		s.api = nil
   274  		s.handler = nil
   275  		return
   276  	}
   277  
   278  	s.api = api
   279  	s.handler = configureAPI(api)
   280  }
   281  
   282  // GetAPI returns the configured API. Modifications on the API must be performed
   283  // before server is started.
   284  func (s *Server) GetAPI() *restapi.KvstoreMeshAPI {
   285  	return s.api
   286  }
   287  
   288  func (s *Server) hasScheme(scheme string) bool {
   289  	schemes := s.EnabledListeners
   290  	if len(schemes) == 0 {
   291  		schemes = defaultSchemes
   292  	}
   293  
   294  	for _, v := range schemes {
   295  		if v == scheme {
   296  			return true
   297  		}
   298  	}
   299  	return false
   300  }
   301  
   302  func (s *Server) Serve() error {
   303  	// TODO remove when this is not needed for compatibility anymore
   304  	if err := s.Start(context.TODO()); err != nil {
   305  		return err
   306  	}
   307  	s.wg.Wait()
   308  	return nil
   309  }
   310  
   311  // Start the server
   312  func (s *Server) Start(cell.HookContext) (err error) {
   313  	if !s.hasListeners {
   314  		if err = s.Listen(); err != nil {
   315  			return err
   316  		}
   317  	}
   318  
   319  	if len(s.servers) != 0 {
   320  		return errors.New("already started")
   321  	}
   322  
   323  	// set default handler, if none is set
   324  	if s.handler == nil {
   325  		if s.api == nil {
   326  			return errors.New("can't create the default handler, as no api is set")
   327  		}
   328  
   329  		s.ConfigureAPI()
   330  		s.SetHandler(s.api.Serve(nil))
   331  	}
   332  
   333  	if s.hasScheme(schemeUnix) {
   334  		domainSocket := new(http.Server)
   335  		domainSocket.MaxHeaderBytes = s.MaxHeaderSize
   336  		domainSocket.Handler = s.handler
   337  		if int64(s.CleanupTimeout) > 0 {
   338  			domainSocket.IdleTimeout = s.CleanupTimeout
   339  		}
   340  
   341  		configureServer(domainSocket, "unix", s.SocketPath)
   342  
   343  		if os.Getuid() == 0 {
   344  			err := api.SetDefaultPermissions(s.SocketPath)
   345  			if err != nil {
   346  				return err
   347  			}
   348  		}
   349  		s.servers = append(s.servers, domainSocket)
   350  		s.wg.Add(1)
   351  		s.Logf("Serving kvstore mesh at unix://%s", s.SocketPath)
   352  		go func(l net.Listener) {
   353  			defer s.wg.Done()
   354  			if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed {
   355  				s.Fatalf("%v", err)
   356  			}
   357  			s.Logf("Stopped serving kvstore mesh at unix://%s", s.SocketPath)
   358  		}(s.domainSocketL)
   359  	}
   360  
   361  	if s.hasScheme(schemeHTTP) {
   362  		httpServer := new(http.Server)
   363  		httpServer.MaxHeaderBytes = s.MaxHeaderSize
   364  		httpServer.ReadTimeout = s.ReadTimeout
   365  		httpServer.WriteTimeout = s.WriteTimeout
   366  		httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
   367  		if s.ListenLimit > 0 {
   368  			s.httpServerL = netutil.LimitListener(s.httpServerL, s.ListenLimit)
   369  		}
   370  
   371  		if int64(s.CleanupTimeout) > 0 {
   372  			httpServer.IdleTimeout = s.CleanupTimeout
   373  		}
   374  
   375  		httpServer.Handler = s.handler
   376  
   377  		configureServer(httpServer, "http", s.httpServerL.Addr().String())
   378  
   379  		s.servers = append(s.servers, httpServer)
   380  		s.wg.Add(1)
   381  		s.Logf("Serving kvstore mesh at http://%s", s.httpServerL.Addr())
   382  		go func(l net.Listener) {
   383  			defer s.wg.Done()
   384  			if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed {
   385  				s.Fatalf("%v", err)
   386  			}
   387  			s.Logf("Stopped serving kvstore mesh at http://%s", l.Addr())
   388  		}(s.httpServerL)
   389  	}
   390  
   391  	if s.hasScheme(schemeHTTPS) {
   392  		httpsServer := new(http.Server)
   393  		httpsServer.MaxHeaderBytes = s.MaxHeaderSize
   394  		httpsServer.ReadTimeout = s.TLSReadTimeout
   395  		httpsServer.WriteTimeout = s.TLSWriteTimeout
   396  		httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
   397  		if s.TLSListenLimit > 0 {
   398  			s.httpsServerL = netutil.LimitListener(s.httpsServerL, s.TLSListenLimit)
   399  		}
   400  		if int64(s.CleanupTimeout) > 0 {
   401  			httpsServer.IdleTimeout = s.CleanupTimeout
   402  		}
   403  		httpsServer.Handler = s.handler
   404  
   405  		// Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
   406  		httpsServer.TLSConfig = &tls.Config{
   407  			// Causes servers to use Go's default ciphersuite preferences,
   408  			// which are tuned to avoid attacks. Does nothing on clients.
   409  			PreferServerCipherSuites: true,
   410  			// Only use curves which have assembly implementations
   411  			// https://github.com/golang/go/tree/master/src/crypto/elliptic
   412  			CurvePreferences: []tls.CurveID{tls.CurveP256},
   413  			// Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
   414  			NextProtos: []string{"h2", "http/1.1"},
   415  			// https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
   416  			MinVersion: tls.VersionTLS12,
   417  			// These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
   418  			CipherSuites: []uint16{
   419  				tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   420  				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   421  				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   422  				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   423  				tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   424  				tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
   425  			},
   426  		}
   427  
   428  		// build standard config from server options
   429  		if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
   430  			httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
   431  			httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(s.TLSCertificate, s.TLSCertificateKey)
   432  			if err != nil {
   433  				return err
   434  			}
   435  		}
   436  
   437  		if s.TLSCACertificate != "" {
   438  			// include specified CA certificate
   439  			caCert, caCertErr := os.ReadFile(s.TLSCACertificate)
   440  			if caCertErr != nil {
   441  				return caCertErr
   442  			}
   443  			caCertPool := x509.NewCertPool()
   444  			ok := caCertPool.AppendCertsFromPEM(caCert)
   445  			if !ok {
   446  				return fmt.Errorf("cannot parse CA certificate")
   447  			}
   448  			httpsServer.TLSConfig.ClientCAs = caCertPool
   449  			httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
   450  		}
   451  
   452  		// call custom TLS configurator
   453  		configureTLS(httpsServer.TLSConfig)
   454  
   455  		if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil {
   456  			// after standard and custom config are passed, this ends up with no certificate
   457  			if s.TLSCertificate == "" {
   458  				if s.TLSCertificateKey == "" {
   459  					s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
   460  				}
   461  				s.Fatalf("the required flag `--tls-certificate` was not specified")
   462  			}
   463  			if s.TLSCertificateKey == "" {
   464  				s.Fatalf("the required flag `--tls-key` was not specified")
   465  			}
   466  			// this happens with a wrong custom TLS configurator
   467  			s.Fatalf("no certificate was configured for TLS")
   468  		}
   469  
   470  		// must have at least one certificate or panics
   471  		httpsServer.TLSConfig.BuildNameToCertificate()
   472  
   473  		configureServer(httpsServer, "https", s.httpsServerL.Addr().String())
   474  
   475  		s.servers = append(s.servers, httpsServer)
   476  		s.wg.Add(1)
   477  		s.Logf("Serving kvstore mesh at https://%s", s.httpsServerL.Addr())
   478  		go func(l net.Listener) {
   479  			defer s.wg.Done()
   480  			if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed {
   481  				s.Fatalf("%v", err)
   482  			}
   483  			s.Logf("Stopped serving kvstore mesh at https://%s", l.Addr())
   484  		}(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig))
   485  	}
   486  
   487  	return nil
   488  }
   489  
   490  // Listen creates the listeners for the server
   491  func (s *Server) Listen() error {
   492  	if s.hasListeners { // already done this
   493  		return nil
   494  	}
   495  
   496  	if s.hasScheme(schemeHTTPS) {
   497  		// Use http host if https host wasn't defined
   498  		if s.TLSHost == "" {
   499  			s.TLSHost = s.Host
   500  		}
   501  		// Use http listen limit if https listen limit wasn't defined
   502  		if s.TLSListenLimit == 0 {
   503  			s.TLSListenLimit = s.ListenLimit
   504  		}
   505  		// Use http tcp keep alive if https tcp keep alive wasn't defined
   506  		if int64(s.TLSKeepAlive) == 0 {
   507  			s.TLSKeepAlive = s.KeepAlive
   508  		}
   509  		// Use http read timeout if https read timeout wasn't defined
   510  		if int64(s.TLSReadTimeout) == 0 {
   511  			s.TLSReadTimeout = s.ReadTimeout
   512  		}
   513  		// Use http write timeout if https write timeout wasn't defined
   514  		if int64(s.TLSWriteTimeout) == 0 {
   515  			s.TLSWriteTimeout = s.WriteTimeout
   516  		}
   517  	}
   518  
   519  	if s.hasScheme(schemeUnix) {
   520  		addr, err := net.ResolveUnixAddr("unix", s.SocketPath)
   521  		if err != nil {
   522  			return err
   523  		}
   524  		domSockListener, err := net.ListenUnix("unix", addr)
   525  		if err != nil {
   526  			return err
   527  		}
   528  		s.domainSocketL = domSockListener
   529  	}
   530  
   531  	if s.hasScheme(schemeHTTP) {
   532  		listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
   533  		if err != nil {
   534  			return err
   535  		}
   536  
   537  		h, p, err := swag.SplitHostPort(listener.Addr().String())
   538  		if err != nil {
   539  			return err
   540  		}
   541  		s.Host = h
   542  		s.Port = p
   543  		s.httpServerL = listener
   544  	}
   545  
   546  	if s.hasScheme(schemeHTTPS) {
   547  		tlsListener, err := net.Listen("tcp", net.JoinHostPort(s.TLSHost, strconv.Itoa(s.TLSPort)))
   548  		if err != nil {
   549  			return err
   550  		}
   551  
   552  		sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
   553  		if err != nil {
   554  			return err
   555  		}
   556  		s.TLSHost = sh
   557  		s.TLSPort = sp
   558  		s.httpsServerL = tlsListener
   559  	}
   560  
   561  	s.hasListeners = true
   562  	return nil
   563  }
   564  
   565  // Shutdown server and clean up resources
   566  func (s *Server) Shutdown() error {
   567  	ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
   568  	defer cancel()
   569  	return s.Stop(ctx)
   570  }
   571  
   572  func (s *Server) Stop(ctx cell.HookContext) error {
   573  	// first execute the pre-shutdown hook
   574  	s.api.PreServerShutdown()
   575  
   576  	shutdownChan := make(chan bool)
   577  	for i := range s.servers {
   578  		server := s.servers[i]
   579  		go func() {
   580  			var success bool
   581  			defer func() {
   582  				shutdownChan <- success
   583  			}()
   584  			if err := server.Shutdown(ctx); err != nil {
   585  				s.Logf("HTTP server Shutdown: %v", err)
   586  
   587  				// Forcefully close open connections.
   588  				server.Close()
   589  			} else {
   590  				success = true
   591  			}
   592  		}()
   593  	}
   594  
   595  	// Wait until all listeners have successfully shut down before calling ServerShutdown
   596  	success := true
   597  	for range s.servers {
   598  		success = success && <-shutdownChan
   599  	}
   600  	if success {
   601  		s.api.ServerShutdown()
   602  	}
   603  
   604  	s.wg.Wait()
   605  	s.servers = nil
   606  
   607  	return nil
   608  }
   609  
   610  // GetHandler returns a handler useful for testing
   611  func (s *Server) GetHandler() http.Handler {
   612  	return s.handler
   613  }
   614  
   615  // SetHandler allows for setting a http handler on this server
   616  func (s *Server) SetHandler(handler http.Handler) {
   617  	s.handler = handler
   618  }
   619  
   620  // UnixListener returns the domain socket listener
   621  func (s *Server) UnixListener() (*net.UnixListener, error) {
   622  	if !s.hasListeners {
   623  		if err := s.Listen(); err != nil {
   624  			return nil, err
   625  		}
   626  	}
   627  	return s.domainSocketL, nil
   628  }
   629  
   630  // HTTPListener returns the http listener
   631  func (s *Server) HTTPListener() (net.Listener, error) {
   632  	if !s.hasListeners {
   633  		if err := s.Listen(); err != nil {
   634  			return nil, err
   635  		}
   636  	}
   637  	return s.httpServerL, nil
   638  }
   639  
   640  // TLSListener returns the https listener
   641  func (s *Server) TLSListener() (net.Listener, error) {
   642  	if !s.hasListeners {
   643  		if err := s.Listen(); err != nil {
   644  			return nil, err
   645  		}
   646  	}
   647  	return s.httpsServerL, nil
   648  }