Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config: apply variable expansion to all keys #364

Merged
merged 3 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package cmd

import (
"bytes"
"context"
"errors"
"flag"
"fmt"
"net"
Expand All @@ -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"
Expand Down Expand Up @@ -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()
Expand All @@ -76,6 +77,7 @@ func deleteDecisions(backend *backend.BackendCTX, decisions []*models.Decision,
}

log.Debugf("deleted %s", *d.Value)

nbDeletedDecisions++
}

Expand Down Expand Up @@ -112,6 +114,7 @@ func addDecisions(backend *backend.BackendCTX, decisions []*models.Decision, con
}

log.Debugf("Adding '%s' for '%s'", *d.Value, *d.Duration)

nbNewDecisions++
}

Expand Down Expand Up @@ -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)
}
Expand All @@ -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
}
Expand All @@ -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 {
Expand All @@ -234,6 +239,7 @@ func Execute() error {

g.Go(func() error {
log.Infof("Processing new and deleted decisions . . .")

for {
select {
case <-ctx.Done():
Expand All @@ -242,6 +248,7 @@ func Execute() error {
if decisions == nil {
continue
}

deleteDecisions(backend, decisions.Deleted, config)
addDecisions(backend, decisions.New, config)
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/backend/backend.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package backend

import (
"errors"
"fmt"
"runtime"

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
13 changes: 5 additions & 8 deletions pkg/cfg/config.go
Original file line number Diff line number Diff line change
@@ -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"
)
Expand Down Expand Up @@ -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)
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions pkg/cfg/logging.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cfg

import (
"fmt"
"errors"
"io"
"os"
"path/filepath"
Expand Down Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions pkg/iptables/iptables.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package iptables

import (
"errors"
"fmt"
"os/exec"
"strings"
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -237,15 +238,15 @@ 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
}

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
Expand Down
17 changes: 17 additions & 0 deletions test/bouncer/test_yaml_local.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os


def test_yaml_local(bouncer, fw_cfg_factory):
cfg = fw_cfg_factory()
Expand All @@ -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()
Loading