diff --git a/.changelog/17609.txt b/.changelog/17609.txt new file mode 100644 index 000000000000..cbace1f8c7d2 --- /dev/null +++ b/.changelog/17609.txt @@ -0,0 +1,4 @@ +```release-note:bug +gateways: Fixed a bug in API gateways where binding a route that only targets a service imported from a peer results +in the programmed gateway having no routes. +``` diff --git a/.changelog/_5669.txt b/.changelog/_5669.txt new file mode 100644 index 000000000000..6528460e69bd --- /dev/null +++ b/.changelog/_5669.txt @@ -0,0 +1,3 @@ +```release-note:improvement +audit-logging: **(Enterprise only)** enable error response and request body logging +``` \ No newline at end of file diff --git a/.changelog/_5740.txt b/.changelog/_5740.txt new file mode 100644 index 000000000000..4f1d6f6448f3 --- /dev/null +++ b/.changelog/_5740.txt @@ -0,0 +1,3 @@ +```release-note:feature +api: (Enterprise only) Add `POST /v1/operator/audit-hash` endpoint to calculate the hash of the data used by the audit log hash function and salt. +``` \ No newline at end of file diff --git a/.changelog/_5750.txt b/.changelog/_5750.txt new file mode 100644 index 000000000000..027753c72156 --- /dev/null +++ b/.changelog/_5750.txt @@ -0,0 +1,3 @@ +```release-note:feature +cli: (Enterprise only) Add a new `consul operator audit hash` command to retrieve and compare the hash of the data used by the audit log hash function and salt. +``` \ No newline at end of file diff --git a/.github/workflows/nightly-test-1.12.x.yaml b/.github/workflows/nightly-test-1.16.x.yaml similarity index 98% rename from .github/workflows/nightly-test-1.12.x.yaml rename to .github/workflows/nightly-test-1.16.x.yaml index 0f016075e261..c30ed6811c2b 100644 --- a/.github/workflows/nightly-test-1.12.x.yaml +++ b/.github/workflows/nightly-test-1.16.x.yaml @@ -1,7 +1,7 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 -name: Nightly Test 1.12.x +name: Nightly Test 1.16.x on: schedule: - cron: '0 4 * * *' @@ -9,8 +9,8 @@ on: env: EMBER_PARTITION_TOTAL: 4 # Has to be changed in tandem with the matrix.partition - BRANCH: "release/1.12.x" - BRANCH_NAME: "release-1.12.x" # Used for naming artifacts + BRANCH: "release/1.16.x" + BRANCH_NAME: "release-1.16.x" # Used for naming artifacts jobs: frontend-test-workspace-node: diff --git a/agent/agent.go b/agent/agent.go index 678d110d534c..0b06688c483b 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -1621,7 +1621,18 @@ func (a *Agent) RPC(ctx context.Context, method string, args interface{}, reply method = e + "." + p[1] } } + + // audit log only on consul clients + _, ok := a.delegate.(*consul.Client) + if ok { + a.writeAuditRPCEvent(method, "OperationStart") + } + a.endpointsLock.RUnlock() + + defer func() { + a.writeAuditRPCEvent(method, "OperationComplete") + }() return a.delegate.RPC(ctx, method, args, reply) } diff --git a/agent/agent_endpoint_test.go b/agent/agent_endpoint_test.go index 66b028b7c083..2955871c723e 100644 --- a/agent/agent_endpoint_test.go +++ b/agent/agent_endpoint_test.go @@ -1822,7 +1822,7 @@ func TestAgent_ReloadDoesNotTriggerWatch(t *testing.T) { for i := 1; i < 7; i++ { contents, err := os.ReadFile(tmpFile) if err != nil { - t.Fatalf("should be able to read file, but had: %#v", err) + r.Fatalf("should be able to read file, but had: %#v", err) } contentsStr = string(contents) if contentsStr != "" { @@ -1909,14 +1909,14 @@ func TestAgent_ReloadDoesNotTriggerWatch(t *testing.T) { ensureNothingCritical(r, "red-is-dead") if err := a.reloadConfigInternal(cfg2); err != nil { - t.Fatalf("got error %v want nil", err) + r.Fatalf("got error %v want nil", err) } // We check that reload does not go to critical ensureNothingCritical(r, "red-is-dead") ensureNothingCritical(r, "testing-agent-reload-001") - require.NoError(t, a.updateTTLCheck(checkID, api.HealthPassing, "testing-agent-reload-002")) + require.NoError(r, a.updateTTLCheck(checkID, api.HealthPassing, "testing-agent-reload-002")) ensureNothingCritical(r, "red-is-dead") }) @@ -2926,7 +2926,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(nodeCheck)) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusForbidden, resp.Code) + require.Equal(r, http.StatusForbidden, resp.Code) }) }) @@ -2936,7 +2936,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req.Header.Add("X-Consul-Token", svcToken.SecretID) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusForbidden, resp.Code) + require.Equal(r, http.StatusForbidden, resp.Code) }) }) @@ -2946,7 +2946,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req.Header.Add("X-Consul-Token", nodeToken.SecretID) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusOK, resp.Code) + require.Equal(r, http.StatusOK, resp.Code) }) }) @@ -2955,7 +2955,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(svcCheck)) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusForbidden, resp.Code) + require.Equal(r, http.StatusForbidden, resp.Code) }) }) @@ -2965,7 +2965,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req.Header.Add("X-Consul-Token", nodeToken.SecretID) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusForbidden, resp.Code) + require.Equal(r, http.StatusForbidden, resp.Code) }) }) @@ -2975,7 +2975,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req.Header.Add("X-Consul-Token", svcToken.SecretID) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusOK, resp.Code) + require.Equal(r, http.StatusOK, resp.Code) }) }) } @@ -5976,17 +5976,17 @@ func TestAgent_Monitor(t *testing.T) { res := httptest.NewRecorder() a.srv.h.ServeHTTP(res, registerReq) if http.StatusOK != res.Code { - t.Fatalf("expected 200 but got %v", res.Code) + r.Fatalf("expected 200 but got %v", res.Code) } // Wait until we have received some type of logging output - require.Eventually(t, func() bool { + require.Eventually(r, func() bool { return len(resp.Body.Bytes()) > 0 }, 3*time.Second, 100*time.Millisecond) cancelFunc() code := <-codeCh - require.Equal(t, http.StatusOK, code) + require.Equal(r, http.StatusOK, code) got := resp.Body.String() // Only check a substring that we are highly confident in finding @@ -6026,11 +6026,11 @@ func TestAgent_Monitor(t *testing.T) { res := httptest.NewRecorder() a.srv.h.ServeHTTP(res, registerReq) if http.StatusOK != res.Code { - t.Fatalf("expected 200 but got %v", res.Code) + r.Fatalf("expected 200 but got %v", res.Code) } // Wait until we have received some type of logging output - require.Eventually(t, func() bool { + require.Eventually(r, func() bool { return len(resp.Body.Bytes()) > 0 }, 3*time.Second, 100*time.Millisecond) cancelFunc() @@ -6063,24 +6063,24 @@ func TestAgent_Monitor(t *testing.T) { res := httptest.NewRecorder() a.srv.h.ServeHTTP(res, registerReq) if http.StatusOK != res.Code { - t.Fatalf("expected 200 but got %v", res.Code) + r.Fatalf("expected 200 but got %v", res.Code) } // Wait until we have received some type of logging output - require.Eventually(t, func() bool { + require.Eventually(r, func() bool { return len(resp.Body.Bytes()) > 0 }, 3*time.Second, 100*time.Millisecond) cancelFunc() code := <-codeCh - require.Equal(t, http.StatusOK, code) + require.Equal(r, http.StatusOK, code) // Each line is output as a separate JSON object, we grab the first and // make sure it can be unmarshalled. firstLine := bytes.Split(resp.Body.Bytes(), []byte("\n"))[0] var output map[string]interface{} if err := json.Unmarshal(firstLine, &output); err != nil { - t.Fatalf("err: %v", err) + r.Fatalf("err: %v", err) } }) }) @@ -6672,7 +6672,7 @@ func TestAgentConnectCARoots_list(t *testing.T) { dec := json.NewDecoder(resp.Body) value := &structs.IndexedCARoots{} - require.NoError(t, dec.Decode(value)) + require.NoError(r, dec.Decode(value)) if ca.ID != value.ActiveRootID { r.Fatalf("%s != %s", ca.ID, value.ActiveRootID) } @@ -7080,7 +7080,7 @@ func TestAgentConnectCALeafCert_goodNotLocal(t *testing.T) { dec := json.NewDecoder(resp.Body) issued2 := &structs.IssuedCert{} - require.NoError(t, dec.Decode(issued2)) + require.NoError(r, dec.Decode(issued2)) if issued.CertPEM == issued2.CertPEM { r.Fatalf("leaf has not updated") } @@ -7092,9 +7092,9 @@ func TestAgentConnectCALeafCert_goodNotLocal(t *testing.T) { } // Verify that the cert is signed by the new CA - requireLeafValidUnderCA(t, issued2, ca) + requireLeafValidUnderCA(r, issued2, ca) - require.NotEqual(t, issued, issued2) + require.NotEqual(r, issued, issued2) }) } } @@ -7471,11 +7471,11 @@ func TestAgentConnectCALeafCert_secondaryDC_good(t *testing.T) { // Try and sign again (note no index/wait arg since cache should update in // background even if we aren't actively blocking) a2.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusOK, resp.Code) + require.Equal(r, http.StatusOK, resp.Code) dec := json.NewDecoder(resp.Body) issued2 := &structs.IssuedCert{} - require.NoError(t, dec.Decode(issued2)) + require.NoError(r, dec.Decode(issued2)) if issued.CertPEM == issued2.CertPEM { r.Fatalf("leaf has not updated") } @@ -7487,9 +7487,9 @@ func TestAgentConnectCALeafCert_secondaryDC_good(t *testing.T) { } // Verify that the cert is signed by the new CA - requireLeafValidUnderCA(t, issued2, dc1_ca2) + requireLeafValidUnderCA(r, issued2, dc1_ca2) - require.NotEqual(t, issued, issued2) + require.NotEqual(r, issued, issued2) }) } @@ -7499,12 +7499,12 @@ func waitForActiveCARoot(t *testing.T, srv *HTTPHandlers, expect *structs.CARoot resp := httptest.NewRecorder() srv.h.ServeHTTP(resp, req) if http.StatusOK != resp.Code { - t.Fatalf("expected 200 but got %v", resp.Code) + r.Fatalf("expected 200 but got %v", resp.Code) } dec := json.NewDecoder(resp.Body) roots := &structs.IndexedCARoots{} - require.NoError(t, dec.Decode(roots)) + require.NoError(r, dec.Decode(roots)) var root *structs.CARoot for _, r := range roots.Roots { diff --git a/agent/agent_oss.go b/agent/agent_oss.go index 93e633cc656f..e8cfea681b3c 100644 --- a/agent/agent_oss.go +++ b/agent/agent_oss.go @@ -69,3 +69,7 @@ func (a *Agent) AgentEnterpriseMeta() *acl.EnterpriseMeta { func (a *Agent) registerEntCache() {} func (*Agent) fillEnterpriseProxyDataSources(*proxycfg.DataSources) {} + +func (a *Agent) writeAuditRPCEvent(_ string, _ string) interface{} { + return nil +} diff --git a/agent/config/config.go b/agent/config/config.go index e26d6edc4d95..d8d7149afebf 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -807,8 +807,9 @@ type ConfigEntries struct { // Audit allows us to enable and define destinations for auditing type Audit struct { - Enabled *bool `mapstructure:"enabled"` - Sinks map[string]AuditSink `mapstructure:"sink"` + Enabled *bool `mapstructure:"enabled"` + Sinks map[string]AuditSink `mapstructure:"sink"` + RPCEnabled *bool `mapstructure:"rpc_enabled"` } // AuditSink can be provided multiple times to define pipelines for auditing diff --git a/agent/consul/acl_endpoint_test.go b/agent/consul/acl_endpoint_test.go index 6f674810b5da..7e09880ad3d6 100644 --- a/agent/consul/acl_endpoint_test.go +++ b/agent/consul/acl_endpoint_test.go @@ -143,7 +143,7 @@ func TestACLEndpoint_ReplicationStatus(t *testing.T) { retry.Run(t, func(r *retry.R) { var status structs.ACLReplicationStatus err := msgpackrpc.CallWithCodec(codec, "ACL.ReplicationStatus", &getR, &status) - require.NoError(t, err) + require.NoError(r, err) require.True(r, status.Enabled) require.True(r, status.Running) @@ -220,7 +220,7 @@ func TestACLEndpoint_TokenRead(t *testing.T) { time.Sleep(200 * time.Millisecond) err := aclEp.TokenRead(&req, &resp) require.Error(r, err) - require.ErrorContains(t, err, "ACL not found") + require.ErrorContains(r, err, "ACL not found") require.Nil(r, resp.Token) }) }) diff --git a/agent/consul/client_test.go b/agent/consul/client_test.go index 3f7542d09032..4b8f5c433d8e 100644 --- a/agent/consul/client_test.go +++ b/agent/consul/client_test.go @@ -179,7 +179,7 @@ func TestClient_LANReap(t *testing.T) { retry.Run(t, func(r *retry.R) { require.Len(r, c1.LANMembersInAgentPartition(), 1) server := c1.router.FindLANServer() - require.Nil(t, server) + require.Nil(r, server) }) } diff --git a/agent/consul/merge_test.go b/agent/consul/merge_test.go index 66992136aa45..f5f5c6d88ff1 100644 --- a/agent/consul/merge_test.go +++ b/agent/consul/merge_test.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/types" + "github.com/hashicorp/consul/version" ) func TestMerge_LAN(t *testing.T) { @@ -282,6 +283,7 @@ func makeTestNode(t *testing.T, tm testMember) *serf.Member { "vsn": "2", "vsn_max": "3", "vsn_min": "2", + "fips": version.GetFIPSInfo(), }, } if tm.partition != "" { diff --git a/agent/consul/multilimiter/multilimiter_test.go b/agent/consul/multilimiter/multilimiter_test.go index 991cd3b989d4..b649bdb6c9c9 100644 --- a/agent/consul/multilimiter/multilimiter_test.go +++ b/agent/consul/multilimiter/multilimiter_test.go @@ -95,7 +95,7 @@ func TestRateLimiterCleanup(t *testing.T) { retry.RunWith(&retry.Timer{Wait: 100 * time.Millisecond, Timeout: 10 * time.Second}, t, func(r *retry.R) { v, ok := limiters.Get(key) require.True(r, ok) - require.NotNil(t, v) + require.NotNil(r, v) }) time.Sleep(c.ReconcileCheckInterval) diff --git a/agent/consul/prepared_query_endpoint_test.go b/agent/consul/prepared_query_endpoint_test.go index 63277adfe27c..af1fd65a876d 100644 --- a/agent/consul/prepared_query_endpoint_test.go +++ b/agent/consul/prepared_query_endpoint_test.go @@ -1539,8 +1539,7 @@ func TestPreparedQuery_Execute(t *testing.T) { assert.Len(t, reply.Nodes, 0) }) - expectNodes := func(t *testing.T, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { - t.Helper() + expectNodes := func(t require.TestingT, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { assert.Len(t, reply.Nodes, n) assert.Equal(t, "dc1", reply.Datacenter) assert.Equal(t, 0, reply.Failovers) @@ -1548,8 +1547,7 @@ func TestPreparedQuery_Execute(t *testing.T) { assert.Equal(t, query.Query.DNS, reply.DNS) assert.True(t, reply.QueryMeta.KnownLeader) } - expectFailoverNodes := func(t *testing.T, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { - t.Helper() + expectFailoverNodes := func(t require.TestingT, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { assert.Len(t, reply.Nodes, n) assert.Equal(t, "dc2", reply.Datacenter) assert.Equal(t, 1, reply.Failovers) @@ -1558,8 +1556,7 @@ func TestPreparedQuery_Execute(t *testing.T) { assert.True(t, reply.QueryMeta.KnownLeader) } - expectFailoverPeerNodes := func(t *testing.T, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { - t.Helper() + expectFailoverPeerNodes := func(t require.TestingT, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { assert.Len(t, reply.Nodes, n) assert.Equal(t, "", reply.Datacenter) assert.Equal(t, es.peeringServer.acceptingPeerName, reply.PeerName) @@ -2372,13 +2369,13 @@ func TestPreparedQuery_Execute(t *testing.T) { } var reply structs.PreparedQueryExecuteResponse - require.NoError(t, msgpackrpc.CallWithCodec(es.server.codec, "PreparedQuery.Execute", &req, &reply)) + require.NoError(r, msgpackrpc.CallWithCodec(es.server.codec, "PreparedQuery.Execute", &req, &reply)) for _, node := range reply.Nodes { - assert.NotEqual(t, "node3", node.Node.Node) + assert.NotEqual(r, "node3", node.Node.Node) } - expectNodes(t, &query, &reply, 9) + expectNodes(r, &query, &reply, 9) }) }) } diff --git a/agent/consul/rate/handler.go b/agent/consul/rate/handler.go index 84faefb6c3e8..c18ec85eddc8 100644 --- a/agent/consul/rate/handler.go +++ b/agent/consul/rate/handler.go @@ -119,15 +119,15 @@ const ( OperationCategoryKV OperationCategory = "KV" OperationCategoryPreparedQuery OperationCategory = "PreparedQuery" OperationCategorySession OperationCategory = "Session" - OperationCategoryStatus OperationCategory = "Status" + OperationCategoryStatus OperationCategory = "Status" // not limited OperationCategoryTxn OperationCategory = "Txn" OperationCategoryAutoConfig OperationCategory = "AutoConfig" OperationCategoryFederationState OperationCategory = "FederationState" OperationCategoryInternal OperationCategory = "Internal" - OperationCategoryOperator OperationCategory = "Operator" + OperationCategoryOperator OperationCategory = "Operator" // not limited OperationCategoryPeerStream OperationCategory = "PeerStream" OperationCategoryPeering OperationCategory = "Peering" - OperationCategoryPartition OperationCategory = "Partition" + OperationCategoryPartition OperationCategory = "Tenancy" OperationCategoryDataPlane OperationCategory = "DataPlane" OperationCategoryDNS OperationCategory = "DNS" OperationCategorySubscribe OperationCategory = "Subscribe" diff --git a/agent/dns_test.go b/agent/dns_test.go index b9d8f86a78e3..46a7e758c7f1 100644 --- a/agent/dns_test.go +++ b/agent/dns_test.go @@ -3189,7 +3189,7 @@ func TestDNS_ServiceLookup_WanTranslation(t *testing.T) { } var out struct{} - require.NoError(t, a2.RPC(context.Background(), "Catalog.Register", args, &out)) + require.NoError(r, a2.RPC(context.Background(), "Catalog.Register", args, &out)) }) // Look up the SRV record via service and prepared query. @@ -3517,11 +3517,11 @@ func TestDNS_CaseInsensitiveServiceLookup(t *testing.T) { retry.Run(t, func(r *retry.R) { in, _, err := c.Exchange(m, a.DNSAddr()) if err != nil { - t.Fatalf("err: %v", err) + r.Fatalf("err: %v", err) } if len(in.Answer) != 1 { - t.Fatalf("question %v, empty lookup: %#v", question, in) + r.Fatalf("question %v, empty lookup: %#v", question, in) } }) } diff --git a/agent/envoyextensions/builtin/property-override/property_override.go b/agent/envoyextensions/builtin/property-override/property_override.go index c018d334a5c3..8164a8092a7f 100644 --- a/agent/envoyextensions/builtin/property-override/property_override.go +++ b/agent/envoyextensions/builtin/property-override/property_override.go @@ -106,8 +106,8 @@ var Ops = extensioncommon.StringSet{string(OpAdd): {}, string(OpRemove): {}} // validProxyTypes is the set of supported proxy types for this extension. var validProxyTypes = extensioncommon.StringSet{ - string(api.ServiceKindConnectProxy): struct{}{}, - string(api.ServiceKindTerminatingGateway): struct{}{}, + // For now, we only support `connect-proxy`. + string(api.ServiceKindConnectProxy): struct{}{}, } // Patch describes a single patch operation to modify the specific field of matching diff --git a/agent/envoyextensions/builtin/property-override/property_override_test.go b/agent/envoyextensions/builtin/property-override/property_override_test.go index 68a895edb846..ca549353faca 100644 --- a/agent/envoyextensions/builtin/property-override/property_override_test.go +++ b/agent/envoyextensions/builtin/property-override/property_override_test.go @@ -618,7 +618,7 @@ func TestCanApply(t *testing.T) { }, "invalid proxy type": { ext: &propertyOverride{ - ProxyType: api.ServiceKindTerminatingGateway, + ProxyType: api.ServiceKindConnectProxy, }, conf: &extensioncommon.RuntimeConfig{ Kind: api.ServiceKindMeshGateway, diff --git a/agent/envoyextensions/registered_extensions.go b/agent/envoyextensions/registered_extensions.go index 4d4d26611605..177ab9cb0342 100644 --- a/agent/envoyextensions/registered_extensions.go +++ b/agent/envoyextensions/registered_extensions.go @@ -6,6 +6,9 @@ package envoyextensions import ( "fmt" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-version" + awslambda "github.com/hashicorp/consul/agent/envoyextensions/builtin/aws-lambda" extauthz "github.com/hashicorp/consul/agent/envoyextensions/builtin/ext-authz" "github.com/hashicorp/consul/agent/envoyextensions/builtin/http/localratelimit" @@ -14,7 +17,6 @@ import ( "github.com/hashicorp/consul/agent/envoyextensions/builtin/wasm" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/envoyextensions/extensioncommon" - "github.com/hashicorp/go-multierror" ) type extensionConstructor func(api.EnvoyExtension) (extensioncommon.EnvoyExtender, error) @@ -50,6 +52,23 @@ func ValidateExtensions(extensions []api.EnvoyExtension) error { output = multierror.Append(output, fmt.Errorf("invalid EnvoyExtensions[%d]: Name is required", i)) continue } + + if v := ext.EnvoyVersion; v != "" { + _, err := version.NewConstraint(v) + if err != nil { + output = multierror.Append(output, fmt.Errorf("invalid EnvoyExtensions[%d].EnvoyVersion: %w", i, err)) + continue + } + } + + if v := ext.ConsulVersion; v != "" { + _, err := version.NewConstraint(v) + if err != nil { + output = multierror.Append(output, fmt.Errorf("invalid EnvoyExtensions[%d].ConsulVersion: %w", i, err)) + continue + } + } + _, err := ConstructExtension(ext) if err != nil { output = multierror.Append(output, fmt.Errorf("invalid EnvoyExtensions[%d][%s]: %w", i, ext.Name, err)) diff --git a/agent/envoyextensions/registered_extensions_test.go b/agent/envoyextensions/registered_extensions_test.go index ebd1bfbbc95b..7f3cb6bbac7d 100644 --- a/agent/envoyextensions/registered_extensions_test.go +++ b/agent/envoyextensions/registered_extensions_test.go @@ -48,6 +48,30 @@ func TestValidateExtensions(t *testing.T) { "missing Script value", }, }, + "invalid consul version constraint": { + input: []api.EnvoyExtension{{ + Name: "builtin/aws/lambda", + Arguments: map[string]interface{}{ + "ARN": "arn:aws:lambda:us-east-1:111111111111:function:lambda-1234", + }, + ConsulVersion: "bad", + }}, + expectErrs: []string{ + "invalid EnvoyExtensions[0].ConsulVersion: Malformed constraint: bad", + }, + }, + "invalid envoy version constraint": { + input: []api.EnvoyExtension{{ + Name: "builtin/aws/lambda", + Arguments: map[string]interface{}{ + "ARN": "arn:aws:lambda:us-east-1:111111111111:function:lambda-1234", + }, + EnvoyVersion: "bad", + }}, + expectErrs: []string{ + "invalid EnvoyExtensions[0].EnvoyVersion: Malformed constraint: bad", + }, + }, } for name, tc := range tests { diff --git a/agent/grpc-external/services/dataplane/get_supported_features_test.go b/agent/grpc-external/services/dataplane/get_supported_features_test.go index 35079a40a808..329b5df0f68f 100644 --- a/agent/grpc-external/services/dataplane/get_supported_features_test.go +++ b/agent/grpc-external/services/dataplane/get_supported_features_test.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/consul/agent/grpc-external/testutils" structs "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto-public/pbdataplane" + "github.com/hashicorp/consul/version" ) const testACLToken = "acl-token" @@ -50,6 +51,8 @@ func TestSupportedDataplaneFeatures_Success(t *testing.T) { require.True(t, feature.GetSupported()) case pbdataplane.DataplaneFeatures_DATAPLANE_FEATURES_ENVOY_BOOTSTRAP_CONFIGURATION: require.True(t, feature.GetSupported()) + case pbdataplane.DataplaneFeatures_DATAPLANE_FEATURES_FIPS: + require.Equal(t, version.IsFIPS(), feature.GetSupported()) default: require.False(t, feature.GetSupported()) } diff --git a/agent/grpc-external/services/peerstream/stream_test.go b/agent/grpc-external/services/peerstream/stream_test.go index da4c55b22717..2d8f6f3e1667 100644 --- a/agent/grpc-external/services/peerstream/stream_test.go +++ b/agent/grpc-external/services/peerstream/stream_test.go @@ -1048,7 +1048,7 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { require.Equal(r, mongo.Service.CompoundServiceName().String(), msg.GetResponse().ResourceID) var nodes pbpeerstream.ExportedService - require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&nodes)) + require.NoError(r, msg.GetResponse().Resource.UnmarshalTo(&nodes)) require.Len(r, nodes.Nodes, 1) }) }) @@ -1077,12 +1077,12 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { msg, err := client.RecvWithTimeout(100 * time.Millisecond) require.NoError(r, err) require.Equal(r, pbpeerstream.TypeURLExportedServiceList, msg.GetResponse().ResourceURL) - require.Equal(t, subExportedServiceList, msg.GetResponse().ResourceID) - require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) + require.Equal(r, subExportedServiceList, msg.GetResponse().ResourceID) + require.Equal(r, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) var exportedServices pbpeerstream.ExportedServiceList - require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) - require.Equal(t, []string{structs.ServiceName{Name: "mongo"}.String()}, exportedServices.Services) + require.NoError(r, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) + require.Equal(r, []string{structs.ServiceName{Name: "mongo"}.String()}, exportedServices.Services) }) }) @@ -1094,12 +1094,12 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { msg, err := client.RecvWithTimeout(100 * time.Millisecond) require.NoError(r, err) require.Equal(r, pbpeerstream.TypeURLExportedServiceList, msg.GetResponse().ResourceURL) - require.Equal(t, subExportedServiceList, msg.GetResponse().ResourceID) - require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) + require.Equal(r, subExportedServiceList, msg.GetResponse().ResourceID) + require.Equal(r, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) var exportedServices pbpeerstream.ExportedServiceList - require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) - require.Len(t, exportedServices.Services, 0) + require.NoError(r, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) + require.Len(r, exportedServices.Services, 0) }) }) } diff --git a/agent/local/state_test.go b/agent/local/state_test.go index 372bf5b8ca40..0a78f321f7a5 100644 --- a/agent/local/state_test.go +++ b/agent/local/state_test.go @@ -1320,13 +1320,13 @@ func TestAgentAntiEntropy_Checks(t *testing.T) { chk.CreateIndex, chk.ModifyIndex = 0, 0 switch chk.CheckID { case "mysql": - require.Equal(t, chk, chk1) + require.Equal(r, chk, chk1) case "redis": - require.Equal(t, chk, chk2) + require.Equal(r, chk, chk2) case "web": - require.Equal(t, chk, chk3) + require.Equal(r, chk, chk3) case "cache": - require.Equal(t, chk, chk5) + require.Equal(r, chk, chk5) case "serfHealth": // ignore default: @@ -1356,9 +1356,9 @@ func TestAgentAntiEntropy_Checks(t *testing.T) { addrs := services.NodeServices.Node.TaggedAddresses meta := services.NodeServices.Node.Meta delete(meta, structs.MetaSegmentKey) // Added later, not in config. - assert.Equal(t, a.Config.NodeID, id) - assert.Equal(t, a.Config.TaggedAddresses, addrs) - assert.Equal(t, unNilMap(a.Config.NodeMeta), meta) + assert.Equal(r, a.Config.NodeID, id) + assert.Equal(r, a.Config.TaggedAddresses, addrs) + assert.Equal(r, unNilMap(a.Config.NodeMeta), meta) } }) retry.Run(t, func(r *retry.R) { @@ -1385,11 +1385,11 @@ func TestAgentAntiEntropy_Checks(t *testing.T) { chk.CreateIndex, chk.ModifyIndex = 0, 0 switch chk.CheckID { case "mysql": - require.Equal(t, chk1, chk) + require.Equal(r, chk1, chk) case "web": - require.Equal(t, chk3, chk) + require.Equal(r, chk3, chk) case "cache": - require.Equal(t, chk5, chk) + require.Equal(r, chk5, chk) case "serfHealth": // ignore default: diff --git a/agent/proxycfg/snapshot.go b/agent/proxycfg/snapshot.go index 5e92013b272f..1880dcd669f6 100644 --- a/agent/proxycfg/snapshot.go +++ b/agent/proxycfg/snapshot.go @@ -741,14 +741,23 @@ type configSnapshotAPIGateway struct { func (c *configSnapshotAPIGateway) synthesizeChains(datacenter string, listener structs.APIGatewayListener, boundListener structs.BoundAPIGatewayListener) ([]structs.IngressService, structs.Upstreams, []*structs.CompiledDiscoveryChain, error) { chains := []*structs.CompiledDiscoveryChain{} - trustDomain := "" + + // We leverage the test trust domain knowing + // that the domain will get overridden if + // there is a target to something other than an + // external/peered service. If the below + // code doesn't get a trust domain due to all the + // targets being external, the chain will + // have the domain munged anyway during synthesis. + trustDomain := connect.TestTrustDomain DOMAIN_LOOP: for _, chain := range c.DiscoveryChain { for _, target := range chain.Targets { if !target.External { - trustDomain = connect.TrustDomainForTarget(*target) - if trustDomain != "" { + domain := connect.TrustDomainForTarget(*target) + if domain != "" { + trustDomain = domain break DOMAIN_LOOP } } diff --git a/agent/rpc/middleware/rate_limit_mappings.go b/agent/rpc/middleware/rate_limit_mappings.go index a31343bb23f9..0df249c93233 100644 --- a/agent/rpc/middleware/rate_limit_mappings.go +++ b/agent/rpc/middleware/rate_limit_mappings.go @@ -144,4 +144,9 @@ var rpcRateLimitSpecs = map[string]rate.OperationSpec{ "Txn.Apply": {Type: rate.OperationTypeWrite, Category: rate.OperationCategoryTxn}, "Txn.Read": {Type: rate.OperationTypeRead, Category: rate.OperationCategoryTxn}, + + "Namespace.Write": {Type: rate.OperationTypeWrite, Category: rate.OperationCategoryPartition}, + "Namespace.Delete": {Type: rate.OperationTypeWrite, Category: rate.OperationCategoryPartition}, + "Namespace.List": {Type: rate.OperationTypeRead, Category: rate.OperationCategoryPartition}, + "Namespace.Read": {Type: rate.OperationTypeRead, Category: rate.OperationCategoryPartition}, } diff --git a/agent/structs/envoy_extension.go b/agent/structs/envoy_extension.go index 5b69afb0d9de..c788aedf37e8 100644 --- a/agent/structs/envoy_extension.go +++ b/agent/structs/envoy_extension.go @@ -9,9 +9,11 @@ import ( // EnvoyExtension has configuration for an extension that patches Envoy resources. type EnvoyExtension struct { - Name string - Required bool - Arguments map[string]interface{} `bexpr:"-"` + Name string + Required bool + Arguments map[string]interface{} `bexpr:"-"` + ConsulVersion string + EnvoyVersion string } type EnvoyExtensions []EnvoyExtension @@ -20,9 +22,11 @@ func (es EnvoyExtensions) ToAPI() []api.EnvoyExtension { extensions := make([]api.EnvoyExtension, len(es)) for i, e := range es { extensions[i] = api.EnvoyExtension{ - Name: e.Name, - Required: e.Required, - Arguments: e.Arguments, + Name: e.Name, + Required: e.Required, + Arguments: e.Arguments, + EnvoyVersion: e.EnvoyVersion, + ConsulVersion: e.ConsulVersion, } } return extensions diff --git a/agent/structs/structs_filtering_test.go b/agent/structs/structs_filtering_test.go index 1bc6599650a7..9739923e0e5a 100644 --- a/agent/structs/structs_filtering_test.go +++ b/agent/structs/structs_filtering_test.go @@ -197,6 +197,16 @@ var expectedFieldConfigEnvoyExtensions bexpr.FieldConfigurations = bexpr.FieldCo CoerceFn: bexpr.CoerceBool, SupportedOperations: []bexpr.MatchOperator{bexpr.MatchEqual, bexpr.MatchNotEqual}, }, + "ConsulVersion": &bexpr.FieldConfiguration{ + StructFieldName: "ConsulVersion", + CoerceFn: bexpr.CoerceString, + SupportedOperations: []bexpr.MatchOperator{bexpr.MatchEqual, bexpr.MatchNotEqual, bexpr.MatchIn, bexpr.MatchNotIn, bexpr.MatchMatches, bexpr.MatchNotMatches}, + }, + "EnvoyVersion": &bexpr.FieldConfiguration{ + StructFieldName: "EnvoyVersion", + CoerceFn: bexpr.CoerceString, + SupportedOperations: []bexpr.MatchOperator{bexpr.MatchEqual, bexpr.MatchNotEqual, bexpr.MatchIn, bexpr.MatchNotIn, bexpr.MatchMatches, bexpr.MatchNotMatches}, + }, } var expectedFieldConfigUpstreams bexpr.FieldConfigurations = bexpr.FieldConfigurations{ "DestinationType": &bexpr.FieldConfiguration{ diff --git a/agent/xds/delta.go b/agent/xds/delta.go index 66072e0b81e4..5e4cf702090a 100644 --- a/agent/xds/delta.go +++ b/agent/xds/delta.go @@ -17,6 +17,8 @@ import ( envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" envoy_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + "github.com/hashicorp/go-hclog" + goversion "github.com/hashicorp/go-version" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -29,6 +31,7 @@ import ( "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/xds/extensionruntime" + "github.com/hashicorp/consul/envoyextensions/extensioncommon" "github.com/hashicorp/consul/envoyextensions/xdscommon" "github.com/hashicorp/consul/logging" "github.com/hashicorp/consul/version" @@ -255,7 +258,7 @@ func (s *Server) processDelta(stream ADSDeltaStream, reqCh <-chan *envoy_discove s.ResourceMapMutateFn(newResourceMap) } - if err = s.applyEnvoyExtensions(newResourceMap, cfgSnap); err != nil { + if err = s.applyEnvoyExtensions(newResourceMap, cfgSnap, node); err != nil { // err is already the result of calling status.Errorf return err } @@ -400,70 +403,123 @@ func (s *Server) processDelta(stream ADSDeltaStream, reqCh <-chan *envoy_discove } } -func (s *Server) applyEnvoyExtensions(resources *xdscommon.IndexedResources, cfgSnap *proxycfg.ConfigSnapshot) error { +func (s *Server) applyEnvoyExtensions(resources *xdscommon.IndexedResources, cfgSnap *proxycfg.ConfigSnapshot, node *envoy_config_core_v3.Node) error { + var err error + envoyVersion := xdscommon.DetermineEnvoyVersionFromNode(node) + consulVersion, err := goversion.NewVersion(version.Version) + + if err != nil { + return status.Errorf(codes.InvalidArgument, "failed to parse Consul version") + } + serviceConfigs := extensionruntime.GetRuntimeConfigurations(cfgSnap) for _, cfgs := range serviceConfigs { for _, cfg := range cfgs { - logFn := s.Logger.Warn - if cfg.EnvoyExtension.Required { - logFn = s.Logger.Error - } - errorParams := []interface{}{ - "extension", cfg.EnvoyExtension.Name, - "service", cfg.ServiceName.Name, - "namespace", cfg.ServiceName.Namespace, - "partition", cfg.ServiceName.Partition, - } - - getMetricLabels := func(err error) []metrics.Label { - return []metrics.Label{ - {Name: "extension", Value: cfg.EnvoyExtension.Name}, - {Name: "version", Value: "builtin/" + version.Version}, - {Name: "service", Value: cfgSnap.Service}, - {Name: "partition", Value: cfgSnap.ProxyID.PartitionOrDefault()}, - {Name: "namespace", Value: cfgSnap.ProxyID.NamespaceOrDefault()}, - {Name: "error", Value: strconv.FormatBool(err != nil)}, - } - } + err = applyEnvoyExtension(s.Logger, cfgSnap, resources, cfg, envoyVersion, consulVersion) - now := time.Now() - extender, err := envoyextensions.ConstructExtension(cfg.EnvoyExtension) - metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate_arguments"}, now, getMetricLabels(err)) if err != nil { - logFn("failed to construct extension", errorParams...) + return err + } + } + } - if cfg.EnvoyExtension.Required { - return status.Errorf(codes.Unavailable, "failed to construct extension %q for service %q", cfg.EnvoyExtension.Name, cfg.ServiceName.Name) - } + return nil +} - continue - } +func applyEnvoyExtension(logger hclog.Logger, cfgSnap *proxycfg.ConfigSnapshot, resources *xdscommon.IndexedResources, runtimeConfig extensioncommon.RuntimeConfig, envoyVersion, consulVersion *goversion.Version) error { + logFn := logger.Warn + if runtimeConfig.EnvoyExtension.Required { + logFn = logger.Error + } - now = time.Now() - err = extender.Validate(&cfg) - metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate"}, now, getMetricLabels(err)) - if err != nil { - errorParams = append(errorParams, "error", err) - logFn("failed to validate extension arguments", errorParams...) - if cfg.EnvoyExtension.Required { - return status.Errorf(codes.Unavailable, "failed to validate arguments for extension %q for service %q", cfg.EnvoyExtension.Name, cfg.ServiceName.Name) - } + svc := runtimeConfig.ServiceName - continue - } + errorParams := []interface{}{ + "extension", runtimeConfig.EnvoyExtension.Name, + "service", svc.Name, + "namespace", svc.Namespace, + "partition", svc.Partition, + } - now = time.Now() - resources, err = extender.Extend(resources, &cfg) - metrics.MeasureSinceWithLabels([]string{"envoy_extension", "extend"}, now, getMetricLabels(err)) - if err == nil { - continue + getMetricLabels := func(err error) []metrics.Label { + return []metrics.Label{ + {Name: "extension", Value: runtimeConfig.EnvoyExtension.Name}, + {Name: "version", Value: "builtin/" + version.Version}, + {Name: "service", Value: cfgSnap.Service}, + {Name: "partition", Value: cfgSnap.ProxyID.PartitionOrDefault()}, + {Name: "namespace", Value: cfgSnap.ProxyID.NamespaceOrDefault()}, + {Name: "error", Value: strconv.FormatBool(err != nil)}, + } + } + + ext := runtimeConfig.EnvoyExtension + + if v := ext.EnvoyVersion; v != "" { + c, err := goversion.NewConstraint(v) + if err != nil { + logFn("failed to parse Envoy extension version constraint", errorParams...) + + if ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to parse Envoy version constraint for extension %q for service %q", ext.Name, svc.Name) } + return nil + } + + if !c.Check(envoyVersion) { + logger.Info("skipping envoy extension due to Envoy version constraint violation", errorParams...) + return nil + } + } + + if v := ext.ConsulVersion; v != "" { + c, err := goversion.NewConstraint(v) + if err != nil { + logFn("failed to parse Consul extension version constraint", errorParams...) - logFn("failed to apply envoy extension", errorParams...) - if cfg.EnvoyExtension.Required { - return status.Errorf(codes.Unavailable, "failed to patch xDS resources in the %q extension: %v", cfg.EnvoyExtension.Name, err) + if ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to parse Consul version constraint for extension %q for service %q", ext.Name, svc.Name) } + return nil + } + + if !c.Check(consulVersion) { + logger.Info("skipping envoy extension due to Consul version constraint violation", errorParams...) + return nil + } + } + + now := time.Now() + extender, err := envoyextensions.ConstructExtension(ext) + metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate_arguments"}, now, getMetricLabels(err)) + if err != nil { + logFn("failed to construct extension", errorParams...) + + if ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to construct extension %q for service %q", ext.Name, svc.Name) + } + + return nil + } + + now = time.Now() + err = extender.Validate(&runtimeConfig) + metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate"}, now, getMetricLabels(err)) + if err != nil { + errorParams = append(errorParams, "error", err) + logFn("failed to validate extension arguments", errorParams...) + if ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to validate arguments for extension %q for service %q", ext.Name, svc.Name) } + + return nil + } + + now = time.Now() + _, err = extender.Extend(resources, &runtimeConfig) + metrics.MeasureSinceWithLabels([]string{"envoy_extension", "extend"}, now, getMetricLabels(err)) + logFn("failed to apply envoy extension", errorParams...) + if err != nil && ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to patch xDS resources in the %q extension: %v", ext.Name, err) } return nil diff --git a/agent/xds/delta_envoy_extender_oss_test.go b/agent/xds/delta_envoy_extender_oss_test.go index dc1521edbe34..3d92b6d25de0 100644 --- a/agent/xds/delta_envoy_extender_oss_test.go +++ b/agent/xds/delta_envoy_extender_oss_test.go @@ -16,11 +16,12 @@ import ( envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" "github.com/hashicorp/consul/agent/xds/testcommon" + "github.com/hashicorp/go-hclog" + goversion "github.com/hashicorp/go-version" testinf "github.com/mitchellh/go-testing-interface" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "github.com/hashicorp/consul/agent/envoyextensions" propertyoverride "github.com/hashicorp/consul/agent/envoyextensions/builtin/property-override" "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" @@ -29,9 +30,12 @@ import ( "github.com/hashicorp/consul/envoyextensions/extensioncommon" "github.com/hashicorp/consul/envoyextensions/xdscommon" "github.com/hashicorp/consul/sdk/testutil" + "github.com/hashicorp/consul/version" ) func TestEnvoyExtenderWithSnapshot(t *testing.T) { + consulVersion, _ := goversion.NewVersion(version.Version) + // If opposite is true, the returned service defaults config entry will have // payload-passthrough=true and invocation-mode=asynchronous. // Otherwise payload-passthrough=false and invocation-mode=synchronous. @@ -65,7 +69,7 @@ func TestEnvoyExtenderWithSnapshot(t *testing.T) { } // Apply Lua extension to the local service and ensure http is used so the extension can be applied. - makeLuaNsFunc := func(inbound bool) func(ns *structs.NodeService) { + makeLuaNsFunc := func(inbound bool, envoyVersion, consulVersion string) func(ns *structs.NodeService) { listener := "inbound" if !inbound { listener = "outbound" @@ -75,7 +79,9 @@ func TestEnvoyExtenderWithSnapshot(t *testing.T) { ns.Proxy.Config["protocol"] = "http" ns.Proxy.EnvoyExtensions = []structs.EnvoyExtension{ { - Name: api.BuiltinLuaExtension, + Name: api.BuiltinLuaExtension, + EnvoyVersion: envoyVersion, + ConsulVersion: consulVersion, Arguments: map[string]interface{}{ "ProxyType": "connect-proxy", "Listener": listener, @@ -464,11 +470,41 @@ end`, name: "lambda-terminating-gateway-with-service-resolvers", create: proxycfg.TestConfigSnapshotTerminatingGatewayWithLambdaServiceAndServiceResolvers, }, + { + name: "lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + // upstreams need to be http in order for lua to be applied to listeners. + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false, "< 1.0.0", ">= 1.0.0"), nil, &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "db", + Protocol: "http", + }, &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "geo-cache", + Protocol: "http", + }) + }, + }, + { + name: "lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + // upstreams need to be http in order for lua to be applied to listeners. + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false, ">= 1.0.0", "< 1.0.0"), nil, &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "db", + Protocol: "http", + }, &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "geo-cache", + Protocol: "http", + }) + }, + }, { name: "lua-outbound-applies-to-local-upstreams", create: func(t testinf.T) *proxycfg.ConfigSnapshot { // upstreams need to be http in order for lua to be applied to listeners. - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false), nil, &structs.ServiceConfigEntry{ + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false, ">= 1.0.0", ">= 1.0.0"), nil, &structs.ServiceConfigEntry{ Kind: structs.ServiceDefaults, Name: "db", Protocol: "http", @@ -487,7 +523,7 @@ end`, create: func(t testinf.T) *proxycfg.ConfigSnapshot { // db is made an HTTP upstream so that the extension _could_ apply, but does not because // the direction for the extension is inbound. - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(true), nil, &structs.ServiceConfigEntry{ + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(true, "", ""), nil, &structs.ServiceConfigEntry{ Kind: structs.ServiceDefaults, Name: "db", Protocol: "http", @@ -497,7 +533,7 @@ end`, { name: "lua-inbound-applies-to-inbound", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(true), nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(true, "", ""), nil) }, }, { @@ -505,14 +541,14 @@ end`, // no upstream HTTP services. We also should not see public listener, which is HTTP, patched. name: "lua-outbound-doesnt-apply-to-inbound", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false), nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false, "", ""), nil) }, }, { name: "lua-outbound-applies-to-local-upstreams-tproxy", create: func(t testinf.T) *proxycfg.ConfigSnapshot { // upstreams need to be http in order for lua to be applied to listeners. - return proxycfg.TestConfigSnapshotTransparentProxyDestinationHTTP(t, makeLuaNsFunc(false)) + return proxycfg.TestConfigSnapshotTransparentProxyDestinationHTTP(t, makeLuaNsFunc(false, "", "")) }, }, { @@ -707,6 +743,7 @@ end`, latestEnvoyVersion := xdscommon.EnvoyVersions[0] for _, envoyVersion := range xdscommon.EnvoyVersions { + parsedEnvoyVersion, _ := goversion.NewVersion(envoyVersion) sf, err := xdscommon.DetermineSupportedProxyFeaturesFromString(envoyVersion) require.NoError(t, err) t.Run("envoy-"+envoyVersion, func(t *testing.T) { @@ -730,11 +767,7 @@ end`, cfgs := extensionruntime.GetRuntimeConfigurations(snap) for _, extensions := range cfgs { for _, ext := range extensions { - extender, err := envoyextensions.ConstructExtension(ext.EnvoyExtension) - require.NoError(t, err) - err = extender.Validate(&ext) - require.NoError(t, err) - indexedResources, err = extender.Extend(indexedResources, &ext) + err := applyEnvoyExtension(hclog.NewNullLogger(), snap, indexedResources, ext, parsedEnvoyVersion, consulVersion) require.NoError(t, err) } } diff --git a/agent/xds/delta_test.go b/agent/xds/delta_test.go index a9febfedfa0c..f9c77835ad11 100644 --- a/agent/xds/delta_test.go +++ b/agent/xds/delta_test.go @@ -14,6 +14,8 @@ import ( "github.com/armon/go-metrics" envoy_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + "github.com/hashicorp/go-hclog" + goversion "github.com/hashicorp/go-version" "github.com/stretchr/testify/require" rpcstatus "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc/codes" @@ -25,6 +27,7 @@ import ( "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/envoyextensions/extensioncommon" "github.com/hashicorp/consul/envoyextensions/xdscommon" "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil/retry" @@ -1609,3 +1612,108 @@ func requireExtensionMetrics( require.True(t, foundLabel) } } + +func Test_applyEnvoyExtension_Validations(t *testing.T) { + type testCase struct { + name string + runtimeConfig extensioncommon.RuntimeConfig + err bool + errString string + } + + envoyVersion, _ := goversion.NewVersion("1.25.0") + consulVersion, _ := goversion.NewVersion("1.16.0") + + svc := api.CompoundServiceName{ + Name: "s1", + Partition: "ap1", + Namespace: "ns1", + } + + makeRuntimeConfig := func(required bool, consulVersion string, envoyVersion string, args map[string]interface{}) extensioncommon.RuntimeConfig { + if args == nil { + args = map[string]interface{}{ + "ARN": "arn:aws:lambda:us-east-1:111111111111:function:lambda-1234", + } + + } + return extensioncommon.RuntimeConfig{ + EnvoyExtension: api.EnvoyExtension{ + Name: api.BuiltinAWSLambdaExtension, + Required: required, + ConsulVersion: consulVersion, + EnvoyVersion: envoyVersion, + Arguments: args, + }, + ServiceName: svc, + } + } + + cases := []testCase{ + { + name: "invalid consul version constraint - required", + runtimeConfig: makeRuntimeConfig(true, "bad", ">= 1.0", nil), + err: true, + errString: "failed to parse Consul version constraint for extension", + }, + { + name: "invalid consul version constraint - not required", + runtimeConfig: makeRuntimeConfig(false, "bad", ">= 1.0", nil), + err: false, + }, + { + name: "invalid envoy version constraint - required", + runtimeConfig: makeRuntimeConfig(true, ">= 1.0", "bad", nil), + err: true, + errString: "failed to parse Envoy version constraint for extension", + }, + { + name: "invalid envoy version constraint - not required", + runtimeConfig: makeRuntimeConfig(false, ">= 1.0", "bad", nil), + err: false, + }, + { + name: "no envoy version constraint match", + runtimeConfig: makeRuntimeConfig(false, "", ">= 2.0.0", nil), + err: false, + }, + { + name: "no consul version constraint match", + runtimeConfig: makeRuntimeConfig(false, ">= 2.0.0", "", nil), + err: false, + }, + { + name: "invalid extension arguments - required", + runtimeConfig: makeRuntimeConfig(true, ">= 1.15.0", ">= 1.25.0", map[string]interface{}{"bad": "args"}), + err: true, + errString: "failed to construct extension", + }, + { + name: "invalid extension arguments - not required", + runtimeConfig: makeRuntimeConfig(false, ">= 1.15.0", ">= 1.25.0", map[string]interface{}{"bad": "args"}), + err: false, + }, + { + name: "valid everything", + runtimeConfig: makeRuntimeConfig(false, ">= 1.15.0", ">= 1.25.0", nil), + err: false, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + snap := proxycfg.ConfigSnapshot{ + ProxyID: proxycfg.ProxyID{ + ServiceID: structs.NewServiceID("s1", nil), + }, + } + err := applyEnvoyExtension(hclog.NewNullLogger(), &snap, nil, tc.runtimeConfig, envoyVersion, consulVersion) + if tc.err { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errString) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden new file mode 100644 index 000000000000..c010ac87b0f4 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden @@ -0,0 +1,127 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": {}, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": {}, + "outlierDetection": {}, + "commonLbConfig": { + "healthyPanicThreshold": {} + }, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + }, + "matchSubjectAltNames": [ + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/db" + } + ] + } + }, + "sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": {}, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": {}, + "outlierDetection": {}, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + }, + "matchSubjectAltNames": [ + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/geo-cache-target" + }, + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target" + } + ] + } + }, + "sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden new file mode 100644 index 000000000000..c010ac87b0f4 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden @@ -0,0 +1,127 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": {}, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": {}, + "outlierDetection": {}, + "commonLbConfig": { + "healthyPanicThreshold": {} + }, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + }, + "matchSubjectAltNames": [ + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/db" + } + ] + } + }, + "sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": {}, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": {}, + "outlierDetection": {}, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + }, + "matchSubjectAltNames": [ + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/geo-cache-target" + }, + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target" + } + ] + } + }, + "sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden new file mode 100644 index 000000000000..5cb4171b9730 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden @@ -0,0 +1,75 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.20.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden new file mode 100644 index 000000000000..5cb4171b9730 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden @@ -0,0 +1,75 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.20.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden new file mode 100644 index 000000000000..8024198d7c4d --- /dev/null +++ b/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden @@ -0,0 +1,265 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "db:127.0.0.1:9191", + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 9191 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "upstream.db.default.default.dc1", + "routeConfig": { + "name": "db", + "virtualHosts": [ + { + "name": "db.default.default.dc1", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ] + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + } + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "prepared_query:geo-cache:127.10.10.10:8181", + "address": { + "socketAddress": { + "address": "127.10.10.10", + "portValue": 8181 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.prepared_query_geo-cache", + "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "public_listener:0.0.0.0:9999", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 9999 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "public_listener", + "routeConfig": { + "name": "public_listener", + "virtualHosts": [ + { + "name": "public_listener", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "local_app" + } + } + ] + } + ] + }, + "httpFilters": [ + { + "name": "envoy.filters.http.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC", + "rules": {} + } + }, + { + "name": "envoy.filters.http.header_to_metadata", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config", + "requestRules": [ + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "trust-domain", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\1" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "partition", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\2" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "namespace", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\3" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "datacenter", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\4" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "service", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\5" + } + } + } + ] + } + }, + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + }, + "forwardClientCertDetails": "APPEND_FORWARD", + "setCurrentClientCertDetails": { + "subject": true, + "cert": true, + "chain": true, + "dns": true, + "uri": true + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + }, + "alpnProtocols": [ + "http/1.1" + ] + }, + "requireClientCertificate": true + } + } + } + ], + "trafficDirection": "INBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden new file mode 100644 index 000000000000..8024198d7c4d --- /dev/null +++ b/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden @@ -0,0 +1,265 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "db:127.0.0.1:9191", + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 9191 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "upstream.db.default.default.dc1", + "routeConfig": { + "name": "db", + "virtualHosts": [ + { + "name": "db.default.default.dc1", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ] + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + } + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "prepared_query:geo-cache:127.10.10.10:8181", + "address": { + "socketAddress": { + "address": "127.10.10.10", + "portValue": 8181 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.prepared_query_geo-cache", + "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "public_listener:0.0.0.0:9999", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 9999 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "public_listener", + "routeConfig": { + "name": "public_listener", + "virtualHosts": [ + { + "name": "public_listener", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "local_app" + } + } + ] + } + ] + }, + "httpFilters": [ + { + "name": "envoy.filters.http.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC", + "rules": {} + } + }, + { + "name": "envoy.filters.http.header_to_metadata", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config", + "requestRules": [ + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "trust-domain", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\1" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "partition", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\2" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "namespace", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\3" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "datacenter", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\4" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "service", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\5" + } + } + } + ] + } + }, + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + }, + "forwardClientCertDetails": "APPEND_FORWARD", + "setCurrentClientCertDetails": { + "subject": true, + "cert": true, + "chain": true, + "dns": true, + "uri": true + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + }, + "alpnProtocols": [ + "http/1.1" + ] + }, + "requireClientCertificate": true + } + } + } + ], + "trafficDirection": "INBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden new file mode 100644 index 000000000000..306f5220e7b9 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden new file mode 100644 index 000000000000..306f5220e7b9 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file diff --git a/api/api_test.go b/api/api_test.go index 49670b41eb86..4d5dd1fda830 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -53,6 +53,22 @@ func makeACLClient(t *testing.T) (*Client, *testutil.TestServer) { }) } +// Makes a client with Audit enabled, it requires ACLs +func makeAuditClient(t *testing.T) (*Client, *testutil.TestServer) { + return makeClientWithConfig(t, func(clientConfig *Config) { + clientConfig.Token = "root" + }, func(serverConfig *testutil.TestServerConfig) { + serverConfig.PrimaryDatacenter = "dc1" + serverConfig.ACL.Tokens.InitialManagement = "root" + serverConfig.ACL.Tokens.Agent = "root" + serverConfig.ACL.Enabled = true + serverConfig.ACL.DefaultPolicy = "deny" + serverConfig.Audit = &testutil.TestAuditConfig{ + Enabled: true, + } + }) +} + func makeNonBootstrappedACLClient(t *testing.T, defaultPolicy string) (*Client, *testutil.TestServer) { return makeClientWithConfig(t, func(clientConfig *Config) { diff --git a/api/config_entry.go b/api/config_entry.go index b4cc966d1f70..125619b55d08 100644 --- a/api/config_entry.go +++ b/api/config_entry.go @@ -144,9 +144,11 @@ type ExposeConfig struct { // EnvoyExtension has configuration for an extension that patches Envoy resources. type EnvoyExtension struct { - Name string - Required bool - Arguments map[string]interface{} `bexpr:"-"` + Name string + Required bool + Arguments map[string]interface{} `bexpr:"-"` + ConsulVersion string + EnvoyVersion string } type ExposePath struct { diff --git a/api/config_entry_rate_limit_ip.go b/api/config_entry_rate_limit_ip.go index 1c91b811a9b8..8df7d4c98e77 100644 --- a/api/config_entry_rate_limit_ip.go +++ b/api/config_entry_rate_limit_ip.go @@ -20,19 +20,29 @@ type RateLimitIPConfigEntry struct { WriteRate float64 //limits specific to a type of call - ACL *ReadWriteRatesConfig `json:",omitempty"` - Catalog *ReadWriteRatesConfig `json:",omitempty"` - ConfigEntry *ReadWriteRatesConfig `json:",omitempty"` - ConnectCA *ReadWriteRatesConfig `json:",omitempty"` - Coordinate *ReadWriteRatesConfig `json:",omitempty"` - DiscoveryChain *ReadWriteRatesConfig `json:",omitempty"` - Health *ReadWriteRatesConfig `json:",omitempty"` - Intention *ReadWriteRatesConfig `json:",omitempty"` - KV *ReadWriteRatesConfig `json:",omitempty"` - Tenancy *ReadWriteRatesConfig `json:",omitempty"` - PreparedQuery *ReadWriteRatesConfig `json:",omitempty"` - Session *ReadWriteRatesConfig `json:",omitempty"` - Txn *ReadWriteRatesConfig `json:",omitempty"` + ACL *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryACL OperationCategory = "ACL" + Catalog *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryCatalog OperationCategory = "Catalog" + ConfigEntry *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryConfigEntry OperationCategory = "ConfigEntry" + ConnectCA *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryConnectCA OperationCategory = "ConnectCA" + Coordinate *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryCoordinate OperationCategory = "Coordinate" + DiscoveryChain *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryDiscoveryChain OperationCategory = "DiscoveryChain" + ServerDiscovery *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryServerDiscovery OperationCategory = "ServerDiscovery" + Health *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryHealth OperationCategory = "Health" + Intention *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryIntention OperationCategory = "Intention" + KV *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryKV OperationCategory = "KV" + Tenancy *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryPartition OperationCategory = "Tenancy" + PreparedQuery *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryPreparedQuery OperationCategory = "PreparedQuery" + Session *ReadWriteRatesConfig `json:",omitempty"` // OperationCategorySession OperationCategory = "Session" + Txn *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryTxn OperationCategory = "Txn" + AutoConfig *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryAutoConfig OperationCategory = "AutoConfig" + FederationState *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryFederationState OperationCategory = "FederationState" + Internal *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryInternal OperationCategory = "Internal" + PeerStream *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryPeerStream OperationCategory = "PeerStream" + Peering *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryPeering OperationCategory = "Peering" + DataPlane *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryDataPlane OperationCategory = "DataPlane" + DNS *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryDNS OperationCategory = "DNS" + Subscribe *ReadWriteRatesConfig `json:",omitempty"` // OperationCategorySubscribe OperationCategory = "Subscribe" + Resource *ReadWriteRatesConfig `json:",omitempty"` // OperationCategoryResource OperationCategory = "Resource" // Partition is the partition the config entry is associated with. // Partitioning is a Consul Enterprise feature. diff --git a/envoyextensions/xdscommon/envoy_versioning.go b/envoyextensions/xdscommon/envoy_versioning.go index 06764f2b65e2..393a96bf9e80 100644 --- a/envoyextensions/xdscommon/envoy_versioning.go +++ b/envoyextensions/xdscommon/envoy_versioning.go @@ -30,7 +30,7 @@ type SupportedProxyFeatures struct { } func DetermineSupportedProxyFeatures(node *envoy_core_v3.Node) (SupportedProxyFeatures, error) { - version := determineEnvoyVersionFromNode(node) + version := DetermineEnvoyVersionFromNode(node) return determineSupportedProxyFeaturesFromVersion(version) } @@ -69,7 +69,7 @@ func determineSupportedProxyFeaturesFromVersion(version *version.Version) (Suppo return sf, nil } -func determineEnvoyVersionFromNode(node *envoy_core_v3.Node) *version.Version { +func DetermineEnvoyVersionFromNode(node *envoy_core_v3.Node) *version.Version { if node == nil { return nil } diff --git a/envoyextensions/xdscommon/envoy_versioning_test.go b/envoyextensions/xdscommon/envoy_versioning_test.go index ff9318239348..3e7507dec551 100644 --- a/envoyextensions/xdscommon/envoy_versioning_test.go +++ b/envoyextensions/xdscommon/envoy_versioning_test.go @@ -59,7 +59,7 @@ func TestDetermineEnvoyVersionFromNode(t *testing.T) { for name, tc := range cases { tc := tc t.Run(name, func(t *testing.T) { - got := determineEnvoyVersionFromNode(tc.node) + got := DetermineEnvoyVersionFromNode(tc.node) if tc.expect != nil { require.Equal(t, tc.expect, got) } else { diff --git a/proto/private/pbcommon/common.gen.go b/proto/private/pbcommon/common.gen.go index d7659b834ee3..c29598a2abf7 100644 --- a/proto/private/pbcommon/common.gen.go +++ b/proto/private/pbcommon/common.gen.go @@ -11,6 +11,8 @@ func EnvoyExtensionToStructs(s *EnvoyExtension, t *structs.EnvoyExtension) { t.Name = s.Name t.Required = s.Required t.Arguments = ProtobufTypesStructToMapStringInterface(s.Arguments) + t.ConsulVersion = s.ConsulVersion + t.EnvoyVersion = s.EnvoyVersion } func EnvoyExtensionFromStructs(t *structs.EnvoyExtension, s *EnvoyExtension) { if s == nil { @@ -19,6 +21,8 @@ func EnvoyExtensionFromStructs(t *structs.EnvoyExtension, s *EnvoyExtension) { s.Name = t.Name s.Required = t.Required s.Arguments = MapStringInterfaceToProtobufTypesStruct(t.Arguments) + s.ConsulVersion = t.ConsulVersion + s.EnvoyVersion = t.EnvoyVersion } func LocalityToStructs(s *Locality, t *structs.Locality) { if s == nil { diff --git a/proto/private/pbcommon/common.pb.go b/proto/private/pbcommon/common.pb.go index 8a8ae5fe9401..dd6240ad85e9 100644 --- a/proto/private/pbcommon/common.pb.go +++ b/proto/private/pbcommon/common.pb.go @@ -607,7 +607,9 @@ type EnvoyExtension struct { Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` Required bool `protobuf:"varint,2,opt,name=Required,proto3" json:"Required,omitempty"` // mog: func-to=ProtobufTypesStructToMapStringInterface func-from=MapStringInterfaceToProtobufTypesStruct - Arguments *structpb.Struct `protobuf:"bytes,3,opt,name=Arguments,proto3" json:"Arguments,omitempty"` + Arguments *structpb.Struct `protobuf:"bytes,3,opt,name=Arguments,proto3" json:"Arguments,omitempty"` + ConsulVersion string `protobuf:"bytes,4,opt,name=ConsulVersion,proto3" json:"ConsulVersion,omitempty"` + EnvoyVersion string `protobuf:"bytes,5,opt,name=EnvoyVersion,proto3" json:"EnvoyVersion,omitempty"` } func (x *EnvoyExtension) Reset() { @@ -663,6 +665,20 @@ func (x *EnvoyExtension) GetArguments() *structpb.Struct { return nil } +func (x *EnvoyExtension) GetConsulVersion() string { + if x != nil { + return x.ConsulVersion + } + return "" +} + +func (x *EnvoyExtension) GetEnvoyVersion() string { + if x != nil { + return x.EnvoyVersion + } + return "" +} + // mog annotation: // // target=github.com/hashicorp/consul/agent/structs.Locality @@ -802,36 +818,40 @@ var file_private_pbcommon_common_proto_rawDesc = []byte{ 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x77, 0x0a, 0x0e, 0x45, - 0x6e, 0x76, 0x6f, 0x79, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, - 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x35, 0x0a, - 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x22, 0x36, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, - 0x12, 0x16, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x5a, 0x6f, 0x6e, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x5a, 0x6f, 0x6e, 0x65, 0x42, 0x8b, 0x02, 0x0a, - 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x2f, - 0x70, 0x62, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xa2, 0x02, 0x04, 0x48, 0x43, 0x49, 0x43, 0xaa, - 0x02, 0x20, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, - 0x75, 0x6c, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0xca, 0x02, 0x20, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xe2, 0x02, 0x2c, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x5c, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x23, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x3a, 0x3a, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc1, 0x01, 0x0a, 0x0e, + 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, + 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x35, + 0x0a, 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x09, 0x41, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x45, + 0x6e, 0x76, 0x6f, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, + 0x36, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x52, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x52, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x5a, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x5a, 0x6f, 0x6e, 0x65, 0x42, 0x8b, 0x02, 0x0a, 0x24, 0x63, 0x6f, 0x6d, 0x2e, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0xa2, 0x02, 0x04, 0x48, 0x43, 0x49, 0x43, 0xaa, 0x02, 0x20, 0x48, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xca, 0x02, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0xe2, 0x02, 0x2c, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x23, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x3a, 0x3a, 0x43, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/private/pbcommon/common.proto b/proto/private/pbcommon/common.proto index 237e9b4e29e2..a86aa2dde53d 100644 --- a/proto/private/pbcommon/common.proto +++ b/proto/private/pbcommon/common.proto @@ -185,6 +185,8 @@ message EnvoyExtension { bool Required = 2; // mog: func-to=ProtobufTypesStructToMapStringInterface func-from=MapStringInterfaceToProtobufTypesStruct google.protobuf.Struct Arguments = 3; + string ConsulVersion = 4; + string EnvoyVersion = 5; } // mog annotation: diff --git a/proto/private/pbcommon/convert_pbstruct.go b/proto/private/pbcommon/convert_pbstruct.go index 4370d7f2e783..e48dce9ae6e0 100644 --- a/proto/private/pbcommon/convert_pbstruct.go +++ b/proto/private/pbcommon/convert_pbstruct.go @@ -47,9 +47,11 @@ func EnvoyExtensionsToStructs(args []*EnvoyExtension) []structs.EnvoyExtension { var e structs.EnvoyExtension if args[i] != nil { e = structs.EnvoyExtension{ - Name: args[i].Name, - Required: args[i].Required, - Arguments: ProtobufTypesStructToMapStringInterface(args[i].Arguments), + Name: args[i].Name, + Required: args[i].Required, + ConsulVersion: args[i].ConsulVersion, + EnvoyVersion: args[i].EnvoyVersion, + Arguments: ProtobufTypesStructToMapStringInterface(args[i].Arguments), } } @@ -65,9 +67,11 @@ func EnvoyExtensionsFromStructs(args []structs.EnvoyExtension) []*EnvoyExtension o := make([]*EnvoyExtension, len(args)) for i, e := range args { o[i] = &EnvoyExtension{ - Name: e.Name, - Required: e.Required, - Arguments: MapStringInterfaceToProtobufTypesStruct(e.Arguments), + Name: e.Name, + Required: e.Required, + ConsulVersion: e.ConsulVersion, + EnvoyVersion: e.EnvoyVersion, + Arguments: MapStringInterfaceToProtobufTypesStruct(e.Arguments), } } diff --git a/sdk/testutil/server.go b/sdk/testutil/server.go index 1c7167d98da5..d00850d5e17a 100644 --- a/sdk/testutil/server.go +++ b/sdk/testutil/server.go @@ -75,6 +75,11 @@ type TestNetworkSegment struct { Advertise string `json:"advertise"` } +// TestAudigConfig contains the configuration for Audit +type TestAuditConfig struct { + Enabled bool `json:"enabled,omitempty"` +} + // Locality is used as the TestServerConfig's Locality. type Locality struct { Region string `json:"region"` @@ -124,6 +129,7 @@ type TestServerConfig struct { Stderr io.Writer `json:"-"` Args []string `json:"-"` ReturnPorts func() `json:"-"` + Audit *TestAuditConfig `json:"audit,omitempty"` } type TestACLs struct { diff --git a/tlsutil/config_test.go b/tlsutil/config_test.go index 18ba11e38b90..30ebd62c206b 100644 --- a/tlsutil/config_test.go +++ b/tlsutil/config_test.go @@ -1,5 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 +//go:build !fips +// +build !fips package tlsutil diff --git a/version/VERSION b/version/VERSION index 1f0d2f335194..ee8855caa4a7 100644 --- a/version/VERSION +++ b/version/VERSION @@ -1 +1 @@ -1.16.0-dev +1.17.0-dev diff --git a/version/version.go b/version/version.go index bd2cfd57aa2f..0b81e19d2bc5 100644 --- a/version/version.go +++ b/version/version.go @@ -52,6 +52,10 @@ func GetHumanVersion() string { version += fmt.Sprintf("-%s", release) } + if IsFIPS() { + version += ".fips1402" + } + if metadata != "" { version += fmt.Sprintf("+%s", metadata) }