Skip to content

Commit

Permalink
Implement traffic redirection exclusion based on proxy config and us…
Browse files Browse the repository at this point in the history
…er-provided values (#10134)

* Use proxy outbound port from TransparentProxyConfig if provided
* If -proxy-id is provided to the redirect-traffic command, exclude any listener ports
  from inbound traffic redirection. This includes envoy_prometheus_bind_addr,
  envoy_stats_bind_addr, and the ListenerPort from the Expose configuration.
* Allow users to provide additional inbound and outbound ports, outbound CIDRs
  and additional user IDs to be excluded from traffic redirection.
  This affects both the traffic-redirect command and the iptables SDK package.
  • Loading branch information
ishustava authored Apr 29, 2021
1 parent cbabf82 commit 8dffb89
Show file tree
Hide file tree
Showing 6 changed files with 485 additions and 11 deletions.
11 changes: 11 additions & 0 deletions .changelog/10134.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
```release-note:feature
cli: Add additional flags to the `consul connect redirect-traffic` command to allow excluding inbound and outbound ports,
outbound CIDRs, and additional user IDs from traffic redirection.
```
```release-note:feature
cli: Automatically exclude ports from `envoy_prometheus_bind_addr`, `envoy_stats_bind_addr`, and `ListenerPort` from `Expose` config
from inbound traffic redirection rules if `proxy-id` flag is provided to the `consul connect redirect-traffic` command.
```
```release-note:feature
sdk: Allow excluding inbound and outbound ports, outbound CIDRs, and additional user IDs from traffic redirection in the `iptables` package.
```
88 changes: 77 additions & 11 deletions command/connect/redirecttraffic/redirect_traffic.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package redirecttraffic
import (
"flag"
"fmt"
"net"
"strconv"

"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/command/flags"
Expand Down Expand Up @@ -34,10 +36,14 @@ type cmd struct {
client *api.Client

// Flags.
proxyUID string
proxyID string
proxyInboundPort int
proxyOutboundPort int
proxyUID string
proxyID string
proxyInboundPort int
proxyOutboundPort int
excludeInboundPorts []string
excludeOutboundPorts []string
excludeOutboundCIDRs []string
excludeUIDs []string
}

func (c *cmd) init() {
Expand All @@ -48,6 +54,14 @@ func (c *cmd) init() {
c.flags.IntVar(&c.proxyInboundPort, "proxy-inbound-port", 0, "The inbound port that the proxy is listening on.")
c.flags.IntVar(&c.proxyOutboundPort, "proxy-outbound-port", iptables.DefaultTProxyOutboundPort,
"The outbound port that the proxy is listening on. When not provided, 15001 is used by default.")
c.flags.Var((*flags.AppendSliceValue)(&c.excludeInboundPorts), "exclude-inbound-port",
"Inbound port to exclude from traffic redirection. May be provided multiple times.")
c.flags.Var((*flags.AppendSliceValue)(&c.excludeOutboundPorts), "exclude-outbound-port",
"Outbound port to exclude from traffic redirection. May be provided multiple times.")
c.flags.Var((*flags.AppendSliceValue)(&c.excludeOutboundCIDRs), "exclude-outbound-cidr",
"Outbound CIDR to exclude from traffic redirection. May be provided multiple times.")
c.flags.Var((*flags.AppendSliceValue)(&c.excludeUIDs), "exclude-uid",
"Additional user ID to exclude from traffic redirection. May be provided multiple times.")

c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.http.ClientFlags())
Expand Down Expand Up @@ -105,12 +119,18 @@ func (c *cmd) Help() string {
// with only the configuration values that we need to parse from Proxy.Config
// to apply traffic redirection rules.
type trafficRedirectProxyConfig struct {
BindPort int `mapstructure:"bind_port"`
BindPort int `mapstructure:"bind_port"`
PrometheusBindAddr string `mapstructure:"envoy_prometheus_bind_addr"`
StatsBindAddr string `mapstructure:"envoy_stats_bind_addr"`
}

// generateConfigFromFlags generates iptables.Config based on command flags.
func (c *cmd) generateConfigFromFlags() (iptables.Config, error) {
cfg := iptables.Config{ProxyUserID: c.proxyUID}
cfg := iptables.Config{
ProxyUserID: c.proxyUID,
ProxyInboundPort: c.proxyInboundPort,
ProxyOutboundPort: c.proxyOutboundPort,
}

// When proxyID is provided, we set up cfg with values
// from proxy's service registration in Consul.
Expand All @@ -132,21 +152,67 @@ func (c *cmd) generateConfigFromFlags() (iptables.Config, error) {
return iptables.Config{}, fmt.Errorf("service %s is not a proxy service", c.proxyID)
}

cfg.ProxyInboundPort = svc.Port
// Decode proxy's opaque config so that we can use it later to configure
// traffic redirection with iptables.
var trCfg trafficRedirectProxyConfig
if err := mapstructure.WeakDecode(svc.Proxy.Config, &trCfg); err != nil {
return iptables.Config{}, fmt.Errorf("failed parsing Proxy.Config: %s", err)
}

// Set the proxy's inbound port.
cfg.ProxyInboundPort = svc.Port
if trCfg.BindPort != 0 {
cfg.ProxyInboundPort = trCfg.BindPort
}

// todo: Change once it's configurable
// Set the proxy's outbound port.
cfg.ProxyOutboundPort = iptables.DefaultTProxyOutboundPort
} else {
cfg.ProxyInboundPort = c.proxyInboundPort
cfg.ProxyOutboundPort = c.proxyOutboundPort
if svc.Proxy.TransparentProxy != nil && svc.Proxy.TransparentProxy.OutboundListenerPort != 0 {
cfg.ProxyOutboundPort = svc.Proxy.TransparentProxy.OutboundListenerPort
}

// Exclude envoy_prometheus_bind_addr port from inbound redirection rules.
if trCfg.PrometheusBindAddr != "" {
_, port, err := net.SplitHostPort(trCfg.PrometheusBindAddr)
if err != nil {
return iptables.Config{}, fmt.Errorf("failed parsing host and port from envoy_prometheus_bind_addr: %s", err)
}

cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, port)
}

// Exclude envoy_stats_bind_addr port from inbound redirection rules.
if trCfg.StatsBindAddr != "" {
_, port, err := net.SplitHostPort(trCfg.StatsBindAddr)
if err != nil {
return iptables.Config{}, fmt.Errorf("failed parsing host and port from envoy_stats_bind_addr: %s", err)
}

cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, port)
}

// Exclude the ListenerPort from Expose configs from inbound traffic redirection.
for _, exposePath := range svc.Proxy.Expose.Paths {
if exposePath.ListenerPort != 0 {
cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposePath.ListenerPort))
}
}
}

for _, port := range c.excludeInboundPorts {
cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, port)
}

for _, port := range c.excludeOutboundPorts {
cfg.ExcludeOutboundPorts = append(cfg.ExcludeOutboundPorts, port)
}

for _, cidr := range c.excludeOutboundCIDRs {
cfg.ExcludeOutboundCIDRs = append(cfg.ExcludeOutboundCIDRs, cidr)
}

for _, uid := range c.excludeUIDs {
cfg.ExcludeUIDs = append(cfg.ExcludeUIDs, uid)
}

return cfg, nil
Expand Down
Loading

0 comments on commit 8dffb89

Please sign in to comment.