feat: implement landing page for the discovery service

Landing page is served on a different port for easier ingress
configuration.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
This commit is contained in:
Andrey Smirnov
2021-10-11 23:15:25 +03:00
parent b579076e4e
commit 95593b8685
3 changed files with 98 additions and 0 deletions

View File

@ -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

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<title>Discovery Service</title>
</head>
<body>
<h1>What is this IP address?</h1>
<p>This is the Kubernetes cluster Member Discovery Service run by <a href="https://www.siderolabs.com/kubespan/">Sidero Labs</a>.</p>
<p>
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.
</p>
<p>
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.
</p>
<p>
For more information, see <a href="https://www.siderolabs.com/kubespan/">https://www.siderolabs.com/kubespan/</a>.
</p>
<h2>Details</h2>
<p>
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.
</p>
<p>
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.
</p>
<p>
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).
</p>
<p>
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.
</p>
</body>
</html>

View File

@ -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
}