csbouncer

package module
v0.0.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 11, 2023 License: MIT Imports: 16 Imported by: 12

README

Go CrowdSec Bouncer

go-cs-bouncer is a golang easy library to use to create golang CrowdSec bouncer.

Installation

To install go-cs-bouncer package, you need to install Go and set your Go workspace first.

  1. You can use the below Go command to install go-cs-bouncer:
$ go get -u github.com/crowdsecurity/go-cs-bouncer
  1. Import it in your code:
import "github.com/crowdsecurity/go-cs-bouncer"

Quick Start

Streaming Bouncer
# assume the following codes in main.go file
$ cat main.go
package main

import (
	"context"
	"fmt"
	"log"

	csbouncer "github.com/crowdsecurity/go-cs-bouncer"
)

func main() {

	bouncer := &csbouncer.StreamBouncer{
		APIKey:         "<API_TOKEN>",
		APIUrl:         "http://localhost:8080/",
		TickerInterval: "20s",
	}

	if err := bouncer.Init(); err != nil {
		log.Fatal(err)
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

        go func() {
            bouncer.Run(ctx)
            cancel()
        }

	for streamDecision := range bouncer.Stream {
		for _, decision := range streamDecision.Deleted {
			fmt.Printf("expired decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
		}
		for _, decision := range streamDecision.New {
			fmt.Printf("new decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
		}
	}
}
# run main.go
$ go run main.go
Live Bouncer
# assume the following codes in main.go file
$ cat main.go
package main

import (
	"fmt"
	"log"

	csbouncer "github.com/crowdsecurity/go-cs-bouncer"
)

func main() {

	bouncer := &csbouncer.LiveBouncer{
		APIKey: "<API_TOKEN>",
		APIUrl: "http://localhost:8080/",
	}

	if err := bouncer.Init(); err != nil {
		log.Fatalf(err.Error())
	}

	ipToQuery := "1.2.3.4"
	response, err := bouncer.Get(ipToQuery)
	if err != nil {
		log.Fatalf("unable to get decision for ip '%s' : '%s'", ipToQuery, err)
	}
	if len(*response) == 0 {
		log.Printf("no decision for '%s'", ipToQuery)
	}

	for _, decision := range *response {
		fmt.Printf("decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
	}
}

# run main.go
$ go run main.go

Decision object

The decision objet correspond to the following structure:

type Decision struct {

	// duration
	Duration *string `json:"duration"`

	EndIP int64 `json:"end_ip,omitempty"`

	ID int64 `json:"id,omitempty"`

	// the origin of the decision : cscli, crowdsec
	Origin *string `json:"origin"`

	// scenario
	Scenario *string `json:"scenario"`

	// the scope of decision : does it apply to an IP, a range, a username, etc
	Scope *string `json:"scope"`

	StartIP int64 `json:"start_ip,omitempty"`

	// the type of decision, might be 'ban', 'captcha' or something custom. Ignored when watcher (cscli/crowdsec) is pushing to APIL.
	Type *string `json:"type"`

	// the value of the decision scope : an IP, a range, a username, etc
	Value *string `json:"value"`
}

Documentation

Overview

Package go-cs-bouncer implements a wrapper for the CrowdSec bouncer API.

It can be used to create 2 types of bouncer:

- A stream bouncer: in this mode, decisions are fetched in bulk at regular intervals. A `Stream` chan is exposed by the struct to allow you to read the decisions.

- A live bouncer: in this mode, you must call the Get() method to check if an IP has a decision associated with it.

Index

Examples

Constants

This section is empty.

Variables

View Source
var TotalLAPICalls = prometheus.NewCounter(prometheus.CounterOpts{
	Name: "lapi_requests_total",
	Help: "The total number of calls to CrowdSec LAPI",
})
View Source
var TotalLAPIError = prometheus.NewCounter(prometheus.CounterOpts{
	Name: "lapi_requests_failures_total",
	Help: "The total number of failed calls to CrowdSec LAPI",
})

Functions

This section is empty.

Types

type LiveBouncer

type LiveBouncer struct {
	APIKey             string `yaml:"api_key"`
	APIUrl             string `yaml:"api_url"`
	InsecureSkipVerify *bool  `yaml:"insecure_skip_verify"`
	CertPath           string `yaml:"cert_path"`
	KeyPath            string `yaml:"key_path"`
	CAPath             string `yaml:"ca_cert_path"`

	APIClient *apiclient.ApiClient
	UserAgent string
}
Example
package main

import (
	"fmt"
	"log"

	csbouncer "github.com/crowdsecurity/go-cs-bouncer"
)

func main() {
	bouncer := &csbouncer.LiveBouncer{
		APIKey: "ebd4db481d51525fd0df924a69193921",
		APIUrl: "http://localhost:8080/",
	}

	if err := bouncer.Init(); err != nil {
		log.Fatalf(err.Error())
	}

	ipToQuery := "1.2.3.4"

	response, err := bouncer.Get(ipToQuery)
	if err != nil {
		log.Fatalf("unable to get decision for ip '%s' : '%s'", ipToQuery, err)
	}

	if len(*response) == 0 {
		log.Printf("no decision for '%s'", ipToQuery)
	}

	for _, decision := range *response {
		fmt.Printf("decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
	}
}
Output:

func (*LiveBouncer) Config

func (b *LiveBouncer) Config(configPath string) error

Config() fills the struct with configuration values from a file. It is not aware of .yaml.local files so it is recommended to use ConfigReader() instead.

Example
package main

import (
	"fmt"
	"log"

	csbouncer "github.com/crowdsecurity/go-cs-bouncer"
)

func main() {
	bouncer := &csbouncer.LiveBouncer{}

	err := bouncer.Config("./config.yaml")

	if err != nil {
		log.Fatal(err)
	}

	if err = bouncer.Init(); err != nil {
		log.Fatalf(err.Error())
	}

	ipToQuery := "1.2.3.4"

	response, err := bouncer.Get(ipToQuery)
	if err != nil {
		log.Fatalf("unable to get decision for ip '%s' : '%s'", ipToQuery, err)
	}

	if len(*response) == 0 {
		log.Printf("no decision for '%s'", ipToQuery)
	}

	for _, decision := range *response {
		fmt.Printf("decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
	}
}
Output:

func (*LiveBouncer) ConfigReader added in v0.0.2

func (b *LiveBouncer) ConfigReader(configReader io.Reader) error

func (*LiveBouncer) Get

func (*LiveBouncer) Init

func (b *LiveBouncer) Init() error

type StreamBouncer

type StreamBouncer struct {
	APIKey              string `yaml:"api_key"`
	APIUrl              string `yaml:"api_url"`
	InsecureSkipVerify  *bool  `yaml:"insecure_skip_verify"`
	CertPath            string `yaml:"cert_path"`
	KeyPath             string `yaml:"key_path"`
	CAPath              string `yaml:"ca_cert_path"`
	RetryInitialConnect bool   `yaml:"retry_initial_connect"`

	TickerInterval         string   `yaml:"update_frequency"`
	Scopes                 []string `yaml:"scopes"`
	ScenariosContaining    []string `yaml:"scenarios_containing"`
	ScenariosNotContaining []string `yaml:"scenarios_not_containing"`
	Origins                []string `yaml:"origins"`

	TickerIntervalDuration time.Duration
	Stream                 chan *models.DecisionsStreamResponse
	APIClient              *apiclient.ApiClient
	UserAgent              string
	Opts                   apiclient.DecisionsStreamOpts
}
Example
package main

import (
	"context"
	"fmt"
	"log"

	csbouncer "github.com/crowdsecurity/go-cs-bouncer"
)

func main() {
	bouncer := &csbouncer.StreamBouncer{
		APIKey: "ebd4db481d51525fd0df924a69193921",
		APIUrl: "http://localhost:8080/",
	}

	if err := bouncer.Init(); err != nil {
		log.Fatalf(err.Error())
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		bouncer.Run(ctx)
		cancel()
	}()

	for streamDecision := range bouncer.Stream {
		for _, decision := range streamDecision.Deleted {
			fmt.Printf("expired decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
		}
		for _, decision := range streamDecision.New {
			fmt.Printf("new decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
		}
	}
}
Output:

func (*StreamBouncer) Config

func (b *StreamBouncer) Config(configPath string) error

Config() fills the struct with configuration values from a file. It is not aware of .yaml.local files so it is recommended to use ConfigReader() instead.

Example
package main

import (
	"context"
	"fmt"
	"log"

	csbouncer "github.com/crowdsecurity/go-cs-bouncer"
)

func main() {
	bouncer := &csbouncer.StreamBouncer{}

	err := bouncer.Config("./config.yaml")

	if err != nil {
		log.Fatal(err)
	}

	if err := bouncer.Init(); err != nil {
		log.Fatalf(err.Error())
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		bouncer.Run(ctx)
		cancel()
	}()

	for streamDecision := range bouncer.Stream {
		for _, decision := range streamDecision.Deleted {
			fmt.Printf("expired decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
		}
		for _, decision := range streamDecision.New {
			fmt.Printf("new decisions: IP: %s | Scenario: %s | Duration: %s | Scope : %v\n", *decision.Value, *decision.Scenario, *decision.Duration, *decision.Scope)
		}
	}
}
Output:

func (*StreamBouncer) ConfigReader added in v0.0.2

func (b *StreamBouncer) ConfigReader(configReader io.Reader) error

func (*StreamBouncer) Init

func (b *StreamBouncer) Init() error

func (*StreamBouncer) Run

func (b *StreamBouncer) Run(ctx context.Context)

Directories

Path Synopsis
examples
live Module
live_mtls Module
stream Module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL