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  }