diff --git a/go.mod b/go.mod index ae2caa2aaef..8b91c5cb880 100644 --- a/go.mod +++ b/go.mod @@ -72,8 +72,8 @@ 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-20250224133628-2acbeef29642 // @grafana/alerting-backend - github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 // @grafana/identity-access-team - github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 // @grafana/identity-access-team + github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 // @grafana/identity-access-team + github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 // @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 github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 // @grafana/grafana-backend-group diff --git a/go.sum b/go.sum index edbbd7eb159..7604fb6d2bb 100644 --- a/go.sum +++ b/go.sum @@ -1513,10 +1513,10 @@ 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-20250224133628-2acbeef29642 h1:iQ0h/h+QoguSZDF+ZpPxcM/C+m1kjh+aXjMpxywowPA= github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= -github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= -github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= +github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 h1:FTuDRy/Shw8yOdG+v1DnkeuaCAl8fvwgcfaG9Wccuhg= +github.com/grafana/authlib v0.0.0-20250225105729-99e678595501/go.mod h1:XVpdLhaeYqz414FmGnW00/0vTe1x8c0GRH3KaeRtyg0= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod index 36b8d4b827e..033f48738ec 100644 --- a/pkg/apimachinery/go.mod +++ b/pkg/apimachinery/go.mod @@ -3,8 +3,8 @@ module github.com/grafana/grafana/pkg/apimachinery go 1.23.1 require ( - github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 // @grafana/identity-access-team - github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 // @grafana/identity-access-team + github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 // @grafana/identity-access-team + github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 // @grafana/identity-access-team github.com/stretchr/testify v1.10.0 k8s.io/apimachinery v0.32.1 k8s.io/apiserver v0.32.1 diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum index 5b3d03a464a..bd82bcbb03f 100644 --- a/pkg/apimachinery/go.sum +++ b/pkg/apimachinery/go.sum @@ -32,10 +32,10 @@ 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-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= -github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= +github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 h1:FTuDRy/Shw8yOdG+v1DnkeuaCAl8fvwgcfaG9Wccuhg= +github.com/grafana/authlib v0.0.0-20250225105729-99e678595501/go.mod h1:XVpdLhaeYqz414FmGnW00/0vTe1x8c0GRH3KaeRtyg0= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= diff --git a/pkg/apiserver/go.mod b/pkg/apiserver/go.mod index 83a53b3151a..0c45aa74e58 100644 --- a/pkg/apiserver/go.mod +++ b/pkg/apiserver/go.mod @@ -6,7 +6,7 @@ toolchain go1.23.6 require ( github.com/google/go-cmp v0.6.0 - github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 + github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 github.com/grafana/grafana-app-sdk/logging v0.30.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240701135906-559738ce6ae1 github.com/prometheus/client_golang v1.20.5 diff --git a/pkg/apiserver/go.sum b/pkg/apiserver/go.sum index fddf55e1b93..b3d15d3aee2 100644 --- a/pkg/apiserver/go.sum +++ b/pkg/apiserver/go.sum @@ -79,8 +79,8 @@ 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/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/grafana/grafana-app-sdk/logging v0.30.0 h1:K/P/bm7Cp7Di4tqIJ3EQz2+842JozQGRaz62r95ApME= github.com/grafana/grafana-app-sdk/logging v0.30.0/go.mod h1:xy6ZyVXl50Z3DBDLybvBPphbykPhuVNed/VNmen9DQM= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240701135906-559738ce6ae1 h1:ItDcDxUjVLPKja+hogpqgW/kj8LxUL2qscelXIsN1Bs= diff --git a/pkg/registry/apis/iam/common/common.go b/pkg/registry/apis/iam/common/common.go index a0896d0fb25..a93c90a7d36 100644 --- a/pkg/registry/apis/iam/common/common.go +++ b/pkg/registry/apis/iam/common/common.go @@ -61,7 +61,7 @@ func List[T Resource]( return nil, err } - check := func(_, _, _ string) bool { return true } + check := func(_, _ string) bool { return true } if ac != nil { var err error check, err = ac.Compile(ctx, ident, authlib.ListRequest{ @@ -82,7 +82,7 @@ func List[T Resource]( } for _, item := range first.Items { - if !check(ns.Value, item.AuthID(), "") { + if !check(item.AuthID(), "") { continue } res.Items = append(res.Items, item) @@ -105,7 +105,7 @@ outer: break outer } - if !check(ns.Value, item.AuthID(), "") { + if !check(item.AuthID(), "") { continue } diff --git a/pkg/services/accesscontrol/authorizer.go b/pkg/services/accesscontrol/authorizer.go index fb0bbf93125..f4c8d27ddce 100644 --- a/pkg/services/accesscontrol/authorizer.go +++ b/pkg/services/accesscontrol/authorizer.go @@ -158,7 +158,7 @@ func (c *LegacyAccessClient) Compile(ctx context.Context, id claims.AuthInfo, re } check := Checker(ident, action) - return func(_, name, _ string) bool { + return func(name, _ string) bool { return check(fmt.Sprintf("%s:%s:%s", opts.Resource, opts.Attr, name)) }, nil } diff --git a/pkg/services/apiserver/options/storage.go b/pkg/services/apiserver/options/storage.go index 4d2b7dd1b3f..b24d3780b29 100644 --- a/pkg/services/apiserver/options/storage.go +++ b/pkg/services/apiserver/options/storage.go @@ -11,7 +11,6 @@ import ( genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/options" - "github.com/grafana/authlib/authn" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/setting" @@ -123,17 +122,15 @@ func (o *StorageOptions) ApplyTo(serverConfig *genericapiserver.RecommendedConfi if err != nil { return err } - authCfg := authn.GrpcClientConfig{ - TokenClientConfig: &authn.TokenExchangeConfig{ - Token: o.GrpcClientAuthenticationToken, - TokenExchangeURL: o.GrpcClientAuthenticationTokenExchangeURL, - }, - TokenRequest: &authn.TokenExchangeRequest{ - Audiences: []string{"resourceStore"}, - Namespace: o.GrpcClientAuthenticationTokenNamespace, - }, - } - unified, err := resource.NewRemoteResourceClient(tracer, conn, authCfg, o.GrpcClientAuthenticationAllowInsecure) + + const resourceStoreAudience = "resourceStore" + + unified, err := resource.NewRemoteResourceClient(tracer, conn, resource.RemoteResourceClientConfig{ + Token: o.GrpcClientAuthenticationToken, + TokenExchangeURL: o.GrpcClientAuthenticationTokenExchangeURL, + Namespace: o.GrpcClientAuthenticationTokenNamespace, + Audiences: []string{resourceStoreAudience}, + }) if err != nil { return err } diff --git a/pkg/services/authn/grpcutils/inproc_exchanger.go b/pkg/services/authn/grpcutils/inproc_exchanger.go index af252ca2fb1..6a219abc1e8 100644 --- a/pkg/services/authn/grpcutils/inproc_exchanger.go +++ b/pkg/services/authn/grpcutils/inproc_exchanger.go @@ -1,10 +1,8 @@ package grpcutils import ( - "context" "encoding/base64" "encoding/json" - "fmt" "github.com/go-jose/go-jose/v3/jwt" "github.com/grafana/authlib/authn" @@ -12,29 +10,21 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/identity" ) -type inProcExchanger struct { - tokenResponse *authn.TokenExchangeResponse -} - -func ProvideInProcExchanger() *inProcExchanger { - tokenResponse, err := createInProcToken() +func ProvideInProcExchanger() authn.StaticTokenExchanger { + token, err := createInProcToken() if err != nil { panic(err) } - return &inProcExchanger{tokenResponse} -} - -func (e *inProcExchanger) Exchange(ctx context.Context, r authn.TokenExchangeRequest) (*authn.TokenExchangeResponse, error) { - return e.tokenResponse, nil + return authn.NewStaticTokenExchanger(token) } -func createInProcToken() (*authn.TokenExchangeResponse, error) { +func createInProcToken() (string, error) { claims := authn.Claims[authn.AccessTokenClaims]{ Claims: jwt.Claims{ - Audience: []string{"resourceStore"}, Issuer: "grafana", Subject: types.NewTypeID(types.TypeAccessPolicy, "grafana"), + Audience: []string{"resourceStore"}, }, Rest: authn.AccessTokenClaims{ Namespace: "*", @@ -48,15 +38,13 @@ func createInProcToken() (*authn.TokenExchangeResponse, error) { "typ": authn.TokenTypeAccess, }) if err != nil { - return nil, err + return "", err } payload, err := json.Marshal(claims) if err != nil { - return nil, err + return "", err } - return &authn.TokenExchangeResponse{ - Token: fmt.Sprintf("%s.%s.", base64.RawURLEncoding.EncodeToString(header), base64.RawURLEncoding.EncodeToString(payload)), - }, nil + return base64.RawURLEncoding.EncodeToString(header) + "." + base64.RawURLEncoding.EncodeToString(payload) + ".", nil } diff --git a/pkg/services/authz/token_auth.go b/pkg/services/authz/token_auth.go index 2f6549a4d8b..1546379741e 100644 --- a/pkg/services/authz/token_auth.go +++ b/pkg/services/authz/token_auth.go @@ -25,7 +25,9 @@ func (t *tokenAuth) GetRequestMetadata(ctx context.Context, _ ...string) (map[st return nil, err } - return map[string]string{authn.DefaultAccessTokenMetadataKey: token.Token}, nil + const metadataKey = "X-Access-Token" + + return map[string]string{metadataKey: token.Token}, nil } func (t *tokenAuth) RequireTransportSecurity() bool { return false } diff --git a/pkg/services/authz/zanzana/client/client.go b/pkg/services/authz/zanzana/client/client.go index d430be493a9..6860f6831be 100644 --- a/pkg/services/authz/zanzana/client/client.go +++ b/pkg/services/authz/zanzana/client/client.go @@ -79,7 +79,7 @@ func (c *Client) Compile(ctx context.Context, id authlib.AuthInfo, req authlib.L func newItemChecker(res *authzv1.ListResponse) authlib.ItemChecker { // if we can see all resource of this type we can just return a function that always return true if res.GetAll() { - return func(_, _, _ string) bool { return true } + return func(_, _ string) bool { return true } } folders := make(map[string]struct{}, len(res.Folders)) @@ -92,7 +92,7 @@ func newItemChecker(res *authzv1.ListResponse) authlib.ItemChecker { items[i] = struct{}{} } - return func(_, name, folder string) bool { + return func(name, folder string) bool { if _, ok := items[name]; ok { return true } diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index 16a36800ba0..748b5e929ff 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -14,7 +14,7 @@ exclude k8s.io/client-go v12.0.0+incompatible require ( github.com/bwmarrin/snowflake v0.3.0 github.com/google/uuid v1.6.0 - github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 + github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 github.com/grafana/grafana v11.4.0-00010101000000-000000000000+incompatible github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250220154326-6e5de80ef295 github.com/grafana/grafana/pkg/apiserver v0.0.0-20250220154326-6e5de80ef295 @@ -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-20250224133628-2acbeef29642 // indirect - github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 // indirect + github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 // 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 27c6a2641e9..35a9215a782 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -568,10 +568,10 @@ 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-20250224133628-2acbeef29642 h1:iQ0h/h+QoguSZDF+ZpPxcM/C+m1kjh+aXjMpxywowPA= github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= -github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= -github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= +github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 h1:FTuDRy/Shw8yOdG+v1DnkeuaCAl8fvwgcfaG9Wccuhg= +github.com/grafana/authlib v0.0.0-20250225105729-99e678595501/go.mod h1:XVpdLhaeYqz414FmGnW00/0vTe1x8c0GRH3KaeRtyg0= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= diff --git a/pkg/storage/unified/client.go b/pkg/storage/unified/client.go index 396ce141c06..a0ddcce31a0 100644 --- a/pkg/storage/unified/client.go +++ b/pkg/storage/unified/client.go @@ -15,7 +15,6 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - authnlib "github.com/grafana/authlib/authn" "github.com/grafana/authlib/types" "github.com/grafana/dskit/flagext" "github.com/grafana/dskit/grpcclient" @@ -143,24 +142,20 @@ func newClient(opts options.StorageOptions, } } -func clientCfgMapping(clientCfg *grpcutils.GrpcClientConfig) authnlib.GrpcClientConfig { - return authnlib.GrpcClientConfig{ - TokenClientConfig: &authnlib.TokenExchangeConfig{ - Token: clientCfg.Token, - TokenExchangeURL: clientCfg.TokenExchangeURL, - }, - TokenRequest: &authnlib.TokenExchangeRequest{ - Namespace: clientCfg.TokenNamespace, - Audiences: []string{resourceStoreAudience}, - }, - } -} - func newResourceClient(conn *grpc.ClientConn, cfg *setting.Cfg, features featuremgmt.FeatureToggles, tracer tracing.Tracer) (resource.ResourceClient, error) { if !features.IsEnabledGlobally(featuremgmt.FlagAppPlatformGrpcClientAuth) { return resource.NewLegacyResourceClient(conn), nil } - return resource.NewRemoteResourceClient(tracer, conn, clientCfgMapping(grpcutils.ReadGrpcClientConfig(cfg)), cfg.Env == setting.Dev) + + clientCfg := grpcutils.ReadGrpcClientConfig(cfg) + + return resource.NewRemoteResourceClient(tracer, conn, resource.RemoteResourceClientConfig{ + Token: clientCfg.Token, + TokenExchangeURL: clientCfg.TokenExchangeURL, + Audiences: []string{resourceStoreAudience}, + Namespace: clientCfg.TokenNamespace, + AllowInsecure: cfg.Env == setting.Dev, + }) } // GrpcConn creates a new gRPC connection to the provided address. diff --git a/pkg/storage/unified/resource/access.go b/pkg/storage/unified/resource/access.go index a47ce0e6d1e..16dc0d9d170 100644 --- a/pkg/storage/unified/resource/access.go +++ b/pkg/storage/unified/resource/access.go @@ -153,7 +153,7 @@ func (c authzLimitedClient) Compile(ctx context.Context, id claims.AuthInfo, req )) defer span.End() if fallbackUsed || !c.IsCompatibleWithRBAC(req.Group, req.Resource) { - return func(namespace string, name, folder string) bool { + return func(name, folder string) bool { return true }, nil } diff --git a/pkg/storage/unified/resource/access_test.go b/pkg/storage/unified/resource/access_test.go index 47e17987076..a056099ec36 100644 --- a/pkg/storage/unified/resource/access_test.go +++ b/pkg/storage/unified/resource/access_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/utils" ) func TestAuthzLimitedClient_Check(t *testing.T) { @@ -27,6 +28,7 @@ func TestAuthzLimitedClient_Check(t *testing.T) { req := authlib.CheckRequest{ Group: test.group, Resource: test.resource, + Verb: utils.VerbGet, } resp, err := client.Check(context.Background(), nil, req) assert.NoError(t, err) @@ -52,12 +54,13 @@ func TestAuthzLimitedClient_Compile(t *testing.T) { req := authlib.ListRequest{ Group: test.group, Resource: test.resource, + Verb: utils.VerbGet, } checker, err := client.Compile(context.Background(), nil, req) assert.NoError(t, err) assert.NotNil(t, checker) - result := checker("namespace", "name", "folder") + result := checker("name", "folder") assert.Equal(t, test.expected, result) } } diff --git a/pkg/storage/unified/resource/batch.go b/pkg/storage/unified/resource/batch.go index 4997706a5e1..6f4f449da1d 100644 --- a/pkg/storage/unified/resource/batch.go +++ b/pkg/storage/unified/resource/batch.go @@ -270,7 +270,7 @@ func (b *batchRunner) Next() bool { if !ok { b.err = fmt.Errorf("missing access control for: %s", k) b.rollback = true - } else if !checker(key.Namespace, key.Name, b.request.Folder) { + } else if !checker(key.Name, b.request.Folder) { b.err = fmt.Errorf("not allowed to create resource") b.rollback = true } diff --git a/pkg/storage/unified/resource/client.go b/pkg/storage/unified/resource/client.go index 0fae55ec6b8..e963655b019 100644 --- a/pkg/storage/unified/resource/client.go +++ b/pkg/storage/unified/resource/client.go @@ -75,10 +75,9 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { ) } - clientInt, _ := authnlib.NewGrpcClientInterceptor( - &authnlib.GrpcClientConfig{TokenRequest: &authnlib.TokenExchangeRequest{}}, - authnlib.WithTokenClientOption(grpcutils.ProvideInProcExchanger()), - authnlib.WithIDTokenExtractorOption(idTokenExtractor), + clientInt := authnlib.NewGrpcClientInterceptor( + grpcutils.ProvideInProcExchanger(), + authnlib.WithClientInterceptorIDTokenExtractor(idTokenExtractor), ) cc := grpchan.InterceptClientConn(channel, clientInt.UnaryClientInterceptor, clientInt.StreamClientInterceptor) @@ -92,20 +91,36 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { } } -func NewRemoteResourceClient(tracer tracing.Tracer, conn *grpc.ClientConn, cfg authnlib.GrpcClientConfig, allowInsecure bool) (ResourceClient, error) { - opts := []authnlib.GrpcClientInterceptorOption{ - authnlib.WithIDTokenExtractorOption(idTokenExtractor), - authnlib.WithTracerOption(tracer), - } +type RemoteResourceClientConfig struct { + Token string + TokenExchangeURL string + Audiences []string + Namespace string + AllowInsecure bool +} - if allowInsecure { - opts = allowInsecureTransportOpt(&cfg, opts) +func NewRemoteResourceClient(tracer tracing.Tracer, conn *grpc.ClientConn, cfg RemoteResourceClientConfig) (ResourceClient, error) { + exchangeOpts := []authnlib.ExchangeClientOpts{} + + if cfg.AllowInsecure { + exchangeOpts = append(exchangeOpts, authnlib.WithHTTPClient(&http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}})) } - clientInt, err := authnlib.NewGrpcClientInterceptor(&cfg, opts...) + tc, err := authnlib.NewTokenExchangeClient(authnlib.TokenExchangeConfig{ + Token: cfg.Token, + TokenExchangeURL: cfg.TokenExchangeURL, + }, exchangeOpts...) + if err != nil { return nil, err } + clientInt := authnlib.NewGrpcClientInterceptor( + tc, + authnlib.WithClientInterceptorTracer(tracer), + authnlib.WithClientInterceptorNamespace(cfg.Namespace), + authnlib.WithClientInterceptorAudience(cfg.Audiences), + authnlib.WithClientInterceptorIDTokenExtractor(idTokenExtractor), + ) cc := grpchan.InterceptClientConn(conn, clientInt.UnaryClientInterceptor, clientInt.StreamClientInterceptor) return &resourceClient{ @@ -144,9 +159,3 @@ func idTokenExtractor(ctx context.Context) (string, error) { return "", nil } - -func allowInsecureTransportOpt(grpcClientConfig *authnlib.GrpcClientConfig, opts []authnlib.GrpcClientInterceptorOption) []authnlib.GrpcClientInterceptorOption { - client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}} - tokenClient, _ := authnlib.NewTokenExchangeClient(*grpcClientConfig.TokenClientConfig, authnlib.WithHTTPClient(client)) - return append(opts, authnlib.WithTokenClientOption(tokenClient)) -} diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index 76a89ac0d4f..42bb07c9e45 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -11,8 +11,8 @@ replace ( require ( github.com/fullstorydev/grpchan v1.1.1 github.com/google/uuid v1.6.0 - github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 - github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 + github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 + github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 github.com/grafana/grafana v11.4.0-00010101000000-000000000000+incompatible github.com/grafana/grafana-plugin-sdk-go v0.266.0 diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index a912c869d28..2bc9e773911 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -399,10 +399,10 @@ 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-20250224133628-2acbeef29642 h1:iQ0h/h+QoguSZDF+ZpPxcM/C+m1kjh+aXjMpxywowPA= github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= -github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= -github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= -github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= +github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 h1:FTuDRy/Shw8yOdG+v1DnkeuaCAl8fvwgcfaG9Wccuhg= +github.com/grafana/authlib v0.0.0-20250225105729-99e678595501/go.mod h1:XVpdLhaeYqz414FmGnW00/0vTe1x8c0GRH3KaeRtyg0= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8= +github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 h1:IR+UNYHqaU31t8/TArJk8K/GlDwOyxMpGNkWCXeZ28g= diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index 148de06595a..3422aa1514d 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -752,7 +752,7 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err Value: iter.Value(), } - if !checker(iter.Namespace(), iter.Name(), iter.Folder()) { + if !checker(iter.Name(), iter.Folder()) { continue } @@ -1035,7 +1035,7 @@ func (s *server) Watch(req *WatchRequest, srv ResourceStore_WatchServer) error { } s.log.Debug("Server Broadcasting", "type", event.Type, "rv", event.ResourceVersion, "previousRV", event.PreviousRV, "group", event.Key.Group, "namespace", event.Key.Namespace, "resource", event.Key.Resource, "name", event.Key.Name) if event.ResourceVersion > since && matchesQueryKey(req.Options.Key, event.Key) { - if !checker(event.Key.Namespace, event.Key.Name, event.Folder) { + if !checker(event.Key.Name, event.Folder) { continue } diff --git a/pkg/storage/unified/search/bleve.go b/pkg/storage/unified/search/bleve.go index 3e5264d4d91..d67b145da4d 100644 --- a/pkg/storage/unified/search/bleve.go +++ b/pkg/storage/unified/search/bleve.go @@ -965,7 +965,7 @@ func (q *permissionScopedQuery) Searcher(ctx context.Context, i index.IndexReade q.log.Debug("No resource checker found", "resource", resource) return false } - allowed := q.checkers[resource](ns, name, folder) + allowed := q.checkers[resource](name, folder) if !allowed { q.log.Debug("Denying access", "ns", ns, "name", name, "folder", folder) } diff --git a/pkg/storage/unified/search/bleve_test.go b/pkg/storage/unified/search/bleve_test.go index 66acc8d9a25..b2d90f25c0f 100644 --- a/pkg/storage/unified/search/bleve_test.go +++ b/pkg/storage/unified/search/bleve_test.go @@ -582,7 +582,7 @@ func (nc *StubAccessClient) Check(ctx context.Context, id authlib.AuthInfo, req } func (nc *StubAccessClient) Compile(ctx context.Context, id authlib.AuthInfo, req authlib.ListRequest) (authlib.ItemChecker, error) { - return func(namespace string, name, folder string) bool { + return func(name, folder string) bool { return nc.resourceResponses[req.Resource] }, nil } diff --git a/pkg/storage/unified/sql/test/integration_test.go b/pkg/storage/unified/sql/test/integration_test.go index 07c9bbb6de7..62224e10a1e 100644 --- a/pkg/storage/unified/sql/test/integration_test.go +++ b/pkg/storage/unified/sql/test/integration_test.go @@ -99,7 +99,11 @@ func TestClientServer(t *testing.T) { t.Run("Create a client", func(t *testing.T) { conn, err := unified.GrpcConn(svc.GetAddress(), prometheus.NewPedanticRegistry()) require.NoError(t, err) - client, err = resource.NewRemoteResourceClient(tracing.NewNoopTracerService(), conn, authn.GrpcClientConfig{}, true) + client, err = resource.NewRemoteResourceClient(tracing.NewNoopTracerService(), conn, resource.RemoteResourceClientConfig{ + Token: "some-token", + TokenExchangeURL: "http://some-change-url", + AllowInsecure: true, + }) require.NoError(t, err) })