Skip to content

Commit

Permalink
envoy: add support for bind_config bootstrap options (#2772)
Browse files Browse the repository at this point in the history
* envoy: add support for bind_config bootstrap options

* only add upstream bind config options to individual policy clusters

* update docs for new Envoy keys

Co-authored-by: alexfornuto <alex@fornuto.com>
  • Loading branch information
calebdoxsey and alexfornuto committed Dec 1, 2021
1 parent 1bfdae4 commit bd0a538
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 15 deletions.
1 change: 1 addition & 0 deletions config/constants.go
Expand Up @@ -34,6 +34,7 @@ var ViperPolicyHooks = viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
DecodePolicyHookFunc(),
// parse base-64 encoded POLICY that is bound to environment variable
DecodePolicyBase64Hook(),
decodeNullBoolHookFunc(),
decodeJWTClaimHeadersHookFunc(),
decodeCodecTypeHookFunc(),
decodePPLPolicyHookFunc(),
Expand Down
23 changes: 21 additions & 2 deletions config/custom.go
Expand Up @@ -13,16 +13,35 @@ import (

envoy_config_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
"github.com/mitchellh/mapstructure"
"github.com/volatiletech/null/v9"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"gopkg.in/yaml.v3"

"github.com/pomerium/pomerium/pkg/policy/parser"

"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/pkg/policy/parser"
)

func decodeNullBoolHookFunc() mapstructure.DecodeHookFunc {
return func(f, t reflect.Type, data interface{}) (interface{}, error) {
if t != reflect.TypeOf(null.Bool{}) {
return data, nil
}

bs, err := json.Marshal(data)
if err != nil {
return nil, err
}
var value null.Bool
err = json.Unmarshal(bs, &value)
if err != nil {
return nil, err
}
return value, nil
}
}

// JWTClaimHeaders are headers to add to a request based on IDP claims.
type JWTClaimHeaders map[string]string

Expand Down
22 changes: 22 additions & 0 deletions config/envoyconfig/clusters.go
Expand Up @@ -137,6 +137,28 @@ func (b *Builder) buildPolicyCluster(ctx context.Context, options *config.Option
cluster := new(envoy_config_cluster_v3.Cluster)
proto.Merge(cluster, policy.EnvoyOpts)

if options.EnvoyBindConfigFreebind.IsSet() || options.EnvoyBindConfigSourceAddress != "" {
cluster.UpstreamBindConfig = new(envoy_config_core_v3.BindConfig)
if options.EnvoyBindConfigFreebind.IsSet() {
cluster.UpstreamBindConfig.Freebind = wrapperspb.Bool(options.EnvoyBindConfigFreebind.Bool)
}
if options.EnvoyBindConfigSourceAddress != "" {
cluster.UpstreamBindConfig.SourceAddress = &envoy_config_core_v3.SocketAddress{
Address: options.EnvoyBindConfigSourceAddress,
PortSpecifier: &envoy_config_core_v3.SocketAddress_PortValue{
PortValue: 0,
},
}
} else {
cluster.UpstreamBindConfig.SourceAddress = &envoy_config_core_v3.SocketAddress{
Address: "0.0.0.0",
PortSpecifier: &envoy_config_core_v3.SocketAddress_PortValue{
PortValue: 0,
},
}
}
}

cluster.AltStatName = getClusterStatsName(policy)
upstreamProtocol := getUpstreamProtocolForPolicy(ctx, policy)

Expand Down
52 changes: 52 additions & 0 deletions config/envoyconfig/clusters_test.go
Expand Up @@ -6,10 +6,12 @@ import (
"os"
"path/filepath"
"testing"
"time"

envoy_config_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/volatiletech/null/v9"
"google.golang.org/protobuf/types/known/wrapperspb"

"github.com/pomerium/pomerium/config"
Expand Down Expand Up @@ -828,6 +830,56 @@ func Test_validateClusters(t *testing.T) {
}
}

func Test_bindConfig(t *testing.T) {
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*10)
defer clearTimeout()

b := New("local-grpc", "local-http", filemgr.NewManager(), nil)
t.Run("no bind config", func(t *testing.T) {
cluster, err := b.buildPolicyCluster(ctx, &config.Options{}, &config.Policy{
From: "https://from.example.com",
To: mustParseWeightedURLs(t, "https://to.example.com"),
})
assert.NoError(t, err)
assert.Nil(t, cluster.UpstreamBindConfig)
})
t.Run("freebind", func(t *testing.T) {
cluster, err := b.buildPolicyCluster(ctx, &config.Options{
EnvoyBindConfigFreebind: null.BoolFrom(true),
}, &config.Policy{
From: "https://from.example.com",
To: mustParseWeightedURLs(t, "https://to.example.com"),
})
assert.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `
{
"freebind": true,
"sourceAddress": {
"address": "0.0.0.0",
"portValue": 0
}
}
`, cluster.UpstreamBindConfig)
})
t.Run("source address", func(t *testing.T) {
cluster, err := b.buildPolicyCluster(ctx, &config.Options{
EnvoyBindConfigSourceAddress: "192.168.0.1",
}, &config.Policy{
From: "https://from.example.com",
To: mustParseWeightedURLs(t, "https://to.example.com"),
})
assert.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `
{
"sourceAddress": {
"address": "192.168.0.1",
"portValue": 0
}
}
`, cluster.UpstreamBindConfig)
})
}

func mustParseWeightedURLs(t *testing.T, urls ...string) []config.WeightedURL {
wu, err := config.ParseWeightedUrls(urls...)
require.NoError(t, err)
Expand Down
11 changes: 7 additions & 4 deletions config/options.go
Expand Up @@ -18,6 +18,7 @@ import (

"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
"github.com/volatiletech/null/v9"

"github.com/pomerium/pomerium/internal/directory/azure"
"github.com/pomerium/pomerium/internal/directory/github"
Expand Down Expand Up @@ -279,10 +280,12 @@ type Options struct {
// see https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers.html?highlight=xff_num_trusted_hops#x-forwarded-for
XffNumTrustedHops uint32 `mapstructure:"xff_num_trusted_hops" yaml:"xff_num_trusted_hops,omitempty" json:"xff_num_trusted_hops,omitempty"`

// Envoy bootstrap admin options. These do not support dynamic updates.
EnvoyAdminAccessLogPath string `mapstructure:"envoy_admin_access_log_path" yaml:"envoy_admin_access_log_path"`
EnvoyAdminProfilePath string `mapstructure:"envoy_admin_profile_path" yaml:"envoy_admin_profile_path"`
EnvoyAdminAddress string `mapstructure:"envoy_admin_address" yaml:"envoy_admin_address"`
// Envoy bootstrap options. These do not support dynamic updates.
EnvoyAdminAccessLogPath string `mapstructure:"envoy_admin_access_log_path" yaml:"envoy_admin_access_log_path"`
EnvoyAdminProfilePath string `mapstructure:"envoy_admin_profile_path" yaml:"envoy_admin_profile_path"`
EnvoyAdminAddress string `mapstructure:"envoy_admin_address" yaml:"envoy_admin_address"`
EnvoyBindConfigSourceAddress string `mapstructure:"envoy_bind_config_source_address" yaml:"envoy_bind_config_source_address,omitempty"`
EnvoyBindConfigFreebind null.Bool `mapstructure:"envoy_bind_config_freebind" yaml:"envoy_bind_config_freebind,omitempty"`

// ProgrammaticRedirectDomainWhitelist restricts the allowed redirect URLs when using programmatic login.
ProgrammaticRedirectDomainWhitelist []string `mapstructure:"programmatic_redirect_domain_whitelist" yaml:"programmatic_redirect_domain_whitelist,omitempty" json:"programmatic_redirect_domain_whitelist,omitempty"` //nolint
Expand Down
8 changes: 4 additions & 4 deletions docs/reference/readme.md
Expand Up @@ -674,13 +674,13 @@ tracing_zipkin_endpoint | Url to the Zipkin HTTP endpoint. | ✅
Setting `use_proxy_protocol` will configure Pomerium to require the [HAProxy proxy protocol](https://www.haproxy.org/download/1.9/doc/proxy-protocol.txt) on incoming connections. Versions 1 and 2 of the protocol are supported.


### Envoy Admin Options
- Environment Variable: `ENVOY_ADMIN_ADDRESS`, `ENVOY_ADMIN_ACCESS_LOG_PATH`, `ENVOY_ADMIN_PROFILE_PATH`
- Config File Keys: `envoy_admin_address`, `envoy_admin_access_log_path`, `envoy_admin_profile_path`
### Envoy Bootstrap Options
- Environment Variable: `ENVOY_ADMIN_ADDRESS`, `ENVOY_ADMIN_ACCESS_LOG_PATH`, `ENVOY_ADMIN_PROFILE_PATH`, `ENVOY_BIND_CONFIG_FREEBIND`, `ENVOY_BIND_CONFIG_SOURCE_ADDRESS`
- Config File Keys: `envoy_admin_address`, `envoy_admin_access_log_path`, `envoy_admin_profile_path`, `envoy_bind_config_freebind`, `envoy_bind_config_source_address`
- Type: `string`
- Optional

These options customize Envoy's [bootstrap configuration](https://www.envoyproxy.io/docs/envoy/latest/operations/admin#operations-admin-interface). They cannot be modified at runtime.
The `envoy_admin` keys customize Envoy's [bootstrap configuration](https://www.envoyproxy.io/docs/envoy/latest/operations/admin#operations-admin-interface). The `envoy_bind_config` keys modify the [ClusterManager](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/bootstrap/v3/bootstrap.proto.html#config-bootstrap-v3-clustermanager) configuration. These options cannot be modified at runtime.


## Authenticate Service
Expand Down
10 changes: 5 additions & 5 deletions docs/reference/settings.yaml
Expand Up @@ -764,15 +764,15 @@ settings:
- Optional
doc: |
Setting `use_proxy_protocol` will configure Pomerium to require the [HAProxy proxy protocol](https://www.haproxy.org/download/1.9/doc/proxy-protocol.txt) on incoming connections. Versions 1 and 2 of the protocol are supported.
- name: "Envoy Admin Options"
keys: ["envoy_admin_options"]
- name: "Envoy Bootstrap Options"
keys: ["envoy_admin_address","envoy_admin_access_log_path","envoy_admin_profile_path","envoy_bind_config_freebind","envoy_bind_config_source_address"]
attributes: |
- Environment Variable: `ENVOY_ADMIN_ADDRESS`, `ENVOY_ADMIN_ACCESS_LOG_PATH`, `ENVOY_ADMIN_PROFILE_PATH`
- Config File Keys: `envoy_admin_address`, `envoy_admin_access_log_path`, `envoy_admin_profile_path`
- Environment Variable: `ENVOY_ADMIN_ADDRESS`, `ENVOY_ADMIN_ACCESS_LOG_PATH`, `ENVOY_ADMIN_PROFILE_PATH`, `ENVOY_BIND_CONFIG_FREEBIND`, `ENVOY_BIND_CONFIG_SOURCE_ADDRESS`
- Config File Keys: `envoy_admin_address`, `envoy_admin_access_log_path`, `envoy_admin_profile_path`, `envoy_bind_config_freebind`, `envoy_bind_config_source_address`
- Type: `string`
- Optional
doc: |
These options customize Envoy's [bootstrap configuration](https://www.envoyproxy.io/docs/envoy/latest/operations/admin#operations-admin-interface). They cannot be modified at runtime.
The `envoy_admin` keys customize Envoy's [bootstrap configuration](https://www.envoyproxy.io/docs/envoy/latest/operations/admin#operations-admin-interface). The `envoy_bind_config` keys modify the [ClusterManager](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/bootstrap/v3/bootstrap.proto.html#config-bootstrap-v3-clustermanager) configuration. These options cannot be modified at runtime.
- name: "Authenticate Service"
settings:
- name: "Authenticate Callback Path"
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -59,6 +59,7 @@ require (
github.com/tniswong/go.rfcx v0.0.0-20181019234604-07783c52761f
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/vektah/gqlparser v1.3.1
github.com/volatiletech/null/v9 v9.0.0
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da
go.opencensus.io v0.23.0
go.uber.org/zap v1.19.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -1327,6 +1327,8 @@ github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:tw
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/volatiletech/null/v9 v9.0.0 h1:JCdlHEiSRVxOi7/MABiEfdsqmuj9oTV20Ao7VvZ0JkE=
github.com/volatiletech/null/v9 v9.0.0/go.mod h1:zRFghPVahaiIMRXiUJrc6gsoG83Cm3ZoAfSTw7VHGQc=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
Expand Down

0 comments on commit bd0a538

Please sign in to comment.