diff --git a/pkg/services/authz/zanzana/server/openfga_server.go b/pkg/services/authz/zanzana/server/openfga_server.go index 9baaafc017f..8c8d3b7a4cc 100644 --- a/pkg/services/authz/zanzana/server/openfga_server.go +++ b/pkg/services/authz/zanzana/server/openfga_server.go @@ -32,6 +32,8 @@ func NewOpenFGAServer(cfg setting.ZanzanaServerSettings, store storage.OpenFGADa opts := []server.OpenFGAServiceV1Option{ server.WithDatastore(store), server.WithLogger(zlogger.New(logger)), + + // Cache settings server.WithCheckCacheLimit(cfg.CacheSettings.CheckCacheLimit), server.WithCacheControllerEnabled(cfg.CacheSettings.CacheControllerEnabled), server.WithCacheControllerTTL(cfg.CacheSettings.CacheControllerTTL), @@ -40,16 +42,25 @@ func NewOpenFGAServer(cfg setting.ZanzanaServerSettings, store storage.OpenFGADa server.WithCheckIteratorCacheEnabled(cfg.CacheSettings.CheckIteratorCacheEnabled), server.WithCheckIteratorCacheMaxResults(cfg.CacheSettings.CheckIteratorCacheMaxResults), server.WithCheckIteratorCacheTTL(cfg.CacheSettings.CheckIteratorCacheTTL), + + // ListObjects settings server.WithListObjectsMaxResults(cfg.ListObjectsMaxResults), server.WithListObjectsIteratorCacheEnabled(cfg.CacheSettings.ListObjectsIteratorCacheEnabled), server.WithListObjectsIteratorCacheMaxResults(cfg.CacheSettings.ListObjectsIteratorCacheMaxResults), server.WithListObjectsIteratorCacheTTL(cfg.CacheSettings.ListObjectsIteratorCacheTTL), + server.WithListObjectsDeadline(cfg.ListObjectsDeadline), + + // Shared iterator settings server.WithSharedIteratorEnabled(cfg.CacheSettings.SharedIteratorEnabled), server.WithSharedIteratorLimit(cfg.CacheSettings.SharedIteratorLimit), server.WithSharedIteratorTTL(cfg.CacheSettings.SharedIteratorTTL), - server.WithListObjectsDeadline(cfg.ListObjectsDeadline), + + server.WithContextPropagationToDatastore(true), } + openfgaOpts := withOpenFGAOptions(cfg) + opts = append(opts, openfgaOpts...) + srv, err := server.NewServerWithOpts(opts...) if err != nil { return nil, err @@ -58,6 +69,129 @@ func NewOpenFGAServer(cfg setting.ZanzanaServerSettings, store storage.OpenFGADa return srv, nil } +func withOpenFGAOptions(cfg setting.ZanzanaServerSettings) []server.OpenFGAServiceV1Option { + opts := make([]server.OpenFGAServiceV1Option, 0) + + listOpts := withListOptions(cfg) + opts = append(opts, listOpts...) + + // Check settings + if cfg.OpenFgaServerSettings.MaxConcurrentReadsForCheck != 0 { + opts = append(opts, server.WithMaxConcurrentReadsForCheck(cfg.OpenFgaServerSettings.MaxConcurrentReadsForCheck)) + } + if cfg.OpenFgaServerSettings.CheckDatabaseThrottleThreshold != 0 || cfg.OpenFgaServerSettings.CheckDatabaseThrottleDuration != 0 { + opts = append(opts, server.WithCheckDatabaseThrottle(cfg.OpenFgaServerSettings.CheckDatabaseThrottleThreshold, cfg.OpenFgaServerSettings.CheckDatabaseThrottleDuration)) + } + + // Batch check settings + if cfg.OpenFgaServerSettings.MaxConcurrentChecksPerBatchCheck != 0 { + opts = append(opts, server.WithMaxConcurrentChecksPerBatchCheck(cfg.OpenFgaServerSettings.MaxConcurrentChecksPerBatchCheck)) + } + if cfg.OpenFgaServerSettings.MaxChecksPerBatchCheck != 0 { + opts = append(opts, server.WithMaxChecksPerBatchCheck(cfg.OpenFgaServerSettings.MaxChecksPerBatchCheck)) + } + + // Resolve node settings + if cfg.OpenFgaServerSettings.ResolveNodeLimit != 0 { + opts = append(opts, server.WithResolveNodeLimit(cfg.OpenFgaServerSettings.ResolveNodeLimit)) + } + if cfg.OpenFgaServerSettings.ResolveNodeBreadthLimit != 0 { + opts = append(opts, server.WithResolveNodeBreadthLimit(cfg.OpenFgaServerSettings.ResolveNodeBreadthLimit)) + } + + // Dispatch throttling settings + if cfg.OpenFgaServerSettings.DispatchThrottlingCheckResolverEnabled { + opts = append(opts, server.WithDispatchThrottlingCheckResolverEnabled(cfg.OpenFgaServerSettings.DispatchThrottlingCheckResolverEnabled)) + } + if cfg.OpenFgaServerSettings.DispatchThrottlingCheckResolverFrequency != 0 { + opts = append(opts, server.WithDispatchThrottlingCheckResolverFrequency(cfg.OpenFgaServerSettings.DispatchThrottlingCheckResolverFrequency)) + } + if cfg.OpenFgaServerSettings.DispatchThrottlingCheckResolverThreshold != 0 { + opts = append(opts, server.WithDispatchThrottlingCheckResolverThreshold(cfg.OpenFgaServerSettings.DispatchThrottlingCheckResolverThreshold)) + } + if cfg.OpenFgaServerSettings.DispatchThrottlingCheckResolverMaxThreshold != 0 { + opts = append(opts, server.WithDispatchThrottlingCheckResolverMaxThreshold(cfg.OpenFgaServerSettings.DispatchThrottlingCheckResolverMaxThreshold)) + } + + // Shadow check/query settings + if cfg.OpenFgaServerSettings.ShadowCheckResolverTimeout != 0 { + opts = append(opts, server.WithShadowCheckResolverTimeout(cfg.OpenFgaServerSettings.ShadowCheckResolverTimeout)) + } + if cfg.OpenFgaServerSettings.ShadowListObjectsQueryTimeout != 0 { + opts = append(opts, server.WithShadowListObjectsQueryTimeout(cfg.OpenFgaServerSettings.ShadowListObjectsQueryTimeout)) + } + if cfg.OpenFgaServerSettings.ShadowListObjectsQueryMaxDeltaItems != 0 { + opts = append(opts, server.WithShadowListObjectsQueryMaxDeltaItems(cfg.OpenFgaServerSettings.ShadowListObjectsQueryMaxDeltaItems)) + } + + if cfg.OpenFgaServerSettings.RequestTimeout != 0 { + opts = append(opts, server.WithRequestTimeout(cfg.OpenFgaServerSettings.RequestTimeout)) + } + if cfg.OpenFgaServerSettings.MaxAuthorizationModelSizeInBytes != 0 { + opts = append(opts, server.WithMaxAuthorizationModelSizeInBytes(cfg.OpenFgaServerSettings.MaxAuthorizationModelSizeInBytes)) + } + if cfg.OpenFgaServerSettings.AuthorizationModelCacheSize != 0 { + opts = append(opts, server.WithAuthorizationModelCacheSize(cfg.OpenFgaServerSettings.AuthorizationModelCacheSize)) + } + if cfg.OpenFgaServerSettings.ChangelogHorizonOffset != 0 { + opts = append(opts, server.WithChangelogHorizonOffset(cfg.OpenFgaServerSettings.ChangelogHorizonOffset)) + } + + return opts +} + +func withListOptions(cfg setting.ZanzanaServerSettings) []server.OpenFGAServiceV1Option { + opts := make([]server.OpenFGAServiceV1Option, 0) + + // ListObjects settings + if cfg.OpenFgaServerSettings.MaxConcurrentReadsForListObjects != 0 { + opts = append(opts, server.WithMaxConcurrentReadsForListObjects(cfg.OpenFgaServerSettings.MaxConcurrentReadsForListObjects)) + } + if cfg.OpenFgaServerSettings.ListObjectsDispatchThrottlingEnabled { + opts = append(opts, server.WithListObjectsDispatchThrottlingEnabled(cfg.OpenFgaServerSettings.ListObjectsDispatchThrottlingEnabled)) + } + if cfg.OpenFgaServerSettings.ListObjectsDispatchThrottlingFrequency != 0 { + opts = append(opts, server.WithListObjectsDispatchThrottlingFrequency(cfg.OpenFgaServerSettings.ListObjectsDispatchThrottlingFrequency)) + } + if cfg.OpenFgaServerSettings.ListObjectsDispatchThrottlingThreshold != 0 { + opts = append(opts, server.WithListObjectsDispatchThrottlingThreshold(cfg.OpenFgaServerSettings.ListObjectsDispatchThrottlingThreshold)) + } + if cfg.OpenFgaServerSettings.ListObjectsDispatchThrottlingMaxThreshold != 0 { + opts = append(opts, server.WithListObjectsDispatchThrottlingMaxThreshold(cfg.OpenFgaServerSettings.ListObjectsDispatchThrottlingMaxThreshold)) + } + if cfg.OpenFgaServerSettings.ListObjectsDatabaseThrottleThreshold != 0 || cfg.OpenFgaServerSettings.ListObjectsDatabaseThrottleDuration != 0 { + opts = append(opts, server.WithListObjectsDatabaseThrottle(cfg.OpenFgaServerSettings.ListObjectsDatabaseThrottleThreshold, cfg.OpenFgaServerSettings.ListObjectsDatabaseThrottleDuration)) + } + + // ListUsers settings + if cfg.OpenFgaServerSettings.ListUsersDeadline != 0 { + opts = append(opts, server.WithListUsersDeadline(cfg.OpenFgaServerSettings.ListUsersDeadline)) + } + if cfg.OpenFgaServerSettings.ListUsersMaxResults != 0 { + opts = append(opts, server.WithListUsersMaxResults(cfg.OpenFgaServerSettings.ListUsersMaxResults)) + } + if cfg.OpenFgaServerSettings.MaxConcurrentReadsForListUsers != 0 { + opts = append(opts, server.WithMaxConcurrentReadsForListUsers(cfg.OpenFgaServerSettings.MaxConcurrentReadsForListUsers)) + } + if cfg.OpenFgaServerSettings.ListUsersDispatchThrottlingEnabled { + opts = append(opts, server.WithListUsersDispatchThrottlingEnabled(cfg.OpenFgaServerSettings.ListUsersDispatchThrottlingEnabled)) + } + if cfg.OpenFgaServerSettings.ListUsersDispatchThrottlingFrequency != 0 { + opts = append(opts, server.WithListUsersDispatchThrottlingFrequency(cfg.OpenFgaServerSettings.ListUsersDispatchThrottlingFrequency)) + } + if cfg.OpenFgaServerSettings.ListUsersDispatchThrottlingThreshold != 0 { + opts = append(opts, server.WithListUsersDispatchThrottlingThreshold(cfg.OpenFgaServerSettings.ListUsersDispatchThrottlingThreshold)) + } + if cfg.OpenFgaServerSettings.ListUsersDispatchThrottlingMaxThreshold != 0 { + opts = append(opts, server.WithListUsersDispatchThrottlingMaxThreshold(cfg.OpenFgaServerSettings.ListUsersDispatchThrottlingMaxThreshold)) + } + if cfg.OpenFgaServerSettings.ListUsersDatabaseThrottleThreshold != 0 || cfg.OpenFgaServerSettings.ListUsersDatabaseThrottleDuration != 0 { + opts = append(opts, server.WithListUsersDatabaseThrottle(cfg.OpenFgaServerSettings.ListUsersDatabaseThrottleThreshold, cfg.OpenFgaServerSettings.ListUsersDatabaseThrottleDuration)) + } + + return opts +} + func NewOpenFGAHttpServer(cfg setting.ZanzanaServerSettings, srv grpcserver.Provider) (*http.Server, error) { dialOpts := []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials()), diff --git a/pkg/setting/settings_zanzana.go b/pkg/setting/settings_zanzana.go index d30304e4bd0..f1814ab7be4 100644 --- a/pkg/setting/settings_zanzana.go +++ b/pkg/setting/settings_zanzana.go @@ -37,6 +37,8 @@ type ZanzanaServerSettings struct { OpenFGAHttpAddr string // Cache settings CacheSettings OpenFgaCacheSettings + // OpenFGA server settings + OpenFgaServerSettings OpenFgaServerSettings // Max number of results returned by ListObjects() query. Default is 1000. ListObjectsMaxResults uint32 // Deadline for the ListObjects() query. Default is 3 seconds. @@ -50,6 +52,92 @@ type ZanzanaServerSettings struct { AllowInsecure bool } +type OpenFgaServerSettings struct { + // ListObjects settings + // Max number of concurrent datastore reads for ListObjects queries + MaxConcurrentReadsForListObjects uint32 + // Enable dispatch throttling for ListObjects queries + ListObjectsDispatchThrottlingEnabled bool + // Frequency for dispatch throttling in ListObjects queries + ListObjectsDispatchThrottlingFrequency time.Duration + // Threshold for dispatch throttling in ListObjects queries + ListObjectsDispatchThrottlingThreshold uint32 + // Max threshold for dispatch throttling in ListObjects queries + ListObjectsDispatchThrottlingMaxThreshold uint32 + // Database throttle threshold for ListObjects queries + ListObjectsDatabaseThrottleThreshold int + // Database throttle duration for ListObjects queries + ListObjectsDatabaseThrottleDuration time.Duration + + // ListUsers settings + // Deadline for ListUsers queries + ListUsersDeadline time.Duration + // Max number of results returned by ListUsers queries + ListUsersMaxResults uint32 + // Max number of concurrent datastore reads for ListUsers queries + MaxConcurrentReadsForListUsers uint32 + // Enable dispatch throttling for ListUsers queries + ListUsersDispatchThrottlingEnabled bool + // Frequency for dispatch throttling in ListUsers queries + ListUsersDispatchThrottlingFrequency time.Duration + // Threshold for dispatch throttling in ListUsers queries + ListUsersDispatchThrottlingThreshold uint32 + // Max threshold for dispatch throttling in ListUsers queries + ListUsersDispatchThrottlingMaxThreshold uint32 + // Database throttle threshold for ListUsers queries + ListUsersDatabaseThrottleThreshold int + // Database throttle duration for ListUsers queries + ListUsersDatabaseThrottleDuration time.Duration + + // Check settings + // Max number of concurrent datastore reads for Check queries + MaxConcurrentReadsForCheck uint32 + // Database throttle threshold for Check queries + CheckDatabaseThrottleThreshold int + // Database throttle duration for Check queries + CheckDatabaseThrottleDuration time.Duration + + // Batch check settings + // Max number of concurrent checks per batch check request + MaxConcurrentChecksPerBatchCheck uint32 + // Max number of checks per batch check request + MaxChecksPerBatchCheck uint32 + + // Resolve node settings + // Max number of nodes that can be resolved in a single query + ResolveNodeLimit uint32 + // Max breadth of nodes that can be resolved in a single query + ResolveNodeBreadthLimit uint32 + + // Dispatch throttling settings for Check resolver + // Enable dispatch throttling for Check resolver + DispatchThrottlingCheckResolverEnabled bool + // Frequency for dispatch throttling in Check resolver + DispatchThrottlingCheckResolverFrequency time.Duration + // Threshold for dispatch throttling in Check resolver + DispatchThrottlingCheckResolverThreshold uint32 + // Max threshold for dispatch throttling in Check resolver + DispatchThrottlingCheckResolverMaxThreshold uint32 + + // Shadow check/query settings + // Timeout for shadow check resolver + ShadowCheckResolverTimeout time.Duration + // Timeout for shadow ListObjects query + ShadowListObjectsQueryTimeout time.Duration + // Max delta items for shadow ListObjects query + ShadowListObjectsQueryMaxDeltaItems int + + // Request settings + // Global request timeout + RequestTimeout time.Duration + // Max size in bytes for authorization model + MaxAuthorizationModelSizeInBytes int + // Size of the authorization model cache + AuthorizationModelCacheSize int + // Offset for changelog horizon + ChangelogHorizonOffset int +} + // Parameters to configure OpenFGA cache. type OpenFgaCacheSettings struct { // Number of items that will be kept in the in-memory cache used to resolve Check queries. @@ -156,5 +244,56 @@ func (cfg *Cfg) readZanzanaSettings() { zs.CacheSettings.SharedIteratorLimit = uint32(serverSec.Key("shared_iterator_limit").MustUint(1000)) zs.CacheSettings.SharedIteratorTTL = serverSec.Key("shared_iterator_ttl").MustDuration(10 * time.Second) + openfgaSec := cfg.SectionWithEnvOverrides("openfga") + + // ListObjects settings + zs.OpenFgaServerSettings.MaxConcurrentReadsForListObjects = uint32(openfgaSec.Key("max_concurrent_reads_for_list_objects").MustUint(0)) + zs.OpenFgaServerSettings.ListObjectsDispatchThrottlingEnabled = openfgaSec.Key("list_objects_dispatch_throttling_enabled").MustBool(false) + zs.OpenFgaServerSettings.ListObjectsDispatchThrottlingFrequency = openfgaSec.Key("list_objects_dispatch_throttling_frequency").MustDuration(0) + zs.OpenFgaServerSettings.ListObjectsDispatchThrottlingThreshold = uint32(openfgaSec.Key("list_objects_dispatch_throttling_threshold").MustUint(0)) + zs.OpenFgaServerSettings.ListObjectsDispatchThrottlingMaxThreshold = uint32(openfgaSec.Key("list_objects_dispatch_throttling_max_threshold").MustUint(0)) + zs.OpenFgaServerSettings.ListObjectsDatabaseThrottleThreshold = openfgaSec.Key("list_objects_database_throttle_threshold").MustInt(0) + zs.OpenFgaServerSettings.ListObjectsDatabaseThrottleDuration = openfgaSec.Key("list_objects_database_throttle_duration").MustDuration(0) + + // ListUsers settings + zs.OpenFgaServerSettings.ListUsersDeadline = openfgaSec.Key("list_users_deadline").MustDuration(0) + zs.OpenFgaServerSettings.ListUsersMaxResults = uint32(openfgaSec.Key("list_users_max_results").MustUint(0)) + zs.OpenFgaServerSettings.MaxConcurrentReadsForListUsers = uint32(openfgaSec.Key("max_concurrent_reads_for_list_users").MustUint(0)) + zs.OpenFgaServerSettings.ListUsersDispatchThrottlingEnabled = openfgaSec.Key("list_users_dispatch_throttling_enabled").MustBool(false) + zs.OpenFgaServerSettings.ListUsersDispatchThrottlingFrequency = openfgaSec.Key("list_users_dispatch_throttling_frequency").MustDuration(0) + zs.OpenFgaServerSettings.ListUsersDispatchThrottlingThreshold = uint32(openfgaSec.Key("list_users_dispatch_throttling_threshold").MustUint(0)) + zs.OpenFgaServerSettings.ListUsersDispatchThrottlingMaxThreshold = uint32(openfgaSec.Key("list_users_dispatch_throttling_max_threshold").MustUint(0)) + zs.OpenFgaServerSettings.ListUsersDatabaseThrottleThreshold = openfgaSec.Key("list_users_database_throttle_threshold").MustInt(0) + zs.OpenFgaServerSettings.ListUsersDatabaseThrottleDuration = openfgaSec.Key("list_users_database_throttle_duration").MustDuration(0) + + // Check settings + zs.OpenFgaServerSettings.MaxConcurrentReadsForCheck = uint32(openfgaSec.Key("max_concurrent_reads_for_check").MustUint(0)) + zs.OpenFgaServerSettings.CheckDatabaseThrottleThreshold = openfgaSec.Key("check_database_throttle_threshold").MustInt(0) + zs.OpenFgaServerSettings.CheckDatabaseThrottleDuration = openfgaSec.Key("check_database_throttle_duration").MustDuration(0) + + // Batch check settings + zs.OpenFgaServerSettings.MaxConcurrentChecksPerBatchCheck = uint32(openfgaSec.Key("max_concurrent_checks_per_batch_check").MustUint(0)) + zs.OpenFgaServerSettings.MaxChecksPerBatchCheck = uint32(openfgaSec.Key("max_checks_per_batch_check").MustUint(0)) + + // Resolve node settings + zs.OpenFgaServerSettings.ResolveNodeLimit = uint32(openfgaSec.Key("resolve_node_limit").MustUint(0)) + zs.OpenFgaServerSettings.ResolveNodeBreadthLimit = uint32(openfgaSec.Key("resolve_node_breadth_limit").MustUint(0)) + + // Dispatch throttling settings for Check resolver + zs.OpenFgaServerSettings.DispatchThrottlingCheckResolverEnabled = openfgaSec.Key("dispatch_throttling_check_resolver_enabled").MustBool(false) + zs.OpenFgaServerSettings.DispatchThrottlingCheckResolverFrequency = openfgaSec.Key("dispatch_throttling_check_resolver_frequency").MustDuration(0) + zs.OpenFgaServerSettings.DispatchThrottlingCheckResolverThreshold = uint32(openfgaSec.Key("dispatch_throttling_check_resolver_threshold").MustUint(0)) + zs.OpenFgaServerSettings.DispatchThrottlingCheckResolverMaxThreshold = uint32(openfgaSec.Key("dispatch_throttling_check_resolver_max_threshold").MustUint(0)) + + // Shadow check/query settings + zs.OpenFgaServerSettings.ShadowCheckResolverTimeout = openfgaSec.Key("shadow_check_resolver_timeout").MustDuration(0) + zs.OpenFgaServerSettings.ShadowListObjectsQueryTimeout = openfgaSec.Key("shadow_list_objects_query_timeout").MustDuration(0) + zs.OpenFgaServerSettings.ShadowListObjectsQueryMaxDeltaItems = openfgaSec.Key("shadow_list_objects_query_max_delta_items").MustInt(0) + + zs.OpenFgaServerSettings.RequestTimeout = openfgaSec.Key("request_timeout").MustDuration(0) + zs.OpenFgaServerSettings.MaxAuthorizationModelSizeInBytes = openfgaSec.Key("max_authorization_model_size_in_bytes").MustInt(0) + zs.OpenFgaServerSettings.AuthorizationModelCacheSize = openfgaSec.Key("authorization_model_cache_size").MustInt(0) + zs.OpenFgaServerSettings.ChangelogHorizonOffset = openfgaSec.Key("changelog_horizon_offset").MustInt(0) + cfg.ZanzanaServer = zs }