diff --git a/cmd/crowdsec/api.go b/cmd/crowdsec/api.go index b3b50439d..8648d37ba 100644 --- a/cmd/crowdsec/api.go +++ b/cmd/crowdsec/api.go @@ -18,7 +18,7 @@ func initAPIServer(cConfig *csconfig.Config) (*apiserver.APIServer, error) { if hasPlugins(cConfig.API.Server.Profiles) { log.Info("initiating plugin broker") - err = pluginBroker.Init(cConfig.API.Server.Profiles, cConfig.ConfigPaths) + err = pluginBroker.Init(cConfig.PluginConfig, cConfig.API.Server.Profiles, cConfig.ConfigPaths) if err != nil { return nil, fmt.Errorf("unable to run local API: %s", err) } diff --git a/config/config.yaml b/config/config.yaml index 877b97142..d93c8fbaa 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -30,6 +30,9 @@ db_config: flush: max_items: 5000 max_age: 7d +plugin_config: + user: nobody # plugin process would be ran on behalf of this user + group: nogroup # plugin process would be ran on behalf of this group api: client: insecure_skip_verify: false diff --git a/pkg/csconfig/config.go b/pkg/csconfig/config.go index cf8c8423f..b9c4c7d93 100644 --- a/pkg/csconfig/config.go +++ b/pkg/csconfig/config.go @@ -22,6 +22,7 @@ type Config struct { DbConfig *DatabaseCfg `yaml:"db_config,omitempty"` API *APICfg `yaml:"api,omitempty"` ConfigPaths *ConfigurationPaths `yaml:"config_paths,omitempty"` + PluginConfig *PluginCfg `yaml:"plugin_config,omitempty"` DisableAPI bool `yaml:"-"` DisableAgent bool `yaml:"-"` Hub *Hub `yaml:"-"` diff --git a/pkg/csconfig/plugin_config.go b/pkg/csconfig/plugin_config.go new file mode 100644 index 000000000..3c82ee2c4 --- /dev/null +++ b/pkg/csconfig/plugin_config.go @@ -0,0 +1,6 @@ +package csconfig + +type PluginCfg struct { + User string + Group string +} diff --git a/pkg/csplugin/broker.go b/pkg/csplugin/broker.go index 32cf48d2a..259e3cf21 100644 --- a/pkg/csplugin/broker.go +++ b/pkg/csplugin/broker.go @@ -47,6 +47,8 @@ type PluginBroker struct { notificationPluginByName map[string]Notifier watcher PluginWatcher pluginKillMethods []func() + pluginProcConfig *csconfig.PluginCfg + pluginsTypesToDispatch map[string]struct{} } // holder to determine where to dispatch config and how to format messages @@ -69,7 +71,7 @@ type ProfileAlert struct { Alert *models.Alert } -func (pb *PluginBroker) Init(profileConfigs []*csconfig.ProfileCfg, configPaths *csconfig.ConfigurationPaths) error { +func (pb *PluginBroker) Init(pluginCfg *csconfig.PluginCfg, profileConfigs []*csconfig.ProfileCfg, configPaths *csconfig.ConfigurationPaths) error { pb.PluginChannel = make(chan ProfileAlert) pb.notificationConfigsByPluginType = make(map[string][][]byte) pb.notificationPluginByName = make(map[string]Notifier) @@ -77,6 +79,8 @@ func (pb *PluginBroker) Init(profileConfigs []*csconfig.ProfileCfg, configPaths pb.pluginConfigByName = make(map[string]PluginConfig) pb.alertsByPluginName = make(map[string][]*models.Alert) pb.profileConfigs = profileConfigs + pb.pluginProcConfig = pluginCfg + pb.pluginsTypesToDispatch = make(map[string]struct{}) if err := pb.loadConfig(configPaths.NotificationDir); err != nil { return errors.Wrap(err, "while loading plugin config") } @@ -178,6 +182,7 @@ func (pb *PluginBroker) verifyPluginConfigsWithProfile() error { if _, ok := pb.pluginConfigByName[pluginName]; !ok { return fmt.Errorf("config file for plugin %s not found", pluginName) } + pb.pluginsTypesToDispatch[pb.pluginConfigByName[pluginName].Type] = struct{}{} } } return nil @@ -200,6 +205,10 @@ func (pb *PluginBroker) loadPlugins(path string) error { continue } + if _, ok := pb.pluginsTypesToDispatch[pSubtype]; !ok { + continue + } + pluginClient, err := pb.loadNotificationPlugin(pSubtype, binaryPath) if err != nil { return err @@ -231,7 +240,7 @@ func (pb *PluginBroker) loadNotificationPlugin(name string, binaryPath string) ( return nil, err } cmd := exec.Command(binaryPath) - cmd.SysProcAttr, err = getProccessAtr() + cmd.SysProcAttr, err = getProccessAtr(pb.pluginProcConfig.User, pb.pluginProcConfig.Group) if err != nil { return nil, errors.Wrap(err, "while getting process attributes") } @@ -378,12 +387,12 @@ func getPluginTypeAndSubtypeFromPath(path string) (string, string, error) { return strings.Join(parts[:len(parts)-1], "-"), parts[len(parts)-1], nil } -func getProccessAtr() (*syscall.SysProcAttr, error) { - u, err := user.Lookup("nobody") +func getProccessAtr(username string, groupname string) (*syscall.SysProcAttr, error) { + u, err := user.Lookup(username) if err != nil { return nil, err } - g, err := user.LookupGroup("nogroup") + g, err := user.LookupGroup(groupname) if err != nil { return nil, err }