mirror of
https://github.com/crowdsecurity/cs-firewall-bouncer.git
synced 2024-08-19 01:18:49 +03:00
config: apply variable expansion to all keys (#364)
* fix ennvar expansion in configuration file * CI: test variable expansion * lint
This commit is contained in:
25
cmd/root.go
25
cmd/root.go
@@ -1,8 +1,8 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
csbouncer "github.com/crowdsecurity/go-cs-bouncer"
|
||||
"github.com/crowdsecurity/go-cs-lib/csdaemon"
|
||||
"github.com/crowdsecurity/go-cs-lib/csstring"
|
||||
"github.com/crowdsecurity/go-cs-lib/version"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
@@ -47,9 +48,9 @@ func HandleSignals(ctx context.Context) error {
|
||||
case s := <-signalChan:
|
||||
switch s {
|
||||
case syscall.SIGTERM:
|
||||
return fmt.Errorf("received SIGTERM")
|
||||
return errors.New("received SIGTERM")
|
||||
case os.Interrupt: // cross-platform SIGINT
|
||||
return fmt.Errorf("received interrupt")
|
||||
return errors.New("received interrupt")
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
@@ -76,6 +77,7 @@ func deleteDecisions(backend *backend.BackendCTX, decisions []*models.Decision,
|
||||
}
|
||||
|
||||
log.Debugf("deleted %s", *d.Value)
|
||||
|
||||
nbDeletedDecisions++
|
||||
}
|
||||
|
||||
@@ -112,6 +114,7 @@ func addDecisions(backend *backend.BackendCTX, decisions []*models.Decision, con
|
||||
}
|
||||
|
||||
log.Debugf("Adding '%s' for '%s'", *d.Value, *d.Duration)
|
||||
|
||||
nbNewDecisions++
|
||||
}
|
||||
|
||||
@@ -149,20 +152,22 @@ func Execute() error {
|
||||
}
|
||||
|
||||
if configPath == nil || *configPath == "" {
|
||||
return fmt.Errorf("configuration file is required")
|
||||
return errors.New("configuration file is required")
|
||||
}
|
||||
|
||||
configBytes, err := cfg.MergedConfig(*configPath)
|
||||
configMerged, err := cfg.MergedConfig(*configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read config file: %w", err)
|
||||
}
|
||||
|
||||
if *showConfig {
|
||||
fmt.Println(string(configBytes))
|
||||
fmt.Println(string(configMerged))
|
||||
return nil
|
||||
}
|
||||
|
||||
config, err := cfg.NewConfig(bytes.NewReader(configBytes))
|
||||
configExpanded := csstring.StrictExpand(string(configMerged), os.LookupEnv)
|
||||
|
||||
config, err := cfg.NewConfig(strings.NewReader(configExpanded))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load configuration: %w", err)
|
||||
}
|
||||
@@ -186,7 +191,7 @@ func Execute() error {
|
||||
|
||||
bouncer := &csbouncer.StreamBouncer{}
|
||||
|
||||
err = bouncer.ConfigReader(bytes.NewReader(configBytes))
|
||||
err = bouncer.ConfigReader(strings.NewReader(configExpanded))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -209,7 +214,7 @@ func Execute() error {
|
||||
|
||||
g.Go(func() error {
|
||||
bouncer.Run(ctx)
|
||||
return fmt.Errorf("bouncer stream halted")
|
||||
return errors.New("bouncer stream halted")
|
||||
})
|
||||
|
||||
if config.PrometheusConfig.Enabled {
|
||||
@@ -234,6 +239,7 @@ func Execute() error {
|
||||
|
||||
g.Go(func() error {
|
||||
log.Infof("Processing new and deleted decisions . . .")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@@ -242,6 +248,7 @@ func Execute() error {
|
||||
if decisions == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
deleteDecisions(backend, decisions.Deleted, config)
|
||||
addDecisions(backend, decisions.New, config)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
@@ -72,7 +73,7 @@ func NewBackend(config *cfg.BouncerConfig) (*BackendCTX, error) {
|
||||
switch config.Mode {
|
||||
case cfg.IptablesMode, cfg.IpsetMode:
|
||||
if runtime.GOOS != "linux" {
|
||||
return nil, fmt.Errorf("iptables and ipset is linux only")
|
||||
return nil, errors.New("iptables and ipset is linux only")
|
||||
}
|
||||
|
||||
b.firewall, err = iptables.NewIPTables(config)
|
||||
@@ -81,7 +82,7 @@ func NewBackend(config *cfg.BouncerConfig) (*BackendCTX, error) {
|
||||
}
|
||||
case cfg.NftablesMode:
|
||||
if runtime.GOOS != "linux" {
|
||||
return nil, fmt.Errorf("nftables is linux only")
|
||||
return nil, errors.New("nftables is linux only")
|
||||
}
|
||||
|
||||
b.firewall, err = nftables.NewNFTables(config)
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/crowdsecurity/go-cs-lib/csstring"
|
||||
"github.com/crowdsecurity/go-cs-lib/ptr"
|
||||
"github.com/crowdsecurity/go-cs-lib/yamlpatch"
|
||||
)
|
||||
@@ -86,9 +85,7 @@ func NewConfig(reader io.Reader) (*BouncerConfig, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configBuff := csstring.StrictExpand(string(fcontent), os.LookupEnv)
|
||||
|
||||
err = yaml.Unmarshal([]byte(configBuff), &config)
|
||||
err = yaml.Unmarshal(fcontent, &config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal: %w", err)
|
||||
}
|
||||
@@ -98,7 +95,7 @@ func NewConfig(reader io.Reader) (*BouncerConfig, error) {
|
||||
}
|
||||
|
||||
if config.Mode == "" {
|
||||
return nil, fmt.Errorf("config does not contain 'mode'")
|
||||
return nil, errors.New("config does not contain 'mode'")
|
||||
}
|
||||
|
||||
if len(config.SupportedDecisionsTypes) == 0 {
|
||||
@@ -152,7 +149,7 @@ func NewConfig(reader io.Reader) (*BouncerConfig, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func pfConfig(config *BouncerConfig) error {
|
||||
func pfConfig(_ *BouncerConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -191,7 +188,7 @@ func nftablesConfig(config *BouncerConfig) error {
|
||||
}
|
||||
|
||||
if !*config.Nftables.Ipv4.Enabled && !*config.Nftables.Ipv6.Enabled {
|
||||
return fmt.Errorf("both IPv4 and IPv6 disabled, doing nothing")
|
||||
return errors.New("both IPv4 and IPv6 disabled, doing nothing")
|
||||
}
|
||||
|
||||
if config.NftablesHooks == nil || len(config.NftablesHooks) == 0 {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -75,7 +75,7 @@ func (c *LoggingConfig) setDefaults() {
|
||||
|
||||
func (c *LoggingConfig) validate() error {
|
||||
if c.LogMode != "stdout" && c.LogMode != "file" {
|
||||
return fmt.Errorf("log_mode should be either 'stdout' or 'file'")
|
||||
return errors.New("log_mode should be either 'stdout' or 'file'")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package iptables
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
@@ -68,7 +69,7 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) {
|
||||
|
||||
ipsetBin, err := exec.LookPath("ipset")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to find ipset")
|
||||
return nil, errors.New("unable to find ipset")
|
||||
}
|
||||
|
||||
ipv4Ctx.ipsetBin = ipsetBin
|
||||
@@ -77,7 +78,7 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) {
|
||||
} else {
|
||||
ipv4Ctx.iptablesBin, err = exec.LookPath("iptables")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to find iptables")
|
||||
return nil, errors.New("unable to find iptables")
|
||||
}
|
||||
ipv4Ctx.Chains = config.IptablesChains
|
||||
for _, v := range config.IptablesChains {
|
||||
@@ -109,7 +110,7 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) {
|
||||
} else {
|
||||
ipv6Ctx.iptablesBin, err = exec.LookPath("ip6tables")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to find ip6tables")
|
||||
return nil, errors.New("unable to find ip6tables")
|
||||
}
|
||||
ipv6Ctx.Chains = config.IptablesChains
|
||||
for _, v := range config.IptablesChains {
|
||||
@@ -237,7 +238,7 @@ func (ipt *iptables) Delete(decision *models.Decision) error {
|
||||
}
|
||||
|
||||
if err := ipt.v6.delete(decision); err != nil {
|
||||
return fmt.Errorf("failed deleting ban")
|
||||
return errors.New("failed deleting ban")
|
||||
}
|
||||
|
||||
done = true
|
||||
@@ -245,7 +246,7 @@ func (ipt *iptables) Delete(decision *models.Decision) error {
|
||||
|
||||
if strings.Contains(*decision.Value, ".") {
|
||||
if err := ipt.v4.delete(decision); err != nil {
|
||||
return fmt.Errorf("failed deleting ban")
|
||||
return errors.New("failed deleting ban")
|
||||
}
|
||||
|
||||
done = true
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
|
||||
|
||||
def test_yaml_local(bouncer, fw_cfg_factory):
|
||||
cfg = fw_cfg_factory()
|
||||
@@ -21,3 +23,18 @@ def test_yaml_local(bouncer, fw_cfg_factory):
|
||||
])
|
||||
fw.proc.wait(timeout=0.2)
|
||||
assert not fw.proc.is_running()
|
||||
|
||||
# variable expansion
|
||||
|
||||
config_local = {
|
||||
'mode': '$BOUNCER_MODE'
|
||||
}
|
||||
|
||||
os.environ['BOUNCER_MODE'] = 'fromenv'
|
||||
|
||||
with bouncer(cfg, config_local=config_local) as fw:
|
||||
fw.wait_for_lines_fnmatch([
|
||||
"*firewall 'fromenv' is not supported*",
|
||||
])
|
||||
fw.proc.wait(timeout=0.2)
|
||||
assert not fw.proc.is_running()
|
||||
|
||||
Reference in New Issue
Block a user