From 4df398c0841d90b872b64ab57cba9f1ca08d1eb5 Mon Sep 17 00:00:00 2001 From: Karl Persson <23356117+kalleep@users.noreply.github.com> Date: Tue, 18 Feb 2025 09:09:20 +0100 Subject: [PATCH] Authz: Sync authlib and update authz client setup code (#100817) * Sync authlib and update setup code for authz client --- go.mod | 2 +- go.sum | 4 +- pkg/apimachinery/go.mod | 2 +- pkg/apimachinery/go.sum | 4 +- pkg/services/authz/rbac.go | 93 ++++++++++------------------- pkg/services/authz/rbac/service.go | 2 - pkg/services/authz/token_auth.go | 31 ++++++++++ pkg/services/authz/zanzana.go | 35 +---------- pkg/storage/unified/apistore/go.mod | 2 +- pkg/storage/unified/apistore/go.sum | 4 +- pkg/storage/unified/resource/go.mod | 2 +- pkg/storage/unified/resource/go.sum | 4 +- 12 files changed, 79 insertions(+), 106 deletions(-) create mode 100644 pkg/services/authz/token_auth.go diff --git a/go.mod b/go.mod index 8feb6410e41..05e98b520f3 100644 --- a/go.mod +++ b/go.mod @@ -72,7 +72,7 @@ require ( github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.3 // @grafana/grafana-app-platform-squad github.com/grafana/alerting v0.0.0-20250207161551-04c87cf39038 // @grafana/alerting-backend - github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569 // @grafana/identity-access-team + github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc // @grafana/identity-access-team github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c // @grafana/identity-access-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics github.com/grafana/dataplane/sdata v0.0.9 // @grafana/observability-metrics diff --git a/go.sum b/go.sum index 9f56e65c99a..468bdb10310 100644 --- a/go.sum +++ b/go.sum @@ -1513,8 +1513,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grafana/alerting v0.0.0-20250207161551-04c87cf39038 h1:dG/UKAjY/KlKp9fY8aEm+gSQHHRmPm5q+9cea3hRSu8= github.com/grafana/alerting v0.0.0-20250207161551-04c87cf39038/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU= -github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569 h1:bQw6fdcxVdZ6xmZVhMtRgGEKIT1Zc6y+i1PWF8tMX4Q= -github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8= +github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc h1:qx8avmRi3wx+SuAn6UV0pKma1fJ0/4POUYNc+2rxZkg= +github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc/go.mod h1:HamgITzYqErFp8qLwYM/JwwE3z6fXft0Z+5n0Dx1rUM= github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c h1:b0sPDtt33uFdmvUJjSCld3kwE2E49dUvevuUDSJsEuo= github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod index 03ac780af13..538067db46a 100644 --- a/pkg/apimachinery/go.mod +++ b/pkg/apimachinery/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/pkg/apimachinery go 1.23.1 require ( - github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569 // @grafana/identity-access-team + github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc // @grafana/identity-access-team github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c // @grafana/identity-access-team github.com/stretchr/testify v1.10.0 k8s.io/apimachinery v0.32.1 diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum index 8e526b201f1..1a280d681df 100644 --- a/pkg/apimachinery/go.sum +++ b/pkg/apimachinery/go.sum @@ -32,8 +32,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569 h1:bQw6fdcxVdZ6xmZVhMtRgGEKIT1Zc6y+i1PWF8tMX4Q= -github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8= +github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc h1:qx8avmRi3wx+SuAn6UV0pKma1fJ0/4POUYNc+2rxZkg= +github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc/go.mod h1:HamgITzYqErFp8qLwYM/JwwE3z6fXft0Z+5n0Dx1rUM= github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c h1:b0sPDtt33uFdmvUJjSCld3kwE2E49dUvevuUDSJsEuo= github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= diff --git a/pkg/services/authz/rbac.go b/pkg/services/authz/rbac.go index 4e9daa6f744..a589a5b99a5 100644 --- a/pkg/services/authz/rbac.go +++ b/pkg/services/authz/rbac.go @@ -7,7 +7,6 @@ import ( "net/http" "time" - "github.com/fullstorydev/grpchan" "github.com/fullstorydev/grpchan/inprocgrpc" grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth" "github.com/prometheus/client_golang/prometheus" @@ -26,7 +25,6 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/apiserver" - authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" "github.com/grafana/grafana/pkg/services/authz/rbac" "github.com/grafana/grafana/pkg/services/authz/rbac/store" "github.com/grafana/grafana/pkg/services/featuremgmt" @@ -59,7 +57,7 @@ func ProvideAuthZClient( switch authCfg.mode { case clientModeCloud: - return newRemoteLegacyClient(authCfg, tracer) + return newRemoteRBACClient(authCfg, tracer) default: sql := legacysql.NewDatabaseProvider(db) @@ -80,7 +78,18 @@ func ProvideAuthZClient( reg, cache.NewLocalCache(cache.Config{Expiry: 5 * time.Minute, CleanupInterval: 10 * time.Minute}), ) - return newInProcLegacyClient(server, tracer) + + channel := &inprocgrpc.Channel{} + channel.WithServerUnaryInterceptor(grpcAuth.UnaryServerInterceptor(func(ctx context.Context) (context.Context, error) { + ctx = authlib.WithAuthInfo(ctx, authnlib.NewAccessTokenAuthInfo(authnlib.Claims[authnlib.AccessTokenClaims]{ + Rest: authnlib.AccessTokenClaims{ + Namespace: "*", + }, + })) + return ctx, nil + })) + authzv1.RegisterAuthzServiceServer(channel, server) + return newRBACClient(channel, tracer), nil } } @@ -98,76 +107,41 @@ func ProvideStandaloneAuthZClient( return nil, err } - return newRemoteLegacyClient(authCfg, tracer) + return newRemoteRBACClient(authCfg, tracer) } -func newInProcLegacyClient(server *rbac.Service, tracer tracing.Tracer) (authlib.AccessClient, error) { - // For in-proc use-case authorize add fake service claims - it should be able to access every namespace, as there is only one - staticAuth := func(ctx context.Context) (context.Context, error) { - ctx = authlib.WithAuthInfo(ctx, authnlib.NewAccessTokenAuthInfo(authnlib.Claims[authnlib.AccessTokenClaims]{ - Rest: authnlib.AccessTokenClaims{ - Namespace: "*", - }, - })) - return ctx, nil +func newRemoteRBACClient(clientCfg *authzClientSettings, tracer tracing.Tracer) (authlib.AccessClient, error) { + tokenClient, err := authnlib.NewTokenExchangeClient(authnlib.TokenExchangeConfig{ + Token: clientCfg.token, + TokenExchangeURL: clientCfg.tokenExchangeURL, + }) + if err != nil { + return nil, fmt.Errorf("failed to initialize token exchange client: %w", err) } - channel := &inprocgrpc.Channel{} - channel.RegisterService( - grpchan.InterceptServer( - &authzv1.AuthzService_ServiceDesc, - grpcAuth.UnaryServerInterceptor(staticAuth), - grpcAuth.StreamServerInterceptor(staticAuth), + conn, err := grpc.NewClient( + clientCfg.remoteAddress, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithPerRPCCredentials( + newGRPCTokenAuth(authzServiceAudience, clientCfg.tokenNamespace, tokenClient), ), - server, - ) - - return authzlib.NewClient( - &authzlib.ClientConfig{}, - authzlib.WithGrpcConnectionClientOption(channel), - authzlib.WithTracerClientOption(tracer), - authzlib.WithCacheClientOption(cache.NewLocalCache(cache.Config{ - Expiry: 30 * time.Second, - CleanupInterval: 2 * time.Minute, - })), ) -} - -func newRemoteLegacyClient(clientCfg *authzClientSettings, tracer tracing.Tracer) (authlib.AccessClient, error) { - grpcClientConfig := authnlib.GrpcClientConfig{ - TokenClientConfig: &authnlib.TokenExchangeConfig{ - Token: clientCfg.token, - TokenExchangeURL: clientCfg.tokenExchangeURL, - }, - TokenRequest: &authnlib.TokenExchangeRequest{ - Namespace: clientCfg.tokenNamespace, - Audiences: []string{authzServiceAudience}, - }, - } - - clientInterceptor, err := authnlib.NewGrpcClientInterceptor(&grpcClientConfig, authnlib.WithTracerOption(tracer)) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to create authz client to remote server: %w", err) } - client, err := authzlib.NewClient( - &authzlib.ClientConfig{RemoteAddress: clientCfg.remoteAddress}, - authzlib.WithGrpcDialOptionsClientOption( - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithUnaryInterceptor(clientInterceptor.UnaryClientInterceptor), - grpc.WithStreamInterceptor(clientInterceptor.StreamClientInterceptor), - ), + return newRBACClient(conn, tracer), nil +} + +func newRBACClient(conn grpc.ClientConnInterface, tracer tracing.Tracer) authlib.AccessClient { + return authzlib.NewClient( + conn, authzlib.WithCacheClientOption(cache.NewLocalCache(cache.Config{ Expiry: 30 * time.Second, CleanupInterval: 2 * time.Minute, })), authzlib.WithTracerClientOption(tracer), ) - if err != nil { - return nil, err - } - - return client, nil } func RegisterRBACAuthZService( @@ -210,7 +184,6 @@ func RegisterRBACAuthZService( srv := handler.GetServer() authzv1.RegisterAuthzServiceServer(srv, server) - authzextv1.RegisterAuthzExtentionServiceServer(srv, server) } var _ http.RoundTripper = tokenExhangeRoundTripper{} diff --git a/pkg/services/authz/rbac/service.go b/pkg/services/authz/rbac/service.go index 7a365c0d6f5..910796e29f0 100644 --- a/pkg/services/authz/rbac/service.go +++ b/pkg/services/authz/rbac/service.go @@ -24,7 +24,6 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/iam/common" "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" "github.com/grafana/grafana/pkg/services/accesscontrol" - authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" "github.com/grafana/grafana/pkg/services/authz/rbac/store" "github.com/grafana/grafana/pkg/storage/legacysql" ) @@ -38,7 +37,6 @@ const ( type Service struct { authzv1.UnimplementedAuthzServiceServer - authzextv1.UnimplementedAuthzExtentionServiceServer store store.Store folderStore store.FolderStore diff --git a/pkg/services/authz/token_auth.go b/pkg/services/authz/token_auth.go new file mode 100644 index 00000000000..2f6549a4d8b --- /dev/null +++ b/pkg/services/authz/token_auth.go @@ -0,0 +1,31 @@ +package authz + +import ( + "context" + + "github.com/grafana/authlib/authn" +) + +func newGRPCTokenAuth(audience, namespace string, tc authn.TokenExchanger) *tokenAuth { + return &tokenAuth{audience, namespace, tc} +} + +type tokenAuth struct { + audience string + namespace string + tokenClient authn.TokenExchanger +} + +func (t *tokenAuth) GetRequestMetadata(ctx context.Context, _ ...string) (map[string]string, error) { + token, err := t.tokenClient.Exchange(ctx, authn.TokenExchangeRequest{ + Namespace: t.namespace, + Audiences: []string{t.audience}, + }) + if err != nil { + return nil, err + } + + return map[string]string{authn.DefaultAccessTokenMetadataKey: token.Token}, nil +} + +func (t *tokenAuth) RequireTransportSecurity() bool { return false } diff --git a/pkg/services/authz/zanzana.go b/pkg/services/authz/zanzana.go index 1327689f1b1..60bea71c2ee 100644 --- a/pkg/services/authz/zanzana.go +++ b/pkg/services/authz/zanzana.go @@ -53,18 +53,13 @@ func ProvideZanzana(cfg *setting.Cfg, db db.DB, features featuremgmt.FeatureTogg 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), + grpc.WithPerRPCCredentials( + newGRPCTokenAuth(authzServiceAudience, fmt.Sprintf("stacks-%s", cfg.StackID), tokenClient), + ), } conn, err := grpc.NewClient(cfg.ZanzanaClient.Addr, dialOptions...) @@ -244,27 +239,3 @@ func (z *Zanzana) stopping(err error) error { } 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{authzServiceAudience}, - }) - if err != nil { - return nil, err - } - - return map[string]string{ - authnlib.DefaultAccessTokenMetadataKey: token.Token, - }, nil -} - -func (t *tokenAuth) RequireTransportSecurity() bool { - return false -} diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index 66c04c116bc..3f0c3be423e 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -193,7 +193,7 @@ require ( github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grafana/alerting v0.0.0-20250207161551-04c87cf39038 // indirect - github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569 // indirect + github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 // indirect github.com/grafana/grafana-app-sdk/logging v0.30.0 // indirect diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index 60549ccc425..073beaffb31 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -568,8 +568,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grafana/alerting v0.0.0-20250207161551-04c87cf39038 h1:dG/UKAjY/KlKp9fY8aEm+gSQHHRmPm5q+9cea3hRSu8= github.com/grafana/alerting v0.0.0-20250207161551-04c87cf39038/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU= -github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569 h1:bQw6fdcxVdZ6xmZVhMtRgGEKIT1Zc6y+i1PWF8tMX4Q= -github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8= +github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc h1:qx8avmRi3wx+SuAn6UV0pKma1fJ0/4POUYNc+2rxZkg= +github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc/go.mod h1:HamgITzYqErFp8qLwYM/JwwE3z6fXft0Z+5n0Dx1rUM= github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c h1:b0sPDtt33uFdmvUJjSCld3kwE2E49dUvevuUDSJsEuo= github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index f1e7e7cc290..4ee8027f27d 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -11,7 +11,7 @@ replace ( require ( github.com/fullstorydev/grpchan v1.1.1 github.com/google/uuid v1.6.0 - github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569 + github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 github.com/grafana/grafana v11.4.0-00010101000000-000000000000+incompatible diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index 75ec44cf992..327e5de0cfa 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -399,8 +399,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grafana/alerting v0.0.0-20250207161551-04c87cf39038 h1:dG/UKAjY/KlKp9fY8aEm+gSQHHRmPm5q+9cea3hRSu8= github.com/grafana/alerting v0.0.0-20250207161551-04c87cf39038/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU= -github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569 h1:bQw6fdcxVdZ6xmZVhMtRgGEKIT1Zc6y+i1PWF8tMX4Q= -github.com/grafana/authlib v0.0.0-20250206063954-bf4600a17569/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8= +github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc h1:qx8avmRi3wx+SuAn6UV0pKma1fJ0/4POUYNc+2rxZkg= +github.com/grafana/authlib v0.0.0-20250217135712-106ec5baf6bc/go.mod h1:HamgITzYqErFp8qLwYM/JwwE3z6fXft0Z+5n0Dx1rUM= github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c h1:b0sPDtt33uFdmvUJjSCld3kwE2E49dUvevuUDSJsEuo= github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s=