Browse Source

refactor(v2): share provider runtime and harden exec

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
Moritz Johner 2 months ago
parent
commit
0d9a857cdc

+ 26 - 8
e2e/framework/addon/chart.go

@@ -20,7 +20,6 @@ import (
 	"bytes"
 	"fmt"
 	"os"
-	"os/exec"
 	"path/filepath"
 	"strings"
 
@@ -29,6 +28,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/external-secrets/external-secrets-e2e/framework/log"
+	frameworkutil "github.com/external-secrets/external-secrets-e2e/framework/util"
 )
 
 // HelmChart installs the specified Chart into the cluster.
@@ -69,7 +69,10 @@ func (c *HelmChart) Install() error {
 			"dependency", "update", filepath.Join(AssetDir(), "deploy/charts/external-secrets"),
 		}
 		log.Logf("updating chart dependencies with args: %+q", args)
-		cmd := exec.Command("helm", args...)
+		cmd, err := frameworkutil.Command("helm", args...)
+		if err != nil {
+			return fmt.Errorf("resolve helm executable: %w", err)
+		}
 		output, err := cmd.CombinedOutput()
 		if err != nil {
 			return fmt.Errorf("unable to run update cmd: %w: %s", err, string(output))
@@ -143,12 +146,18 @@ func (c *HelmChart) uninstallArgs() []string {
 
 func (c *HelmChart) runInstall(args []string) ([]byte, error) {
 	log.Logf("installing chart with args: %+q", args)
-	cmd := exec.Command("helm", args...)
+	cmd, err := frameworkutil.Command("helm", args...)
+	if err != nil {
+		return nil, fmt.Errorf("resolve helm executable: %w", err)
+	}
 	return cmd.CombinedOutput()
 }
 
 func (c *HelmChart) cleanupExistingRelease() error {
-	cmd := exec.Command("helm", c.uninstallArgs()...)
+	cmd, err := frameworkutil.Command("helm", c.uninstallArgs()...)
+	if err != nil {
+		return fmt.Errorf("resolve helm executable: %w", err)
+	}
 	output, err := cmd.CombinedOutput()
 	if err != nil && !strings.Contains(string(output), "release: not found") {
 		return fmt.Errorf("unable to uninstall stale helm release: %w: %s", err, string(output))
@@ -162,7 +171,10 @@ func isHelmReleaseNameInUseError(output string) bool {
 
 // Uninstall removes the chart aswell as the repo.
 func (c *HelmChart) Uninstall() error {
-	cmd := exec.Command("helm", c.uninstallArgs()...)
+	cmd, err := frameworkutil.Command("helm", c.uninstallArgs()...)
+	if err != nil {
+		return fmt.Errorf("resolve helm executable: %w", err)
+	}
 	output, err := cmd.CombinedOutput()
 	if err != nil {
 		return fmt.Errorf("unable to uninstall helm release: %w: %s", err, string(output))
@@ -176,10 +188,13 @@ func (c *HelmChart) addRepo() error {
 	}
 	var sout, serr bytes.Buffer
 	args := []string{"repo", "add", c.Repo.Name, c.Repo.URL}
-	cmd := exec.Command("helm", args...)
+	cmd, err := frameworkutil.Command("helm", args...)
+	if err != nil {
+		return fmt.Errorf("resolve helm executable: %w", err)
+	}
 	cmd.Stdout = &sout
 	cmd.Stderr = &serr
-	err := cmd.Run()
+	err = cmd.Run()
 	if err != nil {
 		return fmt.Errorf("unable to add helm repo: %w: %s, %s", err, sout.String(), serr.String())
 	}
@@ -192,7 +207,10 @@ func (c *HelmChart) removeRepo() error {
 	}
 
 	args := []string{"repo", "remove", c.Repo.Name}
-	cmd := exec.Command("helm", args...)
+	cmd, err := frameworkutil.Command("helm", args...)
+	if err != nil {
+		return fmt.Errorf("resolve helm executable: %w", err)
+	}
 	output, err := cmd.CombinedOutput()
 	if err != nil {
 		return fmt.Errorf("unable to remove repo: %w: %s", err, string(output))

+ 10 - 4
e2e/framework/addon/helmserver.go

@@ -20,13 +20,14 @@ import (
 	"fmt"
 	"net/http"
 	"os"
-	"os/exec"
 
 	. "github.com/onsi/ginkgo/v2"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+
+	frameworkutil "github.com/external-secrets/external-secrets-e2e/framework/util"
 )
 
 type HelmServer struct {
@@ -48,15 +49,20 @@ func (s *HelmServer) Setup(config *Config) error {
 		return err
 	}
 
-	// nolint:gosec
-	cmd := exec.Command("helm", "package", s.ChartDir, "--version", s.ChartRevision)
+	cmd, err := frameworkutil.Command("helm", "package", s.ChartDir, "--version", s.ChartRevision)
+	if err != nil {
+		return fmt.Errorf("resolve helm executable: %w", err)
+	}
 	cmd.Dir = s.serveDir
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		return fmt.Errorf("unable to package helm chart: %w %s", err, string(out))
 	}
 
-	cmd = exec.Command("helm", "repo", "index", ".")
+	cmd, err = frameworkutil.Command("helm", "repo", "index", ".")
+	if err != nil {
+		return fmt.Errorf("resolve helm executable: %w", err)
+	}
 	cmd.Dir = s.serveDir
 	out, err = cmd.CombinedOutput()
 	if err != nil {

+ 34 - 0
e2e/framework/util/executil.go

@@ -0,0 +1,34 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package util
+
+import (
+	"fmt"
+	"os/exec"
+
+	"golang.org/x/sys/execabs"
+)
+
+// Command resolves an executable to an absolute path before constructing the command.
+func Command(name string, args ...string) (*exec.Cmd, error) {
+	path, err := execabs.LookPath(name)
+	if err != nil {
+		return nil, fmt.Errorf("find executable %q: %w", name, err)
+	}
+
+	return execabs.Command(path, args...), nil
+}

+ 34 - 0
e2e/framework/util/executil_test.go

@@ -0,0 +1,34 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package util
+
+import (
+	"path/filepath"
+	"testing"
+)
+
+func TestCommandResolvesExecutableToAbsolutePath(t *testing.T) {
+	t.Parallel()
+
+	cmd, err := Command("sh", "-c", "exit 0")
+	if err != nil {
+		t.Fatalf("Command returned error: %v", err)
+	}
+	if !filepath.IsAbs(cmd.Path) {
+		t.Fatalf("expected absolute executable path, got %q", cmd.Path)
+	}
+}

+ 6 - 2
e2e/makefile_test.go

@@ -18,9 +18,10 @@ package e2e
 
 import (
 	"os"
-	"os/exec"
 	"strings"
 	"testing"
+
+	frameworkutil "github.com/external-secrets/external-secrets-e2e/framework/util"
 )
 
 const (
@@ -110,7 +111,10 @@ func runMakeDryRun(t *testing.T, target string, extraArgs ...string) string {
 	t.Helper()
 
 	args := append([]string{"-n", target}, extraArgs...)
-	cmd := exec.Command("make", args...)
+	cmd, err := frameworkutil.Command("make", args...)
+	if err != nil {
+		t.Fatalf("resolve make: %v", err)
+	}
 	cmd.Dir = "."
 	cmd.Env = os.Environ()
 

+ 5 - 3
e2e/suites/flux/install.go

@@ -19,7 +19,6 @@ package flux
 import (
 	"fmt"
 	"os"
-	"os/exec"
 	"path/filepath"
 
 	// nolint
@@ -29,6 +28,7 @@ import (
 	. "github.com/onsi/gomega"
 
 	"github.com/external-secrets/external-secrets-e2e/framework/addon"
+	frameworkutil "github.com/external-secrets/external-secrets-e2e/framework/util"
 )
 
 const (
@@ -38,14 +38,16 @@ const (
 
 func installFlux() {
 	By("installing flux")
-	cmd := exec.Command("kubectl", "apply", "-f", fluxManifests)
+	cmd, err := frameworkutil.Command("kubectl", "apply", "-f", fluxManifests)
+	Expect(err).ToNot(HaveOccurred())
 	out, err := cmd.CombinedOutput()
 	Expect(err).ToNot(HaveOccurred(), string(out))
 }
 
 func uninstallFlux() {
 	By("uninstalling flux")
-	cmd := exec.Command("kubectl", "delete", "-f", fluxManifests)
+	cmd, err := frameworkutil.Command("kubectl", "delete", "-f", fluxManifests)
+	Expect(err).ToNot(HaveOccurred())
 	out, err := cmd.CombinedOutput()
 	Expect(err).ToNot(HaveOccurred(), string(out))
 }

+ 6 - 2
hack/api-docs/makefile_test.go

@@ -18,15 +18,19 @@ package apidocs
 
 import (
 	"os"
-	"os/exec"
 	"strings"
 	"testing"
+
+	"github.com/external-secrets/external-secrets/pkg/executil"
 )
 
 func TestImageTargetForwardsDockerBuildArgs(t *testing.T) {
 	t.Parallel()
 
-	cmd := exec.Command("make", "-n", "image", `DOCKER_BUILD_ARGS=--network host`)
+	cmd, err := executil.Command("make", "-n", "image", `DOCKER_BUILD_ARGS=--network host`)
+	if err != nil {
+		t.Fatalf("resolve make: %v", err)
+	}
 	cmd.Dir = "."
 	cmd.Env = os.Environ()
 

+ 6 - 2
hack/helm_dependency_ensure_test.go

@@ -19,9 +19,10 @@ package hack
 import (
 	"fmt"
 	"os"
-	"os/exec"
 	"path/filepath"
 	"testing"
+
+	"github.com/external-secrets/external-secrets/pkg/executil"
 )
 
 const (
@@ -89,7 +90,10 @@ func writeFakeHelm(t *testing.T, dir, content string) string {
 func runHelper(t *testing.T, fakeHelm string) ([]byte, error) {
 	t.Helper()
 
-	cmd := exec.Command("bash", helperScriptPath, chartPath)
+	cmd, err := executil.Command("bash", helperScriptPath, chartPath)
+	if err != nil {
+		return nil, err
+	}
 	cmd.Dir = "."
 	cmd.Env = append(os.Environ(), helmBinEnvPrefix+fakeHelm)
 

+ 10 - 3
makefile_test.go

@@ -18,15 +18,19 @@ package main_test
 
 import (
 	"os"
-	"os/exec"
 	"strings"
 	"testing"
+
+	"github.com/external-secrets/external-secrets/pkg/executil"
 )
 
 func TestHelmDocsTargetCanUseLocalCommand(t *testing.T) {
 	t.Parallel()
 
-	cmd := exec.Command("make", "-n", "helm.docs", "HELM_DOCS_CMD=helm-docs")
+	cmd, err := executil.Command("make", "-n", "helm.docs", "HELM_DOCS_CMD=helm-docs")
+	if err != nil {
+		t.Fatalf("resolve make: %v", err)
+	}
 	cmd.Dir = "."
 	cmd.Env = os.Environ()
 
@@ -43,7 +47,10 @@ func TestHelmDocsTargetCanUseLocalCommand(t *testing.T) {
 func TestLicenseCheckTargetCanUseLocalCommand(t *testing.T) {
 	t.Parallel()
 
-	cmd := exec.Command("make", "-n", "license.check", "LICENSE_CHECK_CMD=license-eye header check")
+	cmd, err := executil.Command("make", "-n", "license.check", "LICENSE_CHECK_CMD=license-eye header check")
+	if err != nil {
+		t.Fatalf("resolve make: %v", err)
+	}
 	cmd.Dir = "."
 	cmd.Env = os.Environ()
 

+ 34 - 0
pkg/executil/executil.go

@@ -0,0 +1,34 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package executil
+
+import (
+	"fmt"
+	"os/exec"
+
+	"golang.org/x/sys/execabs"
+)
+
+// Command resolves an executable to an absolute path before constructing the command.
+func Command(name string, args ...string) (*exec.Cmd, error) {
+	path, err := execabs.LookPath(name)
+	if err != nil {
+		return nil, fmt.Errorf("find executable %q: %w", name, err)
+	}
+
+	return execabs.Command(path, args...), nil
+}

+ 42 - 0
pkg/executil/executil_test.go

@@ -0,0 +1,42 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package executil
+
+import (
+	"path/filepath"
+	"testing"
+)
+
+func TestCommandResolvesExecutableToAbsolutePath(t *testing.T) {
+	t.Parallel()
+
+	cmd, err := Command("sh", "-c", "exit 0")
+	if err != nil {
+		t.Fatalf("Command returned error: %v", err)
+	}
+	if !filepath.IsAbs(cmd.Path) {
+		t.Fatalf("expected absolute executable path, got %q", cmd.Path)
+	}
+}
+
+func TestCommandReturnsErrorForMissingExecutable(t *testing.T) {
+	t.Parallel()
+
+	if _, err := Command("external-secrets-definitely-missing-command"); err == nil {
+		t.Fatal("expected missing executable to return an error")
+	}
+}

+ 12 - 62
providers/v2/aws/main.go

@@ -19,14 +19,8 @@ limitations under the License.
 package main
 
 import (
-	"context"
 	"flag"
-	"fmt"
 	"log"
-	"net"
-	"os"
-	"os/signal"
-	"syscall"
 
 	genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
 	awsv2alpha1 "github.com/external-secrets/external-secrets/apis/provider/aws/v2alpha1"
@@ -38,9 +32,7 @@ import (
 	generator "github.com/external-secrets/external-secrets/providers/v2/aws/generator"
 	store "github.com/external-secrets/external-secrets/providers/v2/aws/store"
 	grpcserver "github.com/external-secrets/external-secrets/providers/v2/common/grpc/server"
-	"google.golang.org/grpc/health"
-	"google.golang.org/grpc/health/grpc_health_v1"
-	"google.golang.org/grpc/reflection"
+	"google.golang.org/grpc"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
@@ -107,58 +99,16 @@ func main() {
 	adapterServer := adapter.NewServer(kubeClient, scheme, providerMapping, specMapper, generatorMapping)
 
 	log.Printf("[PROVIDER] Using v1 AWS Provider provider with generators wrapped with v2 adapter")
-	grpcServer, err := grpcserver.NewGRPCServer(grpcserver.ServerOptions{
-		EnableTLS: *enableTLS,
-		Verbose:   *verbose,
-	})
-	if err != nil {
-		log.Fatalf("Failed to create gRPC server: %v", err)
-	}
-
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
-
-	metricsServer := grpcserver.NewMetricsServer(grpcserver.DefaultMetricsPort, nil)
-	if err := grpcserver.RegisterMetrics(metricsServer.GetRegistry()); err != nil {
-		log.Fatalf("Failed to register provider metrics: %v", err)
-	}
-	go func() {
-		if err := metricsServer.Start(ctx); err != nil {
-			log.Fatalf("Failed to start provider metrics server: %v", err)
-		}
-	}()
-
-	// Register services
-	pb.RegisterSecretStoreProviderServer(grpcServer, adapterServer)
-	genpb.RegisterGeneratorProviderServer(grpcServer, adapterServer)
-
-	// Register health service
-	healthServer := health.NewServer()
-	grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)
-	healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING)
-
-	// Register reflection service for debugging
-	reflection.Register(grpcServer)
-
-	// Start listening
-	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
-	if err != nil {
-		log.Fatalf("Failed to listen: %v", err)
-	}
-
-	// Handle graceful shutdown
-	go func() {
-		sigChan := make(chan os.Signal, 1)
-		signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
-		sig := <-sigChan
-		log.Printf("Received signal: %v, shutting down gracefully...", sig)
-		cancel()
-		grpcServer.GracefulStop()
-	}()
-
-	// Start serving
-	log.Printf("AWS Provider Provider listening on %s", lis.Addr().String())
-	if err := grpcServer.Serve(lis); err != nil {
-		log.Fatalf("Failed to serve: %v", err)
+	if err := grpcserver.RunProviderServer(grpcserver.RuntimeOptions{
+		ProviderName: "AWS Provider",
+		Port:         *port,
+		EnableTLS:    *enableTLS,
+		Verbose:      *verbose,
+		Register: func(registrar grpc.ServiceRegistrar) {
+			pb.RegisterSecretStoreProviderServer(registrar, adapterServer)
+			genpb.RegisterGeneratorProviderServer(registrar, adapterServer)
+		},
+	}); err != nil {
+		log.Fatalf("Failed to run provider server: %v", err)
 	}
 }

+ 95 - 0
providers/v2/common/grpc/server/runtime.go

@@ -0,0 +1,95 @@
+/*
+Copyright © The ESO Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package server
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"net"
+	"os"
+	"os/signal"
+	"syscall"
+
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/health"
+	"google.golang.org/grpc/health/grpc_health_v1"
+	"google.golang.org/grpc/reflection"
+)
+
+// RuntimeOptions configures a provider gRPC server instance.
+type RuntimeOptions struct {
+	ProviderName string
+	Port         int
+	EnableTLS    bool
+	Verbose      bool
+	Register     func(grpc.ServiceRegistrar)
+}
+
+// RunProviderServer starts the provider gRPC and metrics servers with standard wiring.
+func RunProviderServer(opts RuntimeOptions) error {
+	grpcServer, err := NewGRPCServer(Options{
+		EnableTLS: opts.EnableTLS,
+		Verbose:   opts.Verbose,
+	})
+	if err != nil {
+		return fmt.Errorf("create gRPC server: %w", err)
+	}
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	metricsServer := NewMetricsServer(DefaultMetricsPort, nil)
+	if err := RegisterMetrics(metricsServer.GetRegistry()); err != nil {
+		return fmt.Errorf("register provider metrics: %w", err)
+	}
+	go func() {
+		if err := metricsServer.Start(ctx); err != nil {
+			log.Fatalf("Failed to start provider metrics server: %v", err)
+		}
+	}()
+
+	if opts.Register != nil {
+		opts.Register(grpcServer)
+	}
+
+	healthServer := health.NewServer()
+	grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)
+	healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING)
+	reflection.Register(grpcServer)
+
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", opts.Port))
+	if err != nil {
+		return fmt.Errorf("listen: %w", err)
+	}
+
+	go func() {
+		sigChan := make(chan os.Signal, 1)
+		signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
+		sig := <-sigChan
+		log.Printf("Received signal: %v, shutting down gracefully...", sig)
+		cancel()
+		grpcServer.GracefulStop()
+	}()
+
+	log.Printf("%s Provider listening on %s", opts.ProviderName, lis.Addr().String())
+	if err := grpcServer.Serve(lis); err != nil {
+		return fmt.Errorf("serve: %w", err)
+	}
+
+	return nil
+}

+ 12 - 62
providers/v2/fake/main.go

@@ -19,14 +19,8 @@ limitations under the License.
 package main
 
 import (
-	"context"
 	"flag"
-	"fmt"
 	"log"
-	"net"
-	"os"
-	"os/signal"
-	"syscall"
 
 	genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
 	fakev2alpha1 "github.com/external-secrets/external-secrets/apis/provider/fake/v2alpha1"
@@ -38,9 +32,7 @@ import (
 	grpcserver "github.com/external-secrets/external-secrets/providers/v2/common/grpc/server"
 	generator "github.com/external-secrets/external-secrets/providers/v2/fake/generator"
 	store "github.com/external-secrets/external-secrets/providers/v2/fake/store"
-	"google.golang.org/grpc/health"
-	"google.golang.org/grpc/health/grpc_health_v1"
-	"google.golang.org/grpc/reflection"
+	"google.golang.org/grpc"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
@@ -96,58 +88,16 @@ func main() {
 	adapterServer := adapter.NewServer(kubeClient, scheme, providerMapping, specMapper, generatorMapping)
 
 	log.Printf("[PROVIDER] Using v1 Fake Provider provider with generators wrapped with v2 adapter")
-	grpcServer, err := grpcserver.NewGRPCServer(grpcserver.ServerOptions{
-		EnableTLS: *enableTLS,
-		Verbose:   *verbose,
-	})
-	if err != nil {
-		log.Fatalf("Failed to create gRPC server: %v", err)
-	}
-
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
-
-	metricsServer := grpcserver.NewMetricsServer(grpcserver.DefaultMetricsPort, nil)
-	if err := grpcserver.RegisterMetrics(metricsServer.GetRegistry()); err != nil {
-		log.Fatalf("Failed to register provider metrics: %v", err)
-	}
-	go func() {
-		if err := metricsServer.Start(ctx); err != nil {
-			log.Fatalf("Failed to start provider metrics server: %v", err)
-		}
-	}()
-
-	// Register services
-	pb.RegisterSecretStoreProviderServer(grpcServer, adapterServer)
-	genpb.RegisterGeneratorProviderServer(grpcServer, adapterServer)
-
-	// Register health service
-	healthServer := health.NewServer()
-	grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)
-	healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING)
-
-	// Register reflection service for debugging
-	reflection.Register(grpcServer)
-
-	// Start listening
-	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
-	if err != nil {
-		log.Fatalf("Failed to listen: %v", err)
-	}
-
-	// Handle graceful shutdown
-	go func() {
-		sigChan := make(chan os.Signal, 1)
-		signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
-		sig := <-sigChan
-		log.Printf("Received signal: %v, shutting down gracefully...", sig)
-		cancel()
-		grpcServer.GracefulStop()
-	}()
-
-	// Start serving
-	log.Printf("Fake Provider Provider listening on %s", lis.Addr().String())
-	if err := grpcServer.Serve(lis); err != nil {
-		log.Fatalf("Failed to serve: %v", err)
+	if err := grpcserver.RunProviderServer(grpcserver.RuntimeOptions{
+		ProviderName: "Fake Provider",
+		Port:         *port,
+		EnableTLS:    *enableTLS,
+		Verbose:      *verbose,
+		Register: func(registrar grpc.ServiceRegistrar) {
+			pb.RegisterSecretStoreProviderServer(registrar, adapterServer)
+			genpb.RegisterGeneratorProviderServer(registrar, adapterServer)
+		},
+	}); err != nil {
+		log.Fatalf("Failed to run provider server: %v", err)
 	}
 }

+ 4 - 25
providers/v2/hack/generate-provider-main.go

@@ -23,9 +23,9 @@ import (
 	"encoding/json"
 	"flag"
 	"fmt"
+	"go/format"
 	"log"
 	"os"
-	"os/exec"
 	"path/filepath"
 	"strings"
 	"text/template"
@@ -371,31 +371,10 @@ func executeTemplate(tmpl *template.Template, data any) ([]byte, error) {
 }
 
 func formatGoCode(code []byte) ([]byte, error) {
-	// Try goimports first (better formatting)
-	cmd := exec.Command("goimports")
-	cmd.Stdin = bytes.NewReader(code)
-	var out bytes.Buffer
-	var stderr bytes.Buffer
-	cmd.Stdout = &out
-	cmd.Stderr = &stderr
-
-	err := cmd.Run()
-	if err == nil {
-		return out.Bytes(), nil
-	}
-
-	// Fallback to gofmt if goimports is not available
-	cmd = exec.Command("gofmt")
-	cmd.Stdin = bytes.NewReader(code)
-	out.Reset()
-	stderr.Reset()
-	cmd.Stdout = &out
-	cmd.Stderr = &stderr
-
-	err = cmd.Run()
+	formatted, err := format.Source(code)
 	if err != nil {
-		return nil, fmt.Errorf("gofmt failed: %w, stderr: %s", err, stderr.String())
+		return nil, fmt.Errorf("format Go code: %w", err)
 	}
 
-	return out.Bytes(), nil
+	return formatted, nil
 }

+ 4 - 10
providers/v2/hack/generate_provider_main_test.go

@@ -96,16 +96,10 @@ func TestMainTemplateStartsProviderMetricsServer(t *testing.T) {
 	}
 
 	renderedText := string(rendered)
-	if !strings.Contains(renderedText, "metricsServer := grpcserver.NewMetricsServer(") {
-		t.Fatalf("main template did not create provider metrics server:\n%s", renderedText)
+	if !strings.Contains(renderedText, "grpcserver.RunProviderServer(grpcserver.RuntimeOptions{") {
+		t.Fatalf("main template did not use the shared provider runtime:\n%s", renderedText)
 	}
-	if !strings.Contains(renderedText, "grpcserver.DefaultMetricsPort") {
-		t.Fatalf("main template did not use default provider metrics port:\n%s", renderedText)
-	}
-	if !strings.Contains(renderedText, "grpcserver.RegisterMetrics(metricsServer.GetRegistry())") {
-		t.Fatalf("main template did not register provider metrics:\n%s", renderedText)
-	}
-	if !strings.Contains(renderedText, "go func() {\n\t\tif err := metricsServer.Start(ctx); err != nil {") {
-		t.Fatalf("main template did not start provider metrics server:\n%s", renderedText)
+	if !strings.Contains(renderedText, "Register: func(registrar grpc.ServiceRegistrar)") {
+		t.Fatalf("main template did not register services through the shared provider runtime:\n%s", renderedText)
 	}
 }

+ 17 - 67
providers/v2/hack/templates/main.go.tmpl

@@ -19,18 +19,10 @@ limitations under the License.
 package main
 
 import (
-	"context"
 	"flag"
-	"fmt"
 	"log"
-	"net"
-	"os"
-	"os/signal"
-	"syscall"
-
-	"google.golang.org/grpc/health"
-	"google.golang.org/grpc/health/grpc_health_v1"
-	"google.golang.org/grpc/reflection"
+
+	"google.golang.org/grpc"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
@@ -138,62 +130,20 @@ func main() {
 	{{- end}}
 
 	log.Printf("[PROVIDER] Using v1 {{.Provider.Provider.DisplayName}} provider{{if .HasGenerators}} with generators{{end}} wrapped with v2 adapter")
-	grpcServer, err := grpcserver.NewGRPCServer(grpcserver.ServerOptions{
-		EnableTLS: *enableTLS,
-		Verbose:   *verbose,
-	})
-	if err != nil {
-		log.Fatalf("Failed to create gRPC server: %v", err)
-	}
-
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
-
-	metricsServer := grpcserver.NewMetricsServer(grpcserver.DefaultMetricsPort, nil)
-	if err := grpcserver.RegisterMetrics(metricsServer.GetRegistry()); err != nil {
-		log.Fatalf("Failed to register provider metrics: %v", err)
-	}
-	go func() {
-		if err := metricsServer.Start(ctx); err != nil {
-			log.Fatalf("Failed to start provider metrics server: %v", err)
-		}
-	}()
-
-	// Register services
-	{{- if .HasStores}}
-	pb.RegisterSecretStoreProviderServer(grpcServer, adapterServer)
-	{{- end}}
-	{{- if .HasGenerators}}
-	genpb.RegisterGeneratorProviderServer(grpcServer, adapterServer)
-	{{- end}}
-
-	// Register health service
-	healthServer := health.NewServer()
-	grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)
-	healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING)
-
-	// Register reflection service for debugging
-	reflection.Register(grpcServer)
-
-	// Start listening
-	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
-	if err != nil {
-		log.Fatalf("Failed to listen: %v", err)
-	}
-
-	// Handle graceful shutdown
-	go func() {
-		sigChan := make(chan os.Signal, 1)
-		signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
-		sig := <-sigChan
-		log.Printf("Received signal: %v, shutting down gracefully...", sig)
-		cancel()
-		grpcServer.GracefulStop()
-	}()
-
-	// Start serving
-	log.Printf("{{.Provider.Provider.DisplayName}} Provider listening on %s", lis.Addr().String())
-	if err := grpcServer.Serve(lis); err != nil {
-		log.Fatalf("Failed to serve: %v", err)
+	if err := grpcserver.RunProviderServer(grpcserver.RuntimeOptions{
+		ProviderName: "{{.Provider.Provider.DisplayName}}",
+		Port:         *port,
+		EnableTLS:    *enableTLS,
+		Verbose:      *verbose,
+		Register: func(registrar grpc.ServiceRegistrar) {
+			{{- if .HasStores}}
+			pb.RegisterSecretStoreProviderServer(registrar, adapterServer)
+			{{- end}}
+			{{- if .HasGenerators}}
+			genpb.RegisterGeneratorProviderServer(registrar, adapterServer)
+			{{- end}}
+		},
+	}); err != nil {
+		log.Fatalf("Failed to run provider server: %v", err)
 	}
 }

+ 11 - 61
providers/v2/kubernetes/main.go

@@ -19,23 +19,15 @@ limitations under the License.
 package main
 
 import (
-	"context"
 	"flag"
-	"fmt"
 	"log"
-	"net"
-	"os"
-	"os/signal"
-	"syscall"
 
 	kubernetesv2alpha1 "github.com/external-secrets/external-secrets/apis/provider/kubernetes/v2alpha1"
 	pb "github.com/external-secrets/external-secrets/proto/provider"
 	kubernetes "github.com/external-secrets/external-secrets/providers/v1/kubernetes"
 	adapterstore "github.com/external-secrets/external-secrets/providers/v2/adapter/store"
 	grpcserver "github.com/external-secrets/external-secrets/providers/v2/common/grpc/server"
-	"google.golang.org/grpc/health"
-	"google.golang.org/grpc/health/grpc_health_v1"
-	"google.golang.org/grpc/reflection"
+	"google.golang.org/grpc"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
@@ -82,57 +74,15 @@ func main() {
 	adapterServer := adapterstore.NewServer(kubeClient, providerMapping, specMapper)
 
 	log.Printf("[PROVIDER] Using v1 Kubernetes Provider provider wrapped with v2 adapter")
-	grpcServer, err := grpcserver.NewGRPCServer(grpcserver.ServerOptions{
-		EnableTLS: *enableTLS,
-		Verbose:   *verbose,
-	})
-	if err != nil {
-		log.Fatalf("Failed to create gRPC server: %v", err)
-	}
-
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
-
-	metricsServer := grpcserver.NewMetricsServer(grpcserver.DefaultMetricsPort, nil)
-	if err := grpcserver.RegisterMetrics(metricsServer.GetRegistry()); err != nil {
-		log.Fatalf("Failed to register provider metrics: %v", err)
-	}
-	go func() {
-		if err := metricsServer.Start(ctx); err != nil {
-			log.Fatalf("Failed to start provider metrics server: %v", err)
-		}
-	}()
-
-	// Register services
-	pb.RegisterSecretStoreProviderServer(grpcServer, adapterServer)
-
-	// Register health service
-	healthServer := health.NewServer()
-	grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)
-	healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING)
-
-	// Register reflection service for debugging
-	reflection.Register(grpcServer)
-
-	// Start listening
-	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
-	if err != nil {
-		log.Fatalf("Failed to listen: %v", err)
-	}
-
-	// Handle graceful shutdown
-	go func() {
-		sigChan := make(chan os.Signal, 1)
-		signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
-		sig := <-sigChan
-		log.Printf("Received signal: %v, shutting down gracefully...", sig)
-		cancel()
-		grpcServer.GracefulStop()
-	}()
-
-	// Start serving
-	log.Printf("Kubernetes Provider Provider listening on %s", lis.Addr().String())
-	if err := grpcServer.Serve(lis); err != nil {
-		log.Fatalf("Failed to serve: %v", err)
+	if err := grpcserver.RunProviderServer(grpcserver.RuntimeOptions{
+		ProviderName: "Kubernetes Provider",
+		Port:         *port,
+		EnableTLS:    *enableTLS,
+		Verbose:      *verbose,
+		Register: func(registrar grpc.ServiceRegistrar) {
+			pb.RegisterSecretStoreProviderServer(registrar, adapterServer)
+		},
+	}); err != nil {
+		log.Fatalf("Failed to run provider server: %v", err)
 	}
 }