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 }