github.com/crowdsecurity/crowdsec@v1.6.1/cmd/notification-splunk/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"os"
    11  	"strings"
    12  
    13  	"github.com/crowdsecurity/crowdsec/pkg/protobufs"
    14  	"github.com/hashicorp/go-hclog"
    15  	plugin "github.com/hashicorp/go-plugin"
    16  
    17  	"gopkg.in/yaml.v2"
    18  )
    19  
    20  var logger hclog.Logger = hclog.New(&hclog.LoggerOptions{
    21  	Name:       "splunk-plugin",
    22  	Level:      hclog.LevelFromString("INFO"),
    23  	Output:     os.Stderr,
    24  	JSONFormat: true,
    25  })
    26  
    27  type PluginConfig struct {
    28  	Name     string  `yaml:"name"`
    29  	URL      string  `yaml:"url"`
    30  	Token    string  `yaml:"token"`
    31  	LogLevel *string `yaml:"log_level"`
    32  }
    33  
    34  type Splunk struct {
    35  	PluginConfigByName map[string]PluginConfig
    36  	Client             http.Client
    37  }
    38  
    39  type Payload struct {
    40  	Event string `json:"event"`
    41  }
    42  
    43  func (s *Splunk) Notify(ctx context.Context, notification *protobufs.Notification) (*protobufs.Empty, error) {
    44  	if _, ok := s.PluginConfigByName[notification.Name]; !ok {
    45  		return &protobufs.Empty{}, fmt.Errorf("splunk invalid config name %s", notification.Name)
    46  	}
    47  	cfg := s.PluginConfigByName[notification.Name]
    48  
    49  	if cfg.LogLevel != nil && *cfg.LogLevel != "" {
    50  		logger.SetLevel(hclog.LevelFromString(*cfg.LogLevel))
    51  	}
    52  
    53  	logger.Info(fmt.Sprintf("received notify signal for %s config", notification.Name))
    54  
    55  	p := Payload{Event: notification.Text}
    56  	data, err := json.Marshal(p)
    57  	if err != nil {
    58  		return &protobufs.Empty{}, err
    59  	}
    60  
    61  	req, err := http.NewRequest(http.MethodPost, cfg.URL, strings.NewReader(string(data)))
    62  	if err != nil {
    63  		return &protobufs.Empty{}, err
    64  	}
    65  
    66  	req.Header.Add("Authorization", fmt.Sprintf("Splunk %s", cfg.Token))
    67  	logger.Debug(fmt.Sprintf("posting event %s to %s", string(data), req.URL))
    68  	resp, err := s.Client.Do(req.WithContext(ctx))
    69  	if err != nil {
    70  		return &protobufs.Empty{}, err
    71  	}
    72  
    73  	if resp.StatusCode != http.StatusOK {
    74  		content, err := io.ReadAll(resp.Body)
    75  		if err != nil {
    76  			return &protobufs.Empty{}, fmt.Errorf("got non 200 response and failed to read error %s", err)
    77  		}
    78  		return &protobufs.Empty{}, fmt.Errorf("got non 200 response %s", string(content))
    79  	}
    80  	respData, err := io.ReadAll(resp.Body)
    81  	if err != nil {
    82  		return &protobufs.Empty{}, fmt.Errorf("failed to read response body got error %s", err)
    83  	}
    84  	logger.Debug(fmt.Sprintf("got response %s", string(respData)))
    85  	return &protobufs.Empty{}, nil
    86  }
    87  
    88  func (s *Splunk) Configure(ctx context.Context, config *protobufs.Config) (*protobufs.Empty, error) {
    89  	d := PluginConfig{}
    90  	err := yaml.Unmarshal(config.Config, &d)
    91  	s.PluginConfigByName[d.Name] = d
    92  	logger.Debug(fmt.Sprintf("Splunk plugin '%s' use URL '%s'", d.Name, d.URL))
    93  	return &protobufs.Empty{}, err
    94  }
    95  
    96  func main() {
    97  	var handshake = plugin.HandshakeConfig{
    98  		ProtocolVersion:  1,
    99  		MagicCookieKey:   "CROWDSEC_PLUGIN_KEY",
   100  		MagicCookieValue: os.Getenv("CROWDSEC_PLUGIN_KEY"),
   101  	}
   102  
   103  	tr := &http.Transport{
   104  		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
   105  	}
   106  	client := &http.Client{Transport: tr}
   107  
   108  	sp := &Splunk{PluginConfigByName: make(map[string]PluginConfig), Client: *client}
   109  	plugin.Serve(&plugin.ServeConfig{
   110  		HandshakeConfig: handshake,
   111  		Plugins: map[string]plugin.Plugin{
   112  			"splunk": &protobufs.NotifierPlugin{
   113  				Impl: sp,
   114  			},
   115  		},
   116  		GRPCServer: plugin.DefaultGRPCServer,
   117  		Logger:     logger,
   118  	})
   119  }