Add TransparentProxy opt to proxy definition

This commit is contained in:
freddygv 2021-03-10 23:08:41 -07:00
parent 306ef7d252
commit 6fd30d0384
17 changed files with 211 additions and 39 deletions

View File

@ -197,6 +197,7 @@ func TestAgent_Services_Sidecar(t *testing.T) {
Proxy: structs.ConnectProxyConfig{
DestinationServiceName: "db",
Upstreams: structs.TestUpstreams(t),
TransparentProxy: true,
},
}
a.State.AddService(srv1, "")

View File

@ -1689,6 +1689,7 @@ func (b *builder) serviceProxyVal(v *ServiceProxy) *structs.ConnectProxyConfig {
Upstreams: b.upstreamsVal(v.Upstreams),
MeshGateway: b.meshGatewayConfVal(v.MeshGateway),
Expose: b.exposeConfVal(v.Expose),
TransparentProxy: boolVal(v.TransparentProxy),
}
}

View File

@ -472,6 +472,10 @@ type ServiceProxy struct {
// Expose defines whether checks or paths are exposed through the proxy
Expose *ExposeConfig `mapstructure:"expose"`
// TransparentProxy toggles whether inbound and outbound traffic is being
// redirected to the proxy.
TransparentProxy *bool `mapstructure:"transparent_proxy"`
}
// Upstream represents a single upstream dependency for a service or proxy. It

View File

@ -2582,6 +2582,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
}
]
},
"transparent_proxy": true,
"upstreams": [
{
"destination_name": "db",
@ -2617,7 +2618,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
protocol = "http"
}
]
},
}
transparent_proxy = true
upstreams = [
{
destination_name = "db"
@ -2657,6 +2659,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
},
},
TransparentProxy: true,
Upstreams: structs.Upstreams{
structs.Upstream{
DestinationType: "service",
@ -2711,6 +2714,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
}
]
},
"transparent_proxy": true,
"upstreams": [
{
"destination_name": "db",
@ -2746,7 +2750,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
protocol = "http"
}
]
},
}
transparent_proxy = true,
upstreams = [
{
destination_name = "db"
@ -2786,6 +2791,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
},
},
TransparentProxy: true,
Upstreams: structs.Upstreams{
structs.Upstream{
DestinationType: "service",
@ -3428,7 +3434,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
"mesh_gateway": {
"mode": "remote"
}
},
"transparent_proxy": true
}
]
}
@ -3447,6 +3454,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
mesh_gateway {
mode = "remote"
}
transparent_proxy = true
}
}`},
expected: func(rt *RuntimeConfig) {
@ -3465,6 +3473,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
MeshGateway: structs.MeshGatewayConfig{
Mode: structs.MeshGatewayModeRemote,
},
TransparentProxy: true,
},
}
},
@ -3486,7 +3495,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
"MeshGateway": {
"Mode": "remote"
}
},
"TransparentProxy": true
}
]
}
@ -3505,6 +3515,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
MeshGateway {
Mode = "remote"
}
TransparentProxy = true
}
}`},
expected: func(rt *RuntimeConfig) {
@ -3523,6 +3534,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
MeshGateway: structs.MeshGatewayConfig{
Mode: structs.MeshGatewayModeRemote,
},
TransparentProxy: true,
},
}
},
@ -3544,7 +3556,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
"external_sni": "abc-123",
"mesh_gateway": {
"mode": "remote"
}
},
"transparent_proxy": true
}
]
}
@ -3563,6 +3576,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
mesh_gateway {
mode = "remote"
}
transparent_proxy = true
}
}`},
expected: func(rt *RuntimeConfig) {
@ -3581,6 +3595,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
MeshGateway: structs.MeshGatewayConfig{
Mode: structs.MeshGatewayModeRemote,
},
TransparentProxy: true,
},
}
},
@ -3602,7 +3617,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
"ExternalSNI": "abc-123",
"MeshGateway": {
"Mode": "remote"
}
},
"TransparentProxy": true
}
]
}
@ -3621,6 +3637,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
MeshGateway {
Mode = "remote"
}
TransparentProxy = true
}
}`},
expected: func(rt *RuntimeConfig) {
@ -3639,6 +3656,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
MeshGateway: structs.MeshGatewayConfig{
Mode: structs.MeshGatewayModeRemote,
},
TransparentProxy: true,
},
}
},
@ -5458,6 +5476,7 @@ func TestLoad_FullConfig(t *testing.T) {
},
},
},
TransparentProxy: true,
},
Weights: &structs.Weights{
Passing: 1,

View File

@ -573,6 +573,7 @@ services = [
}
]
}
transparent_proxy = true
}
},
{

View File

@ -554,6 +554,7 @@
}
]
},
"transparent_proxy": true,
"upstreams": [
{
"destination_name": "KPtAj2cb",

View File

@ -357,6 +357,7 @@ func (c *ConfigEntry) ResolveServiceConfig(args *structs.ServiceConfigRequest, r
reply.ProxyConfig = mapCopy.(map[string]interface{})
reply.MeshGateway = proxyConf.MeshGateway
reply.Expose = proxyConf.Expose
reply.TransparentProxy = proxyConf.TransparentProxy
// Extract the global protocol from proxyConf for upstream configs.
rawProtocol := proxyConf.Config["protocol"]
@ -395,6 +396,9 @@ func (c *ConfigEntry) ResolveServiceConfig(args *structs.ServiceConfigRequest, r
}
reply.ProxyConfig["protocol"] = serviceConf.Protocol
}
if serviceConf.TransparentProxy {
reply.TransparentProxy = serviceConf.TransparentProxy
}
}
// First collect all upstreams into a set of seen upstreams.

View File

@ -893,6 +893,105 @@ func TestConfigEntry_ResolveServiceConfig(t *testing.T) {
require.Equal(map[string]interface{}{"foo": 1}, proxyConf.Config)
}
func TestConfigEntry_ResolveServiceConfig_TransparentProxy(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
tt := []struct {
name string
entries []structs.ConfigEntry
request structs.ServiceConfigRequest
proxyCfg structs.ConnectProxyConfig
expect structs.ServiceConfigResponse
}{
{
name: "from proxy-defaults",
entries: []structs.ConfigEntry{
&structs.ProxyConfigEntry{
Kind: structs.ProxyDefaults,
Name: structs.ProxyConfigGlobal,
TransparentProxy: true,
},
},
request: structs.ServiceConfigRequest{
Name: "foo",
Datacenter: "dc1",
},
expect: structs.ServiceConfigResponse{
TransparentProxy: true,
},
},
{
name: "from service-defaults",
entries: []structs.ConfigEntry{
&structs.ServiceConfigEntry{
Kind: structs.ServiceDefaults,
Name: "foo",
TransparentProxy: true,
},
},
request: structs.ServiceConfigRequest{
Name: "foo",
Datacenter: "dc1",
},
expect: structs.ServiceConfigResponse{
TransparentProxy: true,
},
},
{
name: "service-defaults overrides proxy-defaults",
entries: []structs.ConfigEntry{
&structs.ProxyConfigEntry{
Kind: structs.ProxyDefaults,
Name: structs.ProxyConfigGlobal,
TransparentProxy: false,
},
&structs.ServiceConfigEntry{
Kind: structs.ServiceDefaults,
Name: "foo",
TransparentProxy: true,
},
},
request: structs.ServiceConfigRequest{
Name: "foo",
Datacenter: "dc1",
},
expect: structs.ServiceConfigResponse{
TransparentProxy: true,
},
},
}
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
dir1, s1 := testServer(t)
defer os.RemoveAll(dir1)
defer s1.Shutdown()
codec := rpcClient(t, s1)
defer codec.Close()
// Boostrap the config entries
idx := uint64(1)
for _, conf := range tc.entries {
require.NoError(t, s1.fsm.State().EnsureConfigEntry(idx, conf))
idx++
}
var out structs.ServiceConfigResponse
require.NoError(t, msgpackrpc.CallWithCodec(codec, "ConfigEntry.ResolveServiceConfig", &tc.request, &out))
// Don't know what this is deterministically, so we grab it from the response
tc.expect.QueryMeta = out.QueryMeta
require.Equal(t, tc.expect, out)
})
}
}
func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")

View File

@ -379,6 +379,9 @@ func mergeServiceConfig(defaults *structs.ServiceConfigResponse, service *struct
if ns.Proxy.MeshGateway.Mode == structs.MeshGatewayModeDefault {
ns.Proxy.MeshGateway.Mode = defaults.MeshGateway.Mode
}
if !ns.Proxy.TransparentProxy {
ns.Proxy.TransparentProxy = defaults.TransparentProxy
}
// Merge upstream defaults if there were any returned
for i := range ns.Proxy.Upstreams {

View File

@ -79,11 +79,12 @@ type UpdatableConfigEntry interface {
// ServiceConfiguration is the top-level struct for the configuration of a service
// across the entire cluster.
type ServiceConfigEntry struct {
Kind string
Name string
Protocol string
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
Expose ExposeConfig `json:",omitempty"`
Kind string
Name string
Protocol string
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
Expose ExposeConfig `json:",omitempty"`
TransparentProxy bool `json:",omitempty" alias:"transparent_proxy"`
ExternalSNI string `json:",omitempty" alias:"external_sni"`
@ -211,11 +212,12 @@ func (cfg ConnectConfiguration) Validate() error {
// ProxyConfigEntry is the top-level struct for global proxy configuration defaults.
type ProxyConfigEntry struct {
Kind string
Name string
Config map[string]interface{}
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
Expose ExposeConfig `json:",omitempty"`
Kind string
Name string
Config map[string]interface{}
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
Expose ExposeConfig `json:",omitempty"`
TransparentProxy bool `json:",omitempty" alias:"transparent_proxy"`
Meta map[string]string `json:",omitempty"`
EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
@ -852,6 +854,7 @@ type ServiceConfigResponse struct {
UpstreamIDConfigs OpaqueUpstreamConfigs
MeshGateway MeshGatewayConfig `json:",omitempty"`
Expose ExposeConfig `json:",omitempty"`
TransparentProxy bool `json:",omitempty"`
QueryMeta
}

View File

@ -118,6 +118,10 @@ type ConnectProxyConfig struct {
// Expose defines whether checks or paths are exposed through the proxy
Expose ExposeConfig `json:",omitempty"`
// TransparentProxy toggles whether inbound and outbound traffic is being
// redirected to the proxy.
TransparentProxy bool `json:",omitempty" alias:"transparent_proxy"`
}
func (t *ConnectProxyConfig) UnmarshalJSON(data []byte) (err error) {
@ -128,6 +132,7 @@ func (t *ConnectProxyConfig) UnmarshalJSON(data []byte) (err error) {
LocalServiceAddressSnake string `json:"local_service_address"`
LocalServicePortSnake int `json:"local_service_port"`
MeshGatewaySnake MeshGatewayConfig `json:"mesh_gateway"`
TransparentProxySnake bool `json:"transparent_proxy"`
*Alias
}{
@ -151,6 +156,9 @@ func (t *ConnectProxyConfig) UnmarshalJSON(data []byte) (err error) {
if t.MeshGateway.Mode == "" {
t.MeshGateway.Mode = aux.MeshGatewaySnake.Mode
}
if !t.TransparentProxy {
t.TransparentProxy = aux.TransparentProxySnake
}
return nil
@ -183,6 +191,7 @@ func (c *ConnectProxyConfig) ToAPI() *api.AgentServiceConnectProxyConfig {
Upstreams: c.Upstreams.ToAPI(),
MeshGateway: c.MeshGateway.ToAPI(),
Expose: c.Expose.ToAPI(),
TransparentProxy: c.TransparentProxy,
}
}

View File

@ -207,6 +207,11 @@ var expectedFieldConfigConnectProxyConfig bexpr.FieldConfigurations = bexpr.Fiel
StructFieldName: "Expose",
SubFields: expectedFieldConfigExposeConfig,
},
"TransparentProxy": &bexpr.FieldConfiguration{
StructFieldName: "TransparentProxy",
CoerceFn: bexpr.CoerceBool,
SupportedOperations: []bexpr.MatchOperator{bexpr.MatchEqual, bexpr.MatchNotEqual},
},
}
var expectedFieldConfigServiceConnect bexpr.FieldConfigurations = bexpr.FieldConfigurations{

View File

@ -122,6 +122,7 @@ type AgentServiceConnectProxyConfig struct {
Upstreams []Upstream `json:",omitempty"`
MeshGateway MeshGatewayConfig `json:",omitempty"`
Expose ExposeConfig `json:",omitempty"`
TransparentProxy bool `json:",omitempty"`
}
const (

View File

@ -437,6 +437,7 @@ func TestAPI_AgentServices_ExternalConnectProxy(t *testing.T) {
Port: 8001,
Proxy: &AgentServiceConnectProxyConfig{
DestinationServiceName: "foo",
TransparentProxy: true,
},
}
if err := agent.ServiceRegister(reg); err != nil {
@ -453,6 +454,9 @@ func TestAPI_AgentServices_ExternalConnectProxy(t *testing.T) {
if _, ok := services["foo-proxy"]; !ok {
t.Fatalf("missing proxy service: %v", services)
}
if !services["foo-proxy"].Proxy.TransparentProxy {
t.Fatalf("expected transparent proxy mode to be enabled")
}
if err := agent.ServiceDeregister("foo"); err != nil {
t.Fatalf("err: %v", err)

View File

@ -167,17 +167,18 @@ type UpstreamLimits struct {
}
type ServiceConfigEntry struct {
Kind string
Name string
Namespace string `json:",omitempty"`
Protocol string `json:",omitempty"`
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
Connect ConnectConfiguration `json:",omitempty"`
Expose ExposeConfig `json:",omitempty"`
ExternalSNI string `json:",omitempty" alias:"external_sni"`
Meta map[string]string `json:",omitempty"`
CreateIndex uint64
ModifyIndex uint64
Kind string
Name string
Namespace string `json:",omitempty"`
Protocol string `json:",omitempty"`
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
Connect ConnectConfiguration `json:",omitempty"`
Expose ExposeConfig `json:",omitempty"`
TransparentProxy bool `json:",omitempty" alias:"transparent_proxy"`
ExternalSNI string `json:",omitempty" alias:"external_sni"`
Meta map[string]string `json:",omitempty"`
CreateIndex uint64
ModifyIndex uint64
}
func (s *ServiceConfigEntry) GetKind() string {
@ -205,15 +206,16 @@ func (s *ServiceConfigEntry) GetModifyIndex() uint64 {
}
type ProxyConfigEntry struct {
Kind string
Name string
Namespace string `json:",omitempty"`
Config map[string]interface{} `json:",omitempty"`
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
Expose ExposeConfig `json:",omitempty"`
Meta map[string]string `json:",omitempty"`
CreateIndex uint64
ModifyIndex uint64
Kind string
Name string
Namespace string `json:",omitempty"`
Config map[string]interface{} `json:",omitempty"`
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
Expose ExposeConfig `json:",omitempty"`
TransparentProxy bool `json:",omitempty" alias:"transparent_proxy"`
Meta map[string]string `json:",omitempty"`
CreateIndex uint64
ModifyIndex uint64
}
func (p *ProxyConfigEntry) GetKind() string {

View File

@ -296,7 +296,8 @@ func TestDecodeConfigEntry(t *testing.T) {
},
"MeshGateway": {
"Mode": "remote"
}
},
"TransparentProxy": true
}
`,
expect: &ProxyConfigEntry{
@ -316,6 +317,7 @@ func TestDecodeConfigEntry(t *testing.T) {
MeshGateway: MeshGatewayConfig{
Mode: MeshGatewayModeRemote,
},
TransparentProxy: true,
},
},
{
@ -333,6 +335,7 @@ func TestDecodeConfigEntry(t *testing.T) {
"MeshGateway": {
"Mode": "remote"
},
"TransparentProxy": true,
"Connect": {
"UpstreamConfigs": {
"redis": {
@ -377,6 +380,7 @@ func TestDecodeConfigEntry(t *testing.T) {
MeshGateway: MeshGatewayConfig{
Mode: MeshGatewayModeRemote,
},
TransparentProxy: true,
Connect: ConnectConfiguration{
UpstreamConfigs: map[string]UpstreamConfig{
"redis": {

View File

@ -181,6 +181,7 @@ func TestParseConfigEntry(t *testing.T) {
mesh_gateway {
mode = "remote"
}
transparent_proxy = true
`,
camel: `
Kind = "proxy-defaults"
@ -199,6 +200,7 @@ func TestParseConfigEntry(t *testing.T) {
MeshGateway {
Mode = "remote"
}
TransparentProxy = true
`,
snakeJSON: `
{
@ -217,7 +219,8 @@ func TestParseConfigEntry(t *testing.T) {
},
"mesh_gateway": {
"mode": "remote"
}
},
"transparent_proxy": true
}
`,
camelJSON: `
@ -237,7 +240,8 @@ func TestParseConfigEntry(t *testing.T) {
},
"MeshGateway": {
"Mode": "remote"
}
},
"TransparentProxy": true
}
`,
expect: &api.ProxyConfigEntry{
@ -257,6 +261,7 @@ func TestParseConfigEntry(t *testing.T) {
MeshGateway: api.MeshGatewayConfig{
Mode: api.MeshGatewayModeRemote,
},
TransparentProxy: true,
},
expectJSON: &api.ProxyConfigEntry{
Kind: "proxy-defaults",
@ -275,6 +280,7 @@ func TestParseConfigEntry(t *testing.T) {
MeshGateway: api.MeshGatewayConfig{
Mode: api.MeshGatewayModeRemote,
},
TransparentProxy: true,
},
},
{
@ -436,6 +442,7 @@ func TestParseConfigEntry(t *testing.T) {
mesh_gateway {
mode = "remote"
}
transparent_proxy = true
connect {
upstream_configs {
"redis" {
@ -479,6 +486,7 @@ func TestParseConfigEntry(t *testing.T) {
MeshGateway {
Mode = "remote"
}
TransparentProxy = true
connect = {
upstream_configs = {
"redis" = {
@ -523,6 +531,7 @@ func TestParseConfigEntry(t *testing.T) {
"mesh_gateway": {
"mode": "remote"
},
"transparent_proxy": true,
"connect": {
"upstream_configs": {
"redis": {
@ -568,6 +577,7 @@ func TestParseConfigEntry(t *testing.T) {
"MeshGateway": {
"Mode": "remote"
},
"TransparentProxy": true,
"Connect": {
"UpstreamConfigs": {
"redis": {
@ -612,6 +622,7 @@ func TestParseConfigEntry(t *testing.T) {
MeshGateway: api.MeshGatewayConfig{
Mode: api.MeshGatewayModeRemote,
},
TransparentProxy: true,
Connect: api.ConnectConfiguration{
UpstreamConfigs: map[string]api.UpstreamConfig{
"redis": {