diff --git a/cmd/discovery-service/main.go b/cmd/discovery-service/main.go index 9a97d77..e3df611 100644 --- a/cmd/discovery-service/main.go +++ b/cmd/discovery-service/main.go @@ -32,6 +32,7 @@ import ( "google.golang.org/grpc/status" "github.com/talos-systems/discovery-service/api/v1alpha1/server/pb" + "github.com/talos-systems/discovery-service/internal/landing" _ "github.com/talos-systems/discovery-service/internal/proto" "github.com/talos-systems/discovery-service/internal/state" "github.com/talos-systems/discovery-service/pkg/server" @@ -39,6 +40,7 @@ import ( var ( listenAddr = ":3000" + landingAddr = ":3001" metricsAddr = ":2122" debugAddr = ":2123" devMode = false @@ -47,6 +49,7 @@ var ( func init() { flag.StringVar(&listenAddr, "addr", listenAddr, "addr on which to listen") + flag.StringVar(&landingAddr, "landing-addr", landingAddr, "addr on which to listen for landing page") flag.StringVar(&metricsAddr, "metrics-addr", metricsAddr, "prometheus metrics listen addr") flag.BoolVar(&devMode, "debug", devMode, "enable debug mode") flag.DurationVar(&gcInterval, "gc-interval", gcInterval, "garbage collection interval") @@ -143,6 +146,11 @@ func run(ctx context.Context, logger *zap.Logger) error { return fmt.Errorf("failed to listen: %w", err) } + landingLis, err := net.Listen("tcp", landingAddr) + if err != nil { + return fmt.Errorf("failed to listen: %w", err) + } + s := grpc.NewServer(serverOptions...) pb.RegisterClusterServer(s, srv) @@ -160,6 +168,10 @@ func run(ctx context.Context, logger *zap.Logger) error { Handler: &metricsMux, } + landingServer := http.Server{ + Handler: landing.Handler(), + } + eg, ctx := errgroup.WithContext(ctx) eg.Go(func() error { @@ -172,6 +184,16 @@ func run(ctx context.Context, logger *zap.Logger) error { return nil }) + eg.Go(func() error { + logger.Info("landing server starting", zap.Stringer("address", landingLis.Addr())) + + if err := landingServer.Serve(landingLis); err != nil && !errors.Is(err, http.ErrServerClosed) { + return fmt.Errorf("failed to serve: %w", err) + } + + return nil + }) + eg.Go(func() error { logger.Info("metrics starting", zap.String("address", metricsServer.Addr)) @@ -189,6 +211,7 @@ func run(ctx context.Context, logger *zap.Logger) error { defer shutdownCancel() s.GracefulStop() + landingServer.Shutdown(ctx) //nolint:errcheck metricsServer.Shutdown(shutdownCtx) //nolint:errcheck return nil diff --git a/internal/landing/html/index.html b/internal/landing/html/index.html new file mode 100644 index 0000000..c4c2476 --- /dev/null +++ b/internal/landing/html/index.html @@ -0,0 +1,47 @@ + + + + Discovery Service + + +

What is this IP address?

+ +

This is the Kubernetes cluster Member Discovery Service run by Sidero Labs.

+ +

+ If you see traffic to this IP address, it is from Kubernetes nodes in your organization that are using KubeSpan to coordinate secure, encrypted membership of a Kubernetes cluster. + This service provides back information needed to establish the secure communication channels. +

+ +

+ All information to and from this service is encrypted, and the service cannot decrypt the data - only the nodes that are part of the same Kubernetes cluster can decrypt it. +

+ +

+ For more information, see https://www.siderolabs.com/kubespan/. +

+ +

Details

+ +

+ Before sending data to the discovery service, Talos will encrypt the affiliate data with AES-GCM encryption and + separately encrypt endpoints with AES in ECB mode so that endpoints coming from different sources can be deduplicated server-side. +

+ +

+ Each node submits it's data encrypted plus it submits the endpoints it sees from other peers to the discovery service. + The discovery service aggregates the data, deduplicates the endpoints, and sends updates to each connected peer. + Each peer receives information back about other affiliates from the discovery service, decrypts it and uses it to drive KubeSpan and cluster discovery. +

+ +

+ Moreover, the discovery service has no peristence. + Data is stored in memory only with a TTL set by the clients (i.e. Talos). + The cluster ID is used as a key to select the affiliates (so that different clusters see different affiliates). +

+ +

+ To summarize, the discovery service knows the client version, cluster ID, the number of affiliates, some encrypted data for each affiliate, and a list of encrypted endpoints. +

+ + diff --git a/internal/landing/landing.go b/internal/landing/landing.go new file mode 100644 index 0000000..a24b5e9 --- /dev/null +++ b/internal/landing/landing.go @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package landing provides the HTML landing page. +package landing + +import ( + "embed" + "io/fs" + "net/http" +) + +//go:embed "html/index.html" +var static embed.FS + +// Handler returns static landing page handler. +func Handler() http.Handler { + subfs, err := fs.Sub(static, "html") + if err != nil { + panic(err) + } + + mux := http.NewServeMux() + mux.Handle("/", http.FileServer(http.FS(subfs))) + + return mux +}