File 0002-Drop-zanzana.patch of Package grafana

commit c93b7a31c795c24c9ecde78a3d31c9479f913766
Author: Witek Bedyk <wbedyk@suse.com>
Date:   Mon Nov 24 12:23:48 2025 +0100

    Drop Zanzana
    
    Drop experimental authorization server/client implementation which is
    affected by CVE-2025-64751.

diff --git a/pkg/server/module_server.go b/pkg/server/module_server.go
index f20225cba5b..f65ead4ea88 100644
--- a/pkg/server/module_server.go
+++ b/pkg/server/module_server.go
@@ -13,7 +13,6 @@ import (
 	"github.com/grafana/grafana/pkg/api"
 	"github.com/grafana/grafana/pkg/infra/log"
 	"github.com/grafana/grafana/pkg/modules"
-	"github.com/grafana/grafana/pkg/services/authz"
 	"github.com/grafana/grafana/pkg/services/featuremgmt"
 	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/storage/unified/sql"
@@ -138,10 +137,6 @@ func (s *ModuleServer) Run() error {
 		return sql.ProvideUnifiedStorageGrpcService(s.cfg, s.features, nil, s.log, nil, docBuilders)
 	})
 
-	m.RegisterModule(modules.ZanzanaServer, func() (services.Service, error) {
-		return authz.ProvideZanzanaService(s.cfg, s.features)
-	})
-
 	m.RegisterModule(modules.All, nil)
 
 	return m.Run(s.context)
diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go
index 1cff4d1b04f..8d4817d6c4d 100644
--- a/pkg/server/wire_gen.go
+++ b/pkg/server/wire_gen.go
@@ -364,10 +364,6 @@ func Initialize(cfg *setting.Cfg, opts Options, apiOpts api.ServerOptions) (*Ser
 		return nil, err
 	}
 	actionSetService := resourcepermissions.NewActionSetService(featureToggles)
-	client, err := authz.ProvideZanzana(cfg, sqlStore, featureToggles)
-	if err != nil {
-		return nil, err
-	}
 	permissionRegistry := permreg.ProvidePermissionRegistry()
 	serverLockService := serverlock.ProvideService(sqlStore, tracingService)
 	folderStoreImpl := folderimpl.ProvideStore(sqlStore)
@@ -828,10 +824,6 @@ func InitializeForTest(t sqlutil.ITestDB, cfg *setting.Cfg, opts Options, apiOpt
 		return nil, err
 	}
 	actionSetService := resourcepermissions.NewActionSetService(featureToggles)
-	client, err := authz.ProvideZanzana(cfg, sqlStore, featureToggles)
-	if err != nil {
-		return nil, err
-	}
 	permissionRegistry := permreg.ProvidePermissionRegistry()
 	serverLockService := serverlock.ProvideService(sqlStore, tracingService)
 	folderStoreImpl := folderimpl.ProvideStore(sqlStore)
diff --git a/pkg/services/accesscontrol/acimpl/service.go b/pkg/services/accesscontrol/acimpl/service.go
index 3a13f94af69..50452912c37 100644
--- a/pkg/services/accesscontrol/acimpl/service.go
+++ b/pkg/services/accesscontrol/acimpl/service.go
@@ -25,11 +25,9 @@ import (
 	"github.com/grafana/grafana/pkg/services/accesscontrol"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/api"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/database"
-	"github.com/grafana/grafana/pkg/services/accesscontrol/dualwrite"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/migrator"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/permreg"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/pluginutils"
-	"github.com/grafana/grafana/pkg/services/authz/zanzana"
 	"github.com/grafana/grafana/pkg/services/dashboards"
 	"github.com/grafana/grafana/pkg/services/featuremgmt"
 	"github.com/grafana/grafana/pkg/services/folder"
@@ -54,7 +52,7 @@ var OSSRolesPrefixes = []string{accesscontrol.ManagedRolePrefix, accesscontrol.E
 func ProvideService(
 	cfg *setting.Cfg, db db.DB, routeRegister routing.RouteRegister, cache *localcache.CacheService,
 	accessControl accesscontrol.AccessControl, userService user.Service, actionResolver accesscontrol.ActionResolver,
-	features featuremgmt.FeatureToggles, tracer tracing.Tracer, zclient zanzana.Client, permRegistry permreg.PermissionRegistry,
+	features featuremgmt.FeatureToggles, tracer tracing.Tracer, permRegistry permreg.PermissionRegistry,
 	lock *serverlock.ServerLockService, folderService folder.Service,
 ) (*Service, error) {
 	service := ProvideOSSService(
@@ -64,7 +62,6 @@ func ProvideService(
 		cache,
 		features,
 		tracer,
-		zclient,
 		db,
 		permRegistry,
 		lock,
@@ -90,7 +87,7 @@ func ProvideService(
 func ProvideOSSService(
 	cfg *setting.Cfg, store accesscontrol.Store, actionResolver accesscontrol.ActionResolver,
 	cache *localcache.CacheService, features featuremgmt.FeatureToggles, tracer tracing.Tracer,
-	zclient zanzana.Client, db db.DB, permRegistry permreg.PermissionRegistry,
+	db db.DB, permRegistry permreg.PermissionRegistry,
 	lock *serverlock.ServerLockService, folderService folder.Service,
 ) *Service {
 	s := &Service{
@@ -101,7 +98,6 @@ func ProvideOSSService(
 		log:            log.New("accesscontrol.service"),
 		roles:          accesscontrol.BuildBasicRoleDefinitions(),
 		store:          store,
-		reconciler:     dualwrite.NewZanzanaReconciler(cfg, zclient, db, lock, folderService),
 		permRegistry:   permRegistry,
 	}
 
@@ -118,15 +114,11 @@ type Service struct {
 	registrations  accesscontrol.RegistrationList
 	roles          map[string]*accesscontrol.RoleDTO
 	store          accesscontrol.Store
-	reconciler     *dualwrite.ZanzanaReconciler
 	permRegistry   permreg.PermissionRegistry
 }
 
 // Run implements accesscontrol.Service.
 func (s *Service) Run(ctx context.Context) error {
-	if s.features.IsEnabledGlobally(featuremgmt.FlagZanzana) {
-		return s.reconciler.Reconcile(ctx)
-	}
 	return nil
 }
 
diff --git a/pkg/services/authz/wireset.go b/pkg/services/authz/wireset.go
index 4a46f15ea3b..f16235fa4b4 100644
--- a/pkg/services/authz/wireset.go
+++ b/pkg/services/authz/wireset.go
@@ -6,5 +6,4 @@ import (
 
 var WireSet = wire.NewSet(
 	ProvideAuthZClient,
-	ProvideZanzana,
 )
diff --git a/pkg/services/authz/zanzana.go b/pkg/services/authz/zanzana.go
deleted file mode 100644
index 6c1567ef469..00000000000
--- a/pkg/services/authz/zanzana.go
+++ /dev/null
@@ -1,264 +0,0 @@
-package authz
-
-import (
-	"context"
-	"errors"
-	"fmt"
-
-	"github.com/fullstorydev/grpchan/inprocgrpc"
-	authnlib "github.com/grafana/authlib/authn"
-	authzv1 "github.com/grafana/authlib/authz/proto/v1"
-	"github.com/grafana/authlib/claims"
-	"github.com/grafana/dskit/services"
-	grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
-	openfgav1 "github.com/openfga/api/proto/openfga/v1"
-	"github.com/prometheus/client_golang/prometheus"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/credentials/insecure"
-	"google.golang.org/grpc/metadata"
-
-	"github.com/grafana/grafana/pkg/infra/db"
-	"github.com/grafana/grafana/pkg/infra/log"
-	"github.com/grafana/grafana/pkg/infra/tracing"
-	authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
-	"github.com/grafana/grafana/pkg/services/authz/zanzana"
-	zclient "github.com/grafana/grafana/pkg/services/authz/zanzana/client"
-	zserver "github.com/grafana/grafana/pkg/services/authz/zanzana/server"
-	"github.com/grafana/grafana/pkg/services/featuremgmt"
-	"github.com/grafana/grafana/pkg/services/grpcserver"
-	"github.com/grafana/grafana/pkg/services/grpcserver/interceptors"
-	"github.com/grafana/grafana/pkg/setting"
-)
-
-const zanzanaAudience = "zanzana"
-
-// ProvideZanzana used to register ZanzanaClient.
-// It will also start an embedded ZanzanaSever if mode is set to "embedded".
-func ProvideZanzana(cfg *setting.Cfg, db db.DB, features featuremgmt.FeatureToggles) (zanzana.Client, error) {
-	if !features.IsEnabledGlobally(featuremgmt.FlagZanzana) {
-		return zclient.NewNoop(), nil
-	}
-
-	logger := log.New("zanzana")
-
-	var client zanzana.Client
-	switch cfg.Zanzana.Mode {
-	case setting.ZanzanaModeClient:
-		tokenClient, err := authnlib.NewTokenExchangeClient(authnlib.TokenExchangeConfig{
-			Token:            cfg.Zanzana.Token,
-			TokenExchangeURL: cfg.Zanzana.TokenExchangeURL,
-		})
-		if err != nil {
-			return nil, fmt.Errorf("failed to initialize token exchange client: %w", err)
-		}
-
-		if cfg.StackID == "" {
-			return nil, fmt.Errorf("missing stack ID")
-		}
-		namespace := fmt.Sprintf("stacks-%s", cfg.StackID)
-
-		tokenAuthCred := &tokenAuth{
-			cfg:         cfg,
-			namespace:   namespace,
-			tokenClient: tokenClient,
-		}
-
-		dialOptions := []grpc.DialOption{
-			// TODO: add TLS support
-			grpc.WithTransportCredentials(insecure.NewCredentials()),
-			grpc.WithPerRPCCredentials(tokenAuthCred),
-		}
-
-		conn, err := grpc.NewClient(cfg.Zanzana.Addr, dialOptions...)
-		if err != nil {
-			return nil, fmt.Errorf("failed to create zanzana client to remote server: %w", err)
-		}
-
-		client, err = zclient.NewClient(context.Background(), conn, cfg)
-		if err != nil {
-			return nil, fmt.Errorf("failed to initialize zanzana client: %w", err)
-		}
-	case setting.ZanzanaModeEmbedded:
-		store, err := zanzana.NewEmbeddedStore(cfg, db, logger)
-		if err != nil {
-			return nil, fmt.Errorf("failed to start zanzana: %w", err)
-		}
-
-		openfga, err := zserver.NewOpenFGA(&cfg.Zanzana, store, logger)
-		if err != nil {
-			return nil, fmt.Errorf("failed to start zanzana: %w", err)
-		}
-
-		srv, err := zserver.NewAuthzServer(cfg, openfga)
-		if err != nil {
-			return nil, fmt.Errorf("failed to start zanzana: %w", err)
-		}
-
-		channel := &inprocgrpc.Channel{}
-		// Put * as a namespace so we can properly authorize request with in-proc mode
-		channel.WithServerUnaryInterceptor(grpcAuth.UnaryServerInterceptor(func(ctx context.Context) (context.Context, error) {
-			ctx = claims.WithClaims(ctx, authnlib.NewAccessTokenAuthInfo(authnlib.Claims[authnlib.AccessTokenClaims]{
-				Rest: authnlib.AccessTokenClaims{
-					Namespace: "*",
-				},
-			}))
-			return ctx, nil
-		}))
-
-		openfgav1.RegisterOpenFGAServiceServer(channel, openfga)
-		authzv1.RegisterAuthzServiceServer(channel, srv)
-		authzextv1.RegisterAuthzExtentionServiceServer(channel, srv)
-
-		client, err = zclient.NewClient(context.Background(), channel, cfg)
-		if err != nil {
-			return nil, fmt.Errorf("failed to initialize zanzana client: %w", err)
-		}
-
-	default:
-		return nil, fmt.Errorf("unsupported zanzana mode: %s", cfg.Zanzana.Mode)
-	}
-
-	return client, nil
-}
-
-type ZanzanaService interface {
-	services.NamedService
-}
-
-var _ ZanzanaService = (*Zanzana)(nil)
-
-// ProvideZanzanaService is used to register zanzana as a module so we can run it seperatly from grafana.
-func ProvideZanzanaService(cfg *setting.Cfg, features featuremgmt.FeatureToggles) (*Zanzana, error) {
-	s := &Zanzana{
-		cfg:      cfg,
-		features: features,
-		logger:   log.New("zanzana"),
-	}
-
-	s.BasicService = services.NewBasicService(s.start, s.running, s.stopping).WithName("zanzana")
-
-	return s, nil
-}
-
-type Zanzana struct {
-	*services.BasicService
-
-	cfg *setting.Cfg
-
-	logger   log.Logger
-	handle   grpcserver.Provider
-	features featuremgmt.FeatureToggles
-}
-
-func (z *Zanzana) start(ctx context.Context) error {
-	store, err := zanzana.NewStore(z.cfg, z.logger)
-	if err != nil {
-		return fmt.Errorf("failed to initilize zanana store: %w", err)
-	}
-
-	openfga, err := zserver.NewOpenFGA(&z.cfg.Zanzana, store, z.logger)
-	if err != nil {
-		return fmt.Errorf("failed to start zanzana: %w", err)
-	}
-
-	srv, err := zserver.NewAuthzServer(z.cfg, openfga)
-	if err != nil {
-		return fmt.Errorf("failed to start zanzana: %w", err)
-	}
-
-	tracingCfg, err := tracing.ProvideTracingConfig(z.cfg)
-	if err != nil {
-		return err
-	}
-	tracingCfg.ServiceName = "zanzana"
-
-	tracer, err := tracing.ProvideService(tracingCfg)
-	if err != nil {
-		return err
-	}
-
-	authenticator := authnlib.NewAccessTokenAuthenticator(
-		authnlib.NewAccessTokenVerifier(
-			authnlib.VerifierConfig{
-				AllowedAudiences: []string{zanzanaAudience},
-			},
-			authnlib.NewKeyRetriever(authnlib.KeyRetrieverConfig{
-				SigningKeysURL: z.cfg.Zanzana.SigningKeysURL,
-			}),
-		),
-	)
-
-	authfn := interceptors.AuthenticatorFunc(func(ctx context.Context) (context.Context, error) {
-		md, ok := metadata.FromIncomingContext(ctx)
-		if !ok {
-			return nil, fmt.Errorf("missing metadata")
-		}
-		c, err := authenticator.Authenticate(ctx, authnlib.NewGRPCTokenProvider(md))
-		if err != nil {
-			return nil, err
-		}
-		return claims.WithClaims(ctx, c), nil
-	})
-
-	z.handle, err = grpcserver.ProvideService(z.cfg, z.features, authfn, tracer, prometheus.DefaultRegisterer)
-	if err != nil {
-		return fmt.Errorf("failed to create zanzana grpc server: %w", err)
-	}
-
-	s := z.handle.GetServer()
-	openfgav1.RegisterOpenFGAServiceServer(s, openfga)
-	authzv1.RegisterAuthzServiceServer(s, srv)
-	authzextv1.RegisterAuthzExtentionServiceServer(s, srv)
-
-	if _, err := grpcserver.ProvideReflectionService(z.cfg, z.handle); err != nil {
-		return fmt.Errorf("failed to register reflection for zanzana: %w", err)
-	}
-
-	return nil
-}
-
-func (z *Zanzana) running(ctx context.Context) error {
-	if z.cfg.Env == setting.Dev && z.cfg.Zanzana.ListenHTTP {
-		go func() {
-			z.logger.Info("Starting OpenFGA HTTP server")
-			err := zserver.StartOpenFGAHttpSever(z.cfg, z.handle, z.logger)
-			if err != nil {
-				z.logger.Error("failed to start OpenFGA HTTP server", "error", err)
-			}
-		}()
-	}
-
-	// Run is blocking so we can just run it here
-	return z.handle.Run(ctx)
-}
-
-func (z *Zanzana) stopping(err error) error {
-	if err != nil && !errors.Is(err, context.Canceled) {
-		z.logger.Error("Stopping zanzana due to unexpected error", "err", err)
-	}
-	return nil
-}
-
-type tokenAuth struct {
-	cfg         *setting.Cfg
-	namespace   string
-	tokenClient *authnlib.TokenExchangeClient
-}
-
-func (t *tokenAuth) GetRequestMetadata(ctx context.Context, _ ...string) (map[string]string, error) {
-	token, err := t.tokenClient.Exchange(ctx, authnlib.TokenExchangeRequest{
-		Namespace: t.namespace,
-		Audiences: []string{zanzanaAudience},
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	return map[string]string{
-		authnlib.DefaultAccessTokenMetadataKey: token.Token,
-	}, nil
-}
-
-func (t *tokenAuth) RequireTransportSecurity() bool {
-	return false
-}
openSUSE Build Service is sponsored by