From 69b3879f7d32222daad0b4b870f00c96204c1086 Mon Sep 17 00:00:00 2001 From: prithvi <47061269+prithvi081099@users.noreply.github.com> Date: Fri, 19 May 2023 21:32:02 +0530 Subject: [PATCH 1/5] auth-kratos Signed-off-by: prithvi <47061269+prithvi081099@users.noreply.github.com> --- sc-poc/cmd/spacectl/commands/run/run.go | 6 ++ sc-poc/managers/configman/common/http.go | 9 +++ .../modules/auth/handler_auth_verify copy.go | 68 +++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 sc-poc/modules/auth/handler_auth_verify copy.go diff --git a/sc-poc/cmd/spacectl/commands/run/run.go b/sc-poc/cmd/spacectl/commands/run/run.go index ce7daa1dd..900bebb82 100644 --- a/sc-poc/cmd/spacectl/commands/run/run.go +++ b/sc-poc/cmd/spacectl/commands/run/run.go @@ -27,6 +27,8 @@ func NewCommand() *cobra.Command { _ = viper.BindPFlag("config.path", cmd.Flags().Lookup("config-path")) _ = viper.BindPFlag("config.debounce-interval", cmd.Flags().Lookup("debounce-interval")) + _ = viper.BindPFlag("kratos.enable", cmd.Flags().Lookup("kratos-enable")) + _ = viper.BindPFlag("kratos.endpoint", cmd.Flags().Lookup("kratos-endpoint")) }, RunE: func(cmd *cobra.Command, args []string) error { if err := configman.InitializeConfigLoader(); err != nil { @@ -58,5 +60,9 @@ func NewCommand() *cobra.Command { cmd.Flags().StringP("config-path", "", "./sc-config", "Directory to use to manage SpaceCloud configuration") cmd.Flags().StringP("debounce-interval", "", "500ms", "Debounce interval in milliseconds") + // kratos + cmd.Flags().BoolP("kratos-enable", "", false, "To enable kratos for authorisation") + cmd.Flags().StringP("kratos-endpoint", "", "", "The endpoint to send the request to kratos server") + return cmd } diff --git a/sc-poc/managers/configman/common/http.go b/sc-poc/managers/configman/common/http.go index a5fe0e17b..eef8f699d 100644 --- a/sc-poc/managers/configman/common/http.go +++ b/sc-poc/managers/configman/common/http.go @@ -76,6 +76,15 @@ func getAPIRoutes() caddyhttp.Route { }, } + if viper.GetBool("kratos.enable") { + kratos := caddyhttp.Route{ + Group: "api_auth", + HandlersRaw: utils.GetCaddyHandler("auth_kratos_verify", nil), + } + + routeList = append(routeList, kratos) + } + // Create matcher and handler for subroute handler := map[string]interface{}{ "handler": "subroute", diff --git a/sc-poc/modules/auth/handler_auth_verify copy.go b/sc-poc/modules/auth/handler_auth_verify copy.go new file mode 100644 index 000000000..66f2c13a0 --- /dev/null +++ b/sc-poc/modules/auth/handler_auth_verify copy.go @@ -0,0 +1,68 @@ +package auth + +import ( + "net/http" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" + "go.uber.org/zap" + + "github.com/spacecloud-io/space-cloud/modules/auth/types" + "github.com/spacecloud-io/space-cloud/utils" +) + +// AuthKratosVerifyHandler is responsible to authenticate the incoming request +// using Kratos +type AuthKratosVerifyHandler struct { + logger *zap.Logger + //authApp *App +} + +// CaddyModule returns the Caddy module information. +func (AuthKratosVerifyHandler) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + ID: "http.handlers.sc_auth__kratos_verify_handler", + New: func() caddy.Module { return new(AuthKratosVerifyHandler) }, + } +} + +// Provision sets up the auth verify module. +func (h *AuthKratosVerifyHandler) Provision(ctx caddy.Context) error { + h.logger = ctx.Logger(h) + + // Get the auth app + // app, err := ctx.App("auth") + // if err != nil { + // h.logger.Error("Unable to load the auth provider", zap.Error(err)) + // return err + // } + + // h.authApp = app.(*App) + return nil +} + +// ServeHTTP handles the http request +func (h *AuthKratosVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { + // Prepare authentication object + result := types.AuthResult{} + // Check if token is present in the header + token, p := getTokenFromHeader(r) + if p { + // claims, err := h.authApp.Verify(token) + // if err != nil { + // SendUnauthenticatedResponse(w, r, h.logger, err) + // return nil + // } + + // result.IsAuthenticated = true + // result.Claims = claims + } + + // Add the result in the context object + r = utils.StoreAuthenticationResult(r, &result) + return next.ServeHTTP(w, r) +} + +// Interface guard +var _ caddy.Provisioner = (*AuthVerifyHandler)(nil) +var _ caddyhttp.MiddlewareHandler = (*AuthVerifyHandler)(nil) From 6c01295283302e26c584093757048732dbedf335 Mon Sep 17 00:00:00 2001 From: prithvi <47061269+prithvi081099@users.noreply.github.com> Date: Sat, 27 May 2023 11:10:46 +0530 Subject: [PATCH 2/5] getcaddyhandler and makefile updated --- sc-poc/Makefile | 2 +- sc-poc/managers/apis/helpers.go | 17 ++++-- sc-poc/managers/configman/common/http.go | 55 +++++++++++++------ sc-poc/modules/auth/handler_auth_verify.go | 18 +++--- ... copy.go => handler_kratos_auth_verify.go} | 21 ++++--- sc-poc/modules/auth/init.go | 2 +- sc-poc/utils/caddy.go | 31 +++++++---- 7 files changed, 92 insertions(+), 54 deletions(-) rename sc-poc/modules/auth/{handler_auth_verify copy.go => handler_kratos_auth_verify.go} (69%) diff --git a/sc-poc/Makefile b/sc-poc/Makefile index ad6676a4a..6152cc841 100644 --- a/sc-poc/Makefile +++ b/sc-poc/Makefile @@ -25,4 +25,4 @@ install: cd cmd/spacectl && go install run: build - cd cmd/spacectl && ./spacectl run \ No newline at end of file + cd cmd/spacectl && ./spacectl run --kratos-enable \ No newline at end of file diff --git a/sc-poc/managers/apis/helpers.go b/sc-poc/managers/apis/helpers.go index 860a7a2bf..f8a37ac2f 100644 --- a/sc-poc/managers/apis/helpers.go +++ b/sc-poc/managers/apis/helpers.go @@ -110,15 +110,20 @@ func prepareRoute(api *API, path string, methods, indexes []string) caddyhttp.Ro if len(p.Params.Raw) > 0 { _ = json.Unmarshal(p.Params.Raw, ¶ms) } - apiRoute.HandlersRaw = append(apiRoute.HandlersRaw, utils.GetCaddyHandler(p.Driver, params)...) + apiRoute.HandlersRaw = append(apiRoute.HandlersRaw, utils.GetCaddyHandlers(utils.Handler{ + HandlerName: p.Driver, + Params: params, + })...) } // Finally comes the main api route - apiHandler := utils.GetCaddyHandler("api", map[string]interface{}{ - "path": path, - "indexes": indexes, - "app": api.app, - "name": api.Name, + apiHandler := utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "api", + Params: map[string]interface{}{ + "path": path, + "indexes": indexes, + "app": api.app, + "name": api.Name}, }) apiRoute.HandlersRaw = append(apiRoute.HandlersRaw, apiHandler...) diff --git a/sc-poc/managers/configman/common/http.go b/sc-poc/managers/configman/common/http.go index d8059d16e..653405ba2 100644 --- a/sc-poc/managers/configman/common/http.go +++ b/sc-poc/managers/configman/common/http.go @@ -44,8 +44,11 @@ func getRootRoutes(config ConfigType) caddyhttp.RouteList { return caddyhttp.RouteList{ // Routes for CORS caddyhttp.Route{ - Group: "cors", - HandlersRaw: utils.GetCaddyHandler("cors", nil), + Group: "cors", + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "cors", + Params: nil, + }), }, // TODO: Fix this @@ -64,27 +67,36 @@ func getRootRoutes(config ConfigType) caddyhttp.RouteList { } func getAPIRoutes() caddyhttp.Route { + routes := []utils.Handler{ + { + HandlerName: "jwt_auth_verify", + Params: nil, + }, + } + + if viper.GetBool("kratos.enable") { + route := utils.Handler{ + HandlerName: "kratos_auth_verify", + Params: nil, + } + routes = append(routes, route) + } + // Make route list for the sub router routeList := caddyhttp.RouteList{ caddyhttp.Route{ Group: "api_auth", - HandlersRaw: utils.GetCaddyHandler("auth_verify", nil), + HandlersRaw: utils.GetCaddyHandlers(routes...), }, caddyhttp.Route{ - Group: "api_route", - HandlersRaw: utils.GetCaddyHandler("root_api", nil), + Group: "api_route", + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "root_api", + Params: nil, + }), }, } - if viper.GetBool("kratos.enable") { - kratos := caddyhttp.Route{ - Group: "api_auth", - HandlersRaw: utils.GetCaddyHandler("auth_kratos_verify", nil), - } - - routeList = append(routeList, kratos) - } - // Create matcher and handler for subroute handler := map[string]interface{}{ "handler": "subroute", @@ -111,21 +123,30 @@ func getConfigRoutes() caddyhttp.Route { getRoute := caddyhttp.Route{ Group: "config_get", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{path}, []string{http.MethodGet}), - HandlersRaw: utils.GetCaddyHandler("config_get", data), + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "config_get", + Params: data, + }), } // Route for Apply operation applyRoute := caddyhttp.Route{ Group: "config_apply", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{path}, []string{http.MethodPut}), - HandlersRaw: utils.GetCaddyHandler("config_apply", data), + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "config_apply", + Params: data, + }), } // Route for Delete operation deleteRoute := caddyhttp.Route{ Group: "config_delete", MatcherSetsRaw: utils.GetCaddyMatcherSet([]string{path}, []string{http.MethodDelete}), - HandlersRaw: utils.GetCaddyHandler("config_delete", data), + HandlersRaw: utils.GetCaddyHandlers(utils.Handler{ + HandlerName: "config_delete", + Params: data, + }), } configRoutes = append(configRoutes, getRoute, applyRoute, deleteRoute) diff --git a/sc-poc/modules/auth/handler_auth_verify.go b/sc-poc/modules/auth/handler_auth_verify.go index 9402cbaf4..4c3e75be4 100644 --- a/sc-poc/modules/auth/handler_auth_verify.go +++ b/sc-poc/modules/auth/handler_auth_verify.go @@ -11,23 +11,23 @@ import ( "github.com/spacecloud-io/space-cloud/utils" ) -// AuthVerifyHandler is responsible to authenticate the incoming request +// JWTAuthVerifyHandler is responsible to authenticate the incoming request // on a best effort basis -type AuthVerifyHandler struct { +type JWTAuthVerifyHandler struct { logger *zap.Logger authApp *App } // CaddyModule returns the Caddy module information. -func (AuthVerifyHandler) CaddyModule() caddy.ModuleInfo { +func (JWTAuthVerifyHandler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ - ID: "http.handlers.sc_auth_verify_handler", - New: func() caddy.Module { return new(AuthVerifyHandler) }, + ID: "http.handlers.sc_jwt_auth_verify_handler", + New: func() caddy.Module { return new(JWTAuthVerifyHandler) }, } } // Provision sets up the auth verify module. -func (h *AuthVerifyHandler) Provision(ctx caddy.Context) error { +func (h *JWTAuthVerifyHandler) Provision(ctx caddy.Context) error { h.logger = ctx.Logger(h) // Get the auth app @@ -42,7 +42,7 @@ func (h *AuthVerifyHandler) Provision(ctx caddy.Context) error { } // ServeHTTP handles the http request -func (h *AuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { +func (h *JWTAuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { // Prepare authentication object result := types.AuthResult{} // Check if token is present in the header @@ -64,5 +64,5 @@ func (h *AuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, ne } // Interface guard -var _ caddy.Provisioner = (*AuthVerifyHandler)(nil) -var _ caddyhttp.MiddlewareHandler = (*AuthVerifyHandler)(nil) +var _ caddy.Provisioner = (*JWTAuthVerifyHandler)(nil) +var _ caddyhttp.MiddlewareHandler = (*JWTAuthVerifyHandler)(nil) diff --git a/sc-poc/modules/auth/handler_auth_verify copy.go b/sc-poc/modules/auth/handler_kratos_auth_verify.go similarity index 69% rename from sc-poc/modules/auth/handler_auth_verify copy.go rename to sc-poc/modules/auth/handler_kratos_auth_verify.go index 66f2c13a0..e2c1d220f 100644 --- a/sc-poc/modules/auth/handler_auth_verify copy.go +++ b/sc-poc/modules/auth/handler_kratos_auth_verify.go @@ -1,6 +1,7 @@ package auth import ( + "fmt" "net/http" "github.com/caddyserver/caddy/v2" @@ -11,23 +12,23 @@ import ( "github.com/spacecloud-io/space-cloud/utils" ) -// AuthKratosVerifyHandler is responsible to authenticate the incoming request +// KratosAuthVerifyHandler is responsible to authenticate the incoming request // using Kratos -type AuthKratosVerifyHandler struct { +type KratosAuthVerifyHandler struct { logger *zap.Logger //authApp *App } // CaddyModule returns the Caddy module information. -func (AuthKratosVerifyHandler) CaddyModule() caddy.ModuleInfo { +func (KratosAuthVerifyHandler) CaddyModule() caddy.ModuleInfo { return caddy.ModuleInfo{ - ID: "http.handlers.sc_auth__kratos_verify_handler", - New: func() caddy.Module { return new(AuthKratosVerifyHandler) }, + ID: "http.handlers.sc_kratos_auth_verify_handler", + New: func() caddy.Module { return new(KratosAuthVerifyHandler) }, } } // Provision sets up the auth verify module. -func (h *AuthKratosVerifyHandler) Provision(ctx caddy.Context) error { +func (h *KratosAuthVerifyHandler) Provision(ctx caddy.Context) error { h.logger = ctx.Logger(h) // Get the auth app @@ -42,12 +43,14 @@ func (h *AuthKratosVerifyHandler) Provision(ctx caddy.Context) error { } // ServeHTTP handles the http request -func (h *AuthKratosVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { +func (h *KratosAuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { // Prepare authentication object result := types.AuthResult{} // Check if token is present in the header token, p := getTokenFromHeader(r) + fmt.Println(token) if p { + // claims, err := h.authApp.Verify(token) // if err != nil { // SendUnauthenticatedResponse(w, r, h.logger, err) @@ -64,5 +67,5 @@ func (h *AuthKratosVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque } // Interface guard -var _ caddy.Provisioner = (*AuthVerifyHandler)(nil) -var _ caddyhttp.MiddlewareHandler = (*AuthVerifyHandler)(nil) +var _ caddy.Provisioner = (*JWTAuthVerifyHandler)(nil) +var _ caddyhttp.MiddlewareHandler = (*JWTAuthVerifyHandler)(nil) diff --git a/sc-poc/modules/auth/init.go b/sc-poc/modules/auth/init.go index 341f0eae5..66dca40d5 100644 --- a/sc-poc/modules/auth/init.go +++ b/sc-poc/modules/auth/init.go @@ -4,6 +4,6 @@ import "github.com/caddyserver/caddy/v2" func init() { caddy.RegisterModule(App{}) - caddy.RegisterModule(AuthVerifyHandler{}) + caddy.RegisterModule(JWTAuthVerifyHandler{}) caddy.RegisterModule(AuthOPAHandler{}) } diff --git a/sc-poc/utils/caddy.go b/sc-poc/utils/caddy.go index c7560dffd..a44e7b775 100644 --- a/sc-poc/utils/caddy.go +++ b/sc-poc/utils/caddy.go @@ -54,20 +54,29 @@ func GetByteStringArray(val ...string) []byte { return data } -// GetCaddyHandler returns a marshaled caddy handler config -func GetCaddyHandler(handlerName string, params map[string]interface{}) []json.RawMessage { - handler := make(map[string]interface{}) +type Handler struct { + HandlerName string + Params map[string]interface{} +} - // Add the handler name / identifier - handler["handler"] = fmt.Sprintf("sc_%s_handler", handlerName) +// GetCaddyHandlers returns marshaled caddy handlers config +func GetCaddyHandlers(routes ...Handler) []json.RawMessage { + handlers := []json.RawMessage{} + for _, route := range routes { + handler := make(map[string]interface{}) - // Add the params the handler needs - for k, v := range params { - handler[k] = v - } + // Add the handler name / identifier + handler["handler"] = fmt.Sprintf("sc_%s_handler", route.HandlerName) - data, _ := json.Marshal(handler) - return []json.RawMessage{data} + // Add the params the handler needs + for k, v := range route.Params { + handler[k] = v + } + data, _ := json.Marshal(handler) + handlers = append(handlers, data) + + } + return handlers } // GetCaddySubrouter returns a marshaled caddy subrouter From 3d09ca1742574762d37646f8559b7045d15fc21d Mon Sep 17 00:00:00 2001 From: prithvi <47061269+prithvi081099@users.noreply.github.com> Date: Wed, 26 Jul 2023 11:50:05 +0530 Subject: [PATCH 3/5] Kratos-suppport for sc Signed-off-by: prithvi <47061269+prithvi081099@users.noreply.github.com> --- .../auth/handler_kratos_auth_verify.go | 58 +++++++++++++------ sc-poc/modules/auth/init.go | 1 + 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/sc-poc/modules/auth/handler_kratos_auth_verify.go b/sc-poc/modules/auth/handler_kratos_auth_verify.go index e2c1d220f..19070c8fa 100644 --- a/sc-poc/modules/auth/handler_kratos_auth_verify.go +++ b/sc-poc/modules/auth/handler_kratos_auth_verify.go @@ -1,11 +1,13 @@ package auth import ( + "encoding/json" "fmt" "net/http" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/modules/caddyhttp" + "github.com/spf13/viper" "go.uber.org/zap" "github.com/spacecloud-io/space-cloud/modules/auth/types" @@ -31,14 +33,6 @@ func (KratosAuthVerifyHandler) CaddyModule() caddy.ModuleInfo { func (h *KratosAuthVerifyHandler) Provision(ctx caddy.Context) error { h.logger = ctx.Logger(h) - // Get the auth app - // app, err := ctx.App("auth") - // if err != nil { - // h.logger.Error("Unable to load the auth provider", zap.Error(err)) - // return err - // } - - // h.authApp = app.(*App) return nil } @@ -47,19 +41,47 @@ func (h *KratosAuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque // Prepare authentication object result := types.AuthResult{} // Check if token is present in the header - token, p := getTokenFromHeader(r) - fmt.Println(token) - if p { - // claims, err := h.authApp.Verify(token) - // if err != nil { - // SendUnauthenticatedResponse(w, r, h.logger, err) - // return nil - // } + var foo map[string]interface{} + client := &http.Client{} + + kratosEndpoint := viper.GetString("kratos.endpoint") + // Create a new GET request to the /sessions/whoami endpoint + req, err := http.NewRequest("GET", kratosEndpoint+"/sessions/whoami", nil) + if err != nil { + fmt.Println("Error creating GET request:", err) + return err + } + if cookie := r.Header.Get("Cookie"); len(cookie) != 0 { + req.Header.Set("Cookie", cookie) + } + if cookie := r.Header.Get("Cookie"); len(cookie) != 0 { + req.Header.Set("Cookie", cookie) + } + if token, p := getTokenFromHeader(r); p { + req.Header.Set("Authorization", "Bearer "+token) + } + //token := "ory_st_94jGcnytycUNCtKIVchOfiyWrs8wlJYY" + //req.Header.Set("Authorization", "Bearer "+token) + // Send the request + resp, err := client.Do(req) + if err != nil { + fmt.Println("Error sending GET request:", err) + return err + } + defer resp.Body.Close() - // result.IsAuthenticated = true - // result.Claims = claims + // Read the response body + err = json.NewDecoder(resp.Body).Decode(&foo) + //body, err := ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + return err } + // Print the response body + //fmt.Println(string(body)) + j, _ := json.MarshalIndent(foo, "", " ") + fmt.Println(string(j)) // Add the result in the context object r = utils.StoreAuthenticationResult(r, &result) diff --git a/sc-poc/modules/auth/init.go b/sc-poc/modules/auth/init.go index 66dca40d5..f07910f09 100644 --- a/sc-poc/modules/auth/init.go +++ b/sc-poc/modules/auth/init.go @@ -5,5 +5,6 @@ import "github.com/caddyserver/caddy/v2" func init() { caddy.RegisterModule(App{}) caddy.RegisterModule(JWTAuthVerifyHandler{}) + caddy.RegisterModule(KratosAuthVerifyHandler{}) caddy.RegisterModule(AuthOPAHandler{}) } From 4667c224e39e266932c700d01ee6e384c22b0152 Mon Sep 17 00:00:00 2001 From: prithvi <47061269+prithvi081099@users.noreply.github.com> Date: Sun, 6 Aug 2023 00:06:53 +0530 Subject: [PATCH 4/5] add kratos support to auth Signed-off-by: prithvi <47061269+prithvi081099@users.noreply.github.com> --- sc-poc/modules/auth/handler_kratos_auth_verify.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sc-poc/modules/auth/handler_kratos_auth_verify.go b/sc-poc/modules/auth/handler_kratos_auth_verify.go index 19070c8fa..5cc850125 100644 --- a/sc-poc/modules/auth/handler_kratos_auth_verify.go +++ b/sc-poc/modules/auth/handler_kratos_auth_verify.go @@ -89,5 +89,5 @@ func (h *KratosAuthVerifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque } // Interface guard -var _ caddy.Provisioner = (*JWTAuthVerifyHandler)(nil) -var _ caddyhttp.MiddlewareHandler = (*JWTAuthVerifyHandler)(nil) +var _ caddy.Provisioner = (*KratosAuthVerifyHandler)(nil) +var _ caddyhttp.MiddlewareHandler = (*KratosAuthVerifyHandler)(nil) From eb1cd8598c8f24714e751acf87b4f59d59757f15 Mon Sep 17 00:00:00 2001 From: prithvi <47061269+prithvi081099@users.noreply.github.com> Date: Sun, 6 Aug 2023 00:12:26 +0530 Subject: [PATCH 5/5] reverted makefile Signed-off-by: prithvi <47061269+prithvi081099@users.noreply.github.com> --- sc-poc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sc-poc/Makefile b/sc-poc/Makefile index d2289ef28..ef63aac4e 100644 --- a/sc-poc/Makefile +++ b/sc-poc/Makefile @@ -28,4 +28,4 @@ install-deps: go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.12.0 run: build - cd cmd/spacectl && ./spacectl run --kratos-enable \ No newline at end of file + cd cmd/spacectl && ./spacectl run \ No newline at end of file