This commit is contained in:
Claudiu Dragalina-Paraipan 2024-08-02 18:54:29 +03:00
parent c46b42a595
commit 763961210c
6 changed files with 95 additions and 3 deletions

View File

@ -19,6 +19,7 @@ const (
StorageTypeLegacy StorageType = "legacy" StorageTypeLegacy StorageType = "legacy"
StorageTypeUnified StorageType = "unified" StorageTypeUnified StorageType = "unified"
StorageTypeUnifiedGrpc StorageType = "unified-grpc" StorageTypeUnifiedGrpc StorageType = "unified-grpc"
// TODO(drclau): add StorageTypeUnifiedCloud?
) )
type StorageOptions struct { type StorageOptions struct {

View File

@ -288,6 +288,7 @@ func (s *service) start(ctx context.Context) error {
} }
// Create a client instance // Create a client instance
// TODO(drclau): differentiate based on grpc_mode (e.g. on-prem vs. cloud)
client, err := resource.NewResourceStoreClientGRPC(conn) client, err := resource.NewResourceStoreClientGRPC(conn)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,8 @@
package grpcutils package grpcutils
import ( import (
"fmt"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -10,7 +12,7 @@ type GrpcClientConfig struct {
TokenNamespace string TokenNamespace string
} }
func ReadCfg(cfg *setting.Cfg) *GrpcClientConfig { func ReadGrpcClientConfig(cfg *setting.Cfg) *GrpcClientConfig {
section := cfg.SectionWithEnvOverrides("grpc_client_authentication") section := cfg.SectionWithEnvOverrides("grpc_client_authentication")
return &GrpcClientConfig{ return &GrpcClientConfig{
@ -19,3 +21,41 @@ func ReadCfg(cfg *setting.Cfg) *GrpcClientConfig {
TokenNamespace: section.Key("token_namespace").MustString("stack-" + cfg.StackID), TokenNamespace: section.Key("token_namespace").MustString("stack-" + cfg.StackID),
} }
} }
type Mode string
func (s Mode) IsValid() bool {
switch s {
case ModeGRPC, ModeInProc, ModeCloud:
return true
}
return false
}
const (
ModeGRPC Mode = "grpc"
ModeInProc Mode = "inproc"
ModeCloud Mode = "cloud"
)
type GrpcServerConfig struct {
Mode Mode
SigningKeysURL string
AllowedAudiences []string
}
func ReadGprcServerConfig(cfg *setting.Cfg) (*GrpcServerConfig, error) {
section := cfg.SectionWithEnvOverrides("grpc_server_authentication")
mode := Mode(section.Key("mode").MustString(string(ModeGRPC)))
if !mode.IsValid() {
return nil, fmt.Errorf("grpc_server_authentication: invalid mode %q", mode)
}
return &GrpcServerConfig{
Mode: mode,
SigningKeysURL: section.Key("signing_keys_url").MustString(""),
AllowedAudiences: section.Key("allowed_audiences").Strings(","),
}, nil
}

View File

@ -44,6 +44,12 @@ func newLegacyServer(
return s, nil return s, nil
} }
// AuthFuncOverride
// FIXME(drclau): make sure we only run this when app_mode = development
func (s *legacyServer) AuthFuncOverride(ctx context.Context, _ string) (context.Context, error) {
return ctx, nil
}
func (s *legacyServer) Read(ctx context.Context, req *authzv1.ReadRequest) (*authzv1.ReadResponse, error) { func (s *legacyServer) Read(ctx context.Context, req *authzv1.ReadRequest) (*authzv1.ReadResponse, error) {
ctx, span := s.tracer.Start(ctx, "authz.grpc.Read") ctx, span := s.tracer.Start(ctx, "authz.grpc.Read")
defer span.End() defer span.End()

View File

@ -6,6 +6,8 @@ import (
"net" "net"
"time" "time"
authnlib "github.com/grafana/authlib/authn"
authzlib "github.com/grafana/authlib/authz"
"github.com/grafana/dskit/instrument" "github.com/grafana/dskit/instrument"
"github.com/grafana/dskit/middleware" "github.com/grafana/dskit/middleware"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
@ -70,12 +72,21 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, authe
var opts []grpc.ServerOption var opts []grpc.ServerOption
namespaceFmt := authnlib.OnPremNamespaceFormatter
// TODO(drclau): check the actual mode setting here
if cfg.StackID != "" {
namespaceFmt = authnlib.CloudNamespaceFormatter
}
namespaceChecker := authzlib.NewNamespaceAccessChecker(namespaceFmt)
stackIdExtractor := authzlib.MetadataStackIDExtractor(authzlib.DefaultStackIDMetadataKey)
// Default auth is admin token check, but this can be overridden by // Default auth is admin token check, but this can be overridden by
// services which implement ServiceAuthFuncOverride interface. // services which implement ServiceAuthFuncOverride interface.
// See https://github.com/grpc-ecosystem/go-grpc-middleware/blob/main/interceptors/auth/auth.go#L30. // See https://github.com/grpc-ecosystem/go-grpc-middleware/blob/main/interceptors/auth/auth.go#L30.
opts = append(opts, []grpc.ServerOption{ opts = append(opts, []grpc.ServerOption{
grpc.ChainUnaryInterceptor( grpc.ChainUnaryInterceptor(
grpcAuth.UnaryServerInterceptor(authenticator.Authenticate), grpcAuth.UnaryServerInterceptor(authenticator.Authenticate),
authzlib.UnaryNamespaceAccessInterceptor(namespaceChecker, stackIdExtractor),
interceptors.TracingUnaryInterceptor(tracer), interceptors.TracingUnaryInterceptor(tracer),
interceptors.LoggingUnaryInterceptor(s.cfg, s.logger), // needs to be registered after tracing interceptor to get trace id interceptors.LoggingUnaryInterceptor(s.cfg, s.logger), // needs to be registered after tracing interceptor to get trace id
middleware.UnaryServerInstrumentInterceptor(grpcRequestDuration), middleware.UnaryServerInstrumentInterceptor(grpcRequestDuration),
@ -83,6 +94,7 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, authe
grpc.ChainStreamInterceptor( grpc.ChainStreamInterceptor(
interceptors.TracingStreamInterceptor(tracer), interceptors.TracingStreamInterceptor(tracer),
grpcAuth.StreamServerInterceptor(authenticator.Authenticate), grpcAuth.StreamServerInterceptor(authenticator.Authenticate),
authzlib.StreamNamespaceAccessInterceptor(namespaceChecker, stackIdExtractor),
middleware.StreamServerInstrumentInterceptor(grpcRequestDuration), middleware.StreamServerInstrumentInterceptor(grpcRequestDuration),
), ),
}...) }...)

View File

@ -3,6 +3,7 @@ package sql
import ( import (
"context" "context"
authnlib "github.com/grafana/authlib/authn"
"github.com/grafana/dskit/services" "github.com/grafana/dskit/services"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/health/grpc_health_v1"
@ -11,12 +12,12 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/modules" "github.com/grafana/grafana/pkg/modules"
"github.com/grafana/grafana/pkg/services/authn/grpcutils"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/grpcserver" "github.com/grafana/grafana/pkg/services/grpcserver"
"github.com/grafana/grafana/pkg/services/grpcserver/interceptors" "github.com/grafana/grafana/pkg/services/grpcserver/interceptors"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/storage/unified/resource/grpc"
) )
var ( var (
@ -62,7 +63,38 @@ func ProvideService(
return nil, err return nil, err
} }
authn := &grpc.Authenticator{} authCfg, err := grpcutils.ReadGprcServerConfig(cfg)
if err != nil {
return nil, err
}
grpcAuthCfg := authnlib.GrpcAuthenticatorConfig{
KeyRetrieverConfig: authnlib.KeyRetrieverConfig{
SigningKeysURL: authCfg.SigningKeysURL,
},
VerifierConfig: authnlib.VerifierConfig{
AllowedAudiences: authCfg.AllowedAudiences,
},
}
grpcOpts := []authnlib.GrpcAuthenticatorOption{}
switch authCfg.Mode {
case grpcutils.ModeInProc:
// NOOP: IDTokenClaims are added to ctx client-side
// TODO(drclau): do we need orgId?
case grpcutils.ModeGRPC:
grpcOpts = append(grpcOpts,
authnlib.WithDisableAccessTokenAuthOption(),
authnlib.WithIDTokenAuthOption(true),
)
case grpcutils.ModeCloud:
grpcOpts = append(grpcOpts, authnlib.WithIDTokenAuthOption(true))
}
authn, err := authnlib.NewGrpcAuthenticator(
&grpcAuthCfg,
grpcOpts...,
)
s := &service{ s := &service{
cfg: cfg, cfg: cfg,