Files
netbird-kubeapi-proxy/main.go
Philip Laine 080f00d090 Refactor proxy to use upgrade handler and add specific path handlers
This fixes issues with streaming requests and also makes sure that only specific paths are forwarded to the API server.
2026-06-15 13:24:45 +02:00

122 lines
3.0 KiB
Go

// SPDX-License-Identifier: AGPL-3.0
package main
import (
"context"
"errors"
"flag"
"io"
"log/slog"
"net/http"
"net/url"
"os"
"os/signal"
"syscall"
"golang.org/x/sync/errgroup"
"github.com/netbirdio/netbird/client/cmd"
"github.com/netbirdio/netbird/client/embed"
netbird "github.com/netbirdio/netbird/shared/management/client/rest"
"github.com/netbirdio/netbird-kubeapi-proxy/internal/proxy"
)
func main() {
var (
mgmtURL string
apiKey string
setupKey string
kubeAPIServer string
instanceName string
clusterName string
)
flag.StringVar(&mgmtURL, "management-url", "https://api.netbird.io", "NetBird management URL")
flag.StringVar(&apiKey, "api-key", "", "NetBird API key")
flag.StringVar(&setupKey, "setup-key", "", "NetBird setup key")
flag.StringVar(&kubeAPIServer, "kubernetes-api-server", "https://kubernetes.default.svc.cluster.local", "Target Kubernetes API server URL")
flag.StringVar(&instanceName, "instance-name", "", "Name of the instance")
flag.StringVar(&clusterName, "cluster-name", "", "Name of the cluster")
flag.Parse()
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
AddSource: true,
}))
slog.SetDefault(logger)
err := run(context.Background(), kubeAPIServer, mgmtURL, apiKey, setupKey, instanceName, clusterName)
if err != nil {
slog.Default().Error("exit due to error", "error", err)
os.Exit(1)
}
}
func run(ctx context.Context, kubeAPIServer, mgmtURL, apiKey, setupKey, instanceName, clusterName string) error {
ctx, cancel := signal.NotifyContext(ctx, syscall.SIGTERM)
defer cancel()
g, gCtx := errgroup.WithContext(ctx)
kubeAPIServerURL, err := url.Parse(kubeAPIServer)
if err != nil {
return err
}
if kubeAPIServerURL.Scheme != "https" || kubeAPIServerURL.Host == "" {
return errors.New("kubernetes-api-server must be an absolute https URL")
}
netbirdClient := netbird.NewWithOptions(
netbird.WithManagementURL(mgmtURL),
netbird.WithBearerToken(apiKey),
)
opts := embed.Options{
ManagementURL: mgmtURL,
SetupKey: setupKey,
DeviceName: instanceName,
LogOutput: io.Discard,
DNSLabels: []string{clusterName + "." + cmd.KubernetesDNSSuffix},
}
embedClient, err := embed.New(opts)
if err != nil {
return err
}
err = embedClient.Start(ctx)
if err != nil {
return err
}
g.Go(func() error {
<-gCtx.Done()
return embedClient.Stop(context.Background())
})
peerStore := proxy.NewPeerStore(netbirdClient.Peers)
proxySrv, err := proxy.Server(embedClient, peerStore, kubeAPIServerURL)
if err != nil {
return err
}
listener, err := embedClient.ListenTCP(":443")
if err != nil {
return err
}
g.Go(func() error {
err := proxySrv.ServeTLS(listener, "", "")
if err != nil && !errors.Is(err, http.ErrServerClosed) {
return err
}
return nil
})
g.Go(func() error {
<-gCtx.Done()
return proxySrv.Shutdown(context.Background())
})
slog.Default().Info("running API server proxy")
err = g.Wait()
if err != nil {
return err
}
return nil
}