Add a logger instance to bouncer instance (#134)

*  Add a logger instance to bouncer instance

* 🍱 fix test

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix test

* 🍱 fix test

* 🍱 fix lint + test

* 🍱 fix test

* 🍱 fix test

* 🍱 fix test

* 🍱 fix lint

* 🍱 fix lint
This commit is contained in:
maxlerebourg
2024-02-11 11:52:47 +01:00
committed by GitHub
parent 6c183d9231
commit 575d3a02e5
7 changed files with 106 additions and 85 deletions
+32 -29
View File
@@ -75,19 +75,20 @@ type Bouncer struct {
serverPoolStrategy *ip.PoolStrategy serverPoolStrategy *ip.PoolStrategy
httpClient *http.Client httpClient *http.Client
cacheClient *cache.Client cacheClient *cache.Client
log *logger.Log
} }
// New creates the crowdsec bouncer plugin. // New creates the crowdsec bouncer plugin.
func New(ctx context.Context, next http.Handler, config *configuration.Config, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config *configuration.Config, name string) (http.Handler, error) {
logger.Init(config.LogLevel) log := logger.New(config.LogLevel)
err := configuration.ValidateParams(config) err := configuration.ValidateParams(config)
if err != nil { if err != nil {
logger.Error(fmt.Sprintf("New:validateParams %s", err.Error())) log.Error(fmt.Sprintf("New:validateParams %s", err.Error()))
return nil, err return nil, err
} }
serverChecker, _ := ip.NewChecker(config.ForwardedHeadersTrustedIPs) serverChecker, _ := ip.NewChecker(log, config.ForwardedHeadersTrustedIPs)
clientChecker, _ := ip.NewChecker(config.ClientTrustedIPs) clientChecker, _ := ip.NewChecker(log, config.ClientTrustedIPs)
var tlsConfig *tls.Config var tlsConfig *tls.Config
crowdsecStreamRoute := "" crowdsecStreamRoute := ""
@@ -103,14 +104,14 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
} else { } else {
crowdsecStreamRoute = crowdsecLapiStreamRoute crowdsecStreamRoute = crowdsecLapiStreamRoute
crowdsecHeader = crowdsecLapiHeader crowdsecHeader = crowdsecLapiHeader
tlsConfig, err = configuration.GetTLSConfigCrowdsec(config) tlsConfig, err = configuration.GetTLSConfigCrowdsec(config, log)
if err != nil { if err != nil {
logger.Error(fmt.Sprintf("New:getTLSConfigCrowdsec fail to get tlsConfig %s", err.Error())) log.Error(fmt.Sprintf("New:getTLSConfigCrowdsec fail to get tlsConfig %s", err.Error()))
return nil, err return nil, err
} }
apiKey, errAPIKey := configuration.GetVariable(config, "CrowdsecLapiKey") apiKey, errAPIKey := configuration.GetVariable(config, "CrowdsecLapiKey")
if errAPIKey != nil && len(tlsConfig.Certificates) == 0 { if errAPIKey != nil && len(tlsConfig.Certificates) == 0 {
logger.Error(fmt.Sprintf("New:crowdsecLapiKey fail to get CrowdsecLapiKey and no client certificate setup %s", errAPIKey.Error())) log.Error(fmt.Sprintf("New:crowdsecLapiKey fail to get CrowdsecLapiKey and no client certificate setup %s", errAPIKey.Error()))
return nil, err return nil, err
} }
config.CrowdsecLapiKey = apiKey config.CrowdsecLapiKey = apiKey
@@ -137,6 +138,7 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
defaultDecisionTimeout: config.DefaultDecisionSeconds, defaultDecisionTimeout: config.DefaultDecisionSeconds,
crowdsecStreamRoute: crowdsecStreamRoute, crowdsecStreamRoute: crowdsecStreamRoute,
crowdsecHeader: crowdsecHeader, crowdsecHeader: crowdsecHeader,
log: log,
serverPoolStrategy: &ip.PoolStrategy{ serverPoolStrategy: &ip.PoolStrategy{
Checker: serverChecker, Checker: serverChecker,
}, },
@@ -157,7 +159,8 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
return bouncer, nil return bouncer, nil
} }
config.RedisCachePassword, _ = configuration.GetVariable(config, "RedisCachePassword") config.RedisCachePassword, _ = configuration.GetVariable(config, "RedisCachePassword")
bouncer.cacheClient.New( bouncer.cacheClient.Init(
log,
config.RedisCacheEnabled, config.RedisCacheEnabled,
config.RedisCacheHost, config.RedisCacheHost,
config.RedisCachePassword, config.RedisCachePassword,
@@ -167,17 +170,17 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
if (config.CrowdsecMode == configuration.StreamMode || config.CrowdsecMode == configuration.AloneMode) && ticker == nil { if (config.CrowdsecMode == configuration.StreamMode || config.CrowdsecMode == configuration.AloneMode) && ticker == nil {
if config.CrowdsecMode == configuration.AloneMode { if config.CrowdsecMode == configuration.AloneMode {
if err := getToken(bouncer); err != nil { if err := getToken(bouncer); err != nil {
logger.Error(fmt.Sprintf("New:getToken %s", err.Error())) bouncer.log.Error(fmt.Sprintf("New:getToken %s", err.Error()))
return nil, err return nil, err
} }
} }
handleStreamTicker(bouncer) handleStreamTicker(bouncer)
isStartup = false isStartup = false
ticker = startTicker(config, func() { ticker = startTicker(config, log, func() {
handleStreamTicker(bouncer) handleStreamTicker(bouncer)
}) })
} }
logger.Debug(fmt.Sprintf("New initialized mode:%s", config.CrowdsecMode)) bouncer.log.Debug(fmt.Sprintf("New initialized mode:%s", config.CrowdsecMode))
return bouncer, nil return bouncer, nil
} }
@@ -194,18 +197,18 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// Here we check for the trusted IPs in the customHeader // Here we check for the trusted IPs in the customHeader
remoteIP, err := ip.GetRemoteIP(req, bouncer.serverPoolStrategy, bouncer.customHeader) remoteIP, err := ip.GetRemoteIP(req, bouncer.serverPoolStrategy, bouncer.customHeader)
if err != nil { if err != nil {
logger.Error(fmt.Sprintf("ServeHTTP:getRemoteIp ip:%s %s", remoteIP, err.Error())) bouncer.log.Error(fmt.Sprintf("ServeHTTP:getRemoteIp ip:%s %s", remoteIP, err.Error()))
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
return return
} }
isTrusted, err := bouncer.clientPoolStrategy.Checker.Contains(remoteIP) isTrusted, err := bouncer.clientPoolStrategy.Checker.Contains(remoteIP)
if err != nil { if err != nil {
logger.Error(fmt.Sprintf("ServeHTTP:checkerContains ip:%s %s", remoteIP, err.Error())) bouncer.log.Error(fmt.Sprintf("ServeHTTP:checkerContains ip:%s %s", remoteIP, err.Error()))
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
return return
} }
// if our IP is in the trusted list we bypass the next checks // if our IP is in the trusted list we bypass the next checks
logger.Debug(fmt.Sprintf("ServeHTTP ip:%s isTrusted:%v", remoteIP, isTrusted)) bouncer.log.Debug(fmt.Sprintf("ServeHTTP ip:%s isTrusted:%v", remoteIP, isTrusted))
if isTrusted { if isTrusted {
bouncer.next.ServeHTTP(rw, req) bouncer.next.ServeHTTP(rw, req)
return return
@@ -221,14 +224,14 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
isBanned, cacheErr := bouncer.cacheClient.GetDecision(remoteIP) isBanned, cacheErr := bouncer.cacheClient.GetDecision(remoteIP)
if cacheErr != nil { if cacheErr != nil {
errString := cacheErr.Error() errString := cacheErr.Error()
logger.Debug(fmt.Sprintf("ServeHTTP:getDecision ip:%s isBanned:false %s", remoteIP, errString)) bouncer.log.Debug(fmt.Sprintf("ServeHTTP:getDecision ip:%s isBanned:false %s", remoteIP, errString))
if errString != cache.CacheMiss { if errString != cache.CacheMiss {
logger.Error(fmt.Sprintf("ServeHTTP:getDecision ip:%s %s", remoteIP, errString)) bouncer.log.Error(fmt.Sprintf("ServeHTTP:getDecision ip:%s %s", remoteIP, errString))
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
return return
} }
} else { } else {
logger.Debug(fmt.Sprintf("ServeHTTP ip:%s cache:hit isBanned:%v", remoteIP, isBanned)) bouncer.log.Debug(fmt.Sprintf("ServeHTTP ip:%s cache:hit isBanned:%v", remoteIP, isBanned))
if isBanned { if isBanned {
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
} else { } else {
@@ -243,13 +246,13 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if isCrowdsecStreamHealthy { if isCrowdsecStreamHealthy {
handleNextServeHTTP(bouncer, remoteIP, rw, req) handleNextServeHTTP(bouncer, remoteIP, rw, req)
} else { } else {
logger.Debug(fmt.Sprintf("ServeHTTP isCrowdsecStreamHealthy:false ip:%s", remoteIP)) bouncer.log.Debug(fmt.Sprintf("ServeHTTP isCrowdsecStreamHealthy:false ip:%s", remoteIP))
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
} }
} else { } else {
err = handleNoStreamCache(bouncer, remoteIP) err = handleNoStreamCache(bouncer, remoteIP)
if err != nil { if err != nil {
logger.Debug(fmt.Sprintf("ServeHTTP:handleNoStreamCache ip:%s isBanned:true %s", remoteIP, err.Error())) bouncer.log.Debug(fmt.Sprintf("ServeHTTP:handleNoStreamCache ip:%s isBanned:true %s", remoteIP, err.Error()))
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
} else { } else {
handleNextServeHTTP(bouncer, remoteIP, rw, req) handleNextServeHTTP(bouncer, remoteIP, rw, req)
@@ -289,7 +292,7 @@ func handleNextServeHTTP(bouncer *Bouncer, remoteIP string, rw http.ResponseWrit
if bouncer.appsecEnabled { if bouncer.appsecEnabled {
err := appsecQuery(bouncer, remoteIP, req) err := appsecQuery(bouncer, remoteIP, req)
if err != nil { if err != nil {
logger.Debug(fmt.Sprintf("handleNextServeHTTP ip:%s isWaf:true %s", remoteIP, err.Error())) bouncer.log.Debug(fmt.Sprintf("handleNextServeHTTP ip:%s isWaf:true %s", remoteIP, err.Error()))
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
return return
} }
@@ -300,17 +303,17 @@ func handleNextServeHTTP(bouncer *Bouncer, remoteIP string, rw http.ResponseWrit
func handleStreamTicker(bouncer *Bouncer) { func handleStreamTicker(bouncer *Bouncer) {
if err := handleStreamCache(bouncer); err != nil { if err := handleStreamCache(bouncer); err != nil {
isCrowdsecStreamHealthy = false isCrowdsecStreamHealthy = false
logger.Error(err.Error()) bouncer.log.Error(err.Error())
} else { } else {
isCrowdsecStreamHealthy = true isCrowdsecStreamHealthy = true
} }
} }
func startTicker(config *configuration.Config, work func()) chan bool { func startTicker(config *configuration.Config, log *logger.Log, work func()) chan bool {
ticker := time.NewTicker(time.Duration(config.UpdateIntervalSeconds) * time.Second) ticker := time.NewTicker(time.Duration(config.UpdateIntervalSeconds) * time.Second)
stop := make(chan bool, 1) stop := make(chan bool, 1)
go func() { go func() {
defer logger.Debug("ticker:stopped") defer log.Debug("ticker:stopped")
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
@@ -387,7 +390,7 @@ func getToken(bouncer *Bouncer) error {
} }
if login.Code == 200 && len(login.Token) > 0 { if login.Code == 200 && len(login.Token) > 0 {
bouncer.crowdsecKey = login.Token bouncer.crowdsecKey = login.Token
logger.Debug(fmt.Sprintf("getToken statusCode:%d", login.Code)) bouncer.log.Debug(fmt.Sprintf("getToken statusCode:%d", login.Code))
return nil return nil
} }
return fmt.Errorf("getToken statusCode:%d", login.Code) return fmt.Errorf("getToken statusCode:%d", login.Code)
@@ -400,7 +403,7 @@ func handleStreamCache(bouncer *Bouncer) error {
// because updated routine information is in the cache // because updated routine information is in the cache
_, err := bouncer.cacheClient.GetDecision(cacheTimeoutKey) _, err := bouncer.cacheClient.GetDecision(cacheTimeoutKey)
if err == nil { if err == nil {
logger.Debug("handleStreamCache:alreadyUpdated") bouncer.log.Debug("handleStreamCache:alreadyUpdated")
return nil return nil
} }
if err.Error() != cache.CacheMiss { if err.Error() != cache.CacheMiss {
@@ -431,7 +434,7 @@ func handleStreamCache(bouncer *Bouncer) error {
for _, decision := range stream.Deleted { for _, decision := range stream.Deleted {
bouncer.cacheClient.DeleteDecision(decision.Value) bouncer.cacheClient.DeleteDecision(decision.Value)
} }
logger.Debug("handleStreamCache:updated") bouncer.log.Debug("handleStreamCache:updated")
isCrowdsecStreamHealthy = true isCrowdsecStreamHealthy = true
return nil return nil
} }
@@ -456,7 +459,7 @@ func crowdsecQuery(bouncer *Bouncer, stringURL string, isPost bool) ([]byte, err
} }
defer func() { defer func() {
if err = res.Body.Close(); err != nil { if err = res.Body.Close(); err != nil {
logger.Error(fmt.Sprintf("crowdsecQuery:closeBody %s", err.Error())) bouncer.log.Error(fmt.Sprintf("crowdsecQuery:closeBody %s", err.Error()))
} }
}() }()
if res.StatusCode == http.StatusUnauthorized && bouncer.crowdsecMode == configuration.AloneMode { if res.StatusCode == http.StatusUnauthorized && bouncer.crowdsecMode == configuration.AloneMode {
@@ -511,11 +514,11 @@ func appsecQuery(bouncer *Bouncer, ip string, httpReq *http.Request) error {
} }
defer func() { defer func() {
if err = res.Body.Close(); err != nil { if err = res.Body.Close(); err != nil {
logger.Error(fmt.Sprintf("appsecQuery:closeBody %s", err.Error())) bouncer.log.Error(fmt.Sprintf("appsecQuery:closeBody %s", err.Error()))
} }
}() }()
if res.StatusCode == http.StatusInternalServerError { if res.StatusCode == http.StatusInternalServerError {
logger.Debug("crowdsecQuery statusCode:500") bouncer.log.Debug("crowdsecQuery statusCode:500")
if bouncer.appsecFailureBlock { if bouncer.appsecFailureBlock {
return fmt.Errorf("appsecQuery statusCode:%d", res.StatusCode) return fmt.Errorf("appsecQuery statusCode:%d", res.StatusCode)
} }
+23 -19
View File
@@ -44,7 +44,9 @@ func (localCache) deleteDecision(clientIP string) {
cache.Del(clientIP) cache.Del(clientIP)
} }
type redisCache struct{} type redisCache struct {
log *logger.Log
}
func (redisCache) getDecision(clientIP string) (bool, error) { func (redisCache) getDecision(clientIP string) (bool, error) {
banned, err := redis.Get(clientIP) banned, err := redis.Get(clientIP)
@@ -58,15 +60,15 @@ func (redisCache) getDecision(clientIP string) (bool, error) {
return false, err return false, err
} }
func (redisCache) setDecision(clientIP string, value string, duration int64) { func (rc redisCache) setDecision(clientIP string, value string, duration int64) {
if err := redis.Set(clientIP, []byte(value), duration); err != nil { if err := redis.Set(clientIP, []byte(value), duration); err != nil {
logger.Error(fmt.Sprintf("cache:setDecisionRedisCache %s", err.Error())) rc.log.Error(fmt.Sprintf("cache:setDecisionRedisCache %s", err.Error()))
} }
} }
func (redisCache) deleteDecision(clientIP string) { func (rc redisCache) deleteDecision(clientIP string) {
if err := redis.Del(clientIP); err != nil { if err := redis.Del(clientIP); err != nil {
logger.Error(fmt.Sprintf("cache:deleteDecisionRedisCache %s", err.Error())) rc.log.Error(fmt.Sprintf("cache:deleteDecisionRedisCache %s", err.Error()))
} }
} }
@@ -79,40 +81,42 @@ type cacheInterface interface {
// Client Cache client. // Client Cache client.
type Client struct { type Client struct {
cache cacheInterface cache cacheInterface
log *logger.Log
} }
// New Initialize cache client. // Init Initialize cache client.
func (client *Client) New(isRedis bool, host, pass, database string) { func (c *Client) Init(log *logger.Log, isRedis bool, host, pass, database string) {
c.log = log
if isRedis { if isRedis {
redis.Init(host, pass, database) redis.Init(host, pass, database)
client.cache = &redisCache{} c.cache = &redisCache{log: log}
} else { } else {
client.cache = &localCache{} c.cache = &localCache{}
} }
logger.Debug(fmt.Sprintf("cache:New initialized isRedis:%v", isRedis)) c.log.Debug(fmt.Sprintf("cache:New initialized isRedis:%v", isRedis))
} }
// DeleteDecision delete decision in cache. // DeleteDecision delete decision in cache.
func (client *Client) DeleteDecision(clientIP string) { func (c *Client) DeleteDecision(clientIP string) {
logger.Debug(fmt.Sprintf("cache:DeleteDecision ip:%v", clientIP)) c.log.Debug(fmt.Sprintf("cache:DeleteDecision ip:%v", clientIP))
client.cache.deleteDecision(clientIP) c.cache.deleteDecision(clientIP)
} }
// GetDecision check in the cache if the IP has the banned / not banned value. // GetDecision check in the cache if the IP has the banned / not banned value.
// Otherwise return with an error to add the IP in cache if we are on. // Otherwise return with an error to add the IP in cache if we are on.
func (client *Client) GetDecision(clientIP string) (bool, error) { func (c *Client) GetDecision(clientIP string) (bool, error) {
logger.Debug(fmt.Sprintf("cache:GetDecision ip:%v", clientIP)) c.log.Debug(fmt.Sprintf("cache:GetDecision ip:%v", clientIP))
return client.cache.getDecision(clientIP) return c.cache.getDecision(clientIP)
} }
// SetDecision update the cache with the IP as key and the value banned / not banned. // SetDecision update the cache with the IP as key and the value banned / not banned.
func (client *Client) SetDecision(clientIP string, isBanned bool, duration int64) { func (c *Client) SetDecision(clientIP string, isBanned bool, duration int64) {
logger.Debug(fmt.Sprintf("cache:SetDecision ip:%v isBanned:%v duration:%vs", clientIP, isBanned, duration)) c.log.Debug(fmt.Sprintf("cache:SetDecision ip:%v isBanned:%v duration:%vs", clientIP, isBanned, duration))
var value string var value string
if isBanned { if isBanned {
value = cacheBannedValue value = cacheBannedValue
} else { } else {
value = cacheNoBannedValue value = cacheNoBannedValue
} }
client.cache.setDecision(clientIP, value, duration) c.cache.setDecision(clientIP, value, duration)
} }
+5 -3
View File
@@ -4,12 +4,14 @@ package cache
import ( import (
"testing" "testing"
logger "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/logger"
) )
func Test_GetDecision(t *testing.T) { func Test_GetDecision(t *testing.T) {
IPInCache := "10.0.0.10" IPInCache := "10.0.0.10"
IPNotInCache := "10.0.0.20" IPNotInCache := "10.0.0.20"
client := &Client{cache: &localCache{}} client := &Client{cache: &localCache{}, log: logger.New("INFO")}
client.SetDecision(IPInCache, true, 10) client.SetDecision(IPInCache, true, 10)
type args struct { type args struct {
clientIP string clientIP string
@@ -45,7 +47,7 @@ func Test_GetDecision(t *testing.T) {
} }
func Test_SetDecision(t *testing.T) { func Test_SetDecision(t *testing.T) {
client := &Client{cache: &localCache{}} client := &Client{cache: &localCache{}, log: logger.New("INFO")}
IPInCache := "10.0.0.11" IPInCache := "10.0.0.11"
type args struct { type args struct {
clientIP string clientIP string
@@ -76,7 +78,7 @@ func Test_SetDecision(t *testing.T) {
func Test_DeleteDecision(t *testing.T) { func Test_DeleteDecision(t *testing.T) {
IPInCache := "10.0.0.12" IPInCache := "10.0.0.12"
IPNotInCache := "10.0.0.22" IPNotInCache := "10.0.0.22"
client := &Client{cache: &localCache{}} client := &Client{cache: &localCache{}, log: logger.New("INFO")}
client.SetDecision(IPInCache, true, 10) client.SetDecision(IPInCache, true, 10)
type args struct { type args struct {
clientIP string clientIP string
+10 -9
View File
@@ -235,11 +235,9 @@ func validateParamsTLS(config *Config) error {
func validateParamsIPs(listIP []string, key string) error { func validateParamsIPs(listIP []string, key string) error {
if len(listIP) > 0 { if len(listIP) > 0 {
if _, err := ip.NewChecker(listIP); err != nil { if _, err := ip.NewChecker(logger.New("INFO"), listIP); err != nil {
return fmt.Errorf("%s must be a list of IP/CIDR :%w", key, err) return fmt.Errorf("%s must be a list of IP/CIDR :%w", key, err)
} }
} else {
logger.Debug(fmt.Sprintf("No IP provided for %s", key))
} }
return nil return nil
} }
@@ -275,16 +273,18 @@ func validateParamsRequired(config *Config) error {
} }
// GetTLSConfigCrowdsec get TLS config from Config. // GetTLSConfigCrowdsec get TLS config from Config.
func GetTLSConfigCrowdsec(config *Config) (*tls.Config, error) { //
//nolint:nestif
func GetTLSConfigCrowdsec(config *Config, log *logger.Log) (*tls.Config, error) {
tlsConfig := new(tls.Config) tlsConfig := new(tls.Config)
tlsConfig.RootCAs = x509.NewCertPool() tlsConfig.RootCAs = x509.NewCertPool()
//nolint:gocritic //nolint:gocritic
if config.CrowdsecLapiScheme != HTTPS { if config.CrowdsecLapiScheme != HTTPS {
logger.Debug("getTLSConfigCrowdsec:CrowdsecLapiScheme https:no") log.Debug("getTLSConfigCrowdsec:CrowdsecLapiScheme https:no")
return tlsConfig, nil return tlsConfig, nil
} else if config.CrowdsecLapiTLSInsecureVerify { } else if config.CrowdsecLapiTLSInsecureVerify {
logger.Debug("getTLSConfigCrowdsec:CrowdsecLapiTLSInsecureVerify tlsInsecure:true")
tlsConfig.InsecureSkipVerify = true tlsConfig.InsecureSkipVerify = true
log.Debug("getTLSConfigCrowdsec:CrowdsecLapiTLSInsecureVerify tlsInsecure:true")
// If we return here and still want to use client auth this won't work // If we return here and still want to use client auth this won't work
// return tlsConfig, nil // return tlsConfig, nil
} else { } else {
@@ -292,13 +292,14 @@ func GetTLSConfigCrowdsec(config *Config) (*tls.Config, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
cert := []byte(certAuthority) if len(certAuthority) > 0 {
if !tlsConfig.RootCAs.AppendCertsFromPEM(cert) { if !tlsConfig.RootCAs.AppendCertsFromPEM([]byte(certAuthority)) {
logger.Debug("getTLSConfigCrowdsec:CrowdsecLapiTLSCertificateAuthority read cert failed")
// here we return because if CrowdsecLapiTLSInsecureVerify is false // here we return because if CrowdsecLapiTLSInsecureVerify is false
// and CA not load, we can't communicate with https // and CA not load, we can't communicate with https
return nil, fmt.Errorf("getTLSConfigCrowdsec:cannot load CA and verify cert is enabled") return nil, fmt.Errorf("getTLSConfigCrowdsec:cannot load CA and verify cert is enabled")
} }
log.Debug("getTLSConfigCrowdsec:CrowdsecLapiTLSCertificateAuthority CA added successfully")
}
} }
certBouncer, err := GetVariable(config, "CrowdsecLapiTLSCertificateBouncer") certBouncer, err := GetVariable(config, "CrowdsecLapiTLSCertificateBouncer")
+4 -2
View File
@@ -4,6 +4,8 @@ import (
"crypto/tls" "crypto/tls"
"reflect" "reflect"
"testing" "testing"
logger "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/logger"
) )
func getMinimalConfig() *Config { func getMinimalConfig() *Config {
@@ -147,7 +149,7 @@ func Test_validateParamsIPs(t *testing.T) {
{name: "Not validate localhost", args: args{listIP: []string{0: "localhost"}}, wantErr: true}, {name: "Not validate localhost", args: args{listIP: []string{0: "localhost"}}, wantErr: true},
{name: "Not validate a weird ip", args: args{listIP: []string{0: "0.0.0.0/89"}}, wantErr: true}, {name: "Not validate a weird ip", args: args{listIP: []string{0: "0.0.0.0/89"}}, wantErr: true},
{name: "Not validate a weird ip 2", args: args{listIP: []string{0: "0.0.0.256/12"}}, wantErr: true}, {name: "Not validate a weird ip 2", args: args{listIP: []string{0: "0.0.0.256/12"}}, wantErr: true},
{name: "Validate an ip not trimed", args: args{listIP: []string{0: " 0.0.0.0/0"}}, wantErr: false}, {name: "Validate an ip not trimmed", args: args{listIP: []string{0: " 0.0.0.0/0"}}, wantErr: false},
{name: "Validate an ip", args: args{listIP: []string{0: "0.0.0.0/12"}}, wantErr: false}, {name: "Validate an ip", args: args{listIP: []string{0: "0.0.0.0/12"}}, wantErr: false},
{name: "Validate an ip list", args: args{listIP: []string{0: "0.0.0.0/0", 1: "1.1.1.1/1"}}, wantErr: false}, {name: "Validate an ip list", args: args{listIP: []string{0: "0.0.0.0/0", 1: "1.1.1.1/1"}}, wantErr: false},
} }
@@ -231,7 +233,7 @@ func Test_GetTLSConfigCrowdsec(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := GetTLSConfigCrowdsec(tt.args.config) got, err := GetTLSConfigCrowdsec(tt.args.config, logger.New("INFO"))
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("getTLSConfigCrowdsec() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("getTLSConfigCrowdsec() error = %v, wantErr %v", err, tt.wantErr)
return return
+4 -4
View File
@@ -8,7 +8,7 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/logger" logger "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/logger"
) )
// CHECKER // CHECKER
@@ -20,14 +20,14 @@ type Checker struct {
} }
// NewChecker builds a new Checker given a list of CIDR-Strings to trusted IPs. // NewChecker builds a new Checker given a list of CIDR-Strings to trusted IPs.
func NewChecker(trustedIPs []string) (*Checker, error) { func NewChecker(log *logger.Log, trustedIPs []string) (*Checker, error) {
checker := &Checker{} checker := &Checker{}
for _, ipMaskRaw := range trustedIPs { for _, ipMaskRaw := range trustedIPs {
ipMask := strings.TrimSpace(ipMaskRaw) ipMask := strings.TrimSpace(ipMaskRaw)
if ipAddr := net.ParseIP(ipMask); ipAddr != nil { if ipAddr := net.ParseIP(ipMask); ipAddr != nil {
checker.authorizedIPs = append(checker.authorizedIPs, &ipAddr) checker.authorizedIPs = append(checker.authorizedIPs, &ipAddr)
logger.Debug(fmt.Sprintf("IP %v is trusted", ipAddr)) log.Debug(fmt.Sprintf("IP %v is trusted", ipAddr))
continue continue
} }
@@ -36,7 +36,7 @@ func NewChecker(trustedIPs []string) (*Checker, error) {
return nil, fmt.Errorf("parsing CIDR trusted IPs %s: %w", ipAddr, err) return nil, fmt.Errorf("parsing CIDR trusted IPs %s: %w", ipAddr, err)
} }
checker.authorizedIPsNet = append(checker.authorizedIPsNet, ipAddr) checker.authorizedIPsNet = append(checker.authorizedIPsNet, ipAddr)
logger.Debug(fmt.Sprintf("IP network %v is trusted", ipAddr)) log.Debug(fmt.Sprintf("IP network %v is trusted", ipAddr))
} }
return checker, nil return checker, nil
+25 -16
View File
@@ -8,32 +8,41 @@ import (
"os" "os"
) )
var ( // Log Logger struct.
loggerInfo = log.New(io.Discard, "INFO: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime) //nolint:gochecknoglobals type Log struct {
loggerDebug = log.New(io.Discard, "DEBUG: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime) //nolint:gochecknoglobals logError *log.Logger
loggerError = log.New(io.Discard, "ERROR: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime) //nolint:gochecknoglobals logInfo *log.Logger
) logDebug *log.Logger
}
// Init Set Default log level to info in case log level to defined. // New Set Default log level to info in case log level to defined.
func Init(logLevel string) { func New(logLevel string) *Log {
loggerError.SetOutput(os.Stderr) logError := log.New(io.Discard, "ERROR: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime)
loggerInfo.SetOutput(os.Stdout) logInfo := log.New(io.Discard, "INFO: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime)
logDebug := log.New(io.Discard, "DEBUG: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime)
logError.SetOutput(os.Stderr)
logInfo.SetOutput(os.Stdout)
if logLevel == "DEBUG" { if logLevel == "DEBUG" {
loggerDebug.SetOutput(os.Stdout) logDebug.SetOutput(os.Stdout)
}
return &Log{
logError: logError,
logInfo: logInfo,
logDebug: logDebug,
} }
} }
// Info log to Stdout. // Info log to Stdout.
func Info(str string) { func (l *Log) Info(str string) {
loggerInfo.Printf(str) l.logInfo.Printf(str)
} }
// Debug log to Stdout. // Debug log to Stdout.
func Debug(str string) { func (l *Log) Debug(str string) {
loggerDebug.Printf(str) l.logDebug.Printf(str)
} }
// Error log to Stderr. // Error log to Stderr.
func Error(str string) { func (l *Log) Error(str string) {
loggerError.Printf(str) l.logError.Printf(str)
} }