Skip to content

Commit

Permalink
feat: flag to allow blacklisting CIDR ranges (#2589)
Browse files Browse the repository at this point in the history
* feat: flag to allow blacklisting CIDR ranges
  • Loading branch information
docmerlin authored Jul 9, 2021
1 parent ebcb9f1 commit 815bf2b
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 66 deletions.
5 changes: 5 additions & 0 deletions client/v1/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"net/url"
Expand Down Expand Up @@ -450,6 +451,10 @@ func New(conf Config) (*Client, error) {
if rt == nil {
tr = khttp.NewDefaultTransportWithTLS(&tls.Config{
InsecureSkipVerify: conf.InsecureSkipVerify,
}, &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
Control: khttp.Control(khttp.DefaultValidator),
})
if conf.TLSConfig != nil {
tr.TLSClientConfig = conf.TLSConfig
Expand Down
26 changes: 24 additions & 2 deletions cmd/kapacitord/run/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import (
"strings"

"github.com/BurntSushi/toml"
furl "github.com/influxdata/flux/dependencies/url"
"github.com/influxdata/flux/fluxinit"
khttp "github.com/influxdata/kapacitor/http"
"github.com/influxdata/kapacitor/server"
"github.com/influxdata/kapacitor/services/diagnostic"
)
Expand Down Expand Up @@ -104,6 +106,18 @@ func (cmd *Command) Run(args ...string) error {
if options.LogLevel != "" {
config.Logging.Level = options.LogLevel
}

switch options.BlackListCIDRS {
case "":
khttp.DefaultValidator = furl.PassValidator{}
case "private":
khttp.DefaultValidator = furl.PrivateIPValidator{}
default:
if khttp.DefaultValidator, err = khttp.ParseCIDRsString(options.BlackListCIDRS); err != nil {
return fmt.Errorf("flag error: improper CIDRs: %s", err)
}
}

// Initialize Logging Services
cmd.diagService = diagnostic.NewService(config.Logging, cmd.Stdout, cmd.Stderr)
if err := cmd.diagService.Open(); err != nil {
Expand Down Expand Up @@ -197,6 +211,7 @@ func (cmd *Command) ParseFlags(args ...string) (Options, error) {
fs.StringVar(&options.MemProfile, "memprofile", "", "")
fs.StringVar(&options.LogFile, "log-file", "", "")
fs.StringVar(&options.LogLevel, "log-level", "", "")
fs.StringVar(&options.BlackListCIDRS, "blacklist-cidrs", "", "")
fs.StringVar(&options.DisabledAlertHandlers, "disable-handlers", "", "")
fs.Usage = func() { fmt.Fprintln(cmd.Stderr, usage) }
if err := fs.Parse(args); err != nil {
Expand Down Expand Up @@ -248,10 +263,18 @@ func (cmd *Command) ParseConfig(path string) (*server.Config, error) {
var usage = `usage: run [flags]
run starts the Kapacitor server.
-blacklist-cidrs <CIDR1,CIDR2,...>
Comma seperated list of CIDRs to blacklist for
most http get/post operations
-config <path>
Set the path to the configuration file.
-disable-handlers <comma-separated list of alert-handlers>
Disables certain alert handlers. This is useful for
security, reasons. For example: disabling exec on
a shared system.
-hostname <name>
Override the hostname, the 'hostname' configuration
option will be overridden.
Expand All @@ -265,8 +288,6 @@ run starts the Kapacitor server.
-log-level <level>
Sets the log level. One of debug,info,error.
-disable-handlers <comma-separated list of alert-handlers>
Disables certain alert handlers. This is useful for security, reasons. For example: disabling exec on a shared system.
`

// Options represents the command line options that can be parsed.
Expand All @@ -279,4 +300,5 @@ type Options struct {
LogFile string
LogLevel string
DisabledAlertHandlers string
BlackListCIDRS string
}
112 changes: 104 additions & 8 deletions http/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,32 @@ package http

import (
"crypto/tls"
"fmt"
"net"
"net/http"
"net/url"
"strings"
"syscall"
"time"

furl "github.com/influxdata/flux/dependencies/url"
)

// NewDefaultTransport creates a new transport with sane defaults.
func NewDefaultTransport() *http.Transport {
// These defaults are copied from http.DefaultTransport.
return &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
func NewDefaultTransport(dialer *net.Dialer) *http.Transport {

if dialer == nil {
dialer = &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
}
}

// These defaults are copied from http.DefaultTransport.
return &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (dialer).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
Expand All @@ -27,8 +38,93 @@ func NewDefaultTransport() *http.Transport {
}

// NewDefaultTransportWithTLS creates a new transport with the specified TLS configuration.
func NewDefaultTransportWithTLS(tlsConfig *tls.Config) *http.Transport {
t := NewDefaultTransport()
func NewDefaultTransportWithTLS(tlsConfig *tls.Config, dialer *net.Dialer) *http.Transport {
t := NewDefaultTransport(dialer)
t.TLSClientConfig = tlsConfig
return t
}

// Control is called after DNS lookup, but before the network connection is
// initiated.
func Control(urlValidator furl.Validator) func(network, address string, c syscall.RawConn) error {
return func(network, address string, c syscall.RawConn) error {
host, _, err := net.SplitHostPort(address)
if err != nil {
return err
}

ip := net.ParseIP(host)
return urlValidator.ValidateIP(ip)
}
}

// NewDefaultClientWithTLS creates a tls client with sane defaults.
func NewDefaultClientWithTLS(tlsConfig *tls.Config, urlValidator furl.Validator) *http.Client {

// These defaults are copied from http.DefaultTransport.
return &http.Client{
Transport: NewDefaultTransportWithTLS(tlsConfig, &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
Control: Control(urlValidator),
}),
Timeout: 30 * time.Second,
}
}

// NewDefaultClient creates a client with sane defaults.
func NewDefaultClient(urlValidator furl.Validator) *http.Client {

// These defaults are copied from http.DefaultTransport.
return &http.Client{
Transport: NewDefaultTransport(&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
Control: Control(urlValidator),
// DualStack is deprecated
}),
}
}

// DefaultValidator is the default validator, it can be replaced at start time with a different validator
var DefaultValidator furl.Validator = furl.PassValidator{}

type cidrValidator struct {
cidrs []*net.IPNet
}

func (v cidrValidator) Validate(u *url.URL) error {
ips, err := net.LookupIP(u.Hostname())
if err != nil {
return err
}
for _, ip := range ips {
err = v.ValidateIP(ip)
if err != nil {
return err
}
}
return nil
}

func (v cidrValidator) ValidateIP(ip net.IP) error {
for i := range v.cidrs {
if v.cidrs[i].Contains(ip) {
return fmt.Errorf("ip '%s' is blacklisted", ip)
}
}
return nil
}

func ParseCIDRsString(s string) (furl.Validator, error) {
cidrStrings := strings.Split(s, ",")
cidrs := make([]*net.IPNet, 0, len(cidrStrings))
for i := range cidrStrings {
_, cidr, err := net.ParseCIDR(cidrStrings[i])
if err != nil {
return nil, err
}
cidrs = append(cidrs, cidr)
}
return cidrValidator{cidrs: cidrs}, nil
}
22 changes: 21 additions & 1 deletion influxdb/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"strconv"
Expand Down Expand Up @@ -157,8 +158,21 @@ func NewHTTPClient(conf Config) (*HTTPClient, error) {
return nil, errors.Wrap(err, "invalid URLs")
}
if conf.Transport == nil {
conf.Transport = khttp.NewDefaultTransport()
conf.Transport = khttp.NewDefaultTransport(&net.Dialer{
Timeout: 30 * time.Second, // I am not sure if this is the right value to set it to
KeepAlive: 30 * time.Second, // I am not sure if this is the right value to set it to
Control: khttp.Control(khttp.DefaultValidator),
// DualStack is deprecated
})
}

conf.Transport.DialContext = (&net.Dialer{
Timeout: 30 * time.Second, // I am not sure if this is the right value to set it to
KeepAlive: 30 * time.Second, // I am not sure if this is the right value to set it to
Control: khttp.Control(khttp.DefaultValidator),
// DualStack is deprecated
}).DialContext

c := &HTTPClient{
config: conf,
urls: urls,
Expand Down Expand Up @@ -243,6 +257,12 @@ func (c *HTTPClient) Update(new Config) error {
if tr == nil {
tr = old.Transport
}
tr.DialContext = (&net.Dialer{
Timeout: 30 * time.Second, // I am not sure if this is the right value to set it to
KeepAlive: 30 * time.Second, // I am not sure if this is the right value to set it to
Control: khttp.Control(khttp.DefaultValidator),
// DualStack is deprecated
}).DialContext
c.client = &http.Client{
Timeout: new.Timeout,
Transport: tr,
Expand Down
9 changes: 3 additions & 6 deletions services/alerta/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ func NewService(c Config, d Diagnostic) *Service {
diag: d,
}
s.configValue.Store(c)
s.clientValue.Store(&http.Client{
Transport: khttp.NewDefaultTransportWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}),
})
s.clientValue.Store(khttp.NewDefaultClientWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}, khttp.DefaultValidator))

return s
}

Expand Down Expand Up @@ -128,9 +127,7 @@ func (s *Service) Update(newConfig []interface{}) error {
return fmt.Errorf("expected config object to be of type %T, got %T", c, newConfig[0])
} else {
s.configValue.Store(c)
s.clientValue.Store(&http.Client{
Transport: khttp.NewDefaultTransportWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}),
})
s.clientValue.Store(khttp.NewDefaultClientWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}, khttp.DefaultValidator))
}

return nil
Expand Down
8 changes: 2 additions & 6 deletions services/bigpanda/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ func NewService(c Config, d Diagnostic) (*Service, error) {
diag: d,
}
s.configValue.Store(c)
s.clientValue.Store(&http.Client{
Transport: khttp.NewDefaultTransportWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}),
})
s.clientValue.Store(khttp.NewDefaultClientWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}, khttp.DefaultValidator))

return s, nil
}
Expand All @@ -67,9 +65,7 @@ func (s *Service) Update(newConfig []interface{}) error {
return fmt.Errorf("expected config object to be of type %T, got %T", c, newConfig[0])
} else {
s.configValue.Store(c)
s.clientValue.Store(&http.Client{
Transport: khttp.NewDefaultTransportWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}),
})
s.clientValue.Store(khttp.NewDefaultClientWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}, khttp.DefaultValidator))
}
return nil
}
Expand Down
12 changes: 2 additions & 10 deletions services/discord/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,9 @@ func NewWorkspace(c Config) (*Workspace, error) {
return nil, err
}

cl := &http.Client{
Transport: khttp.NewDefaultTransportWithTLS(tlsConfig),
}

return &Workspace{
config: c,
client: cl,
client: khttp.NewDefaultClientWithTLS(tlsConfig, khttp.DefaultValidator),
}, nil
}

Expand All @@ -67,11 +63,7 @@ func (w *Workspace) Update(c Config) error {
return err
}

cl := &http.Client{
Transport: khttp.NewDefaultTransportWithTLS(tlsConfig),
}

w.client = cl
w.client = khttp.NewDefaultClientWithTLS(tlsConfig, khttp.DefaultValidator)
w.config = c

return nil
Expand Down
4 changes: 1 addition & 3 deletions services/httppost/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,7 @@ func (h *handler) Handle(event alert.Event) {
}
}

httpClient := &http.Client{
Transport: khttp.NewDefaultTransportWithTLS(tlsConfig),
}
httpClient := khttp.NewDefaultClientWithTLS(tlsConfig, khttp.DefaultValidator)

// Execute the request
resp, err := httpClient.Do(req)
Expand Down
2 changes: 1 addition & 1 deletion services/influxdb/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ func httpConfig(c Config) (influxdb.Config, error) {
if err != nil {
return influxdb.Config{}, errors.Wrap(err, "invalid TLS options")
}
tr := khttp.NewDefaultTransportWithTLS(tlsConfig)
tr := khttp.NewDefaultTransportWithTLS(tlsConfig, nil)
var credentials influxdb.Credentials
if c.Token != "" {
credentials = influxdb.Credentials{
Expand Down
8 changes: 2 additions & 6 deletions services/k8s/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ func New(c Config) (Client, error) {
return &httpClient{
config: c,
urls: urls,
client: &http.Client{
Transport: khttp.NewDefaultTransportWithTLS(c.TLSConfig),
},
client: khttp.NewDefaultClientWithTLS(c.TLSConfig, khttp.DefaultValidator),
}, nil
}

Expand Down Expand Up @@ -165,9 +163,7 @@ func (c *httpClient) Update(new Config) error {
c.urls = urls

if old.TLSConfig != new.TLSConfig {
c.client = &http.Client{
Transport: khttp.NewDefaultTransportWithTLS(new.TLSConfig),
}
c.client = khttp.NewDefaultClientWithTLS(new.TLSConfig, khttp.DefaultValidator)
}
return nil
}
Expand Down
Loading

0 comments on commit 815bf2b

Please sign in to comment.