From 0e9a27a8c1ecbce7e1e783dfd1a149838bf9dcd9 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 24 Aug 2023 09:43:28 -0400 Subject: [PATCH 1/5] Added placeholder structs for JWT functionality --- agent/xds/gw_per_route_filters_ce.go | 24 ++++++++++++++++++++++++ agent/xds/jwt_authn_ce.go | 22 ++++++++++++++++++++++ agent/xds/rbac.go | 17 ++++++++++++----- agent/xds/resources_ce_test.go | 4 +++- agent/xds/resources_test.go | 2 +- 5 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 agent/xds/gw_per_route_filters_ce.go create mode 100644 agent/xds/jwt_authn_ce.go diff --git a/agent/xds/gw_per_route_filters_ce.go b/agent/xds/gw_per_route_filters_ce.go new file mode 100644 index 000000000000..cbf406cd07a1 --- /dev/null +++ b/agent/xds/gw_per_route_filters_ce.go @@ -0,0 +1,24 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +//go:build !consulent +// +build !consulent + +package xds + +import ( + envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/hashicorp/consul/agent/structs" +) + +type perRouteFilterBuilder struct { + providerMap map[string]*structs.JWTProviderConfigEntry + listener *structs.APIGatewayListener + route *structs.HTTPRouteConfigEntry +} + +func (p perRouteFilterBuilder) buildFilter(match *envoy_route_v3.RouteMatch) (map[string]*anypb.Any, error) { + return nil, nil +} diff --git a/agent/xds/jwt_authn_ce.go b/agent/xds/jwt_authn_ce.go new file mode 100644 index 000000000000..8379d787c696 --- /dev/null +++ b/agent/xds/jwt_authn_ce.go @@ -0,0 +1,22 @@ +//go:build !consulent +// +build !consulent + +package xds + +import ( + envoy_http_jwt_authn_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/jwt_authn/v3" + envoy_http_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" + + "github.com/hashicorp/consul/agent/structs" +) + +type GatewayAuthFilterBuilder struct { + listener structs.APIGatewayListener + route *structs.HTTPRouteConfigEntry + providers map[string]*structs.JWTProviderConfigEntry + envoyProviders map[string]*envoy_http_jwt_authn_v3.JwtProvider +} + +func (g *GatewayAuthFilterBuilder) makeGatewayAuthFilters() ([]*envoy_http_v3.HttpFilter, error) { + return nil, nil +} diff --git a/agent/xds/rbac.go b/agent/xds/rbac.go index 0c00cb92cb0c..68e91d2945ad 100644 --- a/agent/xds/rbac.go +++ b/agent/xds/rbac.go @@ -23,6 +23,11 @@ import ( "github.com/hashicorp/consul/proto/private/pbpeering" ) +const ( + envoyHTTPRBACFilterKey = "envoy.filters.http.rbac" + envoyNetworkRBACFilterKey = "envoy.filters.network.rbac" +) + func makeRBACNetworkFilter( intentions structs.SimplifiedIntentions, intentionDefaultAllow bool, @@ -38,7 +43,7 @@ func makeRBACNetworkFilter( StatPrefix: "connect_authz", Rules: rules, } - return makeFilter("envoy.filters.network.rbac", cfg) + return makeFilter(envoyNetworkRBACFilterKey, cfg) } func makeRBACHTTPFilter( @@ -56,7 +61,7 @@ func makeRBACHTTPFilter( cfg := &envoy_http_rbac_v3.RBAC{ Rules: rules, } - return makeEnvoyHTTPFilter("envoy.filters.http.rbac", cfg) + return makeEnvoyHTTPFilter(envoyHTTPRBACFilterKey, cfg) } func intentionListToIntermediateRBACForm( @@ -326,6 +331,7 @@ func intentionActionFromBool(v bool) intentionAction { return intentionActionDeny } } + func intentionActionFromString(s structs.IntentionAction) intentionAction { if s == structs.IntentionActionAllow { return intentionActionAllow @@ -809,7 +815,6 @@ func segmentToPermission(segments []*envoy_matcher_v3.MetadataMatcher_PathSegmen // }, // }, func pathToSegments(paths []string, payloadKey string) []*envoy_matcher_v3.MetadataMatcher_PathSegment { - segments := make([]*envoy_matcher_v3.MetadataMatcher_PathSegment, 0, len(paths)) segments = append(segments, makeSegment(payloadKey)) @@ -1029,8 +1034,10 @@ func xfccPrincipal(src rbacService) *envoy_rbac_v3.Principal { } } -const anyPath = `[^/]+` -const trustDomain = anyPath + "." + anyPath +const ( + anyPath = `[^/]+` + trustDomain = anyPath + "." + anyPath +) // downstreamServiceIdentityMatcher needs to match XFCC headers in two cases: // 1. Requests to cluster peered services through a mesh gateway. In this case, the XFCC header looks like the following (I added a new line after each ; for readability) diff --git a/agent/xds/resources_ce_test.go b/agent/xds/resources_ce_test.go index fa7134817235..14d5a35253a4 100644 --- a/agent/xds/resources_ce_test.go +++ b/agent/xds/resources_ce_test.go @@ -6,6 +6,8 @@ package xds -func getEnterpriseGoldenTestCases() []goldenTestCase { +import "testing" + +func getEnterpriseGoldenTestCases(t *testing.T) []goldenTestCase { return nil } diff --git a/agent/xds/resources_test.go b/agent/xds/resources_test.go index 926c44fab86e..69a704386b5d 100644 --- a/agent/xds/resources_test.go +++ b/agent/xds/resources_test.go @@ -193,7 +193,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) { tests = append(tests, getConnectProxyTransparentProxyGoldenTestCases()...) tests = append(tests, getMeshGatewayPeeringGoldenTestCases()...) tests = append(tests, getTrafficControlPeeringGoldenTestCases(false)...) - tests = append(tests, getEnterpriseGoldenTestCases()...) + tests = append(tests, getEnterpriseGoldenTestCases(t)...) tests = append(tests, getAPIGatewayGoldenTestCases(t)...) latestEnvoyVersion := xdscommon.EnvoyVersions[0] From fa1e32ceb35663ef2053c965c1e2967e223b109f Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 24 Aug 2023 13:48:30 -0400 Subject: [PATCH 2/5] Added watches for CE vs ENT --- agent/proxycfg/api_gateway.go | 10 ++++++++++ agent/proxycfg/api_gateway_ce.go | 15 +++++++++++++++ agent/xds/routes.go | 14 ++++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 agent/proxycfg/api_gateway_ce.go diff --git a/agent/proxycfg/api_gateway.go b/agent/proxycfg/api_gateway.go index 3ed39481204c..a0ce11d3da4b 100644 --- a/agent/proxycfg/api_gateway.go +++ b/agent/proxycfg/api_gateway.go @@ -48,6 +48,11 @@ func (h *handlerAPIGateway) initialize(ctx context.Context) (ConfigSnapshot, err return snap, err } + err = watchJWTProviders(h) + if err != nil { + return snap, err + } + // Watch the api-gateway's config entry err = h.subscribeToConfigEntry(ctx, structs.APIGateway, h.service, h.proxyID.EnterpriseMeta, apiGatewayConfigWatchID) if err != nil { @@ -118,6 +123,11 @@ func (h *handlerAPIGateway) handleUpdate(ctx context.Context, u UpdateEvent, sna if err := h.handleRouteConfigUpdate(ctx, u, snap); err != nil { return err } + case u.CorrelationID == jwtProviderID: + err := setJWTProvider(u, snap) + if err != nil { + return err + } default: if err := (*handlerUpstreams)(h).handleUpdateUpstreams(ctx, u, snap); err != nil { return err diff --git a/agent/proxycfg/api_gateway_ce.go b/agent/proxycfg/api_gateway_ce.go new file mode 100644 index 000000000000..ee83ce8a1f6b --- /dev/null +++ b/agent/proxycfg/api_gateway_ce.go @@ -0,0 +1,15 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +//go:build !consulent +// +build !consulent + +package proxycfg + +func watchJWTProviders(h *handlerAPIGateway) error { + return nil +} + +func setJWTProvider(u UpdateEvent, snap *ConfigSnapshot) error { + return nil +} diff --git a/agent/xds/routes.go b/agent/xds/routes.go index 6f0d18b05dcb..b98a2cbb87a9 100644 --- a/agent/xds/routes.go +++ b/agent/xds/routes.go @@ -58,7 +58,7 @@ func (s *ResourceGenerator) routesForConnectProxy(cfgSnap *proxycfg.ConfigSnapsh continue } - virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, []string{"*"}, false) + virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, []string{"*"}, false, perRouteFilterBuilder{}) if err != nil { return nil, err } @@ -255,6 +255,7 @@ func (s *ResourceGenerator) routesForMeshGateway(cfgSnap *proxycfg.ConfigSnapsho chain, []string{"*"}, true, + perRouteFilterBuilder{}, ) if err != nil { return nil, err @@ -378,7 +379,7 @@ func (s *ResourceGenerator) routesForIngressGateway(cfgSnap *proxycfg.ConfigSnap } domains := generateUpstreamIngressDomains(listenerKey, u) - virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, domains, false) + virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, domains, false, perRouteFilterBuilder{}) if err != nil { return nil, err } @@ -476,7 +477,7 @@ func (s *ResourceGenerator) routesForAPIGateway(cfgSnap *proxycfg.ConfigSnapshot domains := generateUpstreamAPIsDomains(listenerKey, upstream, reformatedRoute.Hostnames) - virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, domains, false) + virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, domains, false, perRouteFilterBuilder{}) if err != nil { return nil, err } @@ -605,6 +606,7 @@ func (s *ResourceGenerator) makeUpstreamRouteForDiscoveryChain( chain *structs.CompiledDiscoveryChain, serviceDomains []string, forMeshGateway bool, + filterBuilder perRouteFilterBuilder, ) (*envoy_route_v3.VirtualHost, error) { routeName := uid.EnvoyID() var routes []*envoy_route_v3.Route @@ -687,9 +689,13 @@ func (s *ResourceGenerator) makeUpstreamRouteForDiscoveryChain( return nil, fmt.Errorf("failed to apply header manipulation configuration to route: %v", err) } } - + filter, err := filterBuilder.buildFilter(routeMatch) + if err != nil { + return nil, err + } route.Match = routeMatch route.Action = routeAction + route.TypedPerFilterConfig = filter routes = append(routes, route) } From 996f27dbaa5172b6d6f28ecab1f271b7ca26c858 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 24 Aug 2023 13:49:56 -0400 Subject: [PATCH 3/5] Add license header --- agent/xds/jwt_authn_ce.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/agent/xds/jwt_authn_ce.go b/agent/xds/jwt_authn_ce.go index 8379d787c696..ac6d0a31d799 100644 --- a/agent/xds/jwt_authn_ce.go +++ b/agent/xds/jwt_authn_ce.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + //go:build !consulent // +build !consulent From 773a52bbe8de50f2252654ac0464cab29b17ce43 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 24 Aug 2023 14:35:47 -0400 Subject: [PATCH 4/5] Undo plumbing work --- agent/proxycfg/api_gateway.go | 10 ---------- agent/xds/routes.go | 14 ++++---------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/agent/proxycfg/api_gateway.go b/agent/proxycfg/api_gateway.go index a0ce11d3da4b..3ed39481204c 100644 --- a/agent/proxycfg/api_gateway.go +++ b/agent/proxycfg/api_gateway.go @@ -48,11 +48,6 @@ func (h *handlerAPIGateway) initialize(ctx context.Context) (ConfigSnapshot, err return snap, err } - err = watchJWTProviders(h) - if err != nil { - return snap, err - } - // Watch the api-gateway's config entry err = h.subscribeToConfigEntry(ctx, structs.APIGateway, h.service, h.proxyID.EnterpriseMeta, apiGatewayConfigWatchID) if err != nil { @@ -123,11 +118,6 @@ func (h *handlerAPIGateway) handleUpdate(ctx context.Context, u UpdateEvent, sna if err := h.handleRouteConfigUpdate(ctx, u, snap); err != nil { return err } - case u.CorrelationID == jwtProviderID: - err := setJWTProvider(u, snap) - if err != nil { - return err - } default: if err := (*handlerUpstreams)(h).handleUpdateUpstreams(ctx, u, snap); err != nil { return err diff --git a/agent/xds/routes.go b/agent/xds/routes.go index b98a2cbb87a9..6f0d18b05dcb 100644 --- a/agent/xds/routes.go +++ b/agent/xds/routes.go @@ -58,7 +58,7 @@ func (s *ResourceGenerator) routesForConnectProxy(cfgSnap *proxycfg.ConfigSnapsh continue } - virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, []string{"*"}, false, perRouteFilterBuilder{}) + virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, []string{"*"}, false) if err != nil { return nil, err } @@ -255,7 +255,6 @@ func (s *ResourceGenerator) routesForMeshGateway(cfgSnap *proxycfg.ConfigSnapsho chain, []string{"*"}, true, - perRouteFilterBuilder{}, ) if err != nil { return nil, err @@ -379,7 +378,7 @@ func (s *ResourceGenerator) routesForIngressGateway(cfgSnap *proxycfg.ConfigSnap } domains := generateUpstreamIngressDomains(listenerKey, u) - virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, domains, false, perRouteFilterBuilder{}) + virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, domains, false) if err != nil { return nil, err } @@ -477,7 +476,7 @@ func (s *ResourceGenerator) routesForAPIGateway(cfgSnap *proxycfg.ConfigSnapshot domains := generateUpstreamAPIsDomains(listenerKey, upstream, reformatedRoute.Hostnames) - virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, domains, false, perRouteFilterBuilder{}) + virtualHost, err := s.makeUpstreamRouteForDiscoveryChain(cfgSnap, uid, chain, domains, false) if err != nil { return nil, err } @@ -606,7 +605,6 @@ func (s *ResourceGenerator) makeUpstreamRouteForDiscoveryChain( chain *structs.CompiledDiscoveryChain, serviceDomains []string, forMeshGateway bool, - filterBuilder perRouteFilterBuilder, ) (*envoy_route_v3.VirtualHost, error) { routeName := uid.EnvoyID() var routes []*envoy_route_v3.Route @@ -689,13 +687,9 @@ func (s *ResourceGenerator) makeUpstreamRouteForDiscoveryChain( return nil, fmt.Errorf("failed to apply header manipulation configuration to route: %v", err) } } - filter, err := filterBuilder.buildFilter(routeMatch) - if err != nil { - return nil, err - } + route.Match = routeMatch route.Action = routeAction - route.TypedPerFilterConfig = filter routes = append(routes, route) } From 65cdc22bd44a429bb9116e384c02d253ee0bfa97 Mon Sep 17 00:00:00 2001 From: jm96441n Date: Thu, 24 Aug 2023 14:44:59 -0400 Subject: [PATCH 5/5] Add context arg --- agent/proxycfg/api_gateway_ce.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/agent/proxycfg/api_gateway_ce.go b/agent/proxycfg/api_gateway_ce.go index ee83ce8a1f6b..e2a3b375cd10 100644 --- a/agent/proxycfg/api_gateway_ce.go +++ b/agent/proxycfg/api_gateway_ce.go @@ -6,7 +6,9 @@ package proxycfg -func watchJWTProviders(h *handlerAPIGateway) error { +import "context" + +func watchJWTProviders(cxt context.Context, h *handlerAPIGateway) error { return nil }