...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/rules/server/server.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/rules/server

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"net/http"
     8  	"os"
     9  
    10  	"github.com/gin-contrib/requestid"
    11  	"github.com/gin-gonic/gin"
    12  	"github.com/go-logr/logr"
    13  	"github.com/peterbourgon/ff/v3"
    14  
    15  	"edge-infra.dev/pkg/edge/api/middleware"
    16  	eamiddleware "edge-infra.dev/pkg/sds/emergencyaccess/middleware"
    17  	rulesengine "edge-infra.dev/pkg/sds/emergencyaccess/rules"
    18  	"edge-infra.dev/pkg/sds/emergencyaccess/rules/setup"
    19  )
    20  
    21  type RulesEngine interface {
    22  	GetEARolesForCommand(ctx context.Context, command rulesengine.Command, bannerID string) ([]string, error)
    23  	UserHasRoles(_ string, eaRoles []string, userEARoles []string) bool
    24  
    25  	AddCommands(ctx context.Context, names []rulesengine.PostCommandPayload) (rulesengine.AddNameResult, error)
    26  	AddPrivileges(ctx context.Context, privs []rulesengine.PostPrivilegePayload) (rulesengine.AddNameResult, error)
    27  	AddBannerRules(ctx context.Context, bannerName string, rules rulesengine.WriteRules) (rulesengine.AddRuleResult, error)
    28  	AddDefaultRules(ctx context.Context, rules rulesengine.WriteRules) (rulesengine.AddRuleResult, error)
    29  
    30  	DeleteCommand(ctx context.Context, name string) (rulesengine.DeleteResult, error)
    31  	DeletePrivilege(ctx context.Context, name string) (rulesengine.DeleteResult, error)
    32  	DeleteDefaultRule(ctx context.Context, commandName, privilegeName string) (rulesengine.DeleteResult, error)
    33  	DeletePrivilegeFromBannerRule(ctx context.Context, bannerName, commandName, privilegeName string) (rulesengine.DeleteResult, error)
    34  
    35  	ReadCommands(ctx context.Context) ([]rulesengine.Command, error)
    36  	ReadCommand(ctx context.Context, name string) (rulesengine.Command, error)
    37  	ReadPrivileges(ctx context.Context) ([]rulesengine.Privilege, error)
    38  	ReadPrivilege(ctx context.Context, name string) (rulesengine.Privilege, error)
    39  	ReadAllDefaultRules(ctx context.Context) ([]rulesengine.Rule, error)
    40  	ReadDefaultRulesForCommand(ctx context.Context, commandName string) ([]rulesengine.Rule, error)
    41  	ReadRulesForBanner(ctx context.Context, bannerName string) ([]rulesengine.Rule, error)
    42  	ReadRulesForAllBanners(ctx context.Context) ([]rulesengine.ReadBannerRule, error)
    43  	ReadBannerRulesForCommand(ctx context.Context, commandName string) (rulesengine.ReadBannerRule, error)
    44  	ReadBannerRulesForCommandAndBanner(ctx context.Context, bannerName string, commandName string) (rulesengine.Rule, error)
    45  	ReadAllRulesForCommand(ctx context.Context, commandName string) (rulesengine.RuleWithOverrides, error)
    46  }
    47  
    48  type RulesEngineService struct {
    49  	GinEngine   *gin.Engine
    50  	RulesEngine RulesEngine
    51  	logger      logr.Logger
    52  }
    53  
    54  func (res RulesEngineService) newGinServer(checks ...func() error) {
    55  	router := res.GinEngine
    56  
    57  	router.ContextWithFallback = true
    58  
    59  	// Http logging
    60  	router.Use(middleware.SetRequestContext())
    61  	router.Use(gin.Recovery())
    62  
    63  	router.Any("/ready", func(c *gin.Context) {
    64  		c.String(http.StatusOK, "ok")
    65  	})
    66  	router.Any("/health", eamiddleware.HealthCheck(checks...))
    67  
    68  	public := router.Group("/")
    69  	public.Use(requestid.New(requestid.WithCustomHeaderStrKey(eamiddleware.CorrelationIDKey)))
    70  	public.Use(eamiddleware.SetLoggerInContext(res.logger))
    71  	public.Use(eamiddleware.RequestBookendLogs())
    72  	public.POST("/validatecommand", res.validateCommand)
    73  
    74  	admin := public.Group("/admin")
    75  	// commands
    76  	admin.POST("/commands", res.postCommands)
    77  	admin.DELETE("/commands/:name", res.deleteCommand)
    78  	admin.GET("/commands", res.readCommands)
    79  	admin.GET("commands/:name", res.readCommand)
    80  	// privileges
    81  	admin.POST("/privileges", res.postPrivileges)
    82  	admin.DELETE("/privileges/:name", res.deletePrivilege)
    83  	admin.GET("/privileges", res.readPrivileges)
    84  	admin.GET("/privileges/:name", res.readPrivilege)
    85  	// default rules
    86  	admin.POST("/rules/default/commands", res.postDefaultRules)
    87  	admin.DELETE("/rules/default/commands/:commandName/privileges/:privilegeName", res.deleteDefaultRule)
    88  	admin.GET("/rules/default/commands", res.readAllDefaultRules)
    89  	admin.GET("/rules/default/commands/:commandName", res.readDefaultRule)
    90  
    91  	// Banner rules
    92  	admin.POST("/rules/banner/commands", res.postRulesInBanner)
    93  	admin.GET("/rules/banner/commands", res.readAllRulesForBanners)
    94  	admin.GET("/rules/banner/commands/:commandName", res.readBannerRulesForCommand)
    95  	admin.DELETE("/rules/banner/commands/:commandName/privileges/:privilegeName", res.deletePrivilegeFromBannerRule)
    96  
    97  	// overview of rules
    98  	admin.GET("/rules/commands/:commandName", res.readAllRulesForCommand)
    99  }
   100  
   101  func New(router *gin.Engine, rulesengine RulesEngine, logger logr.Logger, checks ...func() error) (RulesEngineService, error) {
   102  	res := RulesEngineService{
   103  		RulesEngine: rulesengine,
   104  		GinEngine:   router,
   105  		logger:      logger,
   106  	}
   107  	res.newGinServer(checks...)
   108  	return res, nil
   109  }
   110  
   111  // Run initialises the rules engine and calls GinEngine.Run.
   112  func Run() error {
   113  	log := newLogger()
   114  
   115  	flags := flag.NewFlagSet("ea-rules", flag.ExitOnError)
   116  	conf := setup.RulesConfig{}
   117  	conf.BindFlags(flags)
   118  
   119  	if err := ff.Parse(flags, os.Args[1:], ff.WithEnvVarNoPrefix(), ff.WithIgnoreUndefined(true)); err != nil {
   120  		return fmt.Errorf("failed to parse arguments: %w", err)
   121  	}
   122  
   123  	router := gin.New()
   124  
   125  	ds, checks, err := setup.CreateDataset(log, conf)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	rulesengine := rulesengine.New(ds)
   131  	res, err := New(router, rulesengine, log, checks...)
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	return res.GinEngine.Run()
   137  }
   138  

View as plain text