feat: implement a client for Thoth, the IP reputation database for Anubis (#637)
* feat(internal): add Thoth client and simple ASN checker Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(thoth): cached ip to asn checker Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: go mod tidy Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(thoth): minor testing fixups, ensure ASNChecker is Checker Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(thoth): make ASNChecker instances Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(thoth): add GeoIP checker Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(thoth): store a thoth client in a context Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: refactor Checker type to its own package Signed-off-by: Xe Iaso <me@xeiaso.net> * test(thoth): add thoth mocking package, ignore context deadline exceeded errors Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(thoth): pre-cache private ranges Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(lib/policy/config): enable thoth ASNs and GeoIP checker parsing Signed-off-by: Xe Iaso <me@xeiaso.net> * chore(thoth): refactor to move checker creation to the checker files Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(policy): enable thoth checks Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(thothmock): test helper function for loading a mock thoth instance Signed-off-by: Xe Iaso <me@xeiaso.net> * feat: wire up Thoth, make thoth checks part of the default config Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: spelling Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(thoth): mend staticcheck errors Signed-off-by: Xe Iaso <me@xeiaso.net> * docs(admin): add Thoth docs Signed-off-by: Xe Iaso <me@xeiaso.net> * chore(policy): update Thoth links in error messages Signed-off-by: Xe Iaso <me@xeiaso.net> * docs: update CHANGELOG Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: spelling Signed-off-by: Xe Iaso <me@xeiaso.net> * chore(docs/manifest): enable Thoth Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: add THOTH_INSECURE for contacting Thoth over plain TCP in extreme circumstances Signed-off-by: Xe Iaso <me@xeiaso.net> * test(thoth): use mock thoth when credentials aren't detected in the environment Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: spelling Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(cmd/anubis): better warnings for half-configured Thoth setups Signed-off-by: Xe Iaso <me@xeiaso.net> * docs(botpolicies): link to Thoth geoip docs Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
parent
823d1be5d1
commit
e3826df3ab
39 changed files with 1101 additions and 82 deletions
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/TecharoHQ/anubis/internal"
|
||||
"github.com/TecharoHQ/anubis/lib/policy/checker"
|
||||
"github.com/yl2chen/cidranger"
|
||||
)
|
||||
|
||||
|
|
@ -16,37 +17,6 @@ var (
|
|||
ErrMisconfiguration = errors.New("[unexpected] policy: administrator misconfiguration")
|
||||
)
|
||||
|
||||
type Checker interface {
|
||||
Check(*http.Request) (bool, error)
|
||||
Hash() string
|
||||
}
|
||||
|
||||
type CheckerList []Checker
|
||||
|
||||
func (cl CheckerList) Check(r *http.Request) (bool, error) {
|
||||
for _, c := range cl {
|
||||
ok, err := c.Check(r)
|
||||
if err != nil {
|
||||
return ok, err
|
||||
}
|
||||
if ok {
|
||||
return ok, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (cl CheckerList) Hash() string {
|
||||
var sb strings.Builder
|
||||
|
||||
for _, c := range cl {
|
||||
fmt.Fprintln(&sb, c.Hash())
|
||||
}
|
||||
|
||||
return internal.SHA256sum(sb.String())
|
||||
}
|
||||
|
||||
type staticHashChecker struct {
|
||||
hash string
|
||||
}
|
||||
|
|
@ -57,7 +27,7 @@ func (staticHashChecker) Check(r *http.Request) (bool, error) {
|
|||
|
||||
func (s staticHashChecker) Hash() string { return s.hash }
|
||||
|
||||
func NewStaticHashChecker(hashable string) Checker {
|
||||
func NewStaticHashChecker(hashable string) checker.Impl {
|
||||
return staticHashChecker{hash: internal.SHA256sum(hashable)}
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +36,7 @@ type RemoteAddrChecker struct {
|
|||
hash string
|
||||
}
|
||||
|
||||
func NewRemoteAddrChecker(cidrs []string) (Checker, error) {
|
||||
func NewRemoteAddrChecker(cidrs []string) (checker.Impl, error) {
|
||||
ranger := cidranger.NewPCTrieRanger()
|
||||
var sb strings.Builder
|
||||
|
||||
|
|
@ -122,11 +92,11 @@ type HeaderMatchesChecker struct {
|
|||
hash string
|
||||
}
|
||||
|
||||
func NewUserAgentChecker(rexStr string) (Checker, error) {
|
||||
func NewUserAgentChecker(rexStr string) (checker.Impl, error) {
|
||||
return NewHeaderMatchesChecker("User-Agent", rexStr)
|
||||
}
|
||||
|
||||
func NewHeaderMatchesChecker(header, rexStr string) (Checker, error) {
|
||||
func NewHeaderMatchesChecker(header, rexStr string) (checker.Impl, error) {
|
||||
rex, err := regexp.Compile(strings.TrimSpace(rexStr))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: regex %s failed parse: %w", ErrMisconfiguration, rexStr, err)
|
||||
|
|
@ -151,7 +121,7 @@ type PathChecker struct {
|
|||
hash string
|
||||
}
|
||||
|
||||
func NewPathChecker(rexStr string) (Checker, error) {
|
||||
func NewPathChecker(rexStr string) (checker.Impl, error) {
|
||||
rex, err := regexp.Compile(strings.TrimSpace(rexStr))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: regex %s failed parse: %w", ErrMisconfiguration, rexStr, err)
|
||||
|
|
@ -171,7 +141,7 @@ func (pc *PathChecker) Hash() string {
|
|||
return pc.hash
|
||||
}
|
||||
|
||||
func NewHeaderExistsChecker(key string) Checker {
|
||||
func NewHeaderExistsChecker(key string) checker.Impl {
|
||||
return headerExistsChecker{strings.TrimSpace(key)}
|
||||
}
|
||||
|
||||
|
|
@ -191,8 +161,8 @@ func (hec headerExistsChecker) Hash() string {
|
|||
return internal.SHA256sum(hec.header)
|
||||
}
|
||||
|
||||
func NewHeadersChecker(headermap map[string]string) (Checker, error) {
|
||||
var result CheckerList
|
||||
func NewHeadersChecker(headermap map[string]string) (checker.Impl, error) {
|
||||
var result checker.List
|
||||
var errs []error
|
||||
|
||||
for key, rexStr := range headermap {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue