diff --git a/extauthz/Makefile b/extauthz/Makefile index 698d679..2f9887a 100644 --- a/extauthz/Makefile +++ b/extauthz/Makefile @@ -22,6 +22,7 @@ build-platform: .PHONY: docker docker: build @docker build --platform=$(DOCKER_PLATFORM) -t gcr.io/openfga/openfga-extauthz:$(PACKAGE_VERSION) -f Dockerfile . + @echo "\nImage available by doing:\n\ndocker pull --platform=$(DOCKER_PLATFORM) gcr.io/openfga/openfga-extauthz:$(PACKAGE_VERSION)\n" .PHONY: e2e e2e: e2e-tools diff --git a/extauthz/cmd/extauthz/main.go b/extauthz/cmd/extauthz/main.go index 12c3e12..f9a3400 100644 --- a/extauthz/cmd/extauthz/main.go +++ b/extauthz/cmd/extauthz/main.go @@ -33,49 +33,59 @@ func main() { log.Fatalf("failed to load config: %v", err) } - fgaClient, err := client.NewSdkClient(&client.ClientConfiguration{ - ApiUrl: cfg.Server.APIURL, - StoreId: cfg.Server.StoreID, - AuthorizationModelId: cfg.Server.AuthorizationModelID, // optional, recommended to be set for production - }) + logger, err := logger.NewLogger(parseLogConfig(cfg.Log)...) if err != nil { - log.Fatalf("failed to initialize OpenFGA client: %v", err) + log.Fatalf("failed to create logger: %v", err) } + defer logger.Sync() - extractionSet := make([]extractor.ExtractorKit, 0, len(cfg.ExtractionSet)) - for _, es := range cfg.ExtractionSet { - var ( - eSet extractor.ExtractorKit - err error - ) - - eSet.Name = es.Name - - eSet.User, err = extractor.MakeExtractor(es.User.Type, es.User.Config) + var filter auth_pb.AuthorizationServer = authz.NoopFilter{} + if cfg.Mode != config.AuthModeDisabled { + fgaClient, err := client.NewSdkClient(&client.ClientConfiguration{ + ApiUrl: cfg.Server.APIURL, + StoreId: cfg.Server.StoreID, + AuthorizationModelId: cfg.Server.AuthorizationModelID, // optional, recommended to be set for production + }) if err != nil { - log.Fatalf("failed to create user extractor: %v", err) + logger.Fatal("failed to initialize OpenFGA client", zap.Error(err)) } - eSet.Object, err = extractor.MakeExtractor(es.Object.Type, es.Object.Config) - if err != nil { - log.Fatalf("failed to create object extractor: %v", err) - } + extractionSet := make([]extractor.ExtractorKit, 0, len(cfg.ExtractionSet)) + for _, es := range cfg.ExtractionSet { + var ( + eSet extractor.ExtractorKit + err error + ) - eSet.Relation, err = extractor.MakeExtractor(es.Relation.Type, es.Relation.Config) - if err != nil { - log.Fatalf("failed to create relation extractor: %v", err) - } + eSet.Name = es.Name - extractionSet = append(extractionSet, eSet) - } + eSet.User, err = extractor.MakeExtractor(es.User.Type, es.User.Config) + if err != nil { + logger.Fatal("failed to create user extractor", zap.Error(err)) + } - logger, err := logger.NewLogger(parseLogConfig(cfg.Log)...) - if err != nil { - log.Fatalf("failed to create logger: %v", err) - } - defer logger.Sync() + eSet.Object, err = extractor.MakeExtractor(es.Object.Type, es.Object.Config) + if err != nil { + logger.Fatal("failed to create object extractor", zap.Error(err)) + } - filter := authz.NewExtAuthZFilter(fgaClient, extractionSet, logger) + eSet.Relation, err = extractor.MakeExtractor(es.Relation.Type, es.Relation.Config) + if err != nil { + logger.Fatal("failed to create relation extractor", zap.Error(err)) + } + + extractionSet = append(extractionSet, eSet) + } + + filter = authz.NewExtAuthZFilter( + authz.Config{ + Enforce: cfg.Mode == config.AuthModeEnforce, + ExtractionKits: extractionSet, + }, + fgaClient, + logger, + ) + } server := createServer(filter) @@ -84,11 +94,11 @@ func main() { log.Fatalf("failed start listener: %v", err) } - logger.Info("Starting server", zap.Int("port", port)) + logger.Info("Starting server", zap.Int("port", port), zap.String("mode", cfg.Mode.String())) log.Fatal(server.Serve(listener)) } -func createServer(filter *authz.ExtAuthZFilter) *grpc.Server { +func createServer(filter auth_pb.AuthorizationServer) *grpc.Server { grpcServer := grpc.NewServer() grpc_health_v1.RegisterHealthServer(grpcServer, health.NewServer()) diff --git a/extauthz/cmd/extauthz/main_test.go b/extauthz/cmd/extauthz/main_test.go index 2fd4989..a005753 100644 --- a/extauthz/cmd/extauthz/main_test.go +++ b/extauthz/cmd/extauthz/main_test.go @@ -29,7 +29,10 @@ func server(ctx context.Context, e extractor.ExtractorKit) (auth_pb.Authorizatio panic(err) } - filter := authz.NewExtAuthZFilter(fgaClient, []extractor.ExtractorKit{e}, logger.NewNoopLogger()) + filter := authz.NewExtAuthZFilter(authz.Config{ + Enforce: true, + ExtractionKits: []extractor.ExtractorKit{e}, + }, fgaClient, logger.NewNoopLogger()) baseServer := grpc.NewServer() auth_pb.RegisterAuthorizationServer(baseServer, filter) diff --git a/extauthz/e2e/config.yaml.tmpl b/extauthz/e2e/config.yaml.tmpl index f9ec2e9..2278266 100644 --- a/extauthz/e2e/config.yaml.tmpl +++ b/extauthz/e2e/config.yaml.tmpl @@ -7,6 +7,8 @@ log: level: debug format: json +mode: ENFORCE + extraction_sets: - name: test user: diff --git a/extauthz/go.mod b/extauthz/go.mod index c0aa33c..838009a 100644 --- a/extauthz/go.mod +++ b/extauthz/go.mod @@ -3,13 +3,13 @@ module github.com/openfga/openfga-envoy/extauthz go 1.22.6 require ( - github.com/envoyproxy/go-control-plane v0.12.1-0.20240419124334-0cebb2f428b3 + github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155 github.com/openfga/go-sdk v0.3.5 - github.com/openfga/openfga v1.6.0 + github.com/openfga/openfga v1.6.1-0.20240906222438-b8787d5f9d21 github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd - google.golang.org/grpc v1.65.0 + google.golang.org/grpc v1.66.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/extauthz/go.sum b/extauthz/go.sum index 50c3a5e..9038c7a 100644 --- a/extauthz/go.sum +++ b/extauthz/go.sum @@ -2,8 +2,8 @@ github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnTh github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.12.1-0.20240419124334-0cebb2f428b3 h1:/eklMEyfPvB7C8dULCt9GYwpYDy6shwe7vqHMS+82bI= -github.com/envoyproxy/go-control-plane v0.12.1-0.20240419124334-0cebb2f428b3/go.mod h1:rlr50u7tACJ1Y9jCUMndkfLvGCAX3fWXVVAkj+OfzT4= +github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155 h1:IgJPqnrlY2Mr4pYB6oaMKvFvwJ9H+X6CCY5x1vCTcpc= +github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155/go.mod h1:5Wkq+JduFtdAXihLmeTJf+tRYIT4KBc2vPXDhwVo1pA= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -16,8 +16,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/openfga/go-sdk v0.3.5 h1:KQXhMREh+g/K7HNuZ/YmXuHkREkq0VMKteua4bYr3Uw= github.com/openfga/go-sdk v0.3.5/go.mod h1:u1iErzj5E9/bhe+8nsMv0gigcYbJtImcdgcE5DmpbBg= -github.com/openfga/openfga v1.6.0 h1:AfTEEK2PJzZPywSYWtOS3IXtHmqPKdLxGr/z+LFUMGk= -github.com/openfga/openfga v1.6.0/go.mod h1:/Q7/Bg/VeN3m68pAcmySejw/Xpp8HwTV92zrsLBoavo= +github.com/openfga/openfga v1.6.1-0.20240906222438-b8787d5f9d21 h1:69fhvi0rg4dGyQ0lcvwVsFtXYvDDkrHPjJEsPFGpgj0= +github.com/openfga/openfga v1.6.1-0.20240906222438-b8787d5f9d21/go.mod h1:UrS0j/EOT9HuQGGIPcyDApOyK6JaOmzqiK1+ex1wKoY= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -42,8 +42,8 @@ golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/extauthz/internal/server/authz/authz.go b/extauthz/internal/server/authz/authz.go index 4bb7f8c..bb42949 100644 --- a/extauthz/internal/server/authz/authz.go +++ b/extauthz/internal/server/authz/authz.go @@ -37,41 +37,64 @@ var ( // ExtAuthZFilter is an implementation of the Envoy AuthZ filter. type ExtAuthZFilter struct { - client *client.OpenFgaClient - extractionKit []extractor.ExtractorKit - modelID string - logger logger.Logger + enforce bool + client *client.OpenFgaClient + extractionKits []extractor.ExtractorKit + modelID string + logger logger.Logger } var _ envoy.AuthorizationServer = (*ExtAuthZFilter)(nil) +type Config struct { + Enforce bool + ExtractionKits []extractor.ExtractorKit +} + // NewExtAuthZFilter creates a new ExtAuthZFilter -func NewExtAuthZFilter(c *client.OpenFgaClient, es []extractor.ExtractorKit, logger logger.Logger) *ExtAuthZFilter { - return &ExtAuthZFilter{client: c, extractionKit: es, logger: logger} +func NewExtAuthZFilter(config Config, c *client.OpenFgaClient, logger logger.Logger) *ExtAuthZFilter { + return &ExtAuthZFilter{enforce: config.Enforce, client: c, extractionKits: config.ExtractionKits, logger: logger} } func (e ExtAuthZFilter) Register(server *grpc.Server) { envoy.RegisterAuthorizationServer(server, e) } +// Check the access decision based on the incoming request func (e ExtAuthZFilter) Check(ctx context.Context, req *envoy.CheckRequest) (response *envoy.CheckResponse, err error) { - res, err := e.check(ctx, req) - if err != nil { - e.logger.Error("failed to check permissions", zap.Error(err)) - return nil, err + reqID := req.Attributes.GetRequest().GetHttp().GetHeaders()["x-request-id"] + logger := e.logger + if reqID != "" { + logger = e.logger.With(zap.String("request_id", reqID)) } - return res, nil + res, err := e.check(ctx, req, logger) + if e.enforce { + if err != nil { + logger.Error("Failed to check permissions", zap.Error(err)) + return nil, err + } + + return res, nil + } else { + if err != nil { + logger.Error("Failed to check permissions", zap.Error(err)) + } + + return allow, nil + } } func (e ExtAuthZFilter) extract(ctx context.Context, req *envoy.CheckRequest) (*extractor.Check, error) { - for _, es := range e.extractionKit { + for _, es := range e.extractionKits { + e.logger.Debug("Extracting values", zap.String("extractor", es.Name)) check, err := es.Extract(ctx, req) if err == nil { return check, nil } if errors.Is(err, extractor.ErrValueNotFound) { + e.logger.Debug("Extracing value not found", zap.String("extraction_kit", es.Name), zap.Error(err)) continue } @@ -82,16 +105,14 @@ func (e ExtAuthZFilter) extract(ctx context.Context, req *envoy.CheckRequest) (* } // Check implements the Check method of the Authorization interface. -func (e ExtAuthZFilter) check(ctx context.Context, req *envoy.CheckRequest) (response *envoy.CheckResponse, err error) { - // TODO: create a new logger when the interface includes the method - reqID := req.Attributes.GetRequest().GetHttp().GetHeaders()["x-request-id"] +func (e ExtAuthZFilter) check(ctx context.Context, req *envoy.CheckRequest, logger logger.Logger) (response *envoy.CheckResponse, err error) { check, err := e.extract(ctx, req) if err != nil { return nil, fmt.Errorf("extracting values from request: %w", err) } if check == nil { - e.logger.Error("failed to extract values from request", zap.String("request_id", reqID)) + logger.Error("Failed to extract values from request") return deny(codes.InvalidArgument, "No extraction set found"), nil } @@ -109,15 +130,15 @@ func (e ExtAuthZFilter) check(ctx context.Context, req *envoy.CheckRequest) (res e.logger.Debug("Checking permissions", zap.String("user", check.User), zap.String("relation", check.Relation), zap.String("object", check.Object)) data, err := e.client.Check(ctx).Body(body).Options(options).Execute() if err != nil { - e.logger.Error("Failed to check permissions", zap.Error(err), zap.String("request_id", reqID)) + logger.Error("Failed to check permissions", zap.Error(err)) return deny(codes.Internal, fmt.Sprintf("Error checking permissions: %v", err)), nil } if data.GetAllowed() { - e.logger.Debug("Access granted", zap.String("resolution", data.GetResolution()), zap.String("request_id", reqID)) + logger.Debug("Access granted", zap.String("resolution", data.GetResolution())) return allow, nil } - e.logger.Debug("Access denied", zap.String("request_id", reqID)) + logger.Debug("Access denied") return deny(codes.PermissionDenied, fmt.Sprintf("Access denied: %s", data.GetResolution())), nil } diff --git a/extauthz/internal/server/authz/noop.go b/extauthz/internal/server/authz/noop.go new file mode 100644 index 0000000..5ff3262 --- /dev/null +++ b/extauthz/internal/server/authz/noop.go @@ -0,0 +1,21 @@ +package authz + +import ( + "context" + + envoy "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" + "google.golang.org/grpc" +) + +// NoopFilter is a noop implementation of the Envoy AuthZ filter. +type NoopFilter struct{} + +var _ envoy.AuthorizationServer = NoopFilter{} + +func (e NoopFilter) Register(server *grpc.Server) { + envoy.RegisterAuthorizationServer(server, e) +} + +func (e NoopFilter) Check(ctx context.Context, req *envoy.CheckRequest) (response *envoy.CheckResponse, err error) { + return allow, nil +} diff --git a/extauthz/internal/server/config/config.go b/extauthz/internal/server/config/config.go index 7e1c859..7116e46 100644 --- a/extauthz/internal/server/config/config.go +++ b/extauthz/internal/server/config/config.go @@ -1,6 +1,7 @@ package config import ( + "errors" "fmt" "os" @@ -52,10 +53,47 @@ type ExtractionSet struct { Relation Extractor `yaml:"relation"` } +type AuthMode int8 + +const ( + AuthModeMonitor AuthMode = iota + 1 + AuthModeEnforce + AuthModeDisabled +) + +func (m AuthMode) String() string { + switch m { + case AuthModeMonitor: + return "MONITOR" + case AuthModeEnforce: + return "ENFORCE" + case AuthModeDisabled: + return "DISABLED" + } + + return "UNKNOWN" +} + +func (m *AuthMode) UnmarshalYAML(value *yaml.Node) error { + switch value.Value { + case "ENFORCE": + *m = AuthModeEnforce + case "DISABLED": + *m = AuthModeDisabled + case "MONITOR": + *m = AuthModeMonitor + default: + return errors.New("unknown mode") + } + + return nil +} + type Config struct { ExtractionSet []ExtractionSet `yaml:"extraction_sets"` Server Server `yaml:"server"` - Log Log + Log Log `yaml:"log"` + Mode AuthMode `yaml:"mode"` } type Log struct { diff --git a/extauthz/internal/server/config/config_test.go b/extauthz/internal/server/config/config_test.go index 343a7e9..b4cf56b 100644 --- a/extauthz/internal/server/config/config_test.go +++ b/extauthz/internal/server/config/config_test.go @@ -18,6 +18,8 @@ func TestConfig(t *testing.T) { require.Equal(t, "text", cfg.Log.Format) require.Equal(t, "ISO8601", cfg.Log.TimestampFormat) + require.Equal(t, AuthModeEnforce, cfg.Mode) + require.Len(t, cfg.ExtractionSet, 1) require.Equal(t, "test", cfg.ExtractionSet[0].Name) require.Equal(t, "mock", cfg.ExtractionSet[0].User.Type) diff --git a/extauthz/internal/server/config/testdata/config.yaml b/extauthz/internal/server/config/testdata/config.yaml index bfe1966..5cf4d51 100644 --- a/extauthz/internal/server/config/testdata/config.yaml +++ b/extauthz/internal/server/config/testdata/config.yaml @@ -8,6 +8,8 @@ log: format: text timestamp_format: "ISO8601" +mode: ENFORCE + extraction_sets: - name: test user: diff --git a/go.work.sum b/go.work.sum index d9793a4..be0d6f3 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,25 +1,135 @@ cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v27.1.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jon-whit/go-grpc-prometheus v1.4.0/go.mod h1:iTPm+Iuhh3IIqR0iGZ91JJEg5ax6YQEe1I0f6vtBuao= +github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/natefinch/wrap v0.2.0/go.mod h1:6gMHlAl12DwYEfKP3TkuykYUfLSEAvHw67itm4/KAS8= +github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/openfga/api/proto v0.0.0-20240807201305-c96ec773cae9/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0= +github.com/openfga/api/proto v0.0.0-20240905181937-3583905f61a6/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0= +github.com/openfga/language/pkg/go v0.2.0-beta.0/go.mod h1:mCwEY2IQvyNgfEwbfH0C0ERUwtL8z6UjSAF8zgn5Xbg= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pressly/goose/v3 v3.21.1/go.mod h1:sqthmzV8PitchEkjecFJII//l43dLOCzfWh8pHEe+vE= +github.com/pressly/goose/v3 v3.22.0/go.mod h1:yJM3qwSj2pp7aAaCvso096sguezamNb2OBgxCnh/EYg= +github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= +github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=