istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/bootstrap/server.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bootstrap 16 17 import ( 18 "context" 19 "crypto/tls" 20 "crypto/x509" 21 "encoding/json" 22 "fmt" 23 "net" 24 "net/http" 25 "os" 26 "strings" 27 "sync" 28 "sync/atomic" 29 "time" 30 31 "github.com/fsnotify/fsnotify" 32 grpcprom "github.com/grpc-ecosystem/go-grpc-prometheus" 33 "golang.org/x/net/http2" 34 "google.golang.org/grpc" 35 "google.golang.org/grpc/credentials" 36 "google.golang.org/grpc/reflection" 37 corev1 "k8s.io/api/core/v1" 38 "k8s.io/client-go/rest" 39 40 meshconfig "istio.io/api/mesh/v1alpha1" 41 "istio.io/api/security/v1beta1" 42 "istio.io/istio/pilot/pkg/controllers/untaint" 43 kubecredentials "istio.io/istio/pilot/pkg/credentials/kube" 44 "istio.io/istio/pilot/pkg/features" 45 istiogrpc "istio.io/istio/pilot/pkg/grpc" 46 "istio.io/istio/pilot/pkg/keycertbundle" 47 "istio.io/istio/pilot/pkg/leaderelection" 48 "istio.io/istio/pilot/pkg/model" 49 "istio.io/istio/pilot/pkg/networking/core" 50 sec_model "istio.io/istio/pilot/pkg/security/model" 51 "istio.io/istio/pilot/pkg/server" 52 "istio.io/istio/pilot/pkg/serviceregistry/aggregate" 53 "istio.io/istio/pilot/pkg/serviceregistry/provider" 54 "istio.io/istio/pilot/pkg/serviceregistry/serviceentry" 55 "istio.io/istio/pilot/pkg/status" 56 "istio.io/istio/pilot/pkg/status/distribution" 57 tb "istio.io/istio/pilot/pkg/trustbundle" 58 "istio.io/istio/pilot/pkg/xds" 59 "istio.io/istio/pkg/cluster" 60 "istio.io/istio/pkg/config" 61 "istio.io/istio/pkg/config/constants" 62 "istio.io/istio/pkg/config/mesh" 63 "istio.io/istio/pkg/config/schema/collections" 64 "istio.io/istio/pkg/config/schema/gvk" 65 "istio.io/istio/pkg/config/schema/kind" 66 "istio.io/istio/pkg/ctrlz" 67 "istio.io/istio/pkg/filewatcher" 68 "istio.io/istio/pkg/h2c" 69 istiokeepalive "istio.io/istio/pkg/keepalive" 70 kubelib "istio.io/istio/pkg/kube" 71 "istio.io/istio/pkg/kube/inject" 72 "istio.io/istio/pkg/kube/kclient" 73 "istio.io/istio/pkg/kube/multicluster" 74 "istio.io/istio/pkg/kube/namespace" 75 "istio.io/istio/pkg/log" 76 "istio.io/istio/pkg/network" 77 "istio.io/istio/pkg/security" 78 "istio.io/istio/pkg/spiffe" 79 "istio.io/istio/pkg/util/sets" 80 "istio.io/istio/security/pkg/pki/ca" 81 "istio.io/istio/security/pkg/pki/ra" 82 caserver "istio.io/istio/security/pkg/server/ca" 83 "istio.io/istio/security/pkg/server/ca/authenticate" 84 "istio.io/istio/security/pkg/server/ca/authenticate/kubeauth" 85 ) 86 87 const ( 88 // debounce file watcher events to minimize noise in logs 89 watchDebounceDelay = 100 * time.Millisecond 90 ) 91 92 func init() { 93 // Disable gRPC tracing. It has performance impacts (See https://github.com/grpc/grpc-go/issues/695) 94 grpc.EnableTracing = false 95 } 96 97 // readinessProbe defines a function that will be used indicate whether a server is ready. 98 type readinessProbe func() bool 99 100 // Server contains the runtime configuration for the Pilot discovery service. 101 type Server struct { 102 XDSServer *xds.DiscoveryServer 103 104 clusterID cluster.ID 105 environment *model.Environment 106 107 kubeClient kubelib.Client 108 109 multiclusterController *multicluster.Controller 110 111 configController model.ConfigStoreController 112 ConfigStores []model.ConfigStoreController 113 serviceEntryController *serviceentry.Controller 114 115 httpServer *http.Server // debug, monitoring and readiness Server. 116 httpAddr string 117 httpsServer *http.Server // webhooks HTTPS Server. 118 119 grpcServer *grpc.Server 120 grpcAddress string 121 secureGrpcServer *grpc.Server 122 secureGrpcAddress string 123 124 // monitoringMux listens on monitoringAddr(:15014). 125 // Currently runs prometheus monitoring and debug (if enabled). 126 monitoringMux *http.ServeMux 127 // internalDebugMux is a mux for *internal* calls to the debug interface. That is, authentication is disabled. 128 internalDebugMux *http.ServeMux 129 130 // httpMux listens on the httpAddr (8080). 131 // If a Gateway is used in front and https is off it is also multiplexing 132 // the rest of the features if their port is empty. 133 // Currently runs readiness and debug (if enabled) 134 httpMux *http.ServeMux 135 136 // httpsMux listens on the httpsAddr(15017), handling webhooks 137 // If the address os empty, the webhooks will be set on the default httpPort. 138 httpsMux *http.ServeMux // webhooks 139 140 // fileWatcher used to watch mesh config, networks and certificates. 141 fileWatcher filewatcher.FileWatcher 142 143 // certWatcher watches the certificates for changes and triggers a notification to Istiod. 144 cacertsWatcher *fsnotify.Watcher 145 dnsNames []string 146 147 CA *ca.IstioCA 148 RA ra.RegistrationAuthority 149 caServer *caserver.Server 150 151 // TrustAnchors for workload to workload mTLS 152 workloadTrustBundle *tb.TrustBundle 153 certMu sync.RWMutex 154 istiodCert *tls.Certificate 155 istiodCertBundleWatcher *keycertbundle.Watcher 156 server server.Instance 157 158 readinessProbes map[string]readinessProbe 159 readinessFlags *readinessFlags 160 161 // duration used for graceful shutdown. 162 shutdownDuration time.Duration 163 164 // internalStop is closed when the server is shutdown. This should be avoided as much as possible, in 165 // favor of AddStartFunc. This is only required if we *must* start something outside of this process. 166 // For example, everything depends on mesh config, so we use it there rather than trying to sequence everything 167 // in AddStartFunc 168 internalStop chan struct{} 169 170 webhookInfo *webhookInfo 171 172 statusReporter *distribution.Reporter 173 statusManager *status.Manager 174 // RWConfigStore is the configstore which allows updates, particularly for status. 175 RWConfigStore model.ConfigStoreController 176 } 177 178 type readinessFlags struct { 179 sidecarInjectorReady atomic.Bool 180 configValidationReady atomic.Bool 181 } 182 183 type webhookInfo struct { 184 mu sync.RWMutex 185 wh *inject.Webhook 186 } 187 188 func (w *webhookInfo) GetTemplates() map[string]string { 189 w.mu.RLock() 190 defer w.mu.RUnlock() 191 if w.wh != nil { 192 return w.wh.Config.RawTemplates 193 } 194 return map[string]string{} 195 } 196 197 func (w *webhookInfo) getWebhookConfig() inject.WebhookConfig { 198 w.mu.RLock() 199 defer w.mu.RUnlock() 200 if w.wh != nil { 201 return w.wh.GetConfig() 202 } 203 return inject.WebhookConfig{} 204 } 205 206 func (w *webhookInfo) addHandler(fn func()) { 207 w.mu.Lock() 208 defer w.mu.Unlock() 209 if w.wh != nil { 210 w.wh.MultiCast.AddHandler(func(c *inject.Config, s string) error { 211 fn() 212 return nil 213 }) 214 } 215 } 216 217 // NewServer creates a new Server instance based on the provided arguments. 218 func NewServer(args *PilotArgs, initFuncs ...func(*Server)) (*Server, error) { 219 e := model.NewEnvironment() 220 e.DomainSuffix = args.RegistryOptions.KubeOptions.DomainSuffix 221 e.SetLedger(buildLedger(args.RegistryOptions)) 222 223 ac := aggregate.NewController(aggregate.Options{ 224 MeshHolder: e, 225 }) 226 e.ServiceDiscovery = ac 227 228 s := &Server{ 229 clusterID: getClusterID(args), 230 environment: e, 231 fileWatcher: filewatcher.NewWatcher(), 232 httpMux: http.NewServeMux(), 233 monitoringMux: http.NewServeMux(), 234 readinessProbes: make(map[string]readinessProbe), 235 readinessFlags: &readinessFlags{}, 236 workloadTrustBundle: tb.NewTrustBundle(nil), 237 server: server.New(), 238 shutdownDuration: args.ShutdownDuration, 239 internalStop: make(chan struct{}), 240 istiodCertBundleWatcher: keycertbundle.NewWatcher(), 241 webhookInfo: &webhookInfo{}, 242 } 243 244 // Apply custom initialization functions. 245 for _, fn := range initFuncs { 246 fn(s) 247 } 248 // Initialize workload Trust Bundle before XDS Server 249 e.TrustBundle = s.workloadTrustBundle 250 s.XDSServer = xds.NewDiscoveryServer(e, args.RegistryOptions.KubeOptions.ClusterAliases) 251 configGen := core.NewConfigGenerator(s.XDSServer.Cache) 252 253 grpcprom.EnableHandlingTimeHistogram() 254 255 // make sure we have a readiness probe before serving HTTP to avoid marking ready too soon 256 s.initReadinessProbes() 257 258 s.initServers(args) 259 if err := s.initIstiodAdminServer(args, s.webhookInfo.GetTemplates); err != nil { 260 return nil, fmt.Errorf("error initializing debug server: %v", err) 261 } 262 if err := s.serveHTTP(); err != nil { 263 return nil, fmt.Errorf("error serving http: %v", err) 264 } 265 266 // Apply the arguments to the configuration. 267 if err := s.initKubeClient(args); err != nil { 268 return nil, fmt.Errorf("error initializing kube client: %v", err) 269 } 270 271 s.initMeshConfiguration(args, s.fileWatcher) 272 spiffe.SetTrustDomain(s.environment.Mesh().GetTrustDomain()) 273 // Setup Kubernetes watch filters 274 // Because this relies on meshconfig, it needs to be outside initKubeClient 275 if s.kubeClient != nil { 276 // Build a namespace watcher. This must have no filter, since this is our input to the filter itself. 277 namespaces := kclient.New[*corev1.Namespace](s.kubeClient) 278 filter := namespace.NewDiscoveryNamespacesFilter(namespaces, s.environment.Watcher, s.internalStop) 279 s.kubeClient = kubelib.SetObjectFilter(s.kubeClient, filter) 280 } 281 282 s.initMeshNetworks(args, s.fileWatcher) 283 s.initMeshHandlers(configGen.MeshConfigChanged) 284 s.environment.Init() 285 if err := s.environment.InitNetworksManager(s.XDSServer); err != nil { 286 return nil, err 287 } 288 289 // Options based on the current 'defaults' in istio. 290 caOpts := &caOptions{ 291 TrustDomain: s.environment.Mesh().TrustDomain, 292 Namespace: args.Namespace, 293 ExternalCAType: ra.CaExternalType(externalCaType), 294 CertSignerDomain: features.CertSignerDomain, 295 } 296 297 if caOpts.ExternalCAType == ra.ExtCAK8s { 298 // Older environment variable preserved for backward compatibility 299 caOpts.ExternalCASigner = k8sSigner 300 } 301 // CA signing certificate must be created first if needed. 302 if err := s.maybeCreateCA(caOpts); err != nil { 303 return nil, err 304 } 305 306 if err := s.initControllers(args); err != nil { 307 return nil, err 308 } 309 310 InitGenerators(s.XDSServer, configGen, args.Namespace, s.clusterID, s.internalDebugMux) 311 312 // Initialize workloadTrustBundle after CA has been initialized 313 if err := s.initWorkloadTrustBundle(args); err != nil { 314 return nil, err 315 } 316 317 // Parse and validate Istiod Address. 318 istiodHost, _, err := e.GetDiscoveryAddress() 319 if err != nil { 320 return nil, err 321 } 322 323 // Create Istiod certs and setup watches. 324 if err := s.initIstiodCerts(args, string(istiodHost)); err != nil { 325 return nil, err 326 } 327 328 // Secure gRPC Server must be initialized after CA is created as may use a Citadel generated cert. 329 if err := s.initSecureDiscoveryService(args); err != nil { 330 return nil, fmt.Errorf("error initializing secure gRPC Listener: %v", err) 331 } 332 333 // common https server for webhooks (e.g. injection, validation) 334 if s.kubeClient != nil { 335 s.initSecureWebhookServer(args) 336 wh, err := s.initSidecarInjector(args) 337 if err != nil { 338 return nil, fmt.Errorf("error initializing sidecar injector: %v", err) 339 } 340 s.readinessFlags.sidecarInjectorReady.Store(true) 341 s.webhookInfo.mu.Lock() 342 s.webhookInfo.wh = wh 343 s.webhookInfo.mu.Unlock() 344 if err := s.initConfigValidation(args); err != nil { 345 return nil, fmt.Errorf("error initializing config validator: %v", err) 346 } 347 } 348 349 // This should be called only after controllers are initialized. 350 s.initRegistryEventHandlers() 351 352 s.initDiscoveryService() 353 354 // Notice that the order of authenticators matters, since at runtime 355 // authenticators are activated sequentially and the first successful attempt 356 // is used as the authentication result. 357 authenticators := []security.Authenticator{ 358 &authenticate.ClientCertAuthenticator{}, 359 } 360 if args.JwtRule != "" { 361 jwtAuthn, err := initOIDC(args) 362 if err != nil { 363 return nil, fmt.Errorf("error initializing OIDC: %v", err) 364 } 365 if jwtAuthn == nil { 366 return nil, fmt.Errorf("JWT authenticator is nil") 367 } 368 authenticators = append(authenticators, jwtAuthn) 369 } 370 // The k8s JWT authenticator requires the multicluster registry to be initialized, 371 // so we build it later. 372 if s.kubeClient != nil { 373 authenticators = append(authenticators, 374 kubeauth.NewKubeJWTAuthenticator(s.environment.Watcher, s.kubeClient.Kube(), s.clusterID, s.multiclusterController.GetRemoteKubeClient)) 375 } 376 if len(features.TrustedGatewayCIDR) > 0 { 377 authenticators = append(authenticators, &authenticate.XfccAuthenticator{}) 378 } 379 if features.XDSAuth { 380 s.XDSServer.Authenticators = authenticators 381 } 382 caOpts.Authenticators = authenticators 383 384 // Start CA or RA server. This should be called after CA and Istiod certs have been created. 385 s.startCA(caOpts) 386 387 // TODO: don't run this if galley is started, one ctlz is enough 388 if args.CtrlZOptions != nil { 389 _, _ = ctrlz.Run(args.CtrlZOptions, nil) 390 } 391 392 // This must be last, otherwise we will not know which informers to register 393 if s.kubeClient != nil { 394 s.addStartFunc("kube client", func(stop <-chan struct{}) error { 395 s.kubeClient.RunAndWait(stop) 396 return nil 397 }) 398 } 399 400 return s, nil 401 } 402 403 func initOIDC(args *PilotArgs) (security.Authenticator, error) { 404 // JWTRule is from the JWT_RULE environment variable. 405 // An example of json string for JWTRule is: 406 // `{"issuer": "foo", "jwks_uri": "baz", "audiences": ["aud1", "aud2"]}`. 407 jwtRule := &v1beta1.JWTRule{} 408 err := json.Unmarshal([]byte(args.JwtRule), jwtRule) 409 if err != nil { 410 return nil, fmt.Errorf("failed to unmarshal JWT rule: %v", err) 411 } 412 log.Infof("Istiod authenticating using JWTRule: %v", jwtRule) 413 jwtAuthn, err := authenticate.NewJwtAuthenticator(jwtRule) 414 if err != nil { 415 return nil, fmt.Errorf("failed to create the JWT authenticator: %v", err) 416 } 417 return jwtAuthn, nil 418 } 419 420 func getClusterID(args *PilotArgs) cluster.ID { 421 clusterID := args.RegistryOptions.KubeOptions.ClusterID 422 if clusterID == "" { 423 if hasKubeRegistry(args.RegistryOptions.Registries) { 424 clusterID = cluster.ID(provider.Kubernetes) 425 } 426 } 427 return clusterID 428 } 429 430 // Start starts all components of the error serving tap http serverPilot discovery service on the port specified in DiscoveryServerOptions. 431 // If Port == 0, a port number is automatically chosen. Content serving is started by this method, 432 // but is executed asynchronously. Serving can be canceled at any time by closing the provided stop channel. 433 func (s *Server) Start(stop <-chan struct{}) error { 434 log.Infof("Starting Istiod Server with primary cluster %s", s.clusterID) 435 436 if features.UnsafeFeaturesEnabled() { 437 log.Warn("Server is starting with unsafe features enabled") 438 } 439 440 // Now start all of the components. 441 if err := s.server.Start(stop); err != nil { 442 return err 443 } 444 if !s.waitForCacheSync(stop) { 445 return fmt.Errorf("failed to sync cache") 446 } 447 // Inform Discovery Server so that it can start accepting connections. 448 s.XDSServer.CachesSynced() 449 450 // Race condition - if waitForCache is too fast and we run this as a startup function, 451 // the grpc server would be started before CA is registered. Listening should be last. 452 if s.secureGrpcAddress != "" { 453 grpcListener, err := net.Listen("tcp", s.secureGrpcAddress) 454 if err != nil { 455 return err 456 } 457 go func() { 458 log.Infof("starting secure gRPC discovery service at %s", grpcListener.Addr()) 459 if err := s.secureGrpcServer.Serve(grpcListener); err != nil { 460 log.Errorf("error serving secure GRPC server: %v", err) 461 } 462 }() 463 } 464 465 if s.grpcAddress != "" { 466 grpcListener, err := net.Listen("tcp", s.grpcAddress) 467 if err != nil { 468 return err 469 } 470 go func() { 471 log.Infof("starting gRPC discovery service at %s", grpcListener.Addr()) 472 if err := s.grpcServer.Serve(grpcListener); err != nil { 473 log.Errorf("error serving GRPC server: %v", err) 474 } 475 }() 476 } 477 478 if s.httpsServer != nil { 479 httpsListener, err := net.Listen("tcp", s.httpsServer.Addr) 480 if err != nil { 481 return err 482 } 483 go func() { 484 log.Infof("starting webhook service at %s", httpsListener.Addr()) 485 if err := s.httpsServer.ServeTLS(httpsListener, "", ""); network.IsUnexpectedListenerError(err) { 486 log.Errorf("error serving https server: %v", err) 487 } 488 }() 489 } 490 491 s.waitForShutdown(stop) 492 493 return nil 494 } 495 496 // WaitUntilCompletion waits for everything marked as a "required termination" to complete. 497 // This should be called before exiting. 498 func (s *Server) WaitUntilCompletion() { 499 s.server.Wait() 500 } 501 502 // initSDSServer starts the SDS server 503 func (s *Server) initSDSServer() { 504 if s.kubeClient == nil { 505 return 506 } 507 if !features.EnableXDSIdentityCheck { 508 // Make sure we have security 509 log.Warnf("skipping Kubernetes credential reader; PILOT_ENABLE_XDS_IDENTITY_CHECK must be set to true for this feature.") 510 } else { 511 creds := kubecredentials.NewMulticluster(s.clusterID, s.multiclusterController) 512 creds.AddSecretHandler(func(name string, namespace string) { 513 s.XDSServer.ConfigUpdate(&model.PushRequest{ 514 Full: false, 515 ConfigsUpdated: sets.New(model.ConfigKey{Kind: kind.Secret, Name: name, Namespace: namespace}), 516 517 Reason: model.NewReasonStats(model.SecretTrigger), 518 }) 519 }) 520 s.environment.CredentialsController = creds 521 } 522 } 523 524 // initKubeClient creates the k8s client if running in a k8s environment. 525 // This is determined by the presence of a kube registry, which 526 // uses in-context k8s, or a config source of type k8s. 527 func (s *Server) initKubeClient(args *PilotArgs) error { 528 if s.kubeClient != nil { 529 // Already initialized by startup arguments 530 return nil 531 } 532 hasK8SConfigStore := false 533 if args.RegistryOptions.FileDir == "" { 534 // If file dir is set - config controller will just use file. 535 if _, err := os.Stat(args.MeshConfigFile); !os.IsNotExist(err) { 536 meshConfig, err := mesh.ReadMeshConfig(args.MeshConfigFile) 537 if err != nil { 538 return fmt.Errorf("failed reading mesh config: %v", err) 539 } 540 if len(meshConfig.ConfigSources) == 0 && args.RegistryOptions.KubeConfig != "" { 541 hasK8SConfigStore = true 542 } 543 for _, cs := range meshConfig.ConfigSources { 544 if cs.Address == string(Kubernetes)+"://" { 545 hasK8SConfigStore = true 546 break 547 } 548 } 549 } else if args.RegistryOptions.KubeConfig != "" { 550 hasK8SConfigStore = true 551 } 552 } 553 554 if hasK8SConfigStore || hasKubeRegistry(args.RegistryOptions.Registries) { 555 // Used by validation 556 kubeRestConfig, err := kubelib.DefaultRestConfig(args.RegistryOptions.KubeConfig, "", func(config *rest.Config) { 557 config.QPS = args.RegistryOptions.KubeOptions.KubernetesAPIQPS 558 config.Burst = args.RegistryOptions.KubeOptions.KubernetesAPIBurst 559 }) 560 if err != nil { 561 return fmt.Errorf("failed creating kube config: %v", err) 562 } 563 564 s.kubeClient, err = kubelib.NewClient(kubelib.NewClientConfigForRestConfig(kubeRestConfig), s.clusterID) 565 if err != nil { 566 return fmt.Errorf("failed creating kube client: %v", err) 567 } 568 s.kubeClient = kubelib.EnableCrdWatcher(s.kubeClient) 569 } 570 571 return nil 572 } 573 574 // A single container can't have two readiness probes. Make this readiness probe a generic one 575 // that can handle all istiod related readiness checks including webhook, gRPC etc. 576 // The "http" portion of the readiness check is satisfied by the fact we've started listening on 577 // this handler and everything has already initialized. 578 func (s *Server) istiodReadyHandler(w http.ResponseWriter, _ *http.Request) { 579 for name, fn := range s.readinessProbes { 580 if ready := fn(); !ready { 581 log.Warnf("%s is not ready", name) 582 w.WriteHeader(http.StatusServiceUnavailable) 583 return 584 } 585 } 586 w.WriteHeader(http.StatusOK) 587 } 588 589 // initServers initializes http and grpc servers 590 func (s *Server) initServers(args *PilotArgs) { 591 s.initGrpcServer(args.KeepaliveOptions) 592 multiplexGRPC := false 593 if args.ServerOptions.GRPCAddr != "" { 594 s.grpcAddress = args.ServerOptions.GRPCAddr 595 } else { 596 // This happens only if the GRPC port (15010) is disabled. We will multiplex 597 // it on the HTTP port. Does not impact the HTTPS gRPC or HTTPS. 598 log.Infof("multiplexing gRPC on http addr %v", args.ServerOptions.HTTPAddr) 599 multiplexGRPC = true 600 } 601 h2s := &http2.Server{ 602 MaxConcurrentStreams: uint32(features.MaxConcurrentStreams), 603 } 604 multiplexHandler := h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 605 // If we detect gRPC, serve using grpcServer 606 if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("content-type"), "application/grpc") { 607 s.grpcServer.ServeHTTP(w, r) 608 return 609 } 610 // Otherwise, this is meant for the standard HTTP server 611 s.httpMux.ServeHTTP(w, r) 612 }), h2s) 613 s.httpServer = &http.Server{ 614 Addr: args.ServerOptions.HTTPAddr, 615 Handler: s.httpMux, 616 IdleTimeout: 90 * time.Second, // matches http.DefaultTransport keep-alive timeout 617 ReadTimeout: 30 * time.Second, 618 } 619 if multiplexGRPC { 620 // To allow the gRPC handler to make per-request decision, 621 // use ReadHeaderTimeout instead of ReadTimeout. 622 s.httpServer.ReadTimeout = 0 623 s.httpServer.ReadHeaderTimeout = 30 * time.Second 624 s.httpServer.Handler = multiplexHandler 625 } 626 627 if args.ServerOptions.MonitoringAddr == "" { 628 s.monitoringMux = s.httpMux 629 log.Infof("initializing Istiod admin server multiplexed on httpAddr %v", s.httpServer.Addr) 630 } else { 631 log.Info("initializing Istiod admin server") 632 } 633 } 634 635 // initIstiodAdminServer initializes monitoring, debug and readiness end points. 636 func (s *Server) initIstiodAdminServer(args *PilotArgs, whc func() map[string]string) error { 637 // Debug Server. 638 internalMux := s.XDSServer.InitDebug(s.monitoringMux, args.ServerOptions.EnableProfiling, whc) 639 s.internalDebugMux = internalMux 640 641 // Debug handlers are currently added on monitoring mux and readiness mux. 642 // If monitoring addr is empty, the mux is shared and we only add it once on the shared mux . 643 if args.ServerOptions.MonitoringAddr != "" { 644 s.XDSServer.AddDebugHandlers(s.httpMux, nil, args.ServerOptions.EnableProfiling, whc) 645 } 646 647 // Monitoring Server. 648 if err := s.initMonitor(args.ServerOptions.MonitoringAddr); err != nil { 649 return fmt.Errorf("error initializing monitor: %v", err) 650 } 651 652 // Readiness Handler. 653 s.httpMux.HandleFunc("/ready", s.istiodReadyHandler) 654 655 return nil 656 } 657 658 // initDiscoveryService initializes discovery server on plain text port. 659 func (s *Server) initDiscoveryService() { 660 log.Infof("starting discovery service") 661 // Implement EnvoyXdsServer grace shutdown 662 s.addStartFunc("xds server", func(stop <-chan struct{}) error { 663 log.Infof("Starting ADS server") 664 s.XDSServer.Start(stop) 665 return nil 666 }) 667 } 668 669 // Wait for the stop, and do cleanups 670 func (s *Server) waitForShutdown(stop <-chan struct{}) { 671 go func() { 672 <-stop 673 close(s.internalStop) 674 _ = s.fileWatcher.Close() 675 676 if s.cacertsWatcher != nil { 677 _ = s.cacertsWatcher.Close() 678 } 679 // Stop gRPC services. If gRPC services fail to stop in the shutdown duration, 680 // force stop them. This does not happen normally. 681 stopped := make(chan struct{}) 682 go func() { 683 // Some grpcServer implementations do not support GracefulStop. Unfortunately, this is not 684 // exposed; they just panic. To avoid this, we will recover and do a standard Stop when its not 685 // support. 686 defer func() { 687 if r := recover(); r != nil { 688 s.grpcServer.Stop() 689 if s.secureGrpcServer != nil { 690 s.secureGrpcServer.Stop() 691 } 692 close(stopped) 693 } 694 }() 695 s.grpcServer.GracefulStop() 696 if s.secureGrpcServer != nil { 697 s.secureGrpcServer.GracefulStop() 698 } 699 close(stopped) 700 }() 701 702 t := time.NewTimer(s.shutdownDuration) 703 select { 704 case <-t.C: 705 s.grpcServer.Stop() 706 if s.secureGrpcServer != nil { 707 s.secureGrpcServer.Stop() 708 } 709 case <-stopped: 710 t.Stop() 711 } 712 713 // Stop HTTP services. 714 ctx, cancel := context.WithTimeout(context.Background(), s.shutdownDuration) 715 defer cancel() 716 if err := s.httpServer.Shutdown(ctx); err != nil { 717 log.Warn(err) 718 } 719 if s.httpsServer != nil { 720 if err := s.httpsServer.Shutdown(ctx); err != nil { 721 log.Warn(err) 722 } 723 } 724 725 // Shutdown the DiscoveryServer. 726 s.XDSServer.Shutdown() 727 }() 728 } 729 730 func (s *Server) initGrpcServer(options *istiokeepalive.Options) { 731 interceptors := []grpc.UnaryServerInterceptor{ 732 // setup server prometheus monitoring (as final interceptor in chain) 733 grpcprom.UnaryServerInterceptor, 734 } 735 grpcOptions := istiogrpc.ServerOptions(options, interceptors...) 736 s.grpcServer = grpc.NewServer(grpcOptions...) 737 s.XDSServer.Register(s.grpcServer) 738 reflection.Register(s.grpcServer) 739 } 740 741 // initialize secureGRPCServer. 742 func (s *Server) initSecureDiscoveryService(args *PilotArgs) error { 743 if args.ServerOptions.SecureGRPCAddr == "" { 744 log.Info("The secure discovery port is disabled, multiplexing on httpAddr ") 745 return nil 746 } 747 748 peerCertVerifier, err := s.createPeerCertVerifier(args.ServerOptions.TLSOptions) 749 if err != nil { 750 return err 751 } 752 if peerCertVerifier == nil { 753 // Running locally without configured certs - no TLS mode 754 log.Warnf("The secure discovery service is disabled") 755 return nil 756 } 757 log.Info("initializing secure discovery service") 758 cfg := &tls.Config{ 759 GetCertificate: s.getIstiodCertificate, 760 ClientAuth: tls.VerifyClientCertIfGiven, 761 ClientCAs: peerCertVerifier.GetGeneralCertPool(), 762 VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 763 err := peerCertVerifier.VerifyPeerCert(rawCerts, verifiedChains) 764 if err != nil { 765 log.Infof("Could not verify certificate: %v", err) 766 } 767 return err 768 }, 769 MinVersion: tls.VersionTLS12, 770 CipherSuites: args.ServerOptions.TLSOptions.CipherSuits, 771 } 772 // Compliance for xDS server TLS. 773 sec_model.EnforceGoCompliance(cfg) 774 775 tlsCreds := credentials.NewTLS(cfg) 776 777 s.secureGrpcAddress = args.ServerOptions.SecureGRPCAddr 778 779 interceptors := []grpc.UnaryServerInterceptor{ 780 // setup server prometheus monitoring (as final interceptor in chain) 781 grpcprom.UnaryServerInterceptor, 782 } 783 opts := istiogrpc.ServerOptions(args.KeepaliveOptions, interceptors...) 784 opts = append(opts, grpc.Creds(tlsCreds)) 785 786 s.secureGrpcServer = grpc.NewServer(opts...) 787 s.XDSServer.Register(s.secureGrpcServer) 788 reflection.Register(s.secureGrpcServer) 789 790 s.addStartFunc("secure gRPC", func(stop <-chan struct{}) error { 791 go func() { 792 <-stop 793 s.secureGrpcServer.Stop() 794 }() 795 return nil 796 }) 797 798 return nil 799 } 800 801 // addStartFunc appends a function to be run. These are run synchronously in order, 802 // so the function should start a go routine if it needs to do anything blocking 803 func (s *Server) addStartFunc(name string, fn server.Component) { 804 s.server.RunComponent(name, fn) 805 } 806 807 // adds a readiness probe for Istiod Server. 808 func (s *Server) addReadinessProbe(name string, fn readinessProbe) { 809 s.readinessProbes[name] = fn 810 } 811 812 // addTerminatingStartFunc adds a function that should terminate before the serve shuts down 813 // This is useful to do cleanup activities 814 // This is does not guarantee they will terminate gracefully - best effort only 815 // Function should be synchronous; once it returns it is considered "done" 816 func (s *Server) addTerminatingStartFunc(name string, fn server.Component) { 817 s.server.RunComponentAsyncAndWait(name, fn) 818 } 819 820 func (s *Server) waitForCacheSync(stop <-chan struct{}) bool { 821 start := time.Now() 822 log.Info("Waiting for caches to be synced") 823 if !kubelib.WaitForCacheSync("server", stop, s.cachesSynced) { 824 log.Errorf("Failed waiting for cache sync") 825 return false 826 } 827 log.Infof("All controller caches have been synced up in %v", time.Since(start)) 828 829 // At this point, we know that all update events of the initial state-of-the-world have been 830 // received. We wait to ensure we have committed at least this many updates. This avoids a race 831 // condition where we are marked ready prior to updating the push context, leading to incomplete 832 // pushes. 833 expected := s.XDSServer.InboundUpdates.Load() 834 return kubelib.WaitForCacheSync("push context", stop, func() bool { return s.pushContextReady(expected) }) 835 } 836 837 // pushContextReady indicates whether pushcontext has processed all inbound config updates. 838 func (s *Server) pushContextReady(expected int64) bool { 839 committed := s.XDSServer.CommittedUpdates.Load() 840 if committed < expected { 841 log.Debugf("Waiting for pushcontext to process inbound updates, inbound: %v, committed : %v", expected, committed) 842 return false 843 } 844 return true 845 } 846 847 // cachesSynced checks whether caches have been synced. 848 func (s *Server) cachesSynced() bool { 849 if s.multiclusterController != nil && !s.multiclusterController.HasSynced() { 850 return false 851 } 852 if !s.ServiceController().HasSynced() { 853 return false 854 } 855 if !s.configController.HasSynced() { 856 return false 857 } 858 return true 859 } 860 861 // initRegistryEventHandlers sets up event handlers for config and service updates 862 func (s *Server) initRegistryEventHandlers() { 863 log.Info("initializing registry event handlers") 864 // Flush cached discovery responses whenever services configuration change. 865 serviceHandler := func(prev, curr *model.Service, event model.Event) { 866 pushReq := &model.PushRequest{ 867 Full: true, 868 ConfigsUpdated: sets.New(model.ConfigKey{Kind: kind.ServiceEntry, Name: string(curr.Hostname), Namespace: curr.Attributes.Namespace}), 869 Reason: model.NewReasonStats(model.ServiceUpdate), 870 } 871 s.XDSServer.ConfigUpdate(pushReq) 872 } 873 s.ServiceController().AppendServiceHandler(serviceHandler) 874 875 if s.configController != nil { 876 configHandler := func(prev config.Config, curr config.Config, event model.Event) { 877 if s.statusReporter != nil { 878 defer func() { 879 if event != model.EventDelete { 880 s.statusReporter.AddInProgressResource(curr) 881 } else { 882 s.statusReporter.DeleteInProgressResource(curr) 883 } 884 }() 885 } 886 log.Debugf("Handle event %s for configuration %s", event, curr.Key()) 887 // For update events, trigger push only if spec has changed. 888 if event == model.EventUpdate && !needsPush(prev, curr) { 889 log.Debugf("skipping push for %s as spec has not changed", prev.Key()) 890 return 891 } 892 pushReq := &model.PushRequest{ 893 Full: true, 894 ConfigsUpdated: sets.New(model.ConfigKey{Kind: kind.MustFromGVK(curr.GroupVersionKind), Name: curr.Name, Namespace: curr.Namespace}), 895 Reason: model.NewReasonStats(model.ConfigUpdate), 896 } 897 s.XDSServer.ConfigUpdate(pushReq) 898 } 899 schemas := collections.Pilot.All() 900 if features.EnableGatewayAPI { 901 schemas = collections.PilotGatewayAPI().All() 902 } 903 for _, schema := range schemas { 904 // This resource type was handled in external/servicediscovery.go, no need to rehandle here. 905 if schema.GroupVersionKind() == gvk.ServiceEntry { 906 continue 907 } 908 if schema.GroupVersionKind() == gvk.WorkloadEntry { 909 continue 910 } 911 if schema.GroupVersionKind() == gvk.WorkloadGroup { 912 continue 913 } 914 915 s.configController.RegisterEventHandler(schema.GroupVersionKind(), configHandler) 916 } 917 if s.environment.GatewayAPIController != nil { 918 s.environment.GatewayAPIController.RegisterEventHandler(gvk.Namespace, func(config.Config, config.Config, model.Event) { 919 s.XDSServer.ConfigUpdate(&model.PushRequest{ 920 Full: true, 921 Reason: model.NewReasonStats(model.NamespaceUpdate), 922 }) 923 }) 924 s.environment.GatewayAPIController.RegisterEventHandler(gvk.Secret, func(_ config.Config, gw config.Config, _ model.Event) { 925 s.XDSServer.ConfigUpdate(&model.PushRequest{ 926 Full: true, 927 ConfigsUpdated: map[model.ConfigKey]struct{}{ 928 { 929 Kind: kind.KubernetesGateway, 930 Name: gw.Name, 931 Namespace: gw.Namespace, 932 }: {}, 933 }, 934 Reason: model.NewReasonStats(model.SecretTrigger), 935 }) 936 }) 937 } 938 } 939 } 940 941 func (s *Server) initIstiodCertLoader() error { 942 if err := s.loadIstiodCert(); err != nil { 943 return fmt.Errorf("first time load IstiodCert failed: %v", err) 944 } 945 _, watchCh := s.istiodCertBundleWatcher.AddWatcher() 946 s.addStartFunc("reload certs", func(stop <-chan struct{}) error { 947 go s.reloadIstiodCert(watchCh, stop) 948 return nil 949 }) 950 return nil 951 } 952 953 // initIstiodCerts creates Istiod certificates and also sets up watches to them. 954 func (s *Server) initIstiodCerts(args *PilotArgs, host string) error { 955 // Skip all certificates 956 var err error 957 958 s.dnsNames = getDNSNames(args, host) 959 if hasCustomCertArgsOrWellKnown, tlsCertPath, tlsKeyPath, caCertPath := hasCustomTLSCerts(args.ServerOptions.TLSOptions); hasCustomCertArgsOrWellKnown { 960 // Use the DNS certificate provided via args or in well known location. 961 err = s.initCertificateWatches(TLSOptions{ 962 CaCertFile: caCertPath, 963 KeyFile: tlsKeyPath, 964 CertFile: tlsCertPath, 965 }) 966 if err != nil { 967 // Not crashing istiod - This typically happens if certs are missing and in tests. 968 log.Errorf("error initializing certificate watches: %v", err) 969 return nil 970 } 971 } else if features.EnableCAServer && features.PilotCertProvider == constants.CertProviderIstiod { 972 log.Infof("initializing Istiod DNS certificates host: %s, custom host: %s", host, features.IstiodServiceCustomHost) 973 err = s.initDNSCerts() 974 } else if features.PilotCertProvider == constants.CertProviderKubernetes { 975 log.Infof("initializing Istiod DNS certificates host: %s, custom host: %s", host, features.IstiodServiceCustomHost) 976 err = s.initDNSCerts() 977 } else if strings.HasPrefix(features.PilotCertProvider, constants.CertProviderKubernetesSignerPrefix) { 978 log.Infof("initializing Istiod DNS certificates host: %s, custom host: %s", host, features.IstiodServiceCustomHost) 979 err = s.initDNSCerts() 980 } else { 981 return nil 982 } 983 984 if err == nil { 985 err = s.initIstiodCertLoader() 986 } 987 988 return err 989 } 990 991 func getDNSNames(args *PilotArgs, host string) []string { 992 // Append custom hostname if there is any 993 customHost := features.IstiodServiceCustomHost 994 var cHosts []string 995 996 if customHost != "" { 997 cHosts = strings.Split(customHost, ",") 998 } 999 sans := sets.New(cHosts...) 1000 sans.Insert(host) 1001 // The first is the recommended one, also used by Apiserver for webhooks. 1002 // add a few known hostnames 1003 knownHosts := []string{"istiod", "istiod-remote", "istio-pilot"} 1004 // In some conditions, pilot address for sds is different from other xds, 1005 // like multi-cluster primary-remote mode with revision. 1006 if args.Revision != "" && args.Revision != "default" { 1007 knownHosts = append(knownHosts, "istiod"+"-"+args.Revision) 1008 } 1009 knownSans := make([]string, 0, 2*len(knownHosts)) 1010 for _, altName := range knownHosts { 1011 knownSans = append(knownSans, 1012 fmt.Sprintf("%s.%s.svc", altName, args.Namespace)) 1013 } 1014 sans.InsertAll(knownSans...) 1015 dnsNames := sets.SortedList(sans) 1016 log.Infof("Discover server subject alt names: %v", dnsNames) 1017 return dnsNames 1018 } 1019 1020 // createPeerCertVerifier creates a SPIFFE certificate verifier with the current istiod configuration. 1021 func (s *Server) createPeerCertVerifier(tlsOptions TLSOptions) (*spiffe.PeerCertVerifier, error) { 1022 customTLSCertsExists, _, _, caCertPath := hasCustomTLSCerts(tlsOptions) 1023 if !customTLSCertsExists && s.CA == nil && !s.isCADisabled() { 1024 // Running locally without configured certs - no TLS mode 1025 return nil, nil 1026 } 1027 peerCertVerifier := spiffe.NewPeerCertVerifier() 1028 var rootCertBytes []byte 1029 var err error 1030 if caCertPath != "" { 1031 if rootCertBytes, err = os.ReadFile(caCertPath); err != nil { 1032 return nil, err 1033 } 1034 } else { 1035 if s.RA != nil { 1036 if strings.HasPrefix(features.PilotCertProvider, constants.CertProviderKubernetesSignerPrefix) { 1037 signerName := strings.TrimPrefix(features.PilotCertProvider, constants.CertProviderKubernetesSignerPrefix) 1038 caBundle, _ := s.RA.GetRootCertFromMeshConfig(signerName) 1039 rootCertBytes = append(rootCertBytes, caBundle...) 1040 } else { 1041 rootCertBytes = append(rootCertBytes, s.RA.GetCAKeyCertBundle().GetRootCertPem()...) 1042 } 1043 } 1044 if s.CA != nil { 1045 rootCertBytes = append(rootCertBytes, s.CA.GetCAKeyCertBundle().GetRootCertPem()...) 1046 } 1047 } 1048 1049 if len(rootCertBytes) != 0 { 1050 err := peerCertVerifier.AddMappingFromPEM(spiffe.GetTrustDomain(), rootCertBytes) 1051 if err != nil { 1052 return nil, fmt.Errorf("add root CAs into peerCertVerifier failed: %v", err) 1053 } 1054 } 1055 1056 return peerCertVerifier, nil 1057 } 1058 1059 func checkPathsExist(paths ...string) bool { 1060 for _, path := range paths { 1061 fInfo, err := os.Stat(path) 1062 1063 if err != nil || fInfo.IsDir() { 1064 return false 1065 } 1066 } 1067 return true 1068 } 1069 1070 // hasCustomTLSCerts returns the tls cert paths, used both if custom TLS certificates are configured via args or by mounting in well known. 1071 // while tls args should still take precedence the aim is to encourage loading the DNS tls cert in the well known path locations. 1072 func hasCustomTLSCerts(tlsOptions TLSOptions) (ok bool, tlsCertPath, tlsKeyPath, caCertPath string) { 1073 // load from tls args as priority 1074 if hasCustomTLSCertArgs(tlsOptions) { 1075 return true, tlsOptions.CertFile, tlsOptions.KeyFile, tlsOptions.CaCertFile 1076 } 1077 1078 if ok = checkPathsExist(constants.DefaultPilotTLSCert, constants.DefaultPilotTLSKey, constants.DefaultPilotTLSCaCert); ok { 1079 tlsCertPath = constants.DefaultPilotTLSCert 1080 tlsKeyPath = constants.DefaultPilotTLSKey 1081 caCertPath = constants.DefaultPilotTLSCaCert 1082 return 1083 } 1084 1085 if ok = checkPathsExist(constants.DefaultPilotTLSCert, constants.DefaultPilotTLSKey, constants.DefaultPilotTLSCaCertAlternatePath); ok { 1086 tlsCertPath = constants.DefaultPilotTLSCert 1087 tlsKeyPath = constants.DefaultPilotTLSKey 1088 caCertPath = constants.DefaultPilotTLSCaCertAlternatePath 1089 return 1090 } 1091 1092 return 1093 } 1094 1095 // hasCustomTLSCerts returns true if custom TLS certificates are configured via args. 1096 func hasCustomTLSCertArgs(tlsOptions TLSOptions) bool { 1097 return tlsOptions.CaCertFile != "" && tlsOptions.CertFile != "" && tlsOptions.KeyFile != "" 1098 } 1099 1100 // getIstiodCertificate returns the istiod certificate. 1101 func (s *Server) getIstiodCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error) { 1102 s.certMu.RLock() 1103 defer s.certMu.RUnlock() 1104 if s.istiodCert != nil { 1105 return s.istiodCert, nil 1106 } 1107 return nil, fmt.Errorf("cert not initialized") 1108 } 1109 1110 // initControllers initializes the controllers. 1111 func (s *Server) initControllers(args *PilotArgs) error { 1112 log.Info("initializing controllers") 1113 s.initMulticluster(args) 1114 1115 s.initSDSServer() 1116 1117 if features.EnableNodeUntaintControllers { 1118 s.initNodeUntaintController(args) 1119 } 1120 1121 if err := s.initConfigController(args); err != nil { 1122 return fmt.Errorf("error initializing config controller: %v", err) 1123 } 1124 if err := s.initServiceControllers(args); err != nil { 1125 return fmt.Errorf("error initializing service controllers: %v", err) 1126 } 1127 return nil 1128 } 1129 1130 func (s *Server) initNodeUntaintController(args *PilotArgs) { 1131 s.addStartFunc("nodeUntainter controller", func(stop <-chan struct{}) error { 1132 go leaderelection. 1133 NewLeaderElection(args.Namespace, args.PodName, leaderelection.NodeUntaintController, args.Revision, s.kubeClient). 1134 AddRunFunction(func(leaderStop <-chan struct{}) { 1135 nodeUntainter := untaint.NewNodeUntainter(leaderStop, s.kubeClient, args.CniNamespace, args.Namespace) 1136 nodeUntainter.Run(leaderStop) 1137 }).Run(stop) 1138 return nil 1139 }) 1140 } 1141 1142 func (s *Server) initMulticluster(args *PilotArgs) { 1143 if s.kubeClient == nil { 1144 return 1145 } 1146 s.multiclusterController = multicluster.NewController(s.kubeClient, args.Namespace, s.clusterID, s.environment.Watcher, func(r *rest.Config) { 1147 r.QPS = args.RegistryOptions.KubeOptions.KubernetesAPIQPS 1148 r.Burst = args.RegistryOptions.KubeOptions.KubernetesAPIBurst 1149 }) 1150 s.XDSServer.ListRemoteClusters = s.multiclusterController.ListRemoteClusters 1151 s.addStartFunc("multicluster controller", func(stop <-chan struct{}) error { 1152 return s.multiclusterController.Run(stop) 1153 }) 1154 } 1155 1156 // maybeCreateCA creates and initializes CA Key if needed. 1157 func (s *Server) maybeCreateCA(caOpts *caOptions) error { 1158 // CA signing certificate must be created only if CA is enabled. 1159 if features.EnableCAServer { 1160 log.Info("creating CA and initializing public key") 1161 var err error 1162 if useRemoteCerts.Get() { 1163 if err = s.loadCACerts(caOpts, LocalCertDir.Get()); err != nil { 1164 return fmt.Errorf("failed to load remote CA certs: %v", err) 1165 } 1166 } 1167 // May return nil, if the CA is missing required configs - This is not an error. 1168 if caOpts.ExternalCAType != "" { 1169 if s.RA, err = s.createIstioRA(caOpts); err != nil { 1170 return fmt.Errorf("failed to create RA: %v", err) 1171 } 1172 } 1173 if !s.isCADisabled() { 1174 if s.CA, err = s.createIstioCA(caOpts); err != nil { 1175 return fmt.Errorf("failed to create CA: %v", err) 1176 } 1177 } 1178 } 1179 return nil 1180 } 1181 1182 func (s *Server) shouldStartNsController() bool { 1183 if s.isCADisabled() { 1184 return true 1185 } 1186 if s.CA == nil { 1187 return false 1188 } 1189 1190 // For Kubernetes CA, we don't distribute it; it is mounted in all pods by Kubernetes. 1191 if features.PilotCertProvider == constants.CertProviderKubernetes { 1192 return false 1193 } 1194 // For no CA we don't distribute it either, as there is no cert 1195 if features.PilotCertProvider == constants.CertProviderNone { 1196 return false 1197 } 1198 1199 return true 1200 } 1201 1202 // StartCA starts the CA or RA server if configured. 1203 func (s *Server) startCA(caOpts *caOptions) { 1204 if s.CA == nil && s.RA == nil { 1205 return 1206 } 1207 // init the RA server if configured, else start init CA server 1208 if s.RA != nil { 1209 log.Infof("initializing CA server with RA") 1210 s.initCAServer(s.RA, caOpts) 1211 } else if s.CA != nil { 1212 log.Infof("initializing CA server with IstioD CA") 1213 s.initCAServer(s.CA, caOpts) 1214 } 1215 s.addStartFunc("ca", func(stop <-chan struct{}) error { 1216 grpcServer := s.secureGrpcServer 1217 if s.secureGrpcServer == nil { 1218 grpcServer = s.grpcServer 1219 } 1220 log.Infof("starting CA server") 1221 s.RunCA(grpcServer) 1222 return nil 1223 }) 1224 } 1225 1226 // initMeshHandlers initializes mesh and network handlers. 1227 func (s *Server) initMeshHandlers(changeHandler func(_ *meshconfig.MeshConfig)) { 1228 log.Info("initializing mesh handlers") 1229 // When the mesh config or networks change, do a full push. 1230 s.environment.AddMeshHandler(func() { 1231 spiffe.SetTrustDomain(s.environment.Mesh().GetTrustDomain()) 1232 changeHandler(s.environment.Mesh()) 1233 s.XDSServer.ConfigUpdate(&model.PushRequest{ 1234 Full: true, 1235 Reason: model.NewReasonStats(model.GlobalUpdate), 1236 }) 1237 }) 1238 } 1239 1240 func (s *Server) addIstioCAToTrustBundle(args *PilotArgs) error { 1241 var err error 1242 if s.CA != nil { 1243 // If IstioCA is setup, derive trustAnchor directly from CA 1244 rootCerts := []string{string(s.CA.GetCAKeyCertBundle().GetRootCertPem())} 1245 err = s.workloadTrustBundle.UpdateTrustAnchor(&tb.TrustAnchorUpdate{ 1246 TrustAnchorConfig: tb.TrustAnchorConfig{Certs: rootCerts}, 1247 Source: tb.SourceIstioCA, 1248 }) 1249 if err != nil { 1250 log.Errorf("unable to add CA root from namespace %s as trustAnchor", args.Namespace) 1251 return err 1252 } 1253 return nil 1254 } 1255 return nil 1256 } 1257 1258 func (s *Server) initWorkloadTrustBundle(args *PilotArgs) error { 1259 var err error 1260 1261 if !features.MultiRootMesh { 1262 return nil 1263 } 1264 1265 s.workloadTrustBundle.UpdateCb(func() { 1266 pushReq := &model.PushRequest{ 1267 Full: true, 1268 Reason: model.NewReasonStats(model.GlobalUpdate), 1269 } 1270 s.XDSServer.ConfigUpdate(pushReq) 1271 }) 1272 1273 s.addStartFunc("remote trust anchors", func(stop <-chan struct{}) error { 1274 go s.workloadTrustBundle.ProcessRemoteTrustAnchors(stop, tb.RemoteDefaultPollPeriod) 1275 return nil 1276 }) 1277 1278 // MeshConfig: Add initial roots 1279 err = s.workloadTrustBundle.AddMeshConfigUpdate(s.environment.Mesh()) 1280 if err != nil { 1281 return err 1282 } 1283 1284 // MeshConfig:Add callback for mesh config update 1285 s.environment.AddMeshHandler(func() { 1286 _ = s.workloadTrustBundle.AddMeshConfigUpdate(s.environment.Mesh()) 1287 }) 1288 1289 err = s.addIstioCAToTrustBundle(args) 1290 if err != nil { 1291 return err 1292 } 1293 1294 // IstioRA: Explicitly add roots corresponding to RA 1295 if s.RA != nil { 1296 // Implicitly add the Istio RA certificates to the Workload Trust Bundle 1297 rootCerts := []string{string(s.RA.GetCAKeyCertBundle().GetRootCertPem())} 1298 err = s.workloadTrustBundle.UpdateTrustAnchor(&tb.TrustAnchorUpdate{ 1299 TrustAnchorConfig: tb.TrustAnchorConfig{Certs: rootCerts}, 1300 Source: tb.SourceIstioRA, 1301 }) 1302 if err != nil { 1303 log.Errorf("fatal: unable to add RA root as trustAnchor") 1304 return err 1305 } 1306 } 1307 log.Infof("done initializing workload trustBundle") 1308 return nil 1309 } 1310 1311 // isCADisabled returns whether CA functionality is disabled in istiod. 1312 // It returns true only if istiod certs is signed by Kubernetes or 1313 // workload certs are signed by external CA 1314 func (s *Server) isCADisabled() bool { 1315 if s.RA == nil { 1316 return false 1317 } 1318 // do not create CA server if PilotCertProvider is `kubernetes` and RA server exists 1319 if features.PilotCertProvider == constants.CertProviderKubernetes { 1320 return true 1321 } 1322 // do not create CA server if PilotCertProvider is `k8s.io/*` and RA server exists 1323 if strings.HasPrefix(features.PilotCertProvider, constants.CertProviderKubernetesSignerPrefix) { 1324 return true 1325 } 1326 return false 1327 } 1328 1329 func (s *Server) initStatusManager(_ *PilotArgs) { 1330 s.addStartFunc("status manager", func(stop <-chan struct{}) error { 1331 s.statusManager = status.NewManager(s.RWConfigStore) 1332 s.statusManager.Start(stop) 1333 return nil 1334 }) 1335 } 1336 1337 func (s *Server) serveHTTP() error { 1338 // At this point we are ready - start Http Listener so that it can respond to readiness events. 1339 httpListener, err := net.Listen("tcp", s.httpServer.Addr) 1340 if err != nil { 1341 return err 1342 } 1343 go func() { 1344 log.Infof("starting HTTP service at %s", httpListener.Addr()) 1345 if err := s.httpServer.Serve(httpListener); network.IsUnexpectedListenerError(err) { 1346 log.Errorf("error serving http server: %v", err) 1347 } 1348 }() 1349 s.httpAddr = httpListener.Addr().String() 1350 return nil 1351 } 1352 1353 func (s *Server) initReadinessProbes() { 1354 probes := map[string]readinessProbe{ 1355 "discovery": func() bool { 1356 return s.XDSServer.IsServerReady() 1357 }, 1358 "sidecar injector": func() bool { 1359 return s.readinessFlags.sidecarInjectorReady.Load() 1360 }, 1361 "config validation": func() bool { 1362 return s.readinessFlags.configValidationReady.Load() 1363 }, 1364 } 1365 for name, probe := range probes { 1366 s.addReadinessProbe(name, probe) 1367 } 1368 }