open-consul/proto/private/pbservice/convert_test.go
Paul Glass d8d89d4b59
Permissive mTLS (#17035)
This implements permissive mTLS , which allows toggling services into "permissive" mTLS mode.
Permissive mTLS mode allows incoming "non Consul-mTLS" traffic to be forward unmodified to the application.

* Update service-defaults and proxy-defaults config entries with a MutualTLSMode field
* Update the mesh config entry with an AllowEnablingPermissiveMutualTLS field and implement the necessary validation. AllowEnablingPermissiveMutualTLS must be true to allow changing to MutualTLSMode=permissive, but this does not require that all proxy-defaults and service-defaults are currently in strict mode.
* Update xDS listener config to add a "permissive filter chain" when MutualTLSMode=permissive for a particular service. The permissive filter chain matches incoming traffic by the destination port. If the destination port matches the service port from the catalog, then no mTLS is required and the traffic sent is forwarded unmodified to the application.
2023-04-19 14:45:00 -05:00

130 lines
3.6 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package pbservice
import (
"os"
"reflect"
"strconv"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
fuzz "github.com/google/gofuzz"
"github.com/hashicorp/consul/agent/structs"
)
func TestNewCheckServiceNodeFromStructs_RoundTrip(t *testing.T) {
repeat(t, func(t *testing.T, fuzzer *fuzz.Fuzzer) {
fuzzer.Funcs(randInt32, randUint32, randInterface, randStructsUpstream, randEnterpriseMeta, randStructsConnectProxyConfig)
var target structs.CheckServiceNode
fuzzer.Fuzz(&target)
result, err := CheckServiceNodeToStructs(NewCheckServiceNodeFromStructs(&target))
if err != nil {
t.Fatalf("unexpected error: %s", err.Error())
}
assertEqual(t, &target, result)
})
}
func repeat(t *testing.T, fn func(t *testing.T, fuzzer *fuzz.Fuzzer)) {
reps := getEnvIntWithDefault(t, "TEST_REPEAT_COUNT", 5)
seed := getEnvIntWithDefault(t, "TEST_RANDOM_SEED", time.Now().UnixNano())
t.Logf("using seed %d for %d repetitions", seed, reps)
fuzzer := fuzz.NewWithSeed(seed)
for i := 0; i < int(reps); i++ {
t.Run(strconv.Itoa(i), func(t *testing.T) {
fn(t, fuzzer)
})
}
}
func getEnvIntWithDefault(t *testing.T, key string, d int64) int64 {
t.Helper()
raw, ok := os.LookupEnv(key)
if !ok {
return d
}
v, err := strconv.Atoi(raw)
if err != nil {
t.Fatalf("invald value for %v: %v", key, err.Error())
}
return int64(v)
}
func assertEqual(t *testing.T, x, y interface{}) {
t.Helper()
if diff := cmp.Diff(x, y, cmpopts.EquateEmpty()); diff != "" {
t.Fatalf("assertion failed: values are not equal\n--- original\n+++ result\n\n%v", diff)
}
}
// randUint32 is a custom fuzzer function which limits all uints to 32 bits.
// This is necessary because the structs types use un-sized uints, however in
// practice they are constrained to 32 bits, and the protobuf types use (u)int32.
// The structs types use (u)int64 for any fields that require 64 bits.
func randUint32(i *uint, c fuzz.Continue) {
*i = uint(c.Rand.Uint32())
}
// see randUint32
func randInt32(i *int, c fuzz.Continue) {
*i = int(c.Rand.Int31())
}
// randStructsConnectProxyConfig is a custom fuzzer function which skips
// generating values for fields enumerated in the ignore-fields annotation.
func randStructsConnectProxyConfig(p *structs.ConnectProxyConfig, c fuzz.Continue) {
v := reflect.ValueOf(p).Elem()
for i := 0; i < v.NumField(); i++ {
switch v.Type().Field(i).Name {
case "MutualTLSMode":
continue
}
c.Fuzz(v.Field(i).Addr().Interface())
}
}
// randStructsUpstream is a custom fuzzer function which skips generating values
// for fields enumerated in the ignore-fields annotation.
func randStructsUpstream(u *structs.Upstream, c fuzz.Continue) {
v := reflect.ValueOf(u).Elem()
for i := 0; i < v.NumField(); i++ {
switch v.Type().Field(i).Name {
case "IngressHosts":
continue
}
c.Fuzz(v.Field(i).Addr().Interface())
}
}
// randInterface is a custom fuzzer function which generates random data for
// interface{} (most likely used in a map[string]interface{}).
// The random data does not contain any ints (or float32) because protobuf
// converts them to float64, which will cause the test to fail.
func randInterface(m *interface{}, c fuzz.Continue) {
switch c.Rand.Intn(6) {
case 0:
*m = nil
case 1:
*m = c.RandBool()
case 2:
*m = c.Rand.Float64()
case 3:
*m = c.RandString()
case 4:
*m = []interface{}{c.RandString(), c.RandBool(), nil, c.Rand.Float64()}
case 5:
*m = map[string]interface{}{
c.RandString(): c.RandString(),
c.RandString(): c.Rand.Float64(),
c.RandString(): nil,
}
}
}