diff --git a/cmds/modules/netlightd/main.go b/cmds/modules/netlightd/main.go index 193f27321..309508449 100644 --- a/cmds/modules/netlightd/main.go +++ b/cmds/modules/netlightd/main.go @@ -107,6 +107,11 @@ func action(cli *cli.Context) error { return fmt.Errorf("failed to apply host nft rules: %w", err) } rules.Close() + + if err := nft.UpdateNFTWhitelist(); err != nil { + return fmt.Errorf("failed to allow whitelist outgoing traffic") + } + bridge, err := netlight.CreateNDMZBridge() if err != nil { return fmt.Errorf("failed to create ndmz bridge: %w", err) diff --git a/pkg/environment/config.go b/pkg/environment/config.go index 9a0595ff8..261863ee4 100644 --- a/pkg/environment/config.go +++ b/pkg/environment/config.go @@ -27,6 +27,9 @@ type Config struct { Users struct { Authorized []string `json:"authorized"` } `json:"users"` + Whitelist struct { + Ips []string `json:"ips"` + } `json:"whitelist"` } // Merge, updates current config with cfg merging and override config diff --git a/pkg/netlight/nft/nft.go b/pkg/netlight/nft/nft.go index e3486aa57..69a39722f 100644 --- a/pkg/netlight/nft/nft.go +++ b/pkg/netlight/nft/nft.go @@ -1,10 +1,14 @@ package nft import ( + "fmt" "io" "os/exec" + "time" + "github.com/go-co-op/gocron" "github.com/rs/zerolog/log" + "github.com/threefoldtech/zos/pkg/environment" "github.com/pkg/errors" ) @@ -32,3 +36,72 @@ func Apply(r io.Reader, ns string) error { } return nil } + +// UpdateNFTWhitelist periodically pull list of ips from config repo and +// update the nft white list +func UpdateNFTWhitelist() error { + scheduler := gocron.NewScheduler(time.UTC) + cron := "0 * * * *" + + updateWhitelist := func() error { + ips, err := whiteList() + if err != nil { + return err + } + + cmds := []string{ + "nft flush chain inet filter output", + "nft add rule inet filter output ct state established,related accept", + "nft add rule inet filter output tcp dport 22 accept", + } + + ipCmdTemplate := "nft add rule inet filter output ip daddr %s accept" + blockCmd := "nft add rule inet filter output drop" + + for _, cmd := range cmds { + if err := runCommand(cmd); err != nil { + return nil + } + } + + for _, ip := range ips { + if err := runCommand(fmt.Sprintf(ipCmdTemplate, ip)); err != nil { + return nil + } + } + + if err := runCommand(blockCmd); err != nil { + return nil + } + + return nil + } + + if err := updateWhitelist(); err != nil { + return err + } + + if _, err := scheduler.Cron(cron).Do(updateWhitelist); err != nil { + return err + } + scheduler.StartAsync() + + return nil +} + +func runCommand(cmdStr string) error { + cmd := exec.Command("sh", "-c", cmdStr) + if output, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("command failed: %s, output: %s", err, output) + } + return nil +} + +func whiteList() ([]string, error) { + cfg, err := environment.GetConfig() + if err != nil { + return nil, err + } + + return cfg.Whitelist.Ips, nil +}