From 514843e15a5151e80958ae58d7e996d32f57cfc5 Mon Sep 17 00:00:00 2001 From: wucm667 <109257021+wucm667@users.noreply.github.com> Date: Mon, 4 May 2026 08:43:16 +0800 Subject: [PATCH 01/12] fix(api): increase RateLimitSelectCondition.headers MaxItems from 16 to 64 (#8906) * fix(api): increase RateLimitSelectCondition.headers MaxItems from 16 to 64 Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: wucm667 Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- api/v1alpha1/ratelimit_types.go | 2 +- .../gateway.envoyproxy.io_backendtrafficpolicies.yaml | 4 ++-- .../gateway.envoyproxy.io_backendtrafficpolicies.yaml | 4 ++-- test/helm/gateway-crds-helm/all.out.yaml | 4 ++-- test/helm/gateway-crds-helm/e2e.out.yaml | 4 ++-- test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/api/v1alpha1/ratelimit_types.go b/api/v1alpha1/ratelimit_types.go index 4603b26bdc..65fd174c78 100644 --- a/api/v1alpha1/ratelimit_types.go +++ b/api/v1alpha1/ratelimit_types.go @@ -228,7 +228,7 @@ type RateLimitSelectCondition struct { // meaning, a request MUST match all the specified headers. // // +optional - // +kubebuilder:validation:MaxItems=16 + // +kubebuilder:validation:MaxItems=64 Headers []HeaderMatch `json:"headers,omitempty"` // Methods is a list of request methods to match. Multiple method values are ORed together, diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index e9a2c99e6f..0b8ce0f5fd 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -1506,7 +1506,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- @@ -1890,7 +1890,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 3fc645eaf2..30739c66ba 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -1505,7 +1505,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- @@ -1889,7 +1889,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 00fbbaec7a..c826ebb424 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -24033,7 +24033,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- @@ -24417,7 +24417,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- diff --git a/test/helm/gateway-crds-helm/e2e.out.yaml b/test/helm/gateway-crds-helm/e2e.out.yaml index 9886bff5e0..e814908295 100644 --- a/test/helm/gateway-crds-helm/e2e.out.yaml +++ b/test/helm/gateway-crds-helm/e2e.out.yaml @@ -2006,7 +2006,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- @@ -2390,7 +2390,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index 4781857643..d8def29527 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -2006,7 +2006,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- @@ -2390,7 +2390,7 @@ spec: required: - name type: object - maxItems: 16 + maxItems: 64 type: array methods: description: |- From 9eb0e67826026d37a69ce39cd94d108936dc0b5c Mon Sep 17 00:00:00 2001 From: Kota Kimura <86363983+kkk777-7@users.noreply.github.com> Date: Tue, 5 May 2026 01:11:12 +0900 Subject: [PATCH 02/12] feat: policy field owner (#8538) * feat: policy field owner Signed-off-by: kkk777-7 Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- internal/gatewayapi/securitypolicy.go | 242 +++++++++-- internal/gatewayapi/securitypolicy_test.go | 219 +++++++++- ...-merge-multi-gateway-same-listener.in.yaml | 22 - ...merge-multi-gateway-same-listener.out.yaml | 12 +- ...typolicy-with-merge-multi-listener.in.yaml | 22 - ...ypolicy-with-merge-multi-listener.out.yaml | 12 +- ...policy-with-merge-needs-fieldowner.in.yaml | 231 +++++++++++ ...olicy-with-merge-needs-fieldowner.out.yaml | 379 ++++++++++++++++++ .../securitypolicy-with-merge.out.yaml | 2 +- internal/utils/merge_test.go | 66 +-- .../utils/testdata/securitypolicy_all.in.yaml | 49 +++ .../securitypolicy_all.jsonmerge.out.yaml | 58 +++ .../testdata/securitypolicy_all.patch.yaml | 50 +++ ...securitypolicy_all.strategicmerge.out.yaml | 61 +++ release-notes/current.yaml | 2 + .../gateway_api_extensions/security-policy.md | 12 +- 16 files changed, 1299 insertions(+), 140 deletions(-) create mode 100644 internal/gatewayapi/testdata/securitypolicy-with-merge-needs-fieldowner.in.yaml create mode 100644 internal/gatewayapi/testdata/securitypolicy-with-merge-needs-fieldowner.out.yaml create mode 100644 internal/utils/testdata/securitypolicy_all.in.yaml create mode 100644 internal/utils/testdata/securitypolicy_all.jsonmerge.out.yaml create mode 100644 internal/utils/testdata/securitypolicy_all.patch.yaml create mode 100644 internal/utils/testdata/securitypolicy_all.strategicmerge.out.yaml diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index 9ccea6da60..f9d9fd43d2 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -412,7 +412,7 @@ func (t *Translator) processSecurityPolicyForRoute( // Check if merging is enabled if policy.Spec.MergeType == nil { // No merging - use existing translation logic - if err := t.translateSecurityPolicyForRoute(policy, targetedRoute, currTarget, resources, xdsIR, nil, nil); err != nil { + if err := t.translateSecurityPolicyForRoute(policy, &securityPolicyOwners{}, targetedRoute, currTarget, resources, xdsIR, nil, nil); err != nil { status.SetTranslationErrorForPolicyAncestors(&policy.Status, ancestorRefs, t.GatewayControllerName, @@ -442,7 +442,7 @@ func (t *Translator) processSecurityPolicyForRoute( if gwPolicy == nil && listenerPolicy == nil { // No parent policy found, fall back to current policy - if err := t.translateSecurityPolicyForRoute(policy, targetedRoute, currTarget, resources, xdsIR, &gwNN, &listener.Name); err != nil { + if err := t.translateSecurityPolicyForRoute(policy, &securityPolicyOwners{}, targetedRoute, currTarget, resources, xdsIR, &gwNN, &listener.Name); err != nil { status.SetConditionForPolicyAncestor(&policy.Status, &ancestorRef, t.GatewayControllerName, @@ -461,7 +461,7 @@ func (t *Translator) processSecurityPolicyForRoute( } // Merge with parent policy - mergedPolicy, err := mergeSecurityPolicy(policy, parentPolicy) + mergedPolicy, owners, err := mergeSecurityPolicy(policy, parentPolicy) if err != nil { status.SetConditionForPolicyAncestor(&policy.Status, &ancestorRef, @@ -487,7 +487,7 @@ func (t *Translator) processSecurityPolicyForRoute( } // Apply merged policy - if err := t.translateSecurityPolicyForRoute(mergedPolicy, targetedRoute, currTarget, resources, xdsIR, &gwNN, &listener.Name); err != nil { + if err := t.translateSecurityPolicyForRoute(mergedPolicy, owners, targetedRoute, currTarget, resources, xdsIR, &gwNN, &listener.Name); err != nil { status.SetConditionForPolicyAncestor(&policy.Status, &ancestorRef, t.GatewayControllerName, @@ -865,6 +865,7 @@ func resolveSecurityPolicyRouteTargetRef( func (t *Translator) translateSecurityPolicyForRoute( policy *egv1a1.SecurityPolicy, + owners *securityPolicyOwners, route RouteContext, target policyTargetReferenceWithSectionName, resources *resource.Resources, @@ -889,7 +890,9 @@ func (t *Translator) translateSecurityPolicyForRoute( if policy.Spec.BasicAuth != nil { if basicAuth, err = t.buildBasicAuth( policy, - resources); err != nil { + owners, + resources, + ); err != nil { err = perr.WithMessage(err, "BasicAuth") errs = errors.Join(errs, err) } @@ -898,14 +901,16 @@ func (t *Translator) translateSecurityPolicyForRoute( if policy.Spec.APIKeyAuth != nil { if apiKeyAuth, err = t.buildAPIKeyAuth( policy, - resources); err != nil { + owners, + resources, + ); err != nil { err = perr.WithMessage(err, "APIKeyAuth") errs = errors.Join(errs, err) } } if policy.Spec.Authorization != nil { - if authorization, err = t.buildAuthorization(policy); err != nil { + if authorization, err = t.buildAuthorization(policy, owners); err != nil { err = perr.WithMessage(err, "Authorization") errs = errors.Join(errs, err) } @@ -945,8 +950,10 @@ func (t *Translator) translateSecurityPolicyForRoute( if policy.Spec.ExtAuth != nil { if extAuth, extAuthErr = t.buildExtAuth( policy, + owners, resources, - gtwCtx); extAuthErr != nil { + gtwCtx, + ); extAuthErr != nil { extAuthErr = perr.WithMessage(extAuthErr, "ExtAuth") errs = errors.Join(errs, extAuthErr) } @@ -956,8 +963,10 @@ func (t *Translator) translateSecurityPolicyForRoute( if policy.Spec.OIDC != nil { if oidc, err = t.buildOIDC( policy, + owners, resources, - gtwCtx); err != nil { + gtwCtx, + ); err != nil { err = perr.WithMessage(err, "OIDC") errs = errors.Join(errs, err) hasNonExtAuthError = true @@ -968,8 +977,10 @@ func (t *Translator) translateSecurityPolicyForRoute( if policy.Spec.JWT != nil { if jwt, err = t.buildJWT( policy, + owners, resources, - gtwCtx); err != nil { + gtwCtx, + ); err != nil { err = perr.WithMessage(err, "JWT") errs = errors.Join(errs, err) hasNonExtAuthError = true @@ -1097,6 +1108,7 @@ func (t *Translator) translateSecurityPolicyForGateway( xdsIR resource.XdsIRMap, ) error { // Build IR + noOwners := &securityPolicyOwners{} var ( cors *ir.CORS jwt *ir.JWT @@ -1116,8 +1128,10 @@ func (t *Translator) translateSecurityPolicyForGateway( if policy.Spec.JWT != nil { if jwt, err = t.buildJWT( policy, + noOwners, resources, - gtwCtx); err != nil { + gtwCtx, + ); err != nil { err = perr.WithMessage(err, "JWT") errs = errors.Join(errs, err) } @@ -1126,8 +1140,10 @@ func (t *Translator) translateSecurityPolicyForGateway( if policy.Spec.OIDC != nil { if oidc, err = t.buildOIDC( policy, + noOwners, resources, - gtwCtx); err != nil { + gtwCtx, + ); err != nil { err = perr.WithMessage(err, "OIDC") errs = errors.Join(errs, err) } @@ -1136,7 +1152,9 @@ func (t *Translator) translateSecurityPolicyForGateway( if policy.Spec.BasicAuth != nil { if basicAuth, err = t.buildBasicAuth( policy, - resources); err != nil { + noOwners, + resources, + ); err != nil { err = perr.WithMessage(err, "BasicAuth") errs = errors.Join(errs, err) } @@ -1145,14 +1163,16 @@ func (t *Translator) translateSecurityPolicyForGateway( if policy.Spec.APIKeyAuth != nil { if apiKeyAuth, err = t.buildAPIKeyAuth( policy, - resources); err != nil { + noOwners, + resources, + ); err != nil { err = perr.WithMessage(err, "APIKeyAuth") errs = errors.Join(errs, err) } } if policy.Spec.Authorization != nil { - if authorization, err = t.buildAuthorization(policy); err != nil { + if authorization, err = t.buildAuthorization(policy, noOwners); err != nil { errs = errors.Join(errs, err) } } @@ -1162,8 +1182,10 @@ func (t *Translator) translateSecurityPolicyForGateway( if policy.Spec.ExtAuth != nil { if extAuth, extAuthErr = t.buildExtAuth( policy, + noOwners, resources, - gtwCtx); extAuthErr != nil { + gtwCtx, + ); extAuthErr != nil { extAuthErr = perr.WithMessage(extAuthErr, "ExtAuth") errs = errors.Join(errs, extAuthErr) } @@ -1337,6 +1359,7 @@ func wildcard2regex(wildcard string) string { func (t *Translator) buildJWT( policy *egv1a1.SecurityPolicy, + owners *securityPolicyOwners, resources *resource.Resources, gtwCtx *GatewayContext, ) (*ir.JWT, error) { @@ -1344,6 +1367,7 @@ func (t *Translator) buildJWT( return nil, err } + jwtOwnerPolicy := policyOwnerOr(owners.jwtProviders, policy) providers := make([]ir.JWTProvider, 0, len(policy.Spec.JWT.Providers)) for i, p := range policy.Spec.JWT.Providers { provider := ir.JWTProvider{ @@ -1355,13 +1379,13 @@ func (t *Translator) buildJWT( ExtractFrom: p.ExtractFrom, } if p.RemoteJWKS != nil { - remoteJWKS, err := t.buildRemoteJWKS(policy, p.RemoteJWKS, i, resources, gtwCtx) + remoteJWKS, err := t.buildRemoteJWKS(jwtOwnerPolicy, p.RemoteJWKS, i, resources, gtwCtx) if err != nil { return nil, err } provider.RemoteJWKS = remoteJWKS } else { - localJWKS, err := t.buildLocalJWKS(policy, p.LocalJWKS) + localJWKS, err := t.buildLocalJWKS(jwtOwnerPolicy, p.LocalJWKS) if err != nil { return nil, err } @@ -1552,6 +1576,7 @@ func (t *Translator) buildLocalJWKS( func (t *Translator) buildOIDC( policy *egv1a1.SecurityPolicy, + owners *securityPolicyOwners, resources *resource.Resources, gtwCtx *GatewayContext, ) (*ir.OIDC, error) { @@ -1570,21 +1595,22 @@ func (t *Translator) buildOIDC( err error ) - if provider, err = t.buildOIDCProvider(policy, resources, gtwCtx); err != nil { + if provider, err = t.buildOIDCProvider(policy, owners, resources, gtwCtx); err != nil { return nil, err } - from := crossNamespaceFrom{ - group: egv1a1.GroupName, - kind: resource.KindSecurityPolicy, - namespace: policy.Namespace, - } - // Client ID can be specified either as a string or as a reference to a secret. switch { case oidc.ClientID != nil: clientID = *oidc.ClientID case oidc.ClientIDRef != nil: + ownerPolicy := policyOwnerOr(owners.oidcClientIDRef, policy) + from := crossNamespaceFrom{ + group: egv1a1.GroupName, + kind: resource.KindSecurityPolicy, + namespace: ownerPolicy.Namespace, + } + var clientIDSecret *corev1.Secret if clientIDSecret, err = t.validateSecretRef(true, from, *oidc.ClientIDRef, resources); err != nil { return nil, err @@ -1599,6 +1625,12 @@ func (t *Translator) buildOIDC( return nil, fmt.Errorf("client ID must be specified in OIDC policy %s/%s", policy.Namespace, policy.Name) } + clientSecretOwner := policyOwnerOr(owners.oidcClientSecret, policy) + from := crossNamespaceFrom{ + group: egv1a1.GroupName, + kind: resource.KindSecurityPolicy, + namespace: clientSecretOwner.Namespace, + } if clientSecret, err = t.validateSecretRef(true, from, oidc.ClientSecret, resources); err != nil { return nil, err } @@ -1637,10 +1669,12 @@ func (t *Translator) buildOIDC( disableTokenEncryption = *oidc.DisableTokenEncryption } + oidcOwner := policyOwnerOr(owners.oidc, policy) + // Generate a unique cookie suffix for oauth filters. // This is to avoid cookie name collision when multiple security policies are applied // to the same route. - suffix := utils.Digest32(string(policy.UID)) + suffix := utils.Digest32(string(oidcOwner.UID)) // Get the HMAC secret. // HMAC secret is generated by the CertGen job and stored in a secret @@ -1657,7 +1691,7 @@ func (t *Translator) buildOIDC( } irOIDC := &ir.OIDC{ - Name: irConfigName(policy), + Name: irConfigName(oidcOwner), Provider: *provider, ClientID: clientID, ClientSecret: clientSecretBytes, @@ -1707,6 +1741,7 @@ func (t *Translator) buildOIDC( func (t *Translator) buildOIDCProvider( policy *egv1a1.SecurityPolicy, + owners *securityPolicyOwners, resources *resource.Resources, gtwCtx *GatewayContext, ) (*ir.OIDCProvider, error) { @@ -1739,9 +1774,10 @@ func (t *Translator) buildOIDCProvider( protocol = ir.HTTP } + oidcProviderOwner := policyOwnerOr(owners.oidcProviderBackendRefs, policy) if len(provider.BackendRefs) > 0 { if rd, err = t.translateExtServiceBackendRefs( - policy, provider.BackendRefs, protocol, resources, gtwCtx, "oidc", 0); err != nil { + oidcProviderOwner, provider.BackendRefs, protocol, resources, gtwCtx, "oidc", 0); err != nil { return nil, err } } @@ -2021,12 +2057,14 @@ func validateTokenEndpoint(tokenEndpoint string) error { func (t *Translator) buildAPIKeyAuth( policy *egv1a1.SecurityPolicy, + owners *securityPolicyOwners, resources *resource.Resources, ) (*ir.APIKeyAuth, error) { + ownerPolicy := policyOwnerOr(owners.apiKeyAuthCredentialRefs, policy) from := crossNamespaceFrom{ group: egv1a1.GroupName, kind: resource.KindSecurityPolicy, - namespace: policy.Namespace, + namespace: ownerPolicy.Namespace, } expected := len(policy.Spec.APIKeyAuth.CredentialRefs) @@ -2077,6 +2115,7 @@ func (t *Translator) buildAPIKeyAuth( func (t *Translator) buildBasicAuth( policy *egv1a1.SecurityPolicy, + owners *securityPolicyOwners, resources *resource.Resources, ) (*ir.BasicAuth, error) { var ( @@ -2085,10 +2124,11 @@ func (t *Translator) buildBasicAuth( err error ) + ownerPolicy := policyOwnerOr(owners.basicAuth, policy) from := crossNamespaceFrom{ group: egv1a1.GroupName, kind: resource.KindSecurityPolicy, - namespace: policy.Namespace, + namespace: ownerPolicy.Namespace, } if usersSecret, err = t.validateSecretRef(true, from, basicAuth.Users, resources); err != nil { return nil, err @@ -2111,7 +2151,7 @@ func (t *Translator) buildBasicAuth( } return &ir.BasicAuth{ - Name: irConfigName(policy), + Name: irConfigName(ownerPolicy), Users: usersSecretBytes, ForwardUsernameHeader: basicAuth.ForwardUsernameHeader, }, nil @@ -2150,6 +2190,7 @@ func validateHtpasswdFormat(data []byte) error { func (t *Translator) buildExtAuth( policy *egv1a1.SecurityPolicy, + owners *securityPolicyOwners, resources *resource.Resources, gtwCtx *GatewayContext, ) (*ir.ExtAuth, error) { @@ -2166,6 +2207,8 @@ func (t *Translator) buildExtAuth( contextExtensions []*ir.ContextExtention ) + backendRefsOwnerPolicy := policyOwnerOr(owners.extAuthBackendRefs, policy) + // These are sanity checks, they should never happen because the API server // should have caught them if http == nil && grpc == nil { @@ -2210,7 +2253,7 @@ func (t *Translator) buildExtAuth( } if rd, err = t.translateExtServiceBackendRefs( - policy, backendRefs, protocol, resources, gtwCtx, "extauth", 0); err != nil { + backendRefsOwnerPolicy, backendRefs, protocol, resources, gtwCtx, "extauth", 0); err != nil { return nil, err } @@ -2220,7 +2263,7 @@ func (t *Translator) buildExtAuth( // When translated to XDS, the authority is used on the filter level not on the cluster level. // There's no way to translate to XDS and use a different authority for each backendref if authority == "" { - authority = t.backendRefAuthority(&backendRef.BackendObjectReference, policy) + authority = t.backendRefAuthority(&backendRef.BackendObjectReference, backendRefsOwnerPolicy) } } @@ -2228,12 +2271,13 @@ func (t *Translator) buildExtAuth( return nil, err } - if contextExtensions, err = t.buildContextExtensions(policy.Spec.ExtAuth.ContextExtensions, policy.Namespace); err != nil { + if contextExtensions, err = t.buildContextExtensions(policy.Spec.ExtAuth.ContextExtensions, owners, policy); err != nil { return nil, err } + extAuthOwner := policyOwnerOr(owners.extAuth, policy) extAuth := &ir.ExtAuth{ - Name: irConfigName(policy), + Name: irConfigName(extAuthOwner), HeadersToExtAuth: policy.Spec.ExtAuth.HeadersToExtAuth, ContextExtensions: contextExtensions, FailOpen: policy.Spec.ExtAuth.FailOpen, @@ -2284,7 +2328,8 @@ func parseExtAuthTimeout(timeout *gwapiv1.Duration) *metav1.Duration { func (t *Translator) buildContextExtensions( contextExtensions []*egv1a1.ContextExtension, - policyNs string, + owners *securityPolicyOwners, + defaultOwner *egv1a1.SecurityPolicy, ) ([]*ir.ContextExtention, error) { if len(contextExtensions) == 0 { return nil, nil @@ -2294,8 +2339,9 @@ func (t *Translator) buildContextExtensions( for _, ext := range contextExtensions { var value ir.PrivateBytes if ext.Type == egv1a1.ContextExtensionValueTypeValueRef { + ownerPolicy := policyOwnerOr(owners.extAuthContextExtensions[ext.Name], defaultOwner) var err error - if value, err = t.getContextExtensionValueFromRef(ext.ValueRef, policyNs); err != nil { + if value, err = t.getContextExtensionValueFromRef(ext.ValueRef, ownerPolicy.Namespace); err != nil { return nil, err } } else if ext.Value != nil { @@ -2382,7 +2428,10 @@ func (t *Translator) backendRefAuthority( return fmt.Sprintf("%s.%s", backendRef.Name, backendNamespace) } -func (t *Translator) buildAuthorization(policy *egv1a1.SecurityPolicy) (*ir.Authorization, error) { +func (t *Translator) buildAuthorization( + policy *egv1a1.SecurityPolicy, + owners *securityPolicyOwners, +) (*ir.Authorization, error) { var ( authorization = policy.Spec.Authorization irAuth = &ir.Authorization{} @@ -2390,6 +2439,8 @@ func (t *Translator) buildAuthorization(policy *egv1a1.SecurityPolicy) (*ir.Auth defaultAction = egv1a1.AuthorizationActionDeny ) + ownerPolicy := policyOwnerOr(owners.authorizationRules, policy) + if authorization.DefaultAction != nil { defaultAction = *authorization.DefaultAction } @@ -2416,7 +2467,7 @@ func (t *Translator) buildAuthorization(policy *egv1a1.SecurityPolicy) (*ir.Auth if rule.Name != nil && *rule.Name != "" { name = *rule.Name } else { - name = defaultAuthorizationRuleName(policy, i) + name = defaultAuthorizationRuleName(ownerPolicy, i) } irAuth.Rules = append(irAuth.Rules, &ir.AuthorizationRule{ Name: name, @@ -2516,13 +2567,120 @@ func defaultAuthorizationRuleName(policy *egv1a1.SecurityPolicy, index int) stri strconv.Itoa(index)) } +type securityPolicyOwners struct { + basicAuth *egv1a1.SecurityPolicy + apiKeyAuthCredentialRefs *egv1a1.SecurityPolicy + authorizationRules *egv1a1.SecurityPolicy + extAuth *egv1a1.SecurityPolicy + extAuthBackendRefs *egv1a1.SecurityPolicy + extAuthContextExtensions map[string]*egv1a1.SecurityPolicy + oidc *egv1a1.SecurityPolicy + oidcProviderBackendRefs *egv1a1.SecurityPolicy + oidcClientIDRef *egv1a1.SecurityPolicy + oidcClientSecret *egv1a1.SecurityPolicy + jwtProviders *egv1a1.SecurityPolicy +} + +// policyOwnerOr returns owner if non-nil, otherwise fallback. +// Used to resolve per-field owners from securityPolicyOwners: the owner is the policy +// that contributed the field (route overrides parent), falling back to the active policy +// when no merge occurred or the field was not set by either side. +func policyOwnerOr(owner, fallback *egv1a1.SecurityPolicy) *egv1a1.SecurityPolicy { + if owner != nil { + return owner + } + return fallback +} + // mergeSecurityPolicy merges a route-level SecurityPolicy with a parent (Gateway/Listener) SecurityPolicy. -func mergeSecurityPolicy(routePolicy, parentPolicy *egv1a1.SecurityPolicy) (*egv1a1.SecurityPolicy, error) { +func mergeSecurityPolicy(routePolicy, parentPolicy *egv1a1.SecurityPolicy) (*egv1a1.SecurityPolicy, *securityPolicyOwners, error) { if routePolicy.Spec.MergeType == nil || parentPolicy == nil { - return routePolicy, nil + return routePolicy, nil, nil + } + mergedPolicy, err := utils.Merge[*egv1a1.SecurityPolicy](parentPolicy, routePolicy, *routePolicy.Spec.MergeType) + if err != nil { + return nil, nil, err } + return mergedPolicy, buildSecurityPolicyOwners(routePolicy, parentPolicy), nil +} - return utils.Merge(parentPolicy, routePolicy, *routePolicy.Spec.MergeType) +// ownerOf returns route if routeOwns(route) is true, otherwise parent. +// Use this when ownership of a merged field is determined by a single predicate. +func ownerOf( + route, parent *egv1a1.SecurityPolicy, + routeOwns func(*egv1a1.SecurityPolicy) bool, +) *egv1a1.SecurityPolicy { + if routeOwns(route) { + return route + } + return parent +} + +// buildSecurityPolicyOwners determines, for each merged field, which policy +// (route or parent) is considered the owner. The owner is used later to resolve +// references (e.g. Secrets, BackendRefs) scoped to the owning policy's namespace, +// and to derive IR resource names tied to the owning policy. +func buildSecurityPolicyOwners(route, parent *egv1a1.SecurityPolicy) *securityPolicyOwners { + return &securityPolicyOwners{ + basicAuth: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.BasicAuth != nil + }), + apiKeyAuthCredentialRefs: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.APIKeyAuth != nil && len(p.Spec.APIKeyAuth.CredentialRefs) > 0 + }), + authorizationRules: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.Authorization != nil && len(p.Spec.Authorization.Rules) > 0 + }), + extAuth: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.ExtAuth != nil + }), + extAuthBackendRefs: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + ea := p.Spec.ExtAuth + if ea == nil { + return false + } + if ea.HTTP != nil && (len(ea.HTTP.BackendRefs) > 0 || ea.HTTP.BackendRef != nil) { + return true + } + if ea.GRPC != nil && (len(ea.GRPC.BackendRefs) > 0 || ea.GRPC.BackendRef != nil) { + return true + } + return false + }), + extAuthContextExtensions: buildExtAuthContextExtensionOwners(route, parent), + oidc: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.OIDC != nil + }), + oidcProviderBackendRefs: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.OIDC != nil && len(p.Spec.OIDC.Provider.BackendRefs) > 0 + }), + oidcClientIDRef: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.OIDC != nil && p.Spec.OIDC.ClientIDRef != nil + }), + oidcClientSecret: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.OIDC != nil + }), + jwtProviders: ownerOf(route, parent, func(p *egv1a1.SecurityPolicy) bool { + return p.Spec.JWT != nil && len(p.Spec.JWT.Providers) > 0 + }), + } +} + +// buildExtAuthContextExtensionOwners returns a per-key owner map for ExtAuth ContextExtensions. +// Parent keys are added first so that route-level extensions take precedence on conflict. +func buildExtAuthContextExtensionOwners(route, parent *egv1a1.SecurityPolicy) map[string]*egv1a1.SecurityPolicy { + owners := make(map[string]*egv1a1.SecurityPolicy) + if parent.Spec.ExtAuth != nil { + for _, ext := range parent.Spec.ExtAuth.ContextExtensions { + owners[ext.Name] = parent + } + } + if route.Spec.ExtAuth != nil { + for _, ext := range route.Spec.ExtAuth.ContextExtensions { + owners[ext.Name] = route + } + } + return owners } // securityPolicyCopiesWithStatusDeepCopy returns shallow copies with deep-copied Status fields. diff --git a/internal/gatewayapi/securitypolicy_test.go b/internal/gatewayapi/securitypolicy_test.go index 5ef480a1cb..189db2ff32 100644 --- a/internal/gatewayapi/securitypolicy_test.go +++ b/internal/gatewayapi/securitypolicy_test.go @@ -1421,9 +1421,14 @@ func Test_validateAuthorizationGeoIPForHTTP(t *testing.T) { func Test_buildContextExtensions(t *testing.T) { policyNs := "default" + defaultOwner := &egv1a1.SecurityPolicy{ + ObjectMeta: metav1.ObjectMeta{Namespace: policyNs}, + } tests := []struct { name string contextExtensions []*egv1a1.ContextExtension + owners *securityPolicyOwners + defaultOwner *egv1a1.SecurityPolicy translatorContext *TranslatorContext want []*ir.ContextExtention wantErr bool @@ -1431,11 +1436,13 @@ func Test_buildContextExtensions(t *testing.T) { { name: "Nil", contextExtensions: nil, + owners: &securityPolicyOwners{}, want: nil, }, { name: "Empty", contextExtensions: []*egv1a1.ContextExtension{}, + owners: &securityPolicyOwners{}, want: nil, }, { @@ -1443,11 +1450,13 @@ func Test_buildContextExtensions(t *testing.T) { contextExtensions: []*egv1a1.ContextExtension{ {Name: "foo", Value: new("bar")}, }, - want: []*ir.ContextExtention{{Name: "foo", Value: ir.PrivateBytes("bar")}}, + owners: &securityPolicyOwners{}, + want: []*ir.ContextExtention{{Name: "foo", Value: ir.PrivateBytes("bar")}}, }, { name: "TypeValueEmpty", contextExtensions: []*egv1a1.ContextExtension{{Name: "foo"}}, + owners: &securityPolicyOwners{}, want: []*ir.ContextExtention{{Name: "foo", Value: nil}}, }, { @@ -1459,13 +1468,15 @@ func Test_buildContextExtensions(t *testing.T) { Value: new("bar"), }, }, - want: []*ir.ContextExtention{{Name: "foo", Value: ir.PrivateBytes("bar")}}, + owners: &securityPolicyOwners{}, + want: []*ir.ContextExtention{{Name: "foo", Value: ir.PrivateBytes("bar")}}, }, { name: "TypeValueRefNil", contextExtensions: []*egv1a1.ContextExtension{ {Name: "foo", Type: egv1a1.ContextExtensionValueTypeValueRef}, }, + owners: &securityPolicyOwners{}, wantErr: true, }, { @@ -1481,6 +1492,7 @@ func Test_buildContextExtensions(t *testing.T) { Key: "test-key", }, }}, + owners: &securityPolicyOwners{}, translatorContext: &TranslatorContext{}, wantErr: true, }, @@ -1497,6 +1509,7 @@ func Test_buildContextExtensions(t *testing.T) { Key: "test-key", }, }}, + owners: &securityPolicyOwners{}, translatorContext: &TranslatorContext{ ConfigMapMap: map[types.NamespacedName]*corev1.ConfigMap{ {Namespace: policyNs, Name: "test-cm"}: {}, @@ -1517,6 +1530,7 @@ func Test_buildContextExtensions(t *testing.T) { Key: "test-key", }, }}, + owners: &securityPolicyOwners{}, translatorContext: &TranslatorContext{ ConfigMapMap: map[types.NamespacedName]*corev1.ConfigMap{ {Namespace: policyNs, Name: "test-cm"}: { @@ -1526,6 +1540,56 @@ func Test_buildContextExtensions(t *testing.T) { }, want: []*ir.ContextExtention{{Name: "foo", Value: ir.PrivateBytes("bar")}}, }, + { + name: "TypeValueRefUsesPerKeyOwnerNamespace", + contextExtensions: []*egv1a1.ContextExtension{ + { + Name: "parent-only", + Type: egv1a1.ContextExtensionValueTypeValueRef, + ValueRef: &egv1a1.LocalObjectKeyReference{ + LocalObjectReference: gwapiv1.LocalObjectReference{ + Kind: resource.KindConfigMap, + Name: "parent-cm", + }, + Key: "test-key", + }, + }, + { + Name: "route-only", + Type: egv1a1.ContextExtensionValueTypeValueRef, + ValueRef: &egv1a1.LocalObjectKeyReference{ + LocalObjectReference: gwapiv1.LocalObjectReference{ + Kind: resource.KindConfigMap, + Name: "route-cm", + }, + Key: "test-key", + }, + }, + }, + owners: &securityPolicyOwners{ + extAuthContextExtensions: map[string]*egv1a1.SecurityPolicy{ + "parent-only": {ObjectMeta: metav1.ObjectMeta{Namespace: "parent-ns"}}, + "route-only": {ObjectMeta: metav1.ObjectMeta{Namespace: "route-ns"}}, + }, + }, + defaultOwner: &egv1a1.SecurityPolicy{ + ObjectMeta: metav1.ObjectMeta{Namespace: "default-ns"}, + }, + translatorContext: &TranslatorContext{ + ConfigMapMap: map[types.NamespacedName]*corev1.ConfigMap{ + {Namespace: "parent-ns", Name: "parent-cm"}: { + Data: map[string]string{"test-key": "parent-bar"}, + }, + {Namespace: "route-ns", Name: "route-cm"}: { + Data: map[string]string{"test-key": "route-bar"}, + }, + }, + }, + want: []*ir.ContextExtention{ + {Name: "parent-only", Value: ir.PrivateBytes("parent-bar")}, + {Name: "route-only", Value: ir.PrivateBytes("route-bar")}, + }, + }, { name: "TypeValueRefSecretNotFound", contextExtensions: []*egv1a1.ContextExtension{{ @@ -1539,6 +1603,7 @@ func Test_buildContextExtensions(t *testing.T) { Key: "test-key", }, }}, + owners: &securityPolicyOwners{}, translatorContext: &TranslatorContext{}, wantErr: true, }, @@ -1555,6 +1620,7 @@ func Test_buildContextExtensions(t *testing.T) { Key: "test-key", }, }}, + owners: &securityPolicyOwners{}, translatorContext: &TranslatorContext{ SecretMap: map[types.NamespacedName]*corev1.Secret{ {Namespace: policyNs, Name: "test-secret"}: {}, @@ -1575,6 +1641,7 @@ func Test_buildContextExtensions(t *testing.T) { Key: "test-key", }, }}, + owners: &securityPolicyOwners{}, translatorContext: &TranslatorContext{ SecretMap: map[types.NamespacedName]*corev1.Secret{ {Namespace: policyNs, Name: "test-secret"}: { @@ -1597,13 +1664,18 @@ func Test_buildContextExtensions(t *testing.T) { Key: "test-key", }, }}, + owners: &securityPolicyOwners{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { translator := &Translator{TranslatorContext: tt.translatorContext} - got, err := translator.buildContextExtensions(tt.contextExtensions, policyNs) + owner := tt.defaultOwner + if owner == nil { + owner = defaultOwner + } + got, err := translator.buildContextExtensions(tt.contextExtensions, tt.owners, owner) if tt.wantErr { require.Error(t, err) require.Nil(t, got) @@ -1834,7 +1906,7 @@ func TestMergeSecurityPolicy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := mergeSecurityPolicy(tt.routePolicy, tt.parentPolicy) + got, _, err := mergeSecurityPolicy(tt.routePolicy, tt.parentPolicy) if (err != nil) != tt.wantErr { t.Errorf("mergeSecurityPolicy() error = %v, wantErr %v", err, tt.wantErr) return @@ -1850,3 +1922,142 @@ func TestMergeSecurityPolicy(t *testing.T) { }) } } + +func Test_securityPolicyOwnerChoose(t *testing.T) { + t.Run("route policy overrides parent for the same owner fields", func(t *testing.T) { + parentPolicy := &egv1a1.SecurityPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "parent", Namespace: "parent-ns"}, + Spec: egv1a1.SecurityPolicySpec{ + BasicAuth: &egv1a1.BasicAuth{ + Users: gwapiv1.SecretObjectReference{Name: "parent-users"}, + }, + APIKeyAuth: &egv1a1.APIKeyAuth{ + CredentialRefs: []gwapiv1.SecretObjectReference{{Name: "parent-cred"}}, + }, + Authorization: &egv1a1.Authorization{ + Rules: []egv1a1.AuthorizationRule{{Name: new("parent-rule")}}, + }, + ExtAuth: &egv1a1.ExtAuth{ + HTTP: &egv1a1.HTTPExtAuthService{ + BackendCluster: egv1a1.BackendCluster{ + BackendRefs: []egv1a1.BackendRef{{ + BackendObjectReference: gwapiv1.BackendObjectReference{Name: "parent-http-backend-refs"}, + }}, + }, + }, + ContextExtensions: []*egv1a1.ContextExtension{ + {Name: "shared", Type: egv1a1.ContextExtensionValueTypeValue, Value: new("parent-shared")}, + {Name: "parent-only", Type: egv1a1.ContextExtensionValueTypeValue, Value: new("parent-only")}, + }, + }, + OIDC: &egv1a1.OIDC{ + ClientSecret: gwapiv1.SecretObjectReference{Name: "parent-client-secret"}, + ClientIDRef: &gwapiv1.SecretObjectReference{Name: "parent-client-id"}, + Provider: egv1a1.OIDCProvider{ + Issuer: "https://parent.example.com", + BackendCluster: egv1a1.BackendCluster{ + BackendRefs: []egv1a1.BackendRef{{ + BackendObjectReference: gwapiv1.BackendObjectReference{Name: "parent-oidc-provider"}, + }}, + }, + }, + }, + JWT: &egv1a1.JWT{ + Providers: []egv1a1.JWTProvider{{Name: "parent-jwt-provider"}}, + }, + }, + } + + routePolicy := &egv1a1.SecurityPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "route", Namespace: "route-ns"}, + Spec: egv1a1.SecurityPolicySpec{ + MergeType: new(egv1a1.StrategicMerge), + BasicAuth: &egv1a1.BasicAuth{ + Users: gwapiv1.SecretObjectReference{Name: "route-users"}, + }, + APIKeyAuth: &egv1a1.APIKeyAuth{ + CredentialRefs: []gwapiv1.SecretObjectReference{{Name: "route-cred"}}, + }, + Authorization: &egv1a1.Authorization{ + Rules: []egv1a1.AuthorizationRule{{Name: new("route-rule")}}, + }, + ExtAuth: &egv1a1.ExtAuth{ + HTTP: &egv1a1.HTTPExtAuthService{ + BackendCluster: egv1a1.BackendCluster{ + BackendRefs: []egv1a1.BackendRef{{ + BackendObjectReference: gwapiv1.BackendObjectReference{Name: "route-http-backend-refs"}, + }}, + }, + }, + ContextExtensions: []*egv1a1.ContextExtension{ + {Name: "shared", Type: egv1a1.ContextExtensionValueTypeValue, Value: new("route-shared")}, + {Name: "route-only", Type: egv1a1.ContextExtensionValueTypeValue, Value: new("route-only")}, + }, + }, + OIDC: &egv1a1.OIDC{ + ClientSecret: gwapiv1.SecretObjectReference{Name: "route-client-secret"}, + ClientIDRef: &gwapiv1.SecretObjectReference{Name: "route-client-id"}, + Provider: egv1a1.OIDCProvider{ + Issuer: "https://route.example.com", + BackendCluster: egv1a1.BackendCluster{ + BackendRefs: []egv1a1.BackendRef{{ + BackendObjectReference: gwapiv1.BackendObjectReference{Name: "route-oidc-provider"}, + }}, + }, + }, + }, + JWT: &egv1a1.JWT{ + Providers: []egv1a1.JWTProvider{{Name: "route-jwt-provider"}}, + }, + }, + } + + _, owners, err := mergeSecurityPolicy(routePolicy, parentPolicy) + require.NoError(t, err) + require.NotNil(t, owners) + + assert.Same(t, routePolicy, owners.basicAuth) + assert.Same(t, routePolicy, owners.apiKeyAuthCredentialRefs) + assert.Same(t, routePolicy, owners.authorizationRules) + assert.Same(t, routePolicy, owners.extAuth) + assert.Same(t, routePolicy, owners.extAuthBackendRefs) + assert.Same(t, routePolicy, owners.oidc) + assert.Same(t, routePolicy, owners.oidcClientIDRef) + assert.Same(t, routePolicy, owners.oidcClientSecret) + assert.Same(t, routePolicy, owners.oidcProviderBackendRefs) + assert.Same(t, routePolicy, owners.jwtProviders) + assert.Same(t, routePolicy, owners.extAuthContextExtensions["shared"]) + assert.Same(t, routePolicy, owners.extAuthContextExtensions["route-only"]) + assert.Same(t, parentPolicy, owners.extAuthContextExtensions["parent-only"]) + }) + + t.Run("uses parent owner for grpc backend fields when route does not set them", func(t *testing.T) { + parentPolicy := &egv1a1.SecurityPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "parent", Namespace: "parent-ns"}, + Spec: egv1a1.SecurityPolicySpec{ + MergeType: new(egv1a1.StrategicMerge), + ExtAuth: &egv1a1.ExtAuth{ + GRPC: &egv1a1.GRPCExtAuthService{ + BackendCluster: egv1a1.BackendCluster{ + BackendRefs: []egv1a1.BackendRef{{ + BackendObjectReference: gwapiv1.BackendObjectReference{Name: "parent-grpc-backend-refs"}, + }}, + }, + }, + }, + }, + } + + routePolicy := &egv1a1.SecurityPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "route", Namespace: "route-ns"}, + Spec: egv1a1.SecurityPolicySpec{MergeType: new(egv1a1.StrategicMerge)}, + } + + _, owners, err := mergeSecurityPolicy(routePolicy, parentPolicy) + require.NoError(t, err) + require.NotNil(t, owners) + + assert.Same(t, parentPolicy, owners.extAuth) + assert.Same(t, parentPolicy, owners.extAuthBackendRefs) + }) +} diff --git a/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-gateway-same-listener.in.yaml b/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-gateway-same-listener.in.yaml index e13c11c4b5..ee8b0bb9d9 100644 --- a/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-gateway-same-listener.in.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-gateway-same-listener.in.yaml @@ -108,20 +108,6 @@ services: - port: 9001 name: http protocol: TCP -referenceGrants: -- apiVersion: gateway.networking.k8s.io/v1alpha2 - kind: ReferenceGrant - metadata: - namespace: envoy-gateway - name: allow-securitypolicy-to-auth-service - spec: - from: - - group: gateway.envoyproxy.io - kind: SecurityPolicy - namespace: default - to: - - group: "" - kind: Service endpointSlices: - apiVersion: discovery.k8s.io/v1 kind: EndpointSlice @@ -149,11 +135,3 @@ secrets: type: Opaque data: .htpasswd: dXNlcjE6e1NIQX15LzJzWUFqNXlyUUlONFRMMFlkUGRtR05LcGM9 -- apiVersion: v1 - kind: Secret - metadata: - namespace: default - name: users-secret - type: Opaque - data: - .htpasswd: dXNlcjE6e1NIQX15LzJzWUFqNXlyUUlONFRMMFlkUGRtR05LcGM9 diff --git a/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-gateway-same-listener.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-gateway-same-listener.out.yaml index 96bfbf8a65..90fae2f530 100644 --- a/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-gateway-same-listener.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-gateway-same-listener.out.yaml @@ -372,7 +372,7 @@ xdsIR: prefix: /foo security: basicAuth: - name: securitypolicy/default/policy-for-route + name: securitypolicy/envoy-gateway/policy-for-gateway-1 users: '[redacted]' cors: allowMethods: @@ -473,9 +473,9 @@ xdsIR: destination: metadata: kind: SecurityPolicy - name: policy-for-route - namespace: default - name: securitypolicy/default/policy-for-route/extauth/0 + name: policy-for-gateway-2 + namespace: envoy-gateway + name: securitypolicy/envoy-gateway/policy-for-gateway-2/extauth/0 settings: - addressType: IP endpoints: @@ -486,11 +486,11 @@ xdsIR: name: auth-service namespace: envoy-gateway sectionName: "9001" - name: securitypolicy/default/policy-for-route/extauth/0/backend/0 + name: securitypolicy/envoy-gateway/policy-for-gateway-2/extauth/0/backend/0 protocol: HTTP weight: 1 path: "" - name: securitypolicy/default/policy-for-route + name: securitypolicy/envoy-gateway/policy-for-gateway-2 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-listener.in.yaml b/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-listener.in.yaml index 5dc3bb2a76..4b1592dfc3 100644 --- a/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-listener.in.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-listener.in.yaml @@ -104,20 +104,6 @@ services: - port: 9001 name: http protocol: TCP -referenceGrants: -- apiVersion: gateway.networking.k8s.io/v1alpha2 - kind: ReferenceGrant - metadata: - namespace: envoy-gateway - name: allow-securitypolicy-to-auth-service - spec: - from: - - group: gateway.envoyproxy.io - kind: SecurityPolicy - namespace: default - to: - - group: "" - kind: Service endpointSlices: - apiVersion: discovery.k8s.io/v1 kind: EndpointSlice @@ -145,11 +131,3 @@ secrets: type: Opaque data: .htpasswd: dXNlcjE6e1NIQX15LzJzWUFqNXlyUUlONFRMMFlkUGRtR05LcGM9 -- apiVersion: v1 - kind: Secret - metadata: - namespace: default - name: users-secret-a - type: Opaque - data: - .htpasswd: dXNlcjE6e1NIQX15LzJzWUFqNXlyUUlONFRMMFlkUGRtR05LcGM9 diff --git a/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-listener.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-listener.out.yaml index 19999e159b..5c344fd5ea 100644 --- a/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-listener.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-with-merge-multi-listener.out.yaml @@ -350,7 +350,7 @@ xdsIR: prefix: /foo security: basicAuth: - name: securitypolicy/default/policy-for-route + name: securitypolicy/envoy-gateway/policy-for-listener-a users: '[redacted]' cors: allowMethods: @@ -420,9 +420,9 @@ xdsIR: destination: metadata: kind: SecurityPolicy - name: policy-for-route - namespace: default - name: securitypolicy/default/policy-for-route/extauth/0 + name: policy-for-listener-b + namespace: envoy-gateway + name: securitypolicy/envoy-gateway/policy-for-listener-b/extauth/0 settings: - addressType: IP endpoints: @@ -433,11 +433,11 @@ xdsIR: name: auth-service namespace: envoy-gateway sectionName: "9001" - name: securitypolicy/default/policy-for-route/extauth/0/backend/0 + name: securitypolicy/envoy-gateway/policy-for-listener-b/extauth/0/backend/0 protocol: HTTP weight: 1 path: "" - name: securitypolicy/default/policy-for-route + name: securitypolicy/envoy-gateway/policy-for-listener-b readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/securitypolicy-with-merge-needs-fieldowner.in.yaml b/internal/gatewayapi/testdata/securitypolicy-with-merge-needs-fieldowner.in.yaml new file mode 100644 index 0000000000..691512bb28 --- /dev/null +++ b/internal/gatewayapi/testdata/securitypolicy-with-merge-needs-fieldowner.in.yaml @@ -0,0 +1,231 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/foo" + backendRefs: + - name: service-1 + port: 8080 +services: +- apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: grpc-backend + spec: + ports: + - port: 9000 + name: grpc + protocol: TCP +- apiVersion: v1 + kind: Service + metadata: + namespace: default + name: grpc-backend + spec: + ports: + - port: 9000 + name: grpc + protocol: TCP +endpointSlices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: endpointslice-grpc-backend + labels: + kubernetes.io/service-name: grpc-backend + addressType: IPv4 + ports: + - name: grpc + protocol: TCP + port: 9000 + endpoints: + - addresses: + - 8.8.8.8 + conditions: + ready: true +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: default + name: endpointslice-grpc-backend + labels: + kubernetes.io/service-name: grpc-backend + addressType: IPv4 + ports: + - name: grpc + protocol: TCP + port: 9000 + endpoints: + - addresses: + - 9.9.9.9 + conditions: + ready: true +securityPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: SecurityPolicy + metadata: + namespace: envoy-gateway + name: policy-for-gateway + # check: oidc suffix value [c3556d06] + uid: "aaaaaaaa-0000-0000-0000-000000000001" + spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + sectionName: http + # merge basicAuth check: + # - can resolve auth secret in parent ns (envoy-gateway) + basicAuth: + users: + name: users-secret + # merge extAuth check: + # - can resolve backendRef in parent ns (envoy-gateway) + # - merge contextExtensions by name and resolve each item from its owning policy namespace + extAuth: + grpc: + backendRefs: + - name: grpc-backend + port: 9000 + contextExtensions: + - name: shared + type: ValueRef + valueRef: + Group: "" + Kind: ConfigMap + Name: context-extension-for-gateway + key: data-shared + - name: parent-only + type: ValueRef + valueRef: + Group: "" + Kind: ConfigMap + Name: context-extension-for-gateway + key: data + # merge oidc check: + # - can resolve provider backendRef in parent ns (envoy-gateway) + # - can resolve client secret in parent ns (envoy-gateway) + oidc: + provider: + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-ip + port: 3000 + issuer: "https://oauth.foo.com" + authorizationEndpoint: "https://oauth.foo.com/oauth2/v2/auth" + tokenEndpoint: "https://oauth.foo.com/token" + clientID: "client1.apps.googleusercontent.com" + clientSecret: + name: "client-secret" +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: SecurityPolicy + metadata: + namespace: default + name: policy-for-route + # check: oidc suffix value [6ac6170b] + uid: "bbbbbbbb-0000-0000-0000-000000000002" + spec: + mergeType: StrategicMerge + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + extAuth: + grpc: + backendRefs: + - name: grpc-backend + port: 9000 + contextExtensions: + - name: shared + type: ValueRef + valueRef: + Group: "" + Kind: ConfigMap + Name: context-extension-for-route + key: data-shared + - name: route-only + type: ValueRef + valueRef: + Group: "" + Kind: ConfigMap + Name: context-extension-for-route + key: data +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + namespace: envoy-gateway + name: backend-ip + spec: + endpoints: + - ip: + address: 7.7.7.7 + port: 3000 +secrets: +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: users-secret + type: Opaque + data: + .htpasswd: dXNlcjE6e1NIQX15LzJzWUFqNXlyUUlONFRMMFlkUGRtR05LcGM9 +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: client-secret + data: + client-secret: Y2xpZW50MTpzZWNyZXQK +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway-system + name: envoy-oidc-hmac + data: + hmac-secret: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY= +configmaps: +- apiVersion: v1 + kind: ConfigMap + metadata: + namespace: envoy-gateway + name: context-extension-for-gateway + data: + data-shared: test-key-gateway + data: test-key-gateway +- apiVersion: v1 + kind: ConfigMap + metadata: + namespace: default + name: context-extension-for-route + data: + data-shared: test-key-route + data: test-key-route diff --git a/internal/gatewayapi/testdata/securitypolicy-with-merge-needs-fieldowner.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-merge-needs-fieldowner.out.yaml new file mode 100644 index 0000000000..6abe6abfb9 --- /dev/null +++ b/internal/gatewayapi/testdata/securitypolicy-with-merge-needs-fieldowner.out.yaml @@ -0,0 +1,379 @@ +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + name: backend-ip + namespace: envoy-gateway + spec: + endpoints: + - ip: + address: 7.7.7.7 + port: 3000 + status: + conditions: + - lastTransitionTime: null + message: The Backend was accepted + reason: Accepted + status: "True" + type: Accepted +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: /foo + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +securityPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: SecurityPolicy + metadata: + name: policy-for-route + namespace: default + uid: bbbbbbbb-0000-0000-0000-000000000002 + spec: + extAuth: + contextExtensions: + - name: shared + type: ValueRef + valueRef: + group: "" + key: data-shared + kind: ConfigMap + name: context-extension-for-route + - name: route-only + type: ValueRef + valueRef: + group: "" + key: data + kind: ConfigMap + name: context-extension-for-route + grpc: + backendRefs: + - name: grpc-backend + port: 9000 + mergeType: StrategicMerge + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Merged with policy envoy-gateway/policy-for-gateway + reason: Merged + status: "True" + type: Merged + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: SecurityPolicy + metadata: + name: policy-for-gateway + namespace: envoy-gateway + uid: aaaaaaaa-0000-0000-0000-000000000001 + spec: + basicAuth: + users: + name: users-secret + extAuth: + contextExtensions: + - name: shared + type: ValueRef + valueRef: + group: "" + key: data-shared + kind: ConfigMap + name: context-extension-for-gateway + - name: parent-only + type: ValueRef + valueRef: + group: "" + key: data + kind: ConfigMap + name: context-extension-for-gateway + grpc: + backendRefs: + - name: grpc-backend + port: 9000 + oidc: + clientID: client1.apps.googleusercontent.com + clientSecret: + name: client-secret + provider: + authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-ip + port: 3000 + issuer: https://oauth.foo.com + tokenEndpoint: https://oauth.foo.com/token + targetRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + sectionName: http + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: 'This policy is being merged by other securityPolicies for these + routes: [default/httproute-1]' + reason: Merged + status: "True" + type: Merged + controllerName: gateway.envoyproxy.io/gatewayclass-controller +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/* + pathMatch: + distinct: false + name: "" + prefix: /foo + security: + basicAuth: + name: securitypolicy/envoy-gateway/policy-for-gateway + users: '[redacted]' + extAuth: + contextExtensions: + - name: shared + value: '[redacted]' + - name: route-only + value: '[redacted]' + - name: parent-only + value: '[redacted]' + grpc: + authority: grpc-backend.default:9000 + destination: + metadata: + kind: SecurityPolicy + name: policy-for-route + namespace: default + name: securitypolicy/default/policy-for-route/extauth/0 + settings: + - addressType: IP + endpoints: + - host: 9.9.9.9 + port: 9000 + metadata: + kind: Service + name: grpc-backend + namespace: default + sectionName: "9000" + name: securitypolicy/default/policy-for-route/extauth/0/backend/0 + protocol: GRPC + weight: 1 + name: securitypolicy/default/policy-for-route + oidc: + clientID: client1.apps.googleusercontent.com + clientSecret: '[redacted]' + cookieSuffix: c3556d06 + hmacSecret: '[redacted]' + logoutPath: /logout + name: securitypolicy/envoy-gateway/policy-for-gateway + provider: + authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth + destination: + metadata: + kind: SecurityPolicy + name: policy-for-gateway + namespace: envoy-gateway + name: securitypolicy/envoy-gateway/policy-for-gateway/oidc/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 3000 + metadata: + kind: Backend + name: backend-ip + namespace: envoy-gateway + name: securitypolicy/envoy-gateway/policy-for-gateway/oidc/0/backend/0 + protocol: HTTPS + weight: 1 + tokenEndpoint: https://oauth.foo.com/token + redirectPath: /oauth2/callback + redirectURL: '%REQ(x-forwarded-proto)%://%REQ(:authority)%/oauth2/callback' + refreshToken: true + scopes: + - openid + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/securitypolicy-with-merge.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-merge.out.yaml index ee2655e8a0..b155bfe2ed 100644 --- a/internal/gatewayapi/testdata/securitypolicy-with-merge.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-with-merge.out.yaml @@ -242,7 +242,7 @@ xdsIR: prefix: /foo security: basicAuth: - name: securitypolicy/default/policy-for-route + name: securitypolicy/envoy-gateway/policy-for-gateway users: '[redacted]' cors: allowHeaders: diff --git a/internal/utils/merge_test.go b/internal/utils/merge_test.go index 73f6a584c9..2c91e27bcd 100644 --- a/internal/utils/merge_test.go +++ b/internal/utils/merge_test.go @@ -19,41 +19,55 @@ import ( "github.com/envoyproxy/gateway/internal/utils/test" ) -func TestMergeBackendTrafficPolicy(t *testing.T) { +func TestMergePolicy(t *testing.T) { baseDir := "testdata" - caseFiles, err := filepath.Glob(filepath.Join(baseDir, "backendtrafficpolicy_*.in.yaml")) + caseFiles, err := filepath.Glob(filepath.Join(baseDir, "*policy_*.in.yaml")) require.NoError(t, err) for _, caseFile := range caseFiles { - // get case name from path - caseName := strings.TrimPrefix(strings.TrimSuffix(caseFile, ".in.yaml"), baseDir+"/backendtrafficpolicy_") + caseName := strings.TrimPrefix(strings.TrimSuffix(caseFile, ".in.yaml"), baseDir+"/") + policyType := strings.SplitN(caseName, "_", 2)[0] + t.Run(caseName, func(t *testing.T) { - for _, mergeType := range []egv1a1.MergeType{egv1a1.StrategicMerge, egv1a1.JSONMerge} { - patchedInput := strings.Replace(caseFile, ".in.yaml", ".patch.yaml", 1) - var output string - if mergeType == egv1a1.StrategicMerge { - output = strings.Replace(caseFile, ".in.yaml", ".strategicmerge.out.yaml", 1) - } else { - output = strings.Replace(caseFile, ".in.yaml", ".jsonmerge.out.yaml", 1) - } + switch policyType { + case "backendtrafficpolicy": + runMergePolicyTest[*egv1a1.BackendTrafficPolicy](t, caseFile) + case "securitypolicy": + runMergePolicyTest[*egv1a1.SecurityPolicy](t, caseFile) + default: + t.Fatalf("unsupported policy type %q in %s", policyType, caseFile) + } + }) + } +} - original := readObject[*egv1a1.BackendTrafficPolicy](t, caseFile) - patch := readObject[*egv1a1.BackendTrafficPolicy](t, patchedInput) +func runMergePolicyTest[T client.Object](t *testing.T, caseFile string) { + t.Helper() - got, err := Merge(original, patch, mergeType) - require.NoError(t, err) + for _, mergeType := range []egv1a1.MergeType{egv1a1.StrategicMerge, egv1a1.JSONMerge} { + patchedInput := strings.Replace(caseFile, ".in.yaml", ".patch.yaml", 1) + var output string + if mergeType == egv1a1.StrategicMerge { + output = strings.Replace(caseFile, ".in.yaml", ".strategicmerge.out.yaml", 1) + } else { + output = strings.Replace(caseFile, ".in.yaml", ".jsonmerge.out.yaml", 1) + } - if test.OverrideTestData() { - b, err := yaml.Marshal(got) - require.NoError(t, err) - require.NoError(t, os.WriteFile(output, b, 0o600)) - continue - } + original := readObject[T](t, caseFile) + patch := readObject[T](t, patchedInput) - expected := readObject[*egv1a1.BackendTrafficPolicy](t, output) - require.Equal(t, expected, got) - } - }) + got, err := Merge(original, patch, mergeType) + require.NoError(t, err) + + if test.OverrideTestData() { + b, err := yaml.Marshal(got) + require.NoError(t, err) + require.NoError(t, os.WriteFile(output, b, 0o600)) + continue + } + + expected := readObject[T](t, output) + require.Equal(t, expected, got) } } diff --git a/internal/utils/testdata/securitypolicy_all.in.yaml b/internal/utils/testdata/securitypolicy_all.in.yaml new file mode 100644 index 0000000000..2524a7a0f9 --- /dev/null +++ b/internal/utils/testdata/securitypolicy_all.in.yaml @@ -0,0 +1,49 @@ +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: original +spec: + basicAuth: + users: + name: users-parent + apiKeyAuth: + credentialRefs: + - name: api-keys-parent + authorization: + rules: + - name: parent-rule + action: Allow + principal: + headers: + - name: x-role + values: + - parent + extAuth: + http: + backendRefs: + - name: ext-auth-parent + port: 9001 + contextExtensions: + - name: shared + type: Value + value: parent + - name: parent-only + type: Value + value: parent-only + oidc: + provider: + issuer: https://oidc.parent.example.com + backendRefs: + - name: oidc-parent + port: 443 + clientIDRef: + name: oidc-client-id-parent + clientSecret: + name: oidc-client-secret-parent + jwt: + providers: + - name: jwt-parent + issuer: https://issuer.parent.example.com + localJWKS: + type: Inline + inline: "{}" diff --git a/internal/utils/testdata/securitypolicy_all.jsonmerge.out.yaml b/internal/utils/testdata/securitypolicy_all.jsonmerge.out.yaml new file mode 100644 index 0000000000..eeb4cb0d16 --- /dev/null +++ b/internal/utils/testdata/securitypolicy_all.jsonmerge.out.yaml @@ -0,0 +1,58 @@ +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: patched +spec: + apiKeyAuth: + credentialRefs: + - name: api-keys-route + extractFrom: null + sanitize: true + authorization: + defaultAction: null + rules: + - action: Deny + name: route-rule + principal: + headers: + - name: x-role + values: + - route + basicAuth: + users: + name: users-route + extAuth: + contextExtensions: + - name: shared + type: Value + value: route + - name: route-only + type: Value + value: route-only + grpc: + backendRefs: + - name: ext-auth-route + port: 9002 + http: + backendRefs: + - name: ext-auth-parent + port: 9001 + jwt: + providers: + - issuer: https://issuer.route.example.com + localJWKS: + inline: '{}' + type: Inline + name: jwt-route + oidc: + clientIDRef: + name: oidc-client-id-route + clientSecret: + name: oidc-client-secret-route + provider: + backendRefs: + - name: oidc-route + port: 8443 + issuer: "" +status: + ancestors: null diff --git a/internal/utils/testdata/securitypolicy_all.patch.yaml b/internal/utils/testdata/securitypolicy_all.patch.yaml new file mode 100644 index 0000000000..fcee7aca7d --- /dev/null +++ b/internal/utils/testdata/securitypolicy_all.patch.yaml @@ -0,0 +1,50 @@ +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: patched +spec: + basicAuth: + users: + name: users-route + apiKeyAuth: + credentialRefs: + - name: api-keys-route + sanitize: true + authorization: + rules: + - name: route-rule + action: Deny + principal: + headers: + - name: x-role + values: + - route + extAuth: + grpc: + backendRefs: + - name: ext-auth-route + port: 9002 + # arrays all replace + contextExtensions: + - name: shared + type: Value + value: route + - name: route-only + type: Value + value: route-only + oidc: + provider: + backendRefs: + - name: oidc-route + port: 8443 + clientIDRef: + name: oidc-client-id-route + clientSecret: + name: oidc-client-secret-route + jwt: + providers: + - name: jwt-route + issuer: https://issuer.route.example.com + localJWKS: + type: Inline + inline: "{}" diff --git a/internal/utils/testdata/securitypolicy_all.strategicmerge.out.yaml b/internal/utils/testdata/securitypolicy_all.strategicmerge.out.yaml new file mode 100644 index 0000000000..8eeabc5212 --- /dev/null +++ b/internal/utils/testdata/securitypolicy_all.strategicmerge.out.yaml @@ -0,0 +1,61 @@ +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: patched +spec: + apiKeyAuth: + credentialRefs: + - name: api-keys-route + extractFrom: null + sanitize: true + authorization: + defaultAction: null + rules: + - action: Deny + name: route-rule + principal: + headers: + - name: x-role + values: + - route + basicAuth: + users: + name: users-route + extAuth: + contextExtensions: + - name: shared + type: Value + value: route + - name: route-only + type: Value + value: route-only + - name: parent-only + type: Value + value: parent-only + grpc: + backendRefs: + - name: ext-auth-route + port: 9002 + http: + backendRefs: + - name: ext-auth-parent + port: 9001 + jwt: + providers: + - issuer: https://issuer.route.example.com + localJWKS: + inline: '{}' + type: Inline + name: jwt-route + oidc: + clientIDRef: + name: oidc-client-id-route + clientSecret: + name: oidc-client-secret-route + provider: + backendRefs: + - name: oidc-route + port: 8443 + issuer: "" +status: + ancestors: null diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 3271a4f907..7211ceb5ea 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -2,6 +2,7 @@ date: Pending # Changes that are expected to cause an incompatibility with previous versions, such as deletions or modifications to existing APIs. breaking changes: | + Merged SecurityPolicy IR/xDS resource names (OIDC, BasicAuth, ExtAuth, JWT) now derive from the policy that contributes the field (parent or route) rather than always using the route-level policy. EnvoyPatchPolicy users who reference those generated names must update their patch targets. # Updates addressing vulnerabilities, security flaws, or compliance requirements. security updates: | @@ -10,6 +11,7 @@ security updates: | new features: | bug fixes: | + Fixed SecurityPolicy merge using the wrong policy as the owner for resource references and IR generation. # Enhancements that improve performance. performance improvements: | diff --git a/site/content/en/latest/concepts/gateway_api_extensions/security-policy.md b/site/content/en/latest/concepts/gateway_api_extensions/security-policy.md index 8a2ccd710b..d1454f2f03 100644 --- a/site/content/en/latest/concepts/gateway_api_extensions/security-policy.md +++ b/site/content/en/latest/concepts/gateway_api_extensions/security-policy.md @@ -268,17 +268,7 @@ In this example, the route-level policy merges with the gateway-level policy, re - When `mergeType` is unset, no merging occurs - only the most specific policy takes effect - The merged configuration combines both policies, enabling layered security strategies - When the same security feature is configured in both parent and child policies (e.g., both define CORS), the child policy's configuration takes precedence for that specific feature - -### Important: Namespace Behavior with Secret References - -When policies are merged, secret references inherited from parent policies must be resolvable from the **route policy's namespace**. This is because the merged policy retains the identity (including namespace) of the route-level policy. - -**Example scenario:** -- Gateway policy in namespace `envoy-gateway` references `basic-auth-secret` -- Route policy in namespace `default` merges with the gateway policy -- The secret `basic-auth-secret` must exist in the `default` namespace for the merged policy to work - -**Best Practice:** When using policy merging with secret-based authentication (BasicAuth, OIDC, JWT, APIKeyAuth), ensure that required secrets are available in each route's namespace, or design your namespace strategy accordingly. +- Secret references and backend references are resolved against the namespace of the **policy that originally configured the field** (either route or parent). For example, if a Gateway policy defines BasicAuth, its secret is looked up in the Gateway policy's namespace even after merging. ## Related Resources - [API Key Authentication](../../tasks/security/apikey-auth.md) From 568611a978af5fb9d5453e5b423679c5b0cd2afa Mon Sep 17 00:00:00 2001 From: zirain Date: Mon, 4 May 2026 18:42:45 +0800 Subject: [PATCH 03/12] skip invalid listener first in IR (#8577) * skip invalid listener Signed-off-by: zirain * fix specValid Signed-off-by: zirain * nit Signed-off-by: zirain * fix Signed-off-by: zirain * MUST NOT pick one conflicting Listener as the winner Signed-off-by: zirain * update Signed-off-by: zirain --------- Signed-off-by: zirain Co-authored-by: Isaac Wilson Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- internal/gatewayapi/contexts.go | 4 + internal/gatewayapi/listener.go | 142 +++++--- internal/gatewayapi/route.go | 2 +- ...ndtrafficpolicy-status-conditions.out.yaml | 20 - ...policy-with-routing-type-listener.out.yaml | 20 - ...nttrafficpolicy-status-conditions.out.yaml | 20 - ...extensionpolicy-status-conditions.out.yaml | 20 - .../gateway-with-attached-routes.out.yaml | 22 -- ...flicting-listeners-one-invalid-ref.in.yaml | 64 ++++ ...licting-listeners-one-invalid-ref.out.yaml | 213 +++++++++++ ...valid-allowed-namespaces-selector.out.yaml | 22 -- ...with-invalid-allowed-routes-group.out.yaml | 22 -- ...allowed-routes-kind-and-supported.out.yaml | 22 -- ...-with-invalid-allowed-routes-kind.out.yaml | 22 -- ...th-invalid-allowed-tls-route-kind.out.yaml | 17 - ...nvalid-multiple-tls-configuration.out.yaml | 20 - ...id-tls-configuration-invalid-mode.out.yaml | 22 -- ...configuration-no-certificate-refs.out.yaml | 22 -- ...nfiguration-secret-does-not-exist.out.yaml | 22 -- ...uration-secret-in-other-namespace.out.yaml | 22 -- ...configuration-secret-is-not-valid.out.yaml | 22 -- ...ssing-allowed-namespaces-selector.out.yaml | 22 -- ...h-listener-with-tcp-with-hostname.out.yaml | 17 - ...h-listener-with-udp-with-hostname.out.yaml | 17 - ...istener-with-unsupported-protocol.out.yaml | 7 - ...listeners-on-same-tcp-or-tls-port.out.yaml | 15 - ...th-two-listeners-on-same-udp-port.out.yaml | 9 - ...d-tlsroute-same-hostname-and-port.out.yaml | 32 -- ...eners-with-same-port-and-hostname.out.yaml | 36 -- ...ame-port-and-incompatible-protocol.in.yaml | 14 + ...me-port-and-incompatible-protocol.out.yaml | 42 +-- ...-with-same-port-http-tcp-protocol.out.yaml | 136 ++----- .../listenerset-conflict-listeners.out.yaml | 82 ----- ...tps-tls-misuses-gateway-namespace.out.yaml | 20 - .../testdata/listenerset-invalid.out.yaml | 18 - .../merge-invalid-multiple-gateways.out.yaml | 14 - .../securitypolicy-status-conditions.out.yaml | 20 - ...oute-invalid-no-matching-listener.out.yaml | 17 - ...attaching-to-gateway-with-no-mode.out.yaml | 17 - ...er-both-passthrough-and-cert-data.out.yaml | 17 - internal/gatewayapi/validate.go | 343 ++++++++++++++---- 41 files changed, 697 insertions(+), 960 deletions(-) create mode 100644 internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml create mode 100644 internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml diff --git a/internal/gatewayapi/contexts.go b/internal/gatewayapi/contexts.go index 60670eebd1..96956810bb 100644 --- a/internal/gatewayapi/contexts.go +++ b/internal/gatewayapi/contexts.go @@ -145,6 +145,10 @@ type ListenerContext struct { namespaceSelector labels.Selector + // specValid indicates whether per-listener spec validation succeeded. + // Conflict detection should only consider listeners with specValid=true. + specValid bool + tls ListenerTLSConfig httpIR *ir.HTTPListener diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 78d59e5718..a7bbc26957 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -219,9 +219,84 @@ func validClientCertificateRef(ref *gwapiv1.SecretObjectReference) error { return nil } +// allowedRouteKindsForProtocol returns the route kinds supported by the given listener protocol. +func allowedRouteKindsForProtocol(protocol gwapiv1.ProtocolType, tlsMode *gwapiv1.TLSModeType) []gwapiv1.Kind { + switch protocol { + case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType: + return []gwapiv1.Kind{resource.KindHTTPRoute, resource.KindGRPCRoute} + case gwapiv1.TLSProtocolType: + if tlsMode != nil && *tlsMode == gwapiv1.TLSModePassthrough { + return []gwapiv1.Kind{resource.KindTLSRoute} + } + // Terminate mode or unspecified defaults to accept both TCP and TLS routes + return []gwapiv1.Kind{resource.KindTCPRoute, resource.KindTLSRoute} + case gwapiv1.TCPProtocolType: + return []gwapiv1.Kind{resource.KindTCPRoute} + case gwapiv1.UDPProtocolType: + return []gwapiv1.Kind{resource.KindUDPRoute} + default: + return nil + } +} + +func (t *Translator) validateListenerSpec(listener *ListenerContext, resources *resource.Resources) bool { + // Validate listener spec directly without relying on conditions. + // Start with valid assumption and invalidate on failures. + // Phase 1: Validate fundamental rules + specValid := t.validateAllowedNamespaces(listener) + + // Phase 2: Validate allowed routes based on protocol + if isSupportedListenerProtocol(listener.Protocol) { + var tlsMode *gwapiv1.TLSModeType + if listener.TLS != nil { + tlsMode = listener.TLS.Mode + } + allowedKinds := allowedRouteKindsForProtocol(listener.Protocol, tlsMode) + if !t.validateAllowedRoutes(listener, allowedKinds...) { + specValid = false + } + } else { + // Unsupported protocol + specValid = false + listener.SetSupportedKinds() + listener.SetCondition( + gwapiv1.ListenerConditionAccepted, + metav1.ConditionFalse, + gwapiv1.ListenerReasonUnsupportedProtocol, + fmt.Sprintf("Protocol %s is unsupported, must be %s, %s, %s or %s.", listener.Protocol, + gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType), + ) + } + + // Phase 3: Validate TLS configuration details + if !t.validateTLSConfiguration(listener, resources) { + specValid = false + } + + // Phase 4: Validate Hostname configuration + if !t.validateHostName(listener) { + specValid = false + } + + return specValid +} + func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap, resources *resource.Resources) { // Infra IR proxy ports must be unique. foundPorts := make(map[string][]*protocolPort) + + // Phase 1: Validate each listener's spec independently. + // This must happen before conflict resolution so that invalid listeners + // don't block valid ones during conflict detection. + for _, gateway := range gateways { + for _, listener := range gateway.listeners { + listener.specValid = t.validateListenerSpec(listener, resources) + } + } + + // Phase 2: Run conflict detection. + // Only listeners that haven't been marked as invalid will participate in conflict resolution. + t.validateConflictedProtocolsListeners(gateways) t.validateConflictedLayer7Listeners(gateways) t.validateConflictedLayer4Listeners(gateways, gwapiv1.TCPProtocolType) t.validateConflictedLayer4Listeners(gateways, gwapiv1.UDPProtocolType) @@ -229,9 +304,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource t.validateConflictedMergedListeners(gateways) } - // Iterate through all listeners to validate spec - // and compute status for each, and add valid ones - // to the Xds IR. + // Phase 3: Build IR for valid listeners. for _, gateway := range gateways { irKey := t.getIRKey(gateway.Gateway) @@ -242,49 +315,12 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource t.processProxyObservability(gateway, xdsIR[irKey], infraIR[irKey].Proxy, resources) for _, listener := range gateway.listeners { - // Process protocol & supported kinds - switch listener.Protocol { - case gwapiv1.TLSProtocolType: - if listener.TLS != nil { - switch *listener.TLS.Mode { - case gwapiv1.TLSModePassthrough: - t.validateAllowedRoutes(listener, resource.KindTLSRoute) - case gwapiv1.TLSModeTerminate: - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - default: - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - } - } else { - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - } - case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType: - t.validateAllowedRoutes(listener, resource.KindHTTPRoute, resource.KindGRPCRoute) - case gwapiv1.TCPProtocolType: - t.validateAllowedRoutes(listener, resource.KindTCPRoute) - case gwapiv1.UDPProtocolType: - t.validateAllowedRoutes(listener, resource.KindUDPRoute) - default: - listener.SetSupportedKinds() - listener.SetCondition( - gwapiv1.ListenerConditionAccepted, - metav1.ConditionFalse, - gwapiv1.ListenerReasonUnsupportedProtocol, - fmt.Sprintf("Protocol %s is unsupported, must be %s, %s, %s or %s.", listener.Protocol, - gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType), - ) - } - - // Validate allowed namespaces - t.validateAllowedNamespaces(listener) - - // Process TLS configuration - t.validateTLSConfiguration(listener, resources) - - // Process Hostname configuration - t.validateHostName(listener) - - // Process conditions and check if the listener is ready + // Finalize listener conditions and check readiness. t.validateListenerConditions(listener) + if !listener.IsReady() { + // Skip invalid listeners from IR building + continue + } // Skip listeners with invalid frontend TLS validation as they are not functional. if listener.frontendTLSValidationInvalid() { @@ -427,10 +463,18 @@ func checkOverlappingHostnames(httpsListeners []*ListenerContext) { if overlappingListeners[i] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[i]) { + continue + } for j := i + 1; j < len(httpsListeners); j++ { if overlappingListeners[j] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[j]) { + continue + } if httpsListeners[i].Port != httpsListeners[j].Port { continue } @@ -509,10 +553,18 @@ func checkOverlappingCertificates(httpsListeners []*ListenerContext) { if overlappingListeners[i] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[i]) { + continue + } for j := i + 1; j < len(httpsListeners); j++ { if overlappingListeners[j] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[j]) { + continue + } if httpsListeners[i].Port != httpsListeners[j].Port { continue } diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 4c86bcc38c..da63bf2acf 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -2287,7 +2287,7 @@ func (t *Translator) processAllowedListenersForParentRefs( } parentRefCtx.SetListeners(allowedListeners...) - if !HasReadyListener(selectedListeners) { + if !HasReadyListener(allowedListeners) { routeStatus := GetRouteStatus(routeContext) status.SetRouteStatusCondition(routeStatus, parentRefCtx.routeParentStatusIdx, diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml index af39245f4e..ce7c003177 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml @@ -508,12 +508,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -735,20 +729,6 @@ xdsIR: namespace: envoy-gateway name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/0/* traffic: {} - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml index a29dfb9785..41827b1006 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml @@ -218,12 +218,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-1/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -309,20 +303,6 @@ xdsIR: name: "" prefix: /foo traffic: {} - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-1/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml index 6fa616eead..6d47792238 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml @@ -453,12 +453,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -596,20 +590,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml index 081fd59005..9508ec8d51 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml @@ -508,12 +508,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -727,20 +721,6 @@ xdsIR: name: grpcroute-1 namespace: envoy-gateway name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/0/* - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml b/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml index c2ac20067f..f11b451baf 100644 --- a/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml @@ -326,13 +326,6 @@ infraIR: namespace: envoy-gateway-system envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route: proxy: - listeners: - - name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: unresolved-gateway-with-one-attached-unresolved-route @@ -487,21 +480,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: unresolved-gateway-with-one-attached-unresolved-route - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml new file mode 100644 index 0000000000..1b0dfa84fc --- /dev/null +++ b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml @@ -0,0 +1,64 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + # This listener has an invalid certificate reference (secret does not exist) + # It should have ResolvedRefs=False with InvalidCertificateRef + # and should be skipped during conflict resolution + - name: invalid-https + protocol: HTTPS + port: 443 + hostname: "*.example.com" + allowedRoutes: + namespaces: + from: All + tls: + mode: Terminate + certificateRefs: + - name: non-existent-secret + # This listener has valid configuration and should be accepted + # even though it's on the same port/hostname as the invalid listener + - name: valid-https + protocol: HTTPS + port: 443 + hostname: "*.example.com" + allowedRoutes: + namespaces: + from: All + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 +secrets: + - apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR3RENDQXFpZ0F3SUJBZ0lVVDRyelIreStHd1VzMm9ydExIZ0k1MzBKeG9Fd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkpibU11TVJRd0VnWURWUVFEREF0bGVHRnRjR3hsTG1OdgpiVEFlRncweU5UQTBNakl3TWpVNU1UQmFGdzB6TlRBME1qQXdNalU1TVRCYU1EVXhGREFTQmdOVkJBTU1DMlp2CmJ5NWlZWEl1WTI5dE1SMHdHd1lEVlFRS0RCUmxlR0Z0Y0d4bElHOXlaMkZ1YVhwaGRHbHZiakNDQVNJd0RRWUoKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTE4wbnJNR1NZNjBPT0JuTFVaSGpCRFkxazhqWHA2RwppeG1RaFNOK3lZUi9VQWVqSmhCOVI3S2RuT3d0eGljTnozdUFtL0p0UTFKRUU0dW5xQnhVTU8ydWpvVXl4ZisrCjRnb2tFYmVpTlhNN0ptaklPOGxEWlJjcEhFTlE3eUNJL3d1cEZBcHgwNnVrNUtBSlpRMUlmVXhZWS9RRkJsc3cKdUx0TWozVlB6eDBJYjRIV1lHdGhXcDIzUWduMUdGUWVTOGMwZHdqWWNBTGtrTFdwWWdUZTZGT0VhR3hvUzdwTQpGbitvZnRFUjlxZCtDcnRDSXM5TzFtOW5MUU9UWGJDNU5nSzR1ZFdhMFBuYjJ6TEk4WjZsVHFRSTNSODE2NkxKCkVDQi9ZSlYzVmtMb2cxUmx0d0FrM3hrWHFnbVhTZUxILzY3MHh6MEx5OGZHQVpmejFMQVpkSXNDQXdFQUFhT0IKenpDQnpEQWRCZ05WSFE0RUZnUVUzbVFodVB2dVl1K0lmN0ZaM010eU9jMWdjQ1V3YUFZRFZSMGpCR0V3WDRBVQpXWmxKWFQ1bXlEVnlsUjlSS2JQQTAxTkVlcytoTWFRdk1DMHhGVEFUQmdOVkJBb01ER1Y0WVcxd2JHVWdTVzVqCkxqRVVNQklHQTFVRUF3d0xaWGhoYlhCc1pTNWpiMjJDRkJuNktuTlBhbm1Db1daVStNYmtwKzJScmN4dU1Bc0cKQTFVZER3UUVBd0lDL0RBcEJnTlZIUkVFSWpBZ2dnOW1iMjh1WlhoaGJYQnNaUzVqYjIyQ0RTb3VaWGhoYlhCcwpaUzVqYjIwd0NRWURWUjBTQkFJd0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFIa2xEbzkvNnRLcDNFd3JSCnJjVStKOUtmUkFGajc5YU1DREpVb0NyM2J6RFIycXQ4ZzlsbDdFSzZaeEtFa0xzWkFlYzBxU0Z1QjBvbzVqZFEKM3VvT2hNK1JKTkZoTldFd3dHWmpMb0FlK2oxaXByN1A5ajdmdFNzck8ra3M3TVNMeTE2RW9IV2Q0eG00Rk5QZQpmUVpRYWhpTTdMYVFCdW5wdXlhZWtLdG5tU241RzlkSHpGeTVNelRSbFJyVWxhVzdVbDRUeExlOEROZ2ZpR2ZCCnpjcmpVK2l3RUJXeS94b3B2aDEzNmlybmV3NTg3RWt3dzQ3QXFhc3gvZStMK2NhSlYySGVMd0dSaE5xR2pIcjkKQ2dSVHpud3F5QjdtTVNXYStWaXBNSHlUVmRCNjRvYjZxbkdqTldvWXdRbUUraU0vL0VrTURzd2JVcTc2R1pKMApsWlRkTlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3pkSjZ6QmttT3REamcKWnkxR1I0d1EyTlpQSTE2ZWhvc1prSVVqZnNtRWYxQUhveVlRZlVleW5aenNMY1luRGM5N2dKdnliVU5TUkJPTApwNmdjVkREdHJvNkZNc1gvdnVJS0pCRzNvalZ6T3lab3lEdkpRMlVYS1J4RFVPOGdpUDhMcVJRS2NkT3JwT1NnCkNXVU5TSDFNV0dQMEJRWmJNTGk3VEk5MVQ4OGRDRytCMW1CcllWcWR0MElKOVJoVUhrdkhOSGNJMkhBQzVKQzEKcVdJRTN1aFRoR2hzYUV1NlRCWi9xSDdSRWZhbmZncTdRaUxQVHRadlp5MERrMTJ3dVRZQ3VMblZtdEQ1MjlzeQp5UEdlcFU2a0NOMGZOZXVpeVJBZ2YyQ1ZkMVpDNklOVVpiY0FKTjhaRjZvSmwwbml4Lyt1OU1jOUM4dkh4Z0dYCjg5U3dHWFNMQWdNQkFBRUNnZ0VBSmYrYW53UEV6WS9CdjFwNWpya1ZvbmVYb1hnMno5QmpZYzFsTTZma0djY3YKZGY2SXo5TUhQSDM5UFZGUDlQTUtyUGNGam1hdWE1djRtNGlyb3h2OHBFZGk3RGRkRDVNbW44a1ZhMUhRaVk3TAp5a0lqenJFVGxiemh2Q3RHQnhpYkVLZ0RrMWFZNEc1dzdxWXVuSXB0NVoyTnhKelB4TDFqVUYyY3Z0VmdZS0FPCjN2TWY1dENWbS9kL2JBT2xvWnVVc3ArSnc1ZTYvSFN3c3lEdjV2Y2dDQkRXRjFkTFFiYUxCelZDZGJBY0Fma1AKbFUzeGhZMVYyMGU2NmhBbU0veE53MzArSUhvTUlTUTFiQW9MOXVzN3NsTlYxT2ZNZk5hWC83WVdKWFVab1MzNwpyY1IvVXYwZlRtQkhPR3pwK25oaWpLRUlYU1ZESjNxK040amM4Ni9IeVFLQmdRRFhWbzNKSmlia0cvY1JBZ2pICkVqdWROMHJMSGJvVldPanN5ekZmaXg1MHJKTTYwMDJKZURicGdQeEt4ZUtFdGl4ZkVWQmU0eHdqNG9oK1ZubEIKT0dMU3BWcHRRVFRnRVprWXFvVU1iUDIyNHQ2cUZuSXZsTkkwZFJGWDUyS3I2L1FCS0EwWEk3K0I1bTV3Z2hLcgo4ZEQrMGRWNkZzMmxFT0NMWUJKck1weFNIUUtCZ1FEVlY0REVaUlFvVUo5UGRkb3IyK2IweFV2Y3JHeUJ1NlM2CjJZOFJuMzdWUVlBSThHUnlYRkcxTGxZaHpMOWNwd0tUR21SMVhPRTVkMC9mMStaU3h5TVc1d2FSaXU1b0dFK2cKUlNsMXBBdTNUdlEzM1BVNUJzNFhhcHBLOC9BZVk3cG1pd1JhYnRPSFlQa0FHMXNzL3k1d1NjVGUxQXZiWlpsTAo1TmgwdHZvZ3h3S0JnUUNtRkFJOFhlbG15czZ0Vm1WUXE1WkF0YkZBb0VleFNTWXo0cTdNb200MXpCZXRLZVRHCkhtb3pneUNSeHJiaVplSW8zQ0NoWGdXSkE2RUQxMHVqYW9xRkxiUmxTUUl2d2tMU1RFbGJBUUJZdWZiRE5aYVIKYmZVRk1qalRGQWo4MFhrYUh6cWhXeGZMWnQ1TWRYVlRHYWgzcjN3MnNqbWVranFzSThkdzE5TEtYUUtCZ0NoMQp3T0QrUG5WcTNOdklBUWxpV2dtL3hTUmp1dXhidHVFTTA1cEhBbG5WWXovT3YyNEUzaVliVkpCeWNUUlVKQ1BiCjFJT0JpdUZJSkdqU1hFY0VwejMzc0lJM3RBRWY0eklGQzlqWXRMUWVFQ2pzQ2NHMzdhdjVOcXZTV1k2WjRVY0QKUkY4V041MnNJVzBJd3lEa2dGMGhVR25tRXgyWHhodmptYjJBMmkwUEFvR0FUV1kzbXZRVWtZcmU5R0J0alVqYgpDWUx5Mm1VVElKbjVDcmhjTHMvMlh5MkNoVSt5MnhsT3pIcm1vanRIaHFFcnVCK0xyZkpBd3B3cGVRNmxyWnFQCjFGazVKT2c2bmV2U3lDcWF4SDZaenZRMXJ6VzAycm1IMUJrV1BiY0NwKy9VRTIrS3JselZtNHkvZ0ZoRGVGZlcKRUc5UzIzYndKME1JUmF0WVpFQm0wcWs9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: valid-https + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 diff --git a/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml new file mode 100644 index 0000000000..663bd2014f --- /dev/null +++ b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml @@ -0,0 +1,213 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: '*.example.com' + name: invalid-https + port: 443 + protocol: HTTPS + tls: + certificateRefs: + - name: non-existent-secret + mode: Terminate + - allowedRoutes: + namespaces: + from: All + hostname: '*.example.com' + name: valid-https + port: 443 + protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: 'No valid secrets exist: certificate refs 0: Secret envoy-gateway/non-existent-secret + does not exist.' + reason: InvalidCertificateRef + status: "False" + type: ResolvedRefs + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed + name: invalid-https + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: valid-https + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - name: envoy-gateway/gateway-1/valid-https + ports: + - containerPort: 10443 + name: https-443 + protocol: HTTPS + servicePort: 443 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 443 + hostnames: + - '*.example.com' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https + name: envoy-gateway/gateway-1/valid-https + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10443 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: '*.example.com' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/*_example_com + pathMatch: + distinct: false + name: "" + prefix: / + tls: + alpnProtocols: null + certificates: + - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR3RENDQXFpZ0F3SUJBZ0lVVDRyelIreStHd1VzMm9ydExIZ0k1MzBKeG9Fd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkpibU11TVJRd0VnWURWUVFEREF0bGVHRnRjR3hsTG1OdgpiVEFlRncweU5UQTBNakl3TWpVNU1UQmFGdzB6TlRBME1qQXdNalU1TVRCYU1EVXhGREFTQmdOVkJBTU1DMlp2CmJ5NWlZWEl1WTI5dE1SMHdHd1lEVlFRS0RCUmxlR0Z0Y0d4bElHOXlaMkZ1YVhwaGRHbHZiakNDQVNJd0RRWUoKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTE4wbnJNR1NZNjBPT0JuTFVaSGpCRFkxazhqWHA2RwppeG1RaFNOK3lZUi9VQWVqSmhCOVI3S2RuT3d0eGljTnozdUFtL0p0UTFKRUU0dW5xQnhVTU8ydWpvVXl4ZisrCjRnb2tFYmVpTlhNN0ptaklPOGxEWlJjcEhFTlE3eUNJL3d1cEZBcHgwNnVrNUtBSlpRMUlmVXhZWS9RRkJsc3cKdUx0TWozVlB6eDBJYjRIV1lHdGhXcDIzUWduMUdGUWVTOGMwZHdqWWNBTGtrTFdwWWdUZTZGT0VhR3hvUzdwTQpGbitvZnRFUjlxZCtDcnRDSXM5TzFtOW5MUU9UWGJDNU5nSzR1ZFdhMFBuYjJ6TEk4WjZsVHFRSTNSODE2NkxKCkVDQi9ZSlYzVmtMb2cxUmx0d0FrM3hrWHFnbVhTZUxILzY3MHh6MEx5OGZHQVpmejFMQVpkSXNDQXdFQUFhT0IKenpDQnpEQWRCZ05WSFE0RUZnUVUzbVFodVB2dVl1K0lmN0ZaM010eU9jMWdjQ1V3YUFZRFZSMGpCR0V3WDRBVQpXWmxKWFQ1bXlEVnlsUjlSS2JQQTAxTkVlcytoTWFRdk1DMHhGVEFUQmdOVkJBb01ER1Y0WVcxd2JHVWdTVzVqCkxqRVVNQklHQTFVRUF3d0xaWGhoYlhCc1pTNWpiMjJDRkJuNktuTlBhbm1Db1daVStNYmtwKzJScmN4dU1Bc0cKQTFVZER3UUVBd0lDL0RBcEJnTlZIUkVFSWpBZ2dnOW1iMjh1WlhoaGJYQnNaUzVqYjIyQ0RTb3VaWGhoYlhCcwpaUzVqYjIwd0NRWURWUjBTQkFJd0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFIa2xEbzkvNnRLcDNFd3JSCnJjVStKOUtmUkFGajc5YU1DREpVb0NyM2J6RFIycXQ4ZzlsbDdFSzZaeEtFa0xzWkFlYzBxU0Z1QjBvbzVqZFEKM3VvT2hNK1JKTkZoTldFd3dHWmpMb0FlK2oxaXByN1A5ajdmdFNzck8ra3M3TVNMeTE2RW9IV2Q0eG00Rk5QZQpmUVpRYWhpTTdMYVFCdW5wdXlhZWtLdG5tU241RzlkSHpGeTVNelRSbFJyVWxhVzdVbDRUeExlOEROZ2ZpR2ZCCnpjcmpVK2l3RUJXeS94b3B2aDEzNmlybmV3NTg3RWt3dzQ3QXFhc3gvZStMK2NhSlYySGVMd0dSaE5xR2pIcjkKQ2dSVHpud3F5QjdtTVNXYStWaXBNSHlUVmRCNjRvYjZxbkdqTldvWXdRbUUraU0vL0VrTURzd2JVcTc2R1pKMApsWlRkTlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + name: envoy-gateway/tls-secret-1 + privateKey: '[redacted]' + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml index 898c56910c..fb1bca1c0e 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml @@ -78,13 +78,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -120,21 +113,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml index c1be28da35..d6eddedd1d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml @@ -69,13 +69,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -111,21 +104,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml index 875e056fd0..ad9f652f5d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -113,21 +106,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml index c9e11f45f4..891bdd8a8b 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml @@ -69,13 +69,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -111,21 +104,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml index 0127e45fe8..8a474483bb 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml @@ -38,13 +38,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10080 - name: tls-80 - protocol: TLS - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -116,13 +109,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml index 4e0b318363..82b7f2918d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml @@ -158,12 +158,6 @@ infraIR: name: https-8443 protocol: HTTPS servicePort: 8443 - - name: envoy-gateway/gateway-1/tls-all-invalid-cert - ports: - - containerPort: 8444 - name: https-8444 - protocol: HTTPS - servicePort: 8444 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -302,20 +296,6 @@ xdsIR: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ2VENDQVVTZ0F3SUJBZ0lVU2l2SkdURHdva1M3aGVZLzJjc1JzejR2SkIwd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFptOXZMbUpoY2k1amIyMHdIaGNOTWpRd01qSTVNRGt6TURFd1doY05NelF3TWpJMgpNRGt6TURFd1dqQVdNUlF3RWdZRFZRUUREQXRtYjI4dVltRnlMbU52YlRCMk1CQUdCeXFHU000OUFnRUdCU3VCCkJBQWlBMklBQkZ2cnZSZWJhYVd1UzZNQUVJZDZ3WmZPS3Z1Q1R5VU1PbFpKcUZDRjlUa3pNWWw4Q2lvZnluT3QKQ3JzMHZ2YTlrZC9QMkpNR0JKcWdZZXZid290clJpMTJxTG5IMDQvam9HSWpqVE9LbzNJb2ZyK0ZrOHdMdkFlMwpPMVpLdFI5c3pxTlRNRkV3SFFZRFZSME9CQllFRklLczFRRm5vRHQ5K3Fva1I0T0RXYk16MWYrUE1COEdBMVVkCkl3UVlNQmFBRklLczFRRm5vRHQ5K3Fva1I0T0RXYk16MWYrUE1BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0NnWUkKS29aSXpqMEVBd0lEWndBd1pBSXdIMzF0SHlmVVAwNFhIcGJXR2UxWjFJYUJaQndJdGg1NURVNGhqZlB1OG0rSgpXdjdiVzh6VFNnd0xpcW9yZmN1bkFqQTBnaE5KQkExWDJYdElLRG1sM3M3L1Z4OEZKY1MwNHZwQ2hoK2xBYkxTCnZlYWEyOFIzVExFWTNVK1FUWEkvd0lrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== name: envoy-gateway/tls-secret-ecdsa-2 privateKey: '[redacted]' - - address: 0.0.0.0 - externalPort: 8444 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls-all-invalid-cert - name: envoy-gateway/gateway-1/tls-all-invalid-cert - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8444 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml index f5eb3615ea..d3b527cf81 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml index f0b8e08392..08b2c9ae80 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml @@ -72,13 +72,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -114,21 +107,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml index 17179618ef..fdf22c3ae1 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml index 94d6649edd..be22741fa9 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml @@ -76,13 +76,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -118,21 +111,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml index acfc47f023..5ab341a973 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml index eb0643097a..ed93a40205 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -113,21 +106,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml index 1e3bf50365..eee30d760d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml @@ -35,13 +35,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tcp - ports: - - containerPort: 10080 - name: tcp-80 - protocol: TCP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -82,13 +75,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp - name: envoy-gateway/gateway-1/tcp - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml index f3d7139fc7..cdc8155dc4 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml @@ -35,13 +35,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/udp - ports: - - containerPort: 10080 - name: udp-80 - protocol: UDP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -82,13 +75,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - udp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: udp - name: envoy-gateway/gateway-1/udp - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml index 4672cbedfb..1765434059 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/unsupported - ports: - - containerPort: 10080 - name: "-80" - protocol: "" - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml index 228b0bf29f..f255acbcf4 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml @@ -70,12 +70,6 @@ infraIR: name: tcp-162 protocol: TCP servicePort: 162 - - name: envoy-gateway/gateway-1/tcp2 - ports: - - containerPort: 10162 - name: tls-162 - protocol: TLS - servicePort: 162 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -182,12 +176,3 @@ xdsIR: name: tcproute-1 namespace: default name: tcproute/default/tcproute-1 - - address: 0.0.0.0 - externalPort: 162 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp2 - name: envoy-gateway/gateway-1/tcp2 - port: 10162 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml index cac7a60a43..f858c8d772 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml @@ -175,12 +175,3 @@ xdsIR: protocol: UDP weight: 1 name: udproute/default/udproute-1 - - address: 0.0.0.0 - externalPort: 162 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: udp2 - name: envoy-gateway/gateway-1/udp2 - port: 10162 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml index 823f9813a5..20c4241d1a 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml @@ -106,13 +106,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http-1 - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -179,33 +172,8 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-1 - name: envoy-gateway/gateway-1/http-1 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls-1 - name: envoy-gateway/gateway-1/tls-1 - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml index 0df14ad10c..ecb8190327 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml @@ -106,13 +106,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http-1 - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -148,35 +141,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-1 - name: envoy-gateway/gateway-1/http-1 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-2 - name: envoy-gateway/gateway-1/http-2 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml index 37c0a342f3..4d899da6a8 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml @@ -21,6 +21,20 @@ gateways: allowedRoutes: namespaces: from: All + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 +secrets: + - apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A0QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K httpRoutes: - apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml index 3eab4a3a04..4af2173f3d 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml @@ -21,6 +21,10 @@ gateways: name: http-2 port: 80 protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate status: listeners: - attachedRoutes: 1 @@ -54,7 +58,7 @@ gateways: status: "True" type: Conflicted - lastTransitionTime: null - message: Listener must have TLS set when protocol is HTTPS. + message: Listener is invalid, see other Conditions for details. reason: Invalid status: "False" type: Programmed @@ -106,13 +110,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http-1 - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -148,35 +145,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-1 - name: envoy-gateway/gateway-1/http-1 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - bar.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-2 - name: envoy-gateway/gateway-1/http-2 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml index 476881b619..1a31d49847 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml @@ -25,15 +25,15 @@ gateways: - attachedRoutes: 1 conditions: - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict status: "True" - type: Programmed + type: Conflicted - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -45,18 +45,18 @@ gateways: kind: HTTPRoute - group: gateway.networking.k8s.io kind: GRPCRoute - - attachedRoutes: 1 + - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict status: "True" - type: Programmed + type: Conflicted - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -87,9 +87,9 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" + message: There are no ready listeners for this parent ref + reason: NoReadyListeners + status: "False" type: Accepted - lastTransitionTime: null message: Resolved all the Object references for the Route @@ -103,19 +103,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 - - name: envoy-gateway/gateway-1/tcp - ports: - - containerPort: 10080 - name: tcp-80 - protocol: TCP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -143,9 +130,9 @@ tcpRoutes: parents: - conditions: - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" + message: There are no ready listeners for this parent ref + reason: NoReadyListeners + status: "False" type: Accepted - lastTransitionTime: null message: Resolved all the Object references for the Route @@ -182,89 +169,8 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 - routes: - - destination: - metadata: - kind: HTTPRoute - name: httproute-1 - namespace: default - name: httproute/default/httproute-1/rule/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8080 - metadata: - kind: Service - name: service-1 - namespace: default - sectionName: "8080" - name: httproute/default/httproute-1/rule/0/backend/0 - protocol: HTTP - weight: 1 - hostname: '*' - isHTTP2: false - metadata: - kind: HTTPRoute - name: httproute-1 - namespace: default - name: httproute/default/httproute-1/rule/0/match/0/* - pathMatch: - distinct: false - name: "" - prefix: / readyListener: address: 0.0.0.0 ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp - name: envoy-gateway/gateway-1/tcp - port: 10080 - routes: - - destination: - metadata: - kind: TCPRoute - name: tcproute-1 - namespace: default - name: tcproute/default/tcproute-1/rule/-1 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8163 - metadata: - kind: Service - name: service-1 - namespace: default - sectionName: "8163" - name: tcproute/default/tcproute-1/rule/-1/backend/0 - protocol: TCP - weight: 1 - metadata: - kind: TCPRoute - name: tcproute-1 - namespace: default - name: tcproute/default/tcproute-1 diff --git a/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml b/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml index 736ddb24a9..de19b641c4 100644 --- a/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml @@ -84,18 +84,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: gateway-xls/composite-gateway/conflict-listener - ports: - - containerPort: 8888 - name: http-8888 - protocol: HTTP - servicePort: 8888 - - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-same-xls/conflict-listener-1 - ports: - - containerPort: 8089 - name: http-8089 - protocol: HTTP - servicePort: 8089 - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-two-xlss/good-listener ports: - containerPort: 8090 @@ -409,62 +397,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 8888 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener - name: gateway-xls/composite-gateway/conflict-listener - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8888 - - address: 0.0.0.0 - externalPort: 8089 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener-1 - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-same-xls/conflict-listener-1 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8089 - - address: 0.0.0.0 - externalPort: 8089 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener-2 - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-same-xls/conflict-listener-2 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8089 - - address: 0.0.0.0 - externalPort: 8089 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-two-xlss/conflict-listener - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8089 - address: 0.0.0.0 externalPort: 8090 hostnames: @@ -479,20 +411,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 8090 - - address: 0.0.0.0 - externalPort: 8888 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener - name: gateway-xls/composite-gateway/gateway-xls/listener-conflict-with-gateway/conflict-listener - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8888 - address: 0.0.0.0 externalPort: 8091 hostnames: diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml index a302de7ee8..25283fbf2c 100644 --- a/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml @@ -92,12 +92,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: gateway/composite-gateway/xls/https-xls/extra-https-same-ns - ports: - - containerPort: 8443 - name: https-8443 - protocol: HTTPS - servicePort: 8443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: composite-gateway @@ -204,20 +198,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 8443 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway - sectionName: extra-https-same-ns - name: gateway/composite-gateway/xls/https-xls/extra-https-same-ns - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/listenerset-invalid.out.yaml b/internal/gatewayapi/testdata/listenerset-invalid.out.yaml index d456feeb28..449d97e743 100644 --- a/internal/gatewayapi/testdata/listenerset-invalid.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-invalid.out.yaml @@ -200,30 +200,12 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-invalid/invalid-one - ports: - - containerPort: 8085 - name: "-8085" - protocol: "" - servicePort: 8085 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-invalid/invalid-two - ports: - - containerPort: 8086 - name: "-8086" - protocol: "" - servicePort: 8086 - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-mixed/mixed-valid ports: - containerPort: 8087 name: http-8087 protocol: HTTP servicePort: 8087 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-mixed/mixed-invalid - ports: - - containerPort: 8088 - name: "-8088" - protocol: "" - servicePort: 8088 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: composite-gateway diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index 28b1ac3406..f41c3b186d 100644 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -170,20 +170,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-2/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml index c58cf94f48..68afd0fe72 100644 --- a/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml @@ -228,12 +228,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -551,20 +545,6 @@ xdsIR: name: "" safeRegex: http://.*\.example\.com maxAge: 16m40s - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml b/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml index 70c8273b9f..3ea4f78801 100644 --- a/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml @@ -315,13 +315,6 @@ infraIR: namespace: envoy-gateway-system envoy-gateway/gateway-tlsroute-tcproute-only: proxy: - listeners: - - name: envoy-gateway/gateway-tlsroute-tcproute-only/tls-passthrough - ports: - - containerPort: 10443 - name: tls-443 - protocol: TLS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-tlsroute-tcproute-only @@ -743,16 +736,6 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 443 - metadata: - kind: Gateway - name: gateway-tlsroute-tcproute-only - namespace: envoy-gateway - sectionName: tls-passthrough - name: envoy-gateway/gateway-tlsroute-tcproute-only/tls-passthrough - port: 10443 envoy-gateway/gateway-tlsroute-tls-passthrough-only: accessLog: json: diff --git a/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml b/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml index f7221094bd..5a7b2c7289 100644 --- a/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml @@ -36,13 +36,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10090 - name: tls-90 - protocol: TLS - servicePort: 90 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -114,13 +107,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 90 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10090 diff --git a/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml b/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml index eca1a7d9b6..e1f898a957 100644 --- a/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml @@ -39,13 +39,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10090 - name: tls-90 - protocol: TLS - servicePort: 90 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,13 +110,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 90 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10090 diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index d8138446d9..528a0f03da 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -332,12 +332,49 @@ func (t *Translator) validateListenerConditions(listener *ListenerContext) { "Listener references have been resolved", ) } - // skip computing IR - return } } -func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) { +// hasInvalidCondition checks if a listener has been marked as invalid during per-listener validation. +// A listener is considered invalid if it has Programmed=False, Accepted=False, or ResolvedRefs=False +// (except for the special case of PartiallyInvalidCertificateRef which is allowed). +// This is used during conflict resolution to skip invalid listeners so they don't block valid ones. +func hasInvalidCondition(listener *ListenerContext) bool { + conditions := listener.GetConditions() + for _, cond := range conditions { + if cond.Type == string(gwapiv1.ListenerConditionProgrammed) && cond.Status == metav1.ConditionFalse { + return true + } + if cond.Type == string(gwapiv1.ListenerConditionAccepted) && cond.Status == metav1.ConditionFalse { + return true + } + // ResolvedRefs=False is invalid except for PartiallyInvalidCertificateRef which allows + // the listener to still be programmed with valid certificates + if cond.Type == string(gwapiv1.ListenerConditionResolvedRefs) && + cond.Status == metav1.ConditionFalse && + cond.Reason != string(status.ListenerReasonPartiallyInvalidCertificateRef) { + return true + } + } + return false +} + +// isSpecValidForConflictChecks returns whether a listener should participate in +// conflict detection. In the normal translation flow this is driven by +// listener.specValid. The fallback to hasInvalidCondition exists only for unit +// tests that invoke conflict checks directly without running per-listener spec +// validation (Phase 1) first. Production code paths always run validateListenerSpec +// before conflict detection. +func isSpecValidForConflictChecks(listener *ListenerContext) bool { + if listener.specValid { + return true + } + return !hasInvalidCondition(listener) +} + +// validateAllowedNamespaces validates namespace selector configuration. +// Returns true if the namespace spec is valid, false otherwise. +func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) bool { if listener.AllowedRoutes != nil && listener.AllowedRoutes.Namespaces != nil && listener.AllowedRoutes.Namespaces.From != nil && @@ -349,26 +386,28 @@ func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) { gwapiv1.ListenerReasonInvalid, "The allowedRoutes.namespaces.selector field must be specified when allowedRoutes.namespaces.from is set to \"Selector\".", ) - } else { - selector, err := metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector) - if err != nil { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - fmt.Sprintf("The allowedRoutes.namespaces.selector could not be parsed: %v.", err), - ) - } - - listener.namespaceSelector = selector + return false } + selector, err := metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector) + if err != nil { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + fmt.Sprintf("The allowedRoutes.namespaces.selector could not be parsed: %v.", err), + ) + return false + } + + listener.namespaceSelector = selector } + return true } func (t *Translator) validateTerminateModeAndGetTLSSecrets( listener *ListenerContext, resources *resource.Resources, -) ([]*corev1.Secret, []*x509.Certificate) { +) ([]*corev1.Secret, []*x509.Certificate, bool) { if len(listener.TLS.CertificateRefs) == 0 { listener.SetCondition( gwapiv1.ListenerConditionProgrammed, @@ -376,7 +415,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( gwapiv1.ListenerReasonInvalid, "Listener must have at least 1 TLS certificate ref", ) - return nil, nil + return nil, nil, false } var errs []status.ListenerError @@ -486,7 +525,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( fmt.Sprintf("No valid secrets exist: %v", errors.Join(errList...)), ) - return nil, nil + return nil, nil, false } validSecrets, certs, err := parseCertsFromTLSSecretsData(secrets) @@ -498,7 +537,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( err.Reason(), fmt.Sprintf("No valid secrets exist: %v.", err.Error()), ) - return nil, nil + return nil, nil, false } else { errs = append(errs, err) } @@ -517,13 +556,17 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( fmt.Sprintf("Some secrets are invalid: %v", errors.Join(errList...)), ) } - return validSecrets, certs + return validSecrets, certs, true } +// validateTLSConfiguration validates TLS configuration per protocol. +// Returns true if the TLS spec is valid, false otherwise. func (t *Translator) validateTLSConfiguration( listener *ListenerContext, resources *resource.Resources, -) { +) bool { + specValid := true + switch listener.Protocol { case gwapiv1.HTTPProtocolType, gwapiv1.UDPProtocolType, gwapiv1.TCPProtocolType: if listener.TLS != nil { @@ -533,6 +576,7 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must not have TLS set when protocol is %s.", listener.Protocol), ) + specValid = false } case gwapiv1.HTTPSProtocolType: if listener.TLS == nil { @@ -542,25 +586,29 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must have TLS set when protocol is %s.", listener.Protocol), ) - break - } - - if listener.TLS.Mode != nil && *listener.TLS.Mode != gwapiv1.TLSModeTerminate { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - "UnsupportedTLSMode", - fmt.Sprintf("TLS %s mode is not supported, TLS mode must be Terminate.", *listener.TLS.Mode), - ) - break - } + specValid = false + } else { + if listener.TLS.Mode != nil && *listener.TLS.Mode != gwapiv1.TLSModeTerminate { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + "UnsupportedTLSMode", + fmt.Sprintf("TLS %s mode is not supported, TLS mode must be Terminate.", *listener.TLS.Mode), + ) + specValid = false + } else { + secrets, certs, ok := t.validateTerminateModeAndGetTLSSecrets(listener, resources) + listener.SetTLSSecrets(secrets) - secrets, certs := t.validateTerminateModeAndGetTLSSecrets(listener, resources) - listener.SetTLSSecrets(secrets) + if !ok { + specValid = false + } - listener.tls.certDNSNames = make([]string, 0) - for _, cert := range certs { - listener.tls.certDNSNames = append(listener.tls.certDNSNames, cert.DNSNames...) + listener.tls.certDNSNames = make([]string, 0) + for _, cert := range certs { + listener.tls.certDNSNames = append(listener.tls.certDNSNames, cert.DNSNames...) + } + } } case gwapiv1.TLSProtocolType: if listener.TLS == nil { @@ -570,33 +618,38 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must have TLS set when protocol is %s.", listener.Protocol), ) - break - } - - if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModePassthrough { - if len(listener.TLS.CertificateRefs) > 0 { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - "Listener must not have TLS certificate refs set for TLS mode Passthrough.", - ) - break + specValid = false + } else { + if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModePassthrough { + if len(listener.TLS.CertificateRefs) > 0 { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + "Listener must not have TLS certificate refs set for TLS mode Passthrough.", + ) + specValid = false + } } - } - if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModeTerminate { - if len(listener.TLS.CertificateRefs) == 0 { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - "Listener must have TLS certificate refs set for TLS mode Terminate.", - ) - break + if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModeTerminate { + if len(listener.TLS.CertificateRefs) == 0 { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + "Listener must have TLS certificate refs set for TLS mode Terminate.", + ) + specValid = false + } else { + secrets, _, ok := t.validateTerminateModeAndGetTLSSecrets(listener, resources) + listener.SetTLSSecrets(secrets) + + if !ok { + specValid = false + } + } } - secrets, _ := t.validateTerminateModeAndGetTLSSecrets(listener, resources) - listener.SetTLSSecrets(secrets) } } @@ -630,10 +683,15 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonNoValidCACertificate, message, ) + specValid = false } + + return specValid } -func (t *Translator) validateHostName(listener *ListenerContext) { +// validateHostName validates hostname configuration per protocol. +// Returns true if the hostname spec is valid, false otherwise. +func (t *Translator) validateHostName(listener *ListenerContext) bool { if listener.Protocol == gwapiv1.UDPProtocolType || listener.Protocol == gwapiv1.TCPProtocolType { if listener.Hostname != nil { listener.SetCondition( @@ -642,20 +700,25 @@ func (t *Translator) validateHostName(listener *ListenerContext) { gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must not have hostname set when protocol is %s.", listener.Protocol), ) + return false } } + return true } -func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds ...gwapiv1.Kind) { +// validateAllowedRoutes validates allowed route kinds configuration. +// Returns true if the allowed routes spec is valid, false otherwise. +func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds ...gwapiv1.Kind) bool { canSupportKinds := make([]gwapiv1.RouteGroupKind, len(routeKinds)) for i, routeKind := range routeKinds { canSupportKinds[i] = gwapiv1.RouteGroupKind{Group: GroupPtr(gwapiv1.GroupName), Kind: routeKind} } if listener.AllowedRoutes == nil || len(listener.AllowedRoutes.Kinds) == 0 { listener.SetSupportedKinds(canSupportKinds...) - return + return true } + specValid := true supportedRouteKinds := make([]gwapiv1.Kind, 0) supportedKinds := make([]gwapiv1.RouteGroupKind, 0) unSupportedKinds := make([]gwapiv1.RouteGroupKind, 0) @@ -670,6 +733,7 @@ func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds gwapiv1.ListenerReasonInvalidRouteKinds, fmt.Sprintf("Group is not supported, group must be %s", gwapiv1.GroupName), ) + specValid = false continue } @@ -701,9 +765,11 @@ func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds gwapiv1.ListenerReasonInvalidRouteKinds, fmt.Sprintf("%s is not supported, kind must be one of %v", string(kind.Kind), printRouteKinds), ) + specValid = false } listener.SetSupportedKinds(supportedKinds...) + return specValid } type portListeners struct { @@ -717,6 +783,11 @@ func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContex listenerSets := sets.Set[string]{} for _, gateway := range gateways { for _, listener := range gateway.listeners { + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } hostname := new(gwapiv1.Hostname) if listener.Hostname != nil { hostname = listener.Hostname @@ -735,6 +806,118 @@ func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContex } } +// validateConflictedProtocolsListeners checks for listeners that have conflicting protocols on the same port. +// UDP can coexist with any protocol. HTTPS and TLS are treated as compatible via getProtocolForListener. +func (t *Translator) validateConflictedProtocolsListeners(gateways []*GatewayContext) { + validateByPort := func(listeners []*ListenerContext) { + portListenerInfo := map[gwapiv1.PortNumber][]*ListenerContext{} + for _, listener := range listeners { + if !isSpecValidForConflictChecks(listener) || !isSupportedListenerProtocol(listener.Protocol) { + continue + } + portListenerInfo[listener.Port] = append(portListenerInfo[listener.Port], listener) + } + + for _, listenersOnPort := range portListenerInfo { + nonUDPProtocols := sets.New[string]() + nonListenerSetCount := 0 + for _, listener := range listenersOnPort { + protocol := getProtocolForListener(listener) + if protocol == string(gwapiv1.UDPProtocolType) { + continue + } + nonUDPProtocols.Insert(protocol) + if !listener.isFromListenerSet() { + nonListenerSetCount++ + } + } + + // No protocol conflict when all non-UDP listeners are compatible. + if len(nonUDPProtocols) <= 1 { + continue + } + + // If there are more than 1 non-UDP protocols and more than 1 listener not from ListenerSet, + // we cannot determine a clear winner and all listeners on this port are in conflict. + if nonListenerSetCount > 1 { + // If any conflicted listener is not from ListenerSet, do not pick a winner. + for _, listener := range listenersOnPort { + if getProtocolForListener(listener) == string(gwapiv1.UDPProtocolType) { + continue + } + listener.SetCondition( + gwapiv1.ListenerConditionConflicted, + metav1.ConditionTrue, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + } + continue + } + + // When nonListenerSetCount == 1, explicitly pick the Gateway-owned listener as winner. + // When nonListenerSetCount == 0, pick the first ListenerSet listener as winner. + // Note: UDP conflicts are handled by validateConflictedLayer4Listeners, so we skip + // UDP listeners here (this branch is only reached when len(nonUDPProtocols) > 1). + var winnerProtocol string + if nonListenerSetCount == 1 { + // Find and use the non-ListenerSet listener's protocol as the winner + for _, listener := range listenersOnPort { + protocol := getProtocolForListener(listener) + if !listener.isFromListenerSet() && protocol != string(gwapiv1.UDPProtocolType) { + winnerProtocol = protocol + break + } + } + } + + for _, listener := range listenersOnPort { + protocol := getProtocolForListener(listener) + // Skip UDP listeners as they are handled by validateConflictedLayer4Listeners + if protocol == string(gwapiv1.UDPProtocolType) { + continue + } + + // If we have an explicit winner protocol, use it; otherwise first one wins + if winnerProtocol != "" { + if protocol != winnerProtocol { + listener.SetCondition( + gwapiv1.ListenerConditionConflicted, + metav1.ConditionTrue, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + } + } else { + // All conflicted listeners are from ListenerSet, first one wins + if winnerProtocol == "" { + winnerProtocol = protocol + } else if protocol != winnerProtocol { + listener.SetCondition( + gwapiv1.ListenerConditionConflicted, + metav1.ConditionTrue, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + } + } + } + } + } + + for _, gateway := range gateways { + validateByPort(gateway.listeners) + } + + if t.MergeGateways { + allListeners := make([]*ListenerContext, 0) + for _, gateway := range gateways { + allListeners = append(allListeners, gateway.listeners...) + } + validateByPort(allListeners) + } +} + func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContext) { // Iterate through all layer-7 (HTTP, HTTPS, TLS) listeners and collect info about protocols // and hostnames per port. @@ -744,6 +927,11 @@ func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContex if listener.Protocol == gwapiv1.UDPProtocolType || listener.Protocol == gwapiv1.TCPProtocolType { continue } + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } if portListenerInfo[listener.Port] == nil { portListenerInfo[listener.Port] = &portListeners{ protocols: sets.Set[string]{}, @@ -806,6 +994,11 @@ func (t *Translator) validateConflictedLayer4Listeners(gateways []*GatewayContex for _, gateway := range gateways { portListenerInfo := map[gwapiv1.PortNumber]*portListeners{} for _, listener := range gateway.listeners { + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } for _, protocol := range protocols { if listener.Protocol == protocol { if portListenerInfo[listener.Port] == nil { @@ -832,6 +1025,26 @@ func (t *Translator) validateConflictedLayer4Listeners(gateways []*GatewayContex } } +func getProtocolForListener(listener *ListenerContext) string { + switch listener.Protocol { + // HTTPS and TLS can co-exist on the same port. + case gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType: + return "https/tls" + default: + return string(listener.Protocol) + } +} + +func isSupportedListenerProtocol(protocol gwapiv1.ProtocolType) bool { + switch protocol { + case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType, + gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType: + return true + default: + return false + } +} + // Checks if a hostname is valid according to RFC 1123 and gateway API's requirement that it not be an IP address func (t *Translator) validateHostname(hostname string) error { if errs := validation.IsDNS1123Subdomain(hostname); errs != nil { From c481c91886468b3f8fd02cdcdabfd74496e2fc46 Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Wed, 6 May 2026 11:43:28 +0800 Subject: [PATCH 04/12] fix: remove cross ns policy attachment status (#8901) * Revert "add warning for partially accepted targets" This reverts commit 5d88fbbf8ae2104d86df9d41090d4bddcd9b8f55. Signed-off-by: Huabing (Robin) Zhao * remove warning condition for cross-ns policy attachments without referenceGrants Signed-off-by: Huabing (Robin) Zhao --------- Signed-off-by: Huabing (Robin) Zhao Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- api/v1alpha1/policy_helpers.go | 4 + api/v1alpha1/shared_types.go | 4 - ....envoyproxy.io_backendtrafficpolicies.yaml | 4 + ...y.envoyproxy.io_clienttrafficpolicies.yaml | 4 + ....envoyproxy.io_envoyextensionpolicies.yaml | 4 + ...ateway.envoyproxy.io_securitypolicies.yaml | 4 + ....envoyproxy.io_backendtrafficpolicies.yaml | 4 + ...y.envoyproxy.io_clienttrafficpolicies.yaml | 4 + ....envoyproxy.io_envoyextensionpolicies.yaml | 4 + ...ateway.envoyproxy.io_securitypolicies.yaml | 4 + internal/gatewayapi/backendtrafficpolicy.go | 30 +---- internal/gatewayapi/clienttrafficpolicy.go | 15 +-- internal/gatewayapi/envoyextensionpolicy.go | 30 +---- internal/gatewayapi/helpers.go | 118 ++---------------- internal/gatewayapi/securitypolicy.go | 30 +---- internal/gatewayapi/status/policy.go | 17 --- internal/gatewayapi/status/policy_test.go | 16 --- ...ial-referencegrant-gateway-target.in.yaml} | 0 ...al-referencegrant-gateway-target.out.yaml} | 13 -- ...rtial-referencegrant-route-target.in.yaml} | 0 ...tial-referencegrant-route-target.out.yaml} | 7 -- ...or-missing-referencegrant-gateway.in.yaml} | 0 ...r-missing-referencegrant-gateway.out.yaml} | 30 ----- ...ctor-missing-referencegrant-route.in.yaml} | 0 ...tor-missing-referencegrant-route.out.yaml} | 31 ----- site/content/en/latest/api/extension_types.md | 2 +- .../backendtrafficpolicy_cross_namespace.go | 15 --- test/helm/gateway-crds-helm/all.out.yaml | 16 +++ test/helm/gateway-crds-helm/e2e.out.yaml | 16 +++ .../envoy-gateway-crds.out.yaml | 16 +++ 30 files changed, 111 insertions(+), 331 deletions(-) rename internal/gatewayapi/testdata/{policy-cross-namespace-targetselector-partial-referencegrant-gateway-target.in.yaml => policy-cross-namespace-targetselector-missing-partial-referencegrant-gateway-target.in.yaml} (100%) rename internal/gatewayapi/testdata/{policy-cross-namespace-targetselector-partial-referencegrant-gateway-target.out.yaml => policy-cross-namespace-targetselector-missing-partial-referencegrant-gateway-target.out.yaml} (95%) rename internal/gatewayapi/testdata/{policy-cross-namespace-targetselector-partial-referencegrant-route-target.in.yaml => policy-cross-namespace-targetselector-missing-partial-referencegrant-route-target.in.yaml} (100%) rename internal/gatewayapi/testdata/{policy-cross-namespace-targetselector-partial-referencegrant-route-target.out.yaml => policy-cross-namespace-targetselector-missing-partial-referencegrant-route-target.out.yaml} (96%) rename internal/gatewayapi/testdata/{policy-cross-namespace-targetselector-invalid-referencegrant-gateway.in.yaml => policy-cross-namespace-targetselector-missing-referencegrant-gateway.in.yaml} (100%) rename internal/gatewayapi/testdata/{policy-cross-namespace-targetselector-invalid-referencegrant-gateway.out.yaml => policy-cross-namespace-targetselector-missing-referencegrant-gateway.out.yaml} (84%) rename internal/gatewayapi/testdata/{policy-cross-namespace-targetselector-invalid-referencegrant-route.in.yaml => policy-cross-namespace-targetselector-missing-referencegrant-route.in.yaml} (100%) rename internal/gatewayapi/testdata/{policy-cross-namespace-targetselector-invalid-referencegrant-route.out.yaml => policy-cross-namespace-targetselector-missing-referencegrant-route.out.yaml} (84%) diff --git a/api/v1alpha1/policy_helpers.go b/api/v1alpha1/policy_helpers.go index 10b8e099f7..7a0e2679c7 100644 --- a/api/v1alpha1/policy_helpers.go +++ b/api/v1alpha1/policy_helpers.go @@ -58,6 +58,10 @@ type TargetSelector struct { // When specified, the effective set of namespaces is always constrained to the // namespaces watched by Envoy Gateway. // + // Selecting targets across namespaces requires a ReferenceGrant in the target + // namespace that allows this policy kind to reference the selected target kind. + // Cross-namespace targets without a matching ReferenceGrant are ignored. + // // +optional Namespaces *TargetSelectorNamespaces `json:"namespaces,omitempty"` diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index 7530826341..27c8f3d2d1 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -70,10 +70,6 @@ const ( // PolicyReasonDeprecatedField is used with the "Warning" condition when the policy // uses deprecated fields that should be migrated to newer alternatives. PolicyReasonDeprecatedField gwapiv1.PolicyConditionReason = "DeprecatedField" - - // PolicyReasonRefNotPermitted is used when the policy targets a cross-namespace - // object without a matching ReferenceGrant. - PolicyReasonRefNotPermitted gwapiv1.PolicyConditionReason = "RefNotPermitted" ) // GroupVersionKind unambiguously identifies a Kind. diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 0b8ce0f5fd..447a9865f9 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -2924,6 +2924,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index 5aba61ba83..78e80bb4e5 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -1181,6 +1181,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index e0bd5d49bc..27ee6dd7f8 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -1824,6 +1824,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index 34ba4c7907..d90b11c3ad 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -7142,6 +7142,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 30739c66ba..fa26bf6705 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -2923,6 +2923,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index 62bd176d62..413730fae0 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -1180,6 +1180,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index 85c9878352..a09c724a31 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -1823,6 +1823,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 8de423fd20..791f1ac16b 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -7141,6 +7141,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index cb7c6787cc..599ee047ab 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -295,16 +295,14 @@ func (t *Translator) ProcessBackendTrafficPolicies( // Process the policies targeting Routes for i, currPolicy := range backendTrafficPolicies { policyName := utils.NamespacedName(currPolicy) - allowed, denied := resolvePolicyTargetsFromSelectors( - currPolicy.Spec.TargetSelectors, + targetRefs := resolvePolicyTargets( + currPolicy.Spec.PolicyTargetReferences, routes, resources.ReferenceGrants, egv1a1.GroupName, egv1a1.KindBackendTrafficPolicy, currPolicy.Namespace, t.GetNamespace) - plainTargetRefs := resolvePolicyTargetsFromReferences(currPolicy.Spec.PolicyTargetReferences, currPolicy.Namespace) - targetRefs := composePolicyTargetRefs(allowed, plainTargetRefs) for _, currTarget := range targetRefs { if isRoute(currTarget) { policy, found := handledPolicies[policyName] @@ -318,15 +316,6 @@ func (t *Translator) ProcessBackendTrafficPolicies( routeMap, gatewayRouteMap, gatewayPolicyMerged, gatewayPolicyMap, policy, currTarget) } } - if len(denied) > 0 { - policy, found := handledPolicies[policyName] - if !found { - policy = policyCopies[i] - handledPolicies[policyName] = policy - res = append(res, policy) - } - setPolicyTargetRefNotPermittedStatus(&policy.Status, denied, t.GatewayControllerName, policy.Generation) - } } // Process the policies targeting Listeners @@ -351,16 +340,14 @@ func (t *Translator) ProcessBackendTrafficPolicies( // Process the policies targeting Gateways for i, currPolicy := range backendTrafficPolicies { policyName := utils.NamespacedName(currPolicy) - allowed, denied := resolvePolicyTargetsFromSelectors( - currPolicy.Spec.TargetSelectors, + targetRefs := resolvePolicyTargets( + currPolicy.Spec.PolicyTargetReferences, gateways, resources.ReferenceGrants, egv1a1.GroupName, egv1a1.KindBackendTrafficPolicy, currPolicy.Namespace, t.GetNamespace) - plainTargetRefs := resolvePolicyTargetsFromReferences(currPolicy.Spec.PolicyTargetReferences, currPolicy.Namespace) - targetRefs := composePolicyTargetRefs(allowed, plainTargetRefs) for _, currTarget := range targetRefs { if isGateway(currTarget) { policy, found := handledPolicies[policyName] @@ -373,15 +360,6 @@ func (t *Translator) ProcessBackendTrafficPolicies( gatewayMap, gatewayRouteMap, gatewayPolicyMerged, policy, currTarget) } } - if len(denied) > 0 { - policy, found := handledPolicies[policyName] - if !found { - policy = policyCopies[i] - handledPolicies[policyName] = policy - res = append(res, policy) - } - setPolicyTargetRefNotPermittedStatus(&policy.Status, denied, t.GatewayControllerName, policy.Generation) - } } for _, policy := range res { diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index e06e84380b..10e830e4a0 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -195,8 +195,8 @@ func (t *Translator) ProcessClientTrafficPolicies( // Policy with no section set (targeting all sections) for i, currPolicy := range clientTrafficPolicies { policyName := utils.NamespacedName(currPolicy) - allowed, denied := resolvePolicyTargetsFromSelectors( - currPolicy.Spec.TargetSelectors, + targetRefs := resolvePolicyTargets( + currPolicy.Spec.PolicyTargetReferences, gateways, resources.ReferenceGrants, egv1a1.GroupName, @@ -204,8 +204,6 @@ func (t *Translator) ProcessClientTrafficPolicies( currPolicy.Namespace, t.GetNamespace, ) - plainTargetRefs := resolvePolicyTargetsFromReferences(currPolicy.Spec.PolicyTargetReferences, currPolicy.Namespace) - targetRefs := composePolicyTargetRefs(allowed, plainTargetRefs) for _, currTarget := range targetRefs { if !hasSectionName(&currTarget) { @@ -335,15 +333,6 @@ func (t *Translator) ProcessClientTrafficPolicies( } } } - if len(denied) > 0 { - policy, found := handledPolicies[policyName] - if !found { - policy = policyCopies[i] - res = append(res, policy) - handledPolicies[policyName] = policy - } - setPolicyTargetRefNotPermittedStatus(&policy.Status, denied, t.GatewayControllerName, policy.Generation) - } } for _, policy := range res { diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index 030138cdb6..83ed3b96ed 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -136,16 +136,14 @@ func (t *Translator) ProcessEnvoyExtensionPolicies( // Process the policies targeting xRoutes for i, currPolicy := range envoyExtensionPolicies { policyName := utils.NamespacedName(currPolicy) - allowed, denied := resolvePolicyTargetsFromSelectors( - currPolicy.Spec.TargetSelectors, + targetRefs := resolvePolicyTargets( + currPolicy.Spec.PolicyTargetReferences, routes, resources.ReferenceGrants, egv1a1.GroupName, egv1a1.KindEnvoyExtensionPolicy, currPolicy.Namespace, t.GetNamespace) - plainTargetRefs := resolvePolicyTargetsFromReferences(currPolicy.Spec.PolicyTargetReferences, currPolicy.Namespace) - targetRefs := composePolicyTargetRefs(allowed, plainTargetRefs) for _, currTarget := range targetRefs { if isRoute(currTarget) { policy, found := handledPolicies[policyName] @@ -159,15 +157,6 @@ func (t *Translator) ProcessEnvoyExtensionPolicies( routeMap, gatewayRouteMap, policy, currTarget) } } - if len(denied) > 0 { - policy, found := handledPolicies[policyName] - if !found { - policy = policyCopies[i] - res = append(res, policy) - handledPolicies[policyName] = policy - } - setPolicyTargetRefNotPermittedStatus(&policy.Status, denied, t.GatewayControllerName, policy.Generation) - } } // Process the policies targeting Listeners @@ -193,16 +182,14 @@ func (t *Translator) ProcessEnvoyExtensionPolicies( // Process the policies targeting Gateways for i, currPolicy := range envoyExtensionPolicies { policyName := utils.NamespacedName(currPolicy) - allowed, denied := resolvePolicyTargetsFromSelectors( - currPolicy.Spec.TargetSelectors, + targetRefs := resolvePolicyTargets( + currPolicy.Spec.PolicyTargetReferences, gateways, resources.ReferenceGrants, egv1a1.GroupName, egv1a1.KindEnvoyExtensionPolicy, currPolicy.Namespace, t.GetNamespace) - plainTargetRefs := resolvePolicyTargetsFromReferences(currPolicy.Spec.PolicyTargetReferences, currPolicy.Namespace) - targetRefs := composePolicyTargetRefs(allowed, plainTargetRefs) for _, currTarget := range targetRefs { if isGateway(currTarget) { policy, found := handledPolicies[policyName] @@ -216,15 +203,6 @@ func (t *Translator) ProcessEnvoyExtensionPolicies( gatewayMap, gatewayRouteMap, policy, currTarget) } } - if len(denied) > 0 { - policy, found := handledPolicies[policyName] - if !found { - policy = policyCopies[i] - res = append(res, policy) - handledPolicies[policyName] = policy - } - setPolicyTargetRefNotPermittedStatus(&policy.Status, denied, t.GatewayControllerName, policy.Generation) - } } for _, policy := range res { diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index a4aa6eab9b..ade73750e4 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -27,7 +27,6 @@ import ( egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/gatewayapi/resource" - "github.com/envoyproxy/gateway/internal/gatewayapi/status" "github.com/envoyproxy/gateway/internal/ir" "github.com/envoyproxy/gateway/internal/utils" ) @@ -767,11 +766,6 @@ type policyTargetReferenceWithSectionName struct { SectionName *gwapiv1.SectionName `json:"sectionName,omitempty"` } -type policySelectedTarget[T client.Object] struct { - Target T - Ref policyTargetReferenceWithSectionName -} - func isRouteRule(target policyTargetReferenceWithSectionName) bool { // If the target is not a gateway and the section name is not nil, then it's a route rule. return target.Kind != resource.KindGateway && target.SectionName != nil @@ -899,7 +893,7 @@ func isCrossNamespaceReferencePermitted( return false } -// resolvePolicyTargetsFromSelectors returns a list of policy target refs that are allowed and denied by the policy's TargetSelectors. +// resolvePolicyTargetsFromSelectors returns policy target refs allowed by the policy's TargetSelectors. func resolvePolicyTargetsFromSelectors[T client.Object]( targetSelectors []egv1a1.TargetSelector, potentialTargets []T, @@ -908,9 +902,9 @@ func resolvePolicyTargetsFromSelectors[T client.Object]( policyKind string, policyNamespace string, namespaceLookup func(string) *corev1.Namespace, -) (allowed, denied []policySelectedTarget[T]) { +) []targetRefWithTimestamp { allowedDedup := sets.New[targetRefWithTimestamp]() - deniedDedup := sets.New[policyTargetReferenceWithSectionName]() + targetRefs := make([]targetRefWithTimestamp, 0) for _, currSelector := range targetSelectors { labelSelector := selectorFromTargetSelector(currSelector) for _, obj := range potentialTargets { @@ -952,14 +946,6 @@ func resolvePolicyTargetsFromSelectors[T client.Object]( }, referenceGrants, ) { - if deniedDedup.Has(ref) { - continue - } - deniedDedup.Insert(ref) - denied = append(denied, policySelectedTarget[T]{ - Target: obj, - Ref: ref, - }) continue } @@ -971,14 +957,11 @@ func resolvePolicyTargetsFromSelectors[T client.Object]( continue } allowedDedup.Insert(targetRef) - allowed = append(allowed, policySelectedTarget[T]{ - Target: obj, - Ref: ref, - }) + targetRefs = append(targetRefs, targetRef) } } - return allowed, denied + return targetRefs } // resolvePolicyTargetsFromReferences returns a list of policy target refs specified in the policy's TargetRefs, with the namespace field populated. @@ -1007,23 +990,16 @@ func resolvePolicyTargetsFromReferences( } // composePolicyTargetRefs combines the allowed target refs derived from the selectors and the plain target refs specified in the policy. -func composePolicyTargetRefs[T client.Object]( - matches []policySelectedTarget[T], +func composePolicyTargetRefs( + selectorTargetRefs []targetRefWithTimestamp, plainTargetRefs []policyTargetReferenceWithSectionName, ) []policyTargetReferenceWithSectionName { // First add the target refs derived from the selectors, sorted by the creation timestamp of the matched objects. - selectorsList := make([]targetRefWithTimestamp, 0, len(matches)) - for _, match := range matches { - selectorsList = append(selectorsList, targetRefWithTimestamp{ - CreationTimestamp: match.Target.GetCreationTimestamp(), - policyTargetReferenceWithSectionName: match.Ref, - }) - } - slices.SortFunc(selectorsList, func(i, j targetRefWithTimestamp) int { + slices.SortFunc(selectorTargetRefs, func(i, j targetRefWithTimestamp) int { return i.CreationTimestamp.Compare(j.CreationTimestamp.Time) }) - ret := make([]policyTargetReferenceWithSectionName, len(selectorsList)) - for i, v := range selectorsList { + ret := make([]policyTargetReferenceWithSectionName, len(selectorTargetRefs)) + for i, v := range selectorTargetRefs { ret[i] = v.policyTargetReferenceWithSectionName } @@ -1051,7 +1027,7 @@ func resolvePolicyTargets[T client.Object]( policyNamespace string, namespaceLookup func(string) *corev1.Namespace, ) []policyTargetReferenceWithSectionName { - allowed, _ := resolvePolicyTargetsFromSelectors( + selectorTargetRefs := resolvePolicyTargetsFromSelectors( targetRefs.TargetSelectors, potentialTargets, referenceGrants, @@ -1060,77 +1036,7 @@ func resolvePolicyTargets[T client.Object]( policyNamespace, namespaceLookup) plainTargetRefs := resolvePolicyTargetsFromReferences(targetRefs, policyNamespace) - return composePolicyTargetRefs(allowed, plainTargetRefs) -} - -func setPolicyTargetRefNotPermittedStatus[T client.Object]( - policyStatus *gwapiv1.PolicyStatus, - denied []policySelectedTarget[T], - controllerName string, - generation int64, -) { - for _, deniedMatch := range denied { - msg := fmt.Sprintf( - "Target %s %s/%s is not permitted by any ReferenceGrant.", - deniedMatch.Target.GetObjectKind().GroupVersionKind().Kind, - deniedMatch.Target.GetNamespace(), - deniedMatch.Target.GetName(), - ) - - switch obj := any(deniedMatch.Target).(type) { - case *GatewayContext: - ancestorRef := getAncestorRefForPolicy(utils.NamespacedName(obj), nil) - setPolicyTargetRefNotPermittedStatusForAncestor(policyStatus, &ancestorRef, controllerName, generation, msg) - case RouteContext: - parentRefs := GetManagedParentReferences(obj) - ancestorRefs := make([]*gwapiv1.ParentReference, 0, len(parentRefs)) - for _, p := range parentRefs { - if p.Kind != nil && *p.Kind != resource.KindGateway { - continue - } - namespace := obj.GetNamespace() - if p.Namespace != nil { - namespace = string(*p.Namespace) - } - ancestorRef := getAncestorRefForPolicy(types.NamespacedName{ - Name: string(p.Name), - Namespace: namespace, - }, p.SectionName) - ancestorRefs = append(ancestorRefs, &ancestorRef) - } - for _, ancestorRef := range ancestorRefs { - setPolicyTargetRefNotPermittedStatusForAncestor(policyStatus, ancestorRef, controllerName, generation, msg) - } - } - } -} - -func setPolicyTargetRefNotPermittedStatusForAncestor( - policyStatus *gwapiv1.PolicyStatus, - ancestorRef *gwapiv1.ParentReference, - controllerName string, - generation int64, - message string, -) { - // If an ancestor has at least one effective target: Accepted=True, - // If some targets under that same ancestor were skipped due to missing ReferenceGrant: add Warning=True, reason RefNotPermitted. - if status.IsPolicyAncestorAccepted(policyStatus, ancestorRef, controllerName) { - status.SetWarningForPolicyAncestor( - policyStatus, - ancestorRef, - controllerName, - egv1a1.PolicyReasonRefNotPermitted, - message, - generation, - ) - return - } - - // If an ancestor has no effective target due to all targets being skipped by missing ReferenceGrant, the policy should be Rejected with reason RefNotPermitted. - status.SetResolveErrorForPolicyAncestor(policyStatus, ancestorRef, controllerName, generation, &status.PolicyResolveError{ - Reason: egv1a1.PolicyReasonRefNotPermitted, - Message: message, - }) + return composePolicyTargetRefs(selectorTargetRefs, plainTargetRefs) } // legacy function to get policy target refs without considering cross-namespace policy attachment. diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index f9d9fd43d2..779634d9ec 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -161,16 +161,14 @@ func (t *Translator) ProcessSecurityPolicies( // Process the policies targeting xRoutes (HTTP + TCP) for i, currPolicy := range securityPolicies { policyName := utils.NamespacedName(currPolicy) - allowed, denied := resolvePolicyTargetsFromSelectors( - currPolicy.Spec.TargetSelectors, + targetRefs := resolvePolicyTargets( + currPolicy.Spec.PolicyTargetReferences, routes, resources.ReferenceGrants, egv1a1.GroupName, egv1a1.KindSecurityPolicy, currPolicy.Namespace, t.GetNamespace) - plainTargetRefs := resolvePolicyTargetsFromReferences(currPolicy.Spec.PolicyTargetReferences, currPolicy.Namespace) - targetRefs := composePolicyTargetRefs(allowed, plainTargetRefs) for _, currTarget := range targetRefs { if isRoute(currTarget) { policy, found := handledPolicies[policyName] @@ -183,15 +181,6 @@ func (t *Translator) ProcessSecurityPolicies( t.processSecurityPolicyForRoute(resources, xdsIR, routeMap, gatewayRouteMap, gatewayPolicyMerged, gatewayPolicyMap, policy, currTarget) } } - if len(denied) > 0 { - policy, found := handledPolicies[policyName] - if !found { - policy = policyCopies[i] - handledPolicies[policyName] = policy - res = append(res, policy) - } - setPolicyTargetRefNotPermittedStatus(&policy.Status, denied, t.GatewayControllerName, policy.Generation) - } } // Process the policies targeting Listeners for i, currPolicy := range securityPolicies { @@ -214,16 +203,14 @@ func (t *Translator) ProcessSecurityPolicies( // Process the policies targeting Gateways for i, currPolicy := range securityPolicies { policyName := utils.NamespacedName(currPolicy) - allowed, denied := resolvePolicyTargetsFromSelectors( - currPolicy.Spec.TargetSelectors, + targetRefs := resolvePolicyTargets( + currPolicy.Spec.PolicyTargetReferences, gateways, resources.ReferenceGrants, egv1a1.GroupName, egv1a1.KindSecurityPolicy, currPolicy.Namespace, t.GetNamespace) - plainTargetRefs := resolvePolicyTargetsFromReferences(currPolicy.Spec.PolicyTargetReferences, currPolicy.Namespace) - targetRefs := composePolicyTargetRefs(allowed, plainTargetRefs) for _, currTarget := range targetRefs { if isGateway(currTarget) { @@ -237,15 +224,6 @@ func (t *Translator) ProcessSecurityPolicies( t.processSecurityPolicyForGateway(resources, xdsIR, gatewayMap, gatewayRouteMap, gatewayPolicyMerged, policy, currTarget) } } - if len(denied) > 0 { - policy, found := handledPolicies[policyName] - if !found { - policy = policyCopies[i] - handledPolicies[policyName] = policy - res = append(res, policy) - } - setPolicyTargetRefNotPermittedStatus(&policy.Status, denied, t.GatewayControllerName, policy.Generation) - } } for _, policy := range res { diff --git a/internal/gatewayapi/status/policy.go b/internal/gatewayapi/status/policy.go index 715ad7b5d0..6322e42928 100644 --- a/internal/gatewayapi/status/policy.go +++ b/internal/gatewayapi/status/policy.go @@ -82,13 +82,6 @@ func SetAcceptedForPolicyAncestor(policyStatus *gwapiv1.PolicyStatus, ancestorRe gwapiv1.PolicyConditionAccepted, metav1.ConditionTrue, gwapiv1.PolicyReasonAccepted, message, generation) } -func IsPolicyAncestorAccepted(policyStatus *gwapiv1.PolicyStatus, ancestorRef *gwapiv1.ParentReference, controllerName string) bool { - return meta.IsStatusConditionTrue( - policyAncestorConditions(policyStatus, ancestorRef, controllerName), - string(gwapiv1.PolicyConditionAccepted), - ) -} - // SetDeprecatedFieldsWarningForPolicyAncestors sets deprecated fields warning conditions for each ancestor reference. func SetDeprecatedFieldsWarningForPolicyAncestors(policyStatus *gwapiv1.PolicyStatus, ancestorRefs []*gwapiv1.ParentReference, controllerName string, generation int64, deprecatedFields map[string]string) { for _, ancestorRef := range ancestorRefs { @@ -327,16 +320,6 @@ func getPolicyAncestorCondition(policyStatus *gwapiv1.PolicyStatus, ancestorRef return nil } -func policyAncestorConditions(policyStatus *gwapiv1.PolicyStatus, ancestorRef *gwapiv1.ParentReference, controllerName string) []metav1.Condition { - for _, ancestor := range policyStatus.Ancestors { - if string(ancestor.ControllerName) == controllerName && ancestorRefsEqual(&ancestor.AncestorRef, ancestorRef) { - return ancestor.Conditions - } - } - - return nil -} - func mergePolicyWarningMessages(existing, next string) string { switch { case existing == "": diff --git a/internal/gatewayapi/status/policy_test.go b/internal/gatewayapi/status/policy_test.go index cdff974e5a..7f58333d47 100644 --- a/internal/gatewayapi/status/policy_test.go +++ b/internal/gatewayapi/status/policy_test.go @@ -84,19 +84,3 @@ func TestSetWarningForPolicyAncestorMergesWarnings(t *testing.T) { } } } - -func TestIsPolicyAncestorAccepted(t *testing.T) { - policyStatus := &gwapiv1.PolicyStatus{} - ancestorRef := &gwapiv1.ParentReference{Name: gwapiv1.ObjectName("example")} - controllerName := "example.com/controller" - - assert.False(t, IsPolicyAncestorAccepted(policyStatus, ancestorRef, controllerName)) - - SetConditionForPolicyAncestor(policyStatus, ancestorRef, controllerName, - gwapiv1.PolicyConditionAccepted, metav1.ConditionFalse, egv1a1.PolicyReasonRefNotPermitted, "not permitted", 1) - assert.False(t, IsPolicyAncestorAccepted(policyStatus, ancestorRef, controllerName)) - - SetConditionForPolicyAncestor(policyStatus, ancestorRef, controllerName, - gwapiv1.PolicyConditionAccepted, metav1.ConditionTrue, gwapiv1.PolicyReasonAccepted, "accepted", 1) - assert.True(t, IsPolicyAncestorAccepted(policyStatus, ancestorRef, controllerName)) -} diff --git a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-gateway-target.in.yaml b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-gateway-target.in.yaml similarity index 100% rename from internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-gateway-target.in.yaml rename to internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-gateway-target.in.yaml diff --git a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-gateway-target.out.yaml b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-gateway-target.out.yaml similarity index 95% rename from internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-gateway-target.out.yaml rename to internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-gateway-target.out.yaml index 7be18da1de..2467854087 100644 --- a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-gateway-target.out.yaml +++ b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-gateway-target.out.yaml @@ -27,19 +27,6 @@ backendTrafficPolicies: status: "True" type: Accepted controllerName: gateway.envoyproxy.io/gatewayclass-controller - - ancestorRef: - group: gateway.networking.k8s.io - kind: Gateway - name: denied-gateway - namespace: policy-target-b - conditions: - - lastTransitionTime: null - message: Target Gateway policy-target-b/denied-gateway is not permitted by - any ReferenceGrant. - reason: RefNotPermitted - status: "False" - type: Accepted - controllerName: gateway.envoyproxy.io/gatewayclass-controller gateways: - apiVersion: gateway.networking.k8s.io/v1 kind: Gateway diff --git a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-route-target.in.yaml b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-route-target.in.yaml similarity index 100% rename from internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-route-target.in.yaml rename to internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-route-target.in.yaml diff --git a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-route-target.out.yaml b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-route-target.out.yaml similarity index 96% rename from internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-route-target.out.yaml rename to internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-route-target.out.yaml index 6face1741d..0b5a59838d 100644 --- a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-partial-referencegrant-route-target.out.yaml +++ b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-partial-referencegrant-route-target.out.yaml @@ -27,13 +27,6 @@ backendTrafficPolicies: reason: Accepted status: "True" type: Accepted - - lastTransitionTime: null - message: Target HTTPRoute policy-target-b/denied-route is not permitted by - any ReferenceGrant.; Target HTTPRoute policy-target-c/denied-route is not - permitted by any ReferenceGrant. - reason: RefNotPermitted - status: "True" - type: Warning controllerName: gateway.envoyproxy.io/gatewayclass-controller gateways: - apiVersion: gateway.networking.k8s.io/v1 diff --git a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-gateway.in.yaml b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-gateway.in.yaml similarity index 100% rename from internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-gateway.in.yaml rename to internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-gateway.in.yaml diff --git a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-gateway.out.yaml b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-gateway.out.yaml similarity index 84% rename from internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-gateway.out.yaml rename to internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-gateway.out.yaml index 4a883cbcf0..3a1c15c021 100644 --- a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-gateway.out.yaml +++ b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-gateway.out.yaml @@ -1,33 +1,3 @@ -backendTrafficPolicies: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: BackendTrafficPolicy - metadata: - name: cross-ns-policy - namespace: policy-ns - spec: - targetSelectors: - - group: gateway.networking.k8s.io - kind: Gateway - matchLabels: - policy: selected - namespaces: - from: All - useClientProtocol: true - status: - ancestors: - - ancestorRef: - group: gateway.networking.k8s.io - kind: Gateway - name: target-gateway - namespace: policy-target-ns - conditions: - - lastTransitionTime: null - message: Target Gateway policy-target-ns/target-gateway is not permitted by - any ReferenceGrant. - reason: RefNotPermitted - status: "False" - type: Accepted - controllerName: gateway.envoyproxy.io/gatewayclass-controller gateways: - apiVersion: gateway.networking.k8s.io/v1 kind: Gateway diff --git a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-route.in.yaml b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-route.in.yaml similarity index 100% rename from internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-route.in.yaml rename to internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-route.in.yaml diff --git a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-route.out.yaml b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-route.out.yaml similarity index 84% rename from internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-route.out.yaml rename to internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-route.out.yaml index 7f0dd84ffa..129c29c879 100644 --- a/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-invalid-referencegrant-route.out.yaml +++ b/internal/gatewayapi/testdata/policy-cross-namespace-targetselector-missing-referencegrant-route.out.yaml @@ -1,34 +1,3 @@ -backendTrafficPolicies: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: BackendTrafficPolicy - metadata: - name: cross-ns-policy - namespace: policy-ns - spec: - targetSelectors: - - group: gateway.networking.k8s.io - kind: HTTPRoute - matchLabels: - policy: selected - namespaces: - from: All - useClientProtocol: true - status: - ancestors: - - ancestorRef: - group: gateway.networking.k8s.io - kind: Gateway - name: target-gateway - namespace: policy-target-ns - sectionName: http - conditions: - - lastTransitionTime: null - message: Target HTTPRoute policy-target-ns/target-route is not permitted by - any ReferenceGrant. - reason: RefNotPermitted - status: "False" - type: Accepted - controllerName: gateway.envoyproxy.io/gatewayclass-controller gateways: - apiVersion: gateway.networking.k8s.io/v1 kind: Gateway diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 130bddae4d..ad782c4270 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -6197,7 +6197,7 @@ _Appears in:_ | --- | --- | --- | --- | --- | | `group` | _[Group](#group)_ | true | gateway.networking.k8s.io | Group is the group that this selector targets. Defaults to gateway.networking.k8s.io | | `kind` | _[Kind](#kind)_ | true | | Kind is the resource kind that this selector targets. | -| `namespaces` | _[TargetSelectorNamespaces](#targetselectornamespaces)_ | false | | Namespaces determines which namespaces are considered for target selection.
If unspecified, only targets in the same namespace as this policy are considered.
When specified, the effective set of namespaces is always constrained to the
namespaces watched by Envoy Gateway. | +| `namespaces` | _[TargetSelectorNamespaces](#targetselectornamespaces)_ | false | | Namespaces determines which namespaces are considered for target selection.
If unspecified, only targets in the same namespace as this policy are considered.
When specified, the effective set of namespaces is always constrained to the
namespaces watched by Envoy Gateway.
Selecting targets across namespaces requires a ReferenceGrant in the target
namespace that allows this policy kind to reference the selected target kind.
Cross-namespace targets without a matching ReferenceGrant are ignored. | | `matchLabels` | _object (keys:string, values:string)_ | false | | MatchLabels are the set of label selectors for identifying the targeted resource. | | `matchExpressions` | _[LabelSelectorRequirement](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#labelselectorrequirement-v1-meta) array_ | false | | MatchExpressions is a list of label selector requirements. The requirements are ANDed. | diff --git a/test/e2e/tests/backendtrafficpolicy_cross_namespace.go b/test/e2e/tests/backendtrafficpolicy_cross_namespace.go index 15214415af..2a01fe9ea6 100644 --- a/test/e2e/tests/backendtrafficpolicy_cross_namespace.go +++ b/test/e2e/tests/backendtrafficpolicy_cross_namespace.go @@ -57,12 +57,6 @@ var BackendTrafficPolicyCrossNamespaceTest = suite.ConformanceTest{ Namespace: gatewayapi.NamespacePtr(grantedGatewayNN.Namespace), Name: gwapiv1.ObjectName(grantedGatewayNN.Name), } - deniedAncestorRef := gwapiv1.ParentReference{ - Group: gatewayapi.GroupPtr(gwapiv1.GroupName), - Kind: gatewayapi.KindPtr(resource.KindGateway), - Namespace: gatewayapi.NamespacePtr(deniedGatewayNN.Namespace), - Name: gwapiv1.ObjectName(deniedGatewayNN.Name), - } BackendTrafficPolicyMustBeAccepted( t, @@ -72,15 +66,6 @@ var BackendTrafficPolicyCrossNamespaceTest = suite.ConformanceTest{ grantedAncestorRef, ) - BackendTrafficPolicyMustFail( - t, - suite.Client, - types.NamespacedName{Name: "cross-namespace-btp-denied", Namespace: policyNS}, - suite.ControllerName, - deniedAncestorRef, - "is not permitted by any ReferenceGrant", - ) - grantedResponse := http.ExpectedResponse{ Namespace: grantedNS, Request: http.Request{ diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index c826ebb424..9ebe32e3b9 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -25451,6 +25451,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -27308,6 +27312,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -30088,6 +30096,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -57041,6 +57053,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/test/helm/gateway-crds-helm/e2e.out.yaml b/test/helm/gateway-crds-helm/e2e.out.yaml index e814908295..1c4ddb0c1a 100644 --- a/test/helm/gateway-crds-helm/e2e.out.yaml +++ b/test/helm/gateway-crds-helm/e2e.out.yaml @@ -3424,6 +3424,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -5281,6 +5285,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -8061,6 +8069,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -35014,6 +35026,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index d8def29527..35d05311aa 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -3424,6 +3424,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -5281,6 +5285,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -8061,6 +8069,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same @@ -35014,6 +35026,10 @@ spec: When specified, the effective set of namespaces is always constrained to the namespaces watched by Envoy Gateway. + + Selecting targets across namespaces requires a ReferenceGrant in the target + namespace that allows this policy kind to reference the selected target kind. + Cross-namespace targets without a matching ReferenceGrant are ignored. properties: from: default: Same From 707e11f390a057042acc86757e0c773093325901 Mon Sep 17 00:00:00 2001 From: zirain Date: Thu, 7 May 2026 14:34:30 +0800 Subject: [PATCH 05/12] feat: add runner event metrics (#8802) * add metrics for runner Signed-off-by: zirain * rename Signed-off-by: zirain * rename Signed-off-by: zirain * reuse Signed-off-by: zirain --------- Signed-off-by: zirain Signed-off-by: Arko Dasgupta Co-authored-by: Arko Dasgupta Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- internal/gatewayapi/runner/runner.go | 2 ++ internal/globalratelimit/runner/runner.go | 2 ++ internal/infrastructure/runner/runner.go | 1 + internal/message/metrics.go | 10 ++++++++-- internal/message/watchutil.go | 11 +++++++++++ internal/xds/runner/runner.go | 2 ++ release-notes/current.yaml | 5 +++++ 7 files changed, 31 insertions(+), 2 deletions(-) diff --git a/internal/gatewayapi/runner/runner.go b/internal/gatewayapi/runner/runner.go index e5b6f21c4a..e8ed6f5e56 100644 --- a/internal/gatewayapi/runner/runner.go +++ b/internal/gatewayapi/runner/runner.go @@ -190,6 +190,8 @@ func (r *Runner) subscribeAndTranslate(sub <-chan watchable.Snapshot[string, *re r.Logger, message.Metadata{Runner: r.Name(), Message: message.ProviderResourcesMessageName}, sub, func(update message.Update[string, *resource.ControllerResourcesContext], errChan chan error) { + message.PublishRunnerEventMetric(r.Name(), update.Delete) + parentCtx := context.Background() if update.Value != nil && update.Value.Context != nil { parentCtx = update.Value.Context diff --git a/internal/globalratelimit/runner/runner.go b/internal/globalratelimit/runner/runner.go index d684b59044..fd1bab3e02 100644 --- a/internal/globalratelimit/runner/runner.go +++ b/internal/globalratelimit/runner/runner.go @@ -145,6 +145,8 @@ func (r *Runner) translateFromSubscription(ctx context.Context, c <-chan watchab r.Logger, message.Metadata{Runner: r.Name(), Message: message.XDSIRMessageName}, c, func(update message.Update[string, *message.XdsIRWithContext], errChan chan error) { + message.PublishRunnerEventMetric(r.Name(), update.Delete) + parentCtx := ctx if update.Value != nil && update.Value.Context != nil { parentCtx = update.Value.Context diff --git a/internal/infrastructure/runner/runner.go b/internal/infrastructure/runner/runner.go index 2b031e8a12..bb5f19db78 100644 --- a/internal/infrastructure/runner/runner.go +++ b/internal/infrastructure/runner/runner.go @@ -108,6 +108,7 @@ func (r *Runner) updateProxyInfraFromSubscription(ctx context.Context, sub <-cha default: } r.Logger.Info("received an update", "key", update.Key, "delete", update.Delete) + message.PublishRunnerEventMetric(r.Name(), update.Delete) val := update.Value if update.Delete { diff --git a/internal/message/metrics.go b/internal/message/metrics.go index c4127e7bfa..c6fe385392 100644 --- a/internal/message/metrics.go +++ b/internal/message/metrics.go @@ -34,6 +34,12 @@ var ( "Total number of published updates to watchable queue.", ) - runnerLabel = metrics.NewLabel("runner") - messageLabel = metrics.NewLabel("message") + watchableEventTotal = metrics.NewCounter( + "watchable_event_total", + "Total number of runner events.", + ) + + runnerLabel = metrics.NewLabel("runner") + messageLabel = metrics.NewLabel("message") + runnerEventTypeLabel = metrics.NewLabel("event_type") ) diff --git a/internal/message/watchutil.go b/internal/message/watchutil.go index ac0d6990b6..1f69202731 100644 --- a/internal/message/watchutil.go +++ b/internal/message/watchutil.go @@ -27,6 +27,17 @@ func PublishMetric(meta Metadata, count int) { watchablePublishTotal.WithSuccess(meta.LabelValues()...).Add(float64(count)) } +func PublishRunnerEventMetric(runnerName string, isDelete bool) { + eventType := "update" + if isDelete { + eventType = "delete" + } + watchableEventTotal.With( + runnerEventTypeLabel.Value(eventType), + runnerLabel.Value(runnerName), + ).Add(1) +} + func (m Metadata) LabelValues() []metrics.LabelValue { labels := make([]metrics.LabelValue, 0, 2) if m.Runner != "" { diff --git a/internal/xds/runner/runner.go b/internal/xds/runner/runner.go index e1ffc4d42d..48bbdb678e 100644 --- a/internal/xds/runner/runner.go +++ b/internal/xds/runner/runner.go @@ -263,6 +263,8 @@ func (r *Runner) translateFromSubscription(sub <-chan watchable.Snapshot[string, r.Logger, message.Metadata{Runner: r.Name(), Message: message.XDSIRMessageName}, sub, func(update message.Update[string, *message.XdsIRWithContext], errChan chan error) { + message.PublishRunnerEventMetric(r.Name(), update.Delete) + parentCtx := context.Background() if update.Value != nil && update.Value.Context != nil { parentCtx = update.Value.Context diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 7211ceb5ea..331df07552 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -21,3 +21,8 @@ deprecations: | # Other notable changes not covered by the above sections. Other changes: | + Moved Envoy Gateway CRDs into a sub-chart to avoid the Helm release secret exceeding the 1MB size limit when adding new API fields. Upgrade/Install behavior is unchanged for users. + The maximum number of rules in a RateLimit policy is increased from 128 to 256. + The maximum number of JWT providers allowed in `SecurityPolicy.spec.jwt.providers` is increased from 4 to 16. + Added `runner_event_total` metric to track update and delete events in infrastructure and gateway API runners for improved observability. + From f9d996384d136ec85d0461e217bfda903a8b255f Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Thu, 7 May 2026 18:23:05 -0700 Subject: [PATCH 06/12] fix: respect backend endpoint hostname for health checks (#8929) * fix: respect backend endpoint hostname for health checks ### Summary - Keep BackendTrafficPolicy HTTP health check hostnames as explicit cluster-level hosts, and leave route-derived host fallback to xDS cluster translation. - Preserve Backend endpoint hostnames as per-endpoint overrides via Endpoint.HealthCheckConfig.hostname, ahead of the route fallback. - Update gatewayapi/xDS fixtures, release notes, and generated API docs/CRDs for the host selection order. ### Test plan - go test ./internal/ir - go test ./internal/xds/translator - go test ./internal/gatewayapi -run TestTranslate/backendtrafficpolicy - go test ./internal/gatewayapi -run TestTranslate/(clienttrafficpolicy-http-health-check|envoyextensionpolicy-with-extproc-with-retries|envoyextensionpolicy-with-extproc-with-traffic-features|envoyproxy-accesslog-with-traffic|envoyproxy-tracing-backend-uds|envoyproxy-tracing-backend|securitypolicy-with-jwt-backendcluster|securitypolicy-with-jwt-backendsettings) - make generate - make manifests - git diff --check Signed-off-by: Arko Dasgupta Co-authored-by: Codex * fix gen Signed-off-by: zirain --------- Signed-off-by: Arko Dasgupta Signed-off-by: zirain Co-authored-by: Codex Co-authored-by: zirain Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- api/v1alpha1/healthcheck_types.go | 5 +- ....envoyproxy.io_backendtrafficpolicies.yaml | 5 +- ....envoyproxy.io_envoyextensionpolicies.yaml | 5 +- .../gateway.envoyproxy.io_envoyproxies.yaml | 20 +- ...ateway.envoyproxy.io_securitypolicies.yaml | 20 +- ....envoyproxy.io_backendtrafficpolicies.yaml | 5 +- ....envoyproxy.io_envoyextensionpolicies.yaml | 5 +- .../gateway.envoyproxy.io_envoyproxies.yaml | 20 +- ...ateway.envoyproxy.io_securitypolicies.yaml | 20 +- internal/gatewayapi/backendtrafficpolicy.go | 6 - ...cpolicy-healthcheck-host-hierarchy.in.yaml | 171 ++++++ ...policy-healthcheck-host-hierarchy.out.yaml | 510 ++++++++++++++++++ ...policy-with-healthcheck-overrides.out.yaml | 4 +- ...endtrafficpolicy-with-healthcheck.out.yaml | 4 +- internal/ir/xds.go | 10 - internal/ir/xds_test.go | 3 +- internal/xds/translator/cluster.go | 22 +- .../xds-ir/health-check-host-hierarchy.yaml | 88 +++ .../health-check-host-hierarchy.clusters.yaml | 139 +++++ ...health-check-host-hierarchy.endpoints.yaml | 1 + ...health-check-host-hierarchy.listeners.yaml | 35 ++ .../health-check-host-hierarchy.routes.yaml | 36 ++ release-notes/current.yaml | 1 + site/content/en/latest/api/extension_types.md | 2 +- test/helm/gateway-crds-helm/all.out.yaml | 50 +- test/helm/gateway-crds-helm/e2e.out.yaml | 50 +- .../envoy-gateway-crds.out.yaml | 50 +- 27 files changed, 1155 insertions(+), 132 deletions(-) create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-healthcheck-host-hierarchy.in.yaml create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-healthcheck-host-hierarchy.out.yaml create mode 100644 internal/xds/translator/testdata/in/xds-ir/health-check-host-hierarchy.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.clusters.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.endpoints.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.listeners.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.routes.yaml diff --git a/api/v1alpha1/healthcheck_types.go b/api/v1alpha1/healthcheck_types.go index 7edf17744d..eed9a6a179 100644 --- a/api/v1alpha1/healthcheck_types.go +++ b/api/v1alpha1/healthcheck_types.go @@ -177,8 +177,9 @@ const ( // HTTPActiveHealthChecker defines the settings of http health check. type HTTPActiveHealthChecker struct { - // Hostname defines the HTTP host that will be requested during health checking. - // Default: HTTPRoute or GRPCRoute hostname. + // Hostname defines the HTTP Host header used for active HTTP health checks. + // Host selection uses this order: this field, the associated Backend endpoint + // hostname if available, then the effective Route hostname. // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 447a9865f9..1ad45ac95a 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -671,8 +671,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index 27ee6dd7f8..8b24dac2fc 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -567,8 +567,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml index 8b19d5b1b0..33db2b3cde 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -11837,8 +11837,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -13368,8 +13369,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -15086,8 +15088,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -16694,8 +16697,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index d90b11c3ad..4d618a9f25 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -1194,8 +1194,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -2597,8 +2598,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -4279,8 +4281,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -5993,8 +5996,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index fa26bf6705..64875d52ee 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -670,8 +670,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index a09c724a31..51964f1d6a 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -566,8 +566,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 58f11213f9..19e9614662 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -11836,8 +11836,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -13367,8 +13368,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -15085,8 +15087,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -16693,8 +16696,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 791f1ac16b..47686dab2d 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -1193,8 +1193,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -2596,8 +2597,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -4278,8 +4280,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -5992,8 +5995,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index 599ee047ab..40380b895b 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -1020,9 +1020,6 @@ func (t *Translator) applyTrafficFeatureToRoute(route RouteContext, r.Traffic.Timeout = localTo } - // Update the Host field in HealthCheck, now that we have access to the Route Hostname. - r.Traffic.HealthCheck.SetHTTPHostIfAbsent(r.Hostname) - if policy.Spec.UseClientProtocol != nil { r.UseClientProtocol = policy.Spec.UseClientProtocol } @@ -1321,9 +1318,6 @@ func (t *Translator) translateBackendTrafficPolicyForGateway( r.Traffic.Timeout = localTo } - // Update the Host field in HealthCheck, now that we have access to the Route Hostname. - r.Traffic.HealthCheck.SetHTTPHostIfAbsent(r.Hostname) - if policy.Spec.UseClientProtocol != nil { r.UseClientProtocol = policy.Spec.UseClientProtocol } diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-healthcheck-host-hierarchy.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-healthcheck-host-hierarchy.in.yaml new file mode 100644 index 0000000000..7a45a5401a --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-healthcheck-host-hierarchy.in.yaml @@ -0,0 +1,171 @@ +# Health check Host header hierarchy: +# 1. BackendTrafficPolicy healthCheck.active.http.hostname wins. +# 2. Backend.spec.endpoints[].hostname overrides the route-derived default. +# 3. Effective HTTPRoute/GRPCRoute hostname for the listener remains the fallback +# when the endpoint has no hostname. +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + namespace: default + name: backend-with-hostname + spec: + endpoints: + - hostname: backend-endpoint.example.com + fqdn: + hostname: backend-address.example.com + port: 443 +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + namespace: default + name: backend-without-hostname + spec: + endpoints: + - fqdn: + hostname: backend-no-endpoint-host.example.com + port: 443 +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-btp-host + spec: + hostnames: + - btp-route.example.com + parentRefs: + - namespace: envoy-gateway + name: gateway + sectionName: http + rules: + - matches: + - path: + value: /btp-host + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-with-hostname +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-backend-host + spec: + hostnames: + - backend-route.example.com + parentRefs: + - namespace: envoy-gateway + name: gateway + sectionName: http + rules: + - matches: + - path: + value: /backend-host + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-with-hostname +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-route-host + spec: + hostnames: + - route-fallback.example.com + parentRefs: + - namespace: envoy-gateway + name: gateway + sectionName: http + rules: + - matches: + - path: + value: /route-host + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-without-hostname +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: policy-btp-host + spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-btp-host + healthCheck: + active: + timeout: 2s + interval: 5s + healthyThreshold: 1 + unhealthyThreshold: 3 + type: HTTP + http: + hostname: btp-health.example.com + path: /healthz + method: GET + expectedStatuses: + - 200 +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: policy-backend-host + spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-backend-host + healthCheck: + active: + timeout: 2s + interval: 5s + healthyThreshold: 1 + unhealthyThreshold: 3 + type: HTTP + http: + path: /healthz + method: GET + expectedStatuses: + - 200 +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: policy-route-host + spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-route-host + healthCheck: + active: + timeout: 2s + interval: 5s + healthyThreshold: 1 + unhealthyThreshold: 3 + type: HTTP + http: + path: /healthz + method: GET + expectedStatuses: + - 200 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-healthcheck-host-hierarchy.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-healthcheck-host-hierarchy.out.yaml new file mode 100644 index 0000000000..08dfc3af7b --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-healthcheck-host-hierarchy.out.yaml @@ -0,0 +1,510 @@ +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + name: policy-btp-host + namespace: default + spec: + healthCheck: + active: + healthyThreshold: 1 + http: + expectedStatuses: + - 200 + hostname: btp-health.example.com + method: GET + path: /healthz + interval: 5s + timeout: 2s + type: HTTP + unhealthyThreshold: 3 + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-btp-host + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + name: policy-backend-host + namespace: default + spec: + healthCheck: + active: + healthyThreshold: 1 + http: + expectedStatuses: + - 200 + method: GET + path: /healthz + interval: 5s + timeout: 2s + type: HTTP + unhealthyThreshold: 3 + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-backend-host + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + name: policy-route-host + namespace: default + spec: + healthCheck: + active: + healthyThreshold: 1 + http: + expectedStatuses: + - 200 + method: GET + path: /healthz + interval: 5s + timeout: 2s + type: HTTP + unhealthyThreshold: 3 + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-route-host + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + name: backend-with-hostname + namespace: default + spec: + endpoints: + - fqdn: + hostname: backend-address.example.com + port: 443 + hostname: backend-endpoint.example.com + status: + conditions: + - lastTransitionTime: null + message: The Backend was accepted + reason: Accepted + status: "True" + type: Accepted +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + name: backend-without-hostname + namespace: default + spec: + endpoints: + - fqdn: + hostname: backend-no-endpoint-host.example.com + port: 443 + status: + conditions: + - lastTransitionTime: null + message: The Backend was accepted + reason: Accepted + status: "True" + type: Accepted +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 3 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-btp-host + namespace: default + spec: + hostnames: + - btp-route.example.com + parentRefs: + - name: gateway + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-with-hostname + matches: + - path: + value: /btp-host + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway + namespace: envoy-gateway + sectionName: http +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-backend-host + namespace: default + spec: + hostnames: + - backend-route.example.com + parentRefs: + - name: gateway + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-with-hostname + matches: + - path: + value: /backend-host + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway + namespace: envoy-gateway + sectionName: http +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-route-host + namespace: default + spec: + hostnames: + - route-fallback.example.com + parentRefs: + - name: gateway + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-without-hostname + matches: + - path: + value: /route-host + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway: + proxy: + listeners: + - name: envoy-gateway/gateway/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-966d2c13 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-966d2c13 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-backend-host + namespace: default + name: httproute/default/httproute-backend-host/rule/0 + settings: + - addressType: FQDN + endpoints: + - host: backend-address.example.com + hostname: backend-endpoint.example.com + port: 443 + metadata: + kind: Backend + name: backend-with-hostname + namespace: default + name: httproute/default/httproute-backend-host/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: backend-route.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-backend-host + namespace: default + policies: + - kind: BackendTrafficPolicy + name: policy-backend-host + namespace: default + name: httproute/default/httproute-backend-host/rule/0/match/0/backend-route_example_com + pathMatch: + distinct: false + name: "" + prefix: /backend-host + traffic: + healthCheck: + active: + healthyThreshold: 1 + http: + expectedStatuses: + - 200 + host: "" + method: GET + path: /healthz + interval: 5s + timeout: 2s + unhealthyThreshold: 3 + - destination: + metadata: + kind: HTTPRoute + name: httproute-route-host + namespace: default + name: httproute/default/httproute-route-host/rule/0 + settings: + - addressType: FQDN + endpoints: + - host: backend-no-endpoint-host.example.com + port: 443 + metadata: + kind: Backend + name: backend-without-hostname + namespace: default + name: httproute/default/httproute-route-host/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: route-fallback.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-route-host + namespace: default + policies: + - kind: BackendTrafficPolicy + name: policy-route-host + namespace: default + name: httproute/default/httproute-route-host/rule/0/match/0/route-fallback_example_com + pathMatch: + distinct: false + name: "" + prefix: /route-host + traffic: + healthCheck: + active: + healthyThreshold: 1 + http: + expectedStatuses: + - 200 + host: "" + method: GET + path: /healthz + interval: 5s + timeout: 2s + unhealthyThreshold: 3 + - destination: + metadata: + kind: HTTPRoute + name: httproute-btp-host + namespace: default + name: httproute/default/httproute-btp-host/rule/0 + settings: + - addressType: FQDN + endpoints: + - host: backend-address.example.com + hostname: backend-endpoint.example.com + port: 443 + metadata: + kind: Backend + name: backend-with-hostname + namespace: default + name: httproute/default/httproute-btp-host/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: btp-route.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-btp-host + namespace: default + policies: + - kind: BackendTrafficPolicy + name: policy-btp-host + namespace: default + name: httproute/default/httproute-btp-host/rule/0/match/0/btp-route_example_com + pathMatch: + distinct: false + name: "" + prefix: /btp-host + traffic: + healthCheck: + active: + healthyThreshold: 1 + http: + expectedStatuses: + - 200 + host: btp-health.example.com + method: GET + path: /healthz + interval: 5s + timeout: 2s + unhealthyThreshold: 3 + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck-overrides.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck-overrides.out.yaml index f6b26324dc..6574a89a28 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck-overrides.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck-overrides.out.yaml @@ -446,7 +446,7 @@ xdsIR: http: expectedStatuses: - 200 - host: gateway.envoyproxy.io + host: "" method: GET path: /healthz interval: 5s @@ -493,7 +493,7 @@ xdsIR: http: expectedStatuses: - 200 - host: gateway.envoyproxy.io + host: "" method: GET path: /healthz interval: 5s diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck.out.yaml index a1480de5e0..ead1bb08f2 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck.out.yaml @@ -885,7 +885,7 @@ xdsIR: expectedStatuses: - 200 - 300 - host: '*' + host: "" method: GET path: /healthz interval: 3s @@ -1173,7 +1173,7 @@ xdsIR: text: pong expectedStatuses: - 200 - host: gateway.envoyproxy.io + host: "" method: GET path: /healthz interval: 5s diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 9a1c7e91b3..940996be35 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -69,7 +69,6 @@ var ( ErrHealthCheckUnhealthyThresholdInvalid = errors.New("field HealthCheck.UnhealthyThreshold should be greater than 0") ErrHealthCheckHealthyThresholdInvalid = errors.New("field HealthCheck.HealthyThreshold should be greater than 0") ErrHealthCheckerInvalid = errors.New("health checker setting is invalid, only one health checker can be set") - ErrHCHTTPHostInvalid = errors.New("field HTTPHealthChecker.Host should be specified") ErrHCHTTPPathInvalid = errors.New("field HTTPHealthChecker.Path should be specified") ErrHCHTTPMethodInvalid = errors.New("only one of the GET, HEAD, POST, DELETE, OPTIONS, TRACE, PATCH of HTTPHealthChecker.Method could be set") ErrHCHTTPExpectedStatusesInvalid = errors.New("field HTTPHealthChecker.ExpectedStatuses should be specified") @@ -3196,12 +3195,6 @@ type ActiveHealthCheck struct { Overrides *HealthCheckOverrides `json:"overrides,omitempty" yaml:"overrides,omitempty"` } -func (h *HealthCheck) SetHTTPHostIfAbsent(host string) { - if h != nil && h.Active != nil && h.Active.HTTP != nil && h.Active.HTTP.Host == "" { - h.Active.HTTP.Host = host - } -} - // Validate the fields within the HealthCheck structure. func (h *HealthCheck) Validate() error { var errs error @@ -3295,9 +3288,6 @@ type HTTPHealthChecker struct { // Validate the fields within the HTTPHealthChecker structure. func (c *HTTPHealthChecker) Validate() error { var errs error - if c.Host == "" { - errs = errors.Join(errs, ErrHCHTTPHostInvalid) - } if c.Path == "" { errs = errors.Join(errs, ErrHCHTTPPathInvalid) } diff --git a/internal/ir/xds_test.go b/internal/ir/xds_test.go index e1d4ecadb6..2114eb370b 100644 --- a/internal/ir/xds_test.go +++ b/internal/ir/xds_test.go @@ -1676,7 +1676,7 @@ func TestValidateHealthCheck(t *testing.T) { want: ErrHealthCheckHealthyThresholdInvalid, }, { - name: "http-health-check: invalid host", + name: "http-health-check: empty host", input: HealthCheck{ &ActiveHealthCheck{ Timeout: MetaV1DurationPtr(time.Second), @@ -1692,7 +1692,6 @@ func TestValidateHealthCheck(t *testing.T) { &OutlierDetection{}, new(uint32(10)), }, - want: ErrHCHTTPHostInvalid, }, { name: "http-health-check: invalid path", diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go index 40249b03bb..b1534de16b 100644 --- a/internal/xds/translator/cluster.go +++ b/internal/xds/translator/cluster.go @@ -69,6 +69,7 @@ type xdsClusterArgs struct { proxyProtocol *ir.ProxyProtocol circuitBreaker *ir.CircuitBreaker healthCheck *ir.HealthCheck + routeHostname string http1Settings *ir.HTTP1Settings http2Settings *ir.HTTP2Settings timeout *ir.Timeout @@ -455,7 +456,7 @@ func buildXdsCluster(args *xdsClusterArgs) (*buildClusterResult, error) { } if args.healthCheck != nil && args.healthCheck.Active != nil { - cluster.HealthChecks = buildXdsHealthCheck(args.healthCheck.Active) + cluster.HealthChecks = buildXdsHealthCheck(args.healthCheck.Active, args.routeHostname) } if args.healthCheck != nil && args.healthCheck.Passive != nil { @@ -575,7 +576,7 @@ func buildZoneAwareLbConfig(preferLocal *ir.PreferLocalZone) *commonv3.LocalityL return lbConfig } -func buildXdsHealthCheck(healthcheck *ir.ActiveHealthCheck) []*corev3.HealthCheck { +func buildXdsHealthCheck(healthcheck *ir.ActiveHealthCheck, routeHostname string) []*corev3.HealthCheck { hc := &corev3.HealthCheck{ Timeout: durationpb.New(healthcheck.Timeout.Duration), Interval: durationpb.New(healthcheck.Interval.Duration), @@ -594,7 +595,7 @@ func buildXdsHealthCheck(healthcheck *ir.ActiveHealthCheck) []*corev3.HealthChec switch { case healthcheck.HTTP != nil: httpChecker := &corev3.HealthCheck_HttpHealthCheck{ - Host: healthcheck.HTTP.Host, + Host: httpHealthCheckHost(healthcheck.HTTP, routeHostname), Path: healthcheck.HTTP.Path, } if healthcheck.HTTP.Method != nil { @@ -628,6 +629,13 @@ func buildXdsHealthCheck(healthcheck *ir.ActiveHealthCheck) []*corev3.HealthChec return []*corev3.HealthCheck{hc} } +func httpHealthCheckHost(healthcheck *ir.HTTPHealthChecker, routeHostname string) string { + if healthcheck.Host != "" { + return healthcheck.Host + } + return routeHostname +} + func buildXdsOutlierDetection(outlierDetection *ir.OutlierDetection) *clusterv3.OutlierDetection { od := &clusterv3.OutlierDetection{ BaseEjectionTime: durationpb.New(outlierDetection.BaseEjectionTime.Duration), @@ -1005,10 +1013,9 @@ func getHealthCheckOverridesPort(hc *ir.HealthCheck) *uint32 { } func getHealthCheckOverridesHostname(hc *ir.HealthCheck, ep *ir.DestinationEndpoint) string { - // If Active Health Check has an explicit hostname override, it will be used on Cluster. - // Otherwise, if the endpoint has a hostname, set the hostname on the EndpointHealthCheckConfig - // so that Envoy can use it for health checking. - // Note: The "*" wildcard is not an explicit user-provided hostname + // If active HTTP health check has an explicit hostname override, keep that + // cluster-level host. Route hostname is only a default, so Backend endpoint + // hostname can still override it through EndpointHealthCheckConfig. if hc.Active.HTTP != nil && hc.Active.HTTP.Host != "" && hc.Active.HTTP.Host != "*" { return "" } @@ -1417,6 +1424,7 @@ func (httpRoute *HTTPRouteTranslator) asClusterArgs(name string, settings: settings, tSocket: nil, endpointType: buildEndpointType(settings), + routeHostname: httpRoute.Hostname, metrics: extra.metrics, http1Settings: extra.http1Settings, http2Settings: extra.http2Settings, diff --git a/internal/xds/translator/testdata/in/xds-ir/health-check-host-hierarchy.yaml b/internal/xds/translator/testdata/in/xds-ir/health-check-host-hierarchy.yaml new file mode 100644 index 0000000000..7a3ce9243a --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/health-check-host-hierarchy.yaml @@ -0,0 +1,88 @@ +# Health check Host header hierarchy: +# 1. Explicit BackendTrafficPolicy hostname is a cluster-level health check host. +# 2. Backend endpoint hostname is emitted as Endpoint.HealthCheckConfig.hostname +# when the cluster-level host was only defaulted from the effective route +# hostname for the listener. +# 3. Effective route hostname stays as the cluster-level fallback when no +# endpoint hostname exists. +http: +- name: health-check-host-hierarchy-listener + address: "::" + path: + mergeSlashes: true + escapedSlashesAction: UnescapeAndRedirect + port: 10080 + hostnames: + - "*" + routes: + - name: btp-host-route + hostname: btp-route.example.com + traffic: + healthCheck: + active: + timeout: 2s + interval: 5s + healthyThreshold: 1 + unhealthyThreshold: 3 + http: + host: btp-health.example.com + path: /healthz + method: GET + expectedStatuses: + - 200 + destination: + name: btp-host-route-dest + settings: + - name: btp-host-route-dest/backend/0 + addressType: FQDN + endpoints: + - host: backend-address.example.com + hostname: backend-endpoint.example.com + port: 443 + - name: backend-host-route + hostname: backend-route.example.com + traffic: + healthCheck: + active: + timeout: 2s + interval: 5s + healthyThreshold: 1 + unhealthyThreshold: 3 + http: + host: "" + path: /healthz + method: GET + expectedStatuses: + - 200 + destination: + name: backend-host-route-dest + settings: + - name: backend-host-route-dest/backend/0 + addressType: FQDN + endpoints: + - host: backend-address.example.com + hostname: backend-endpoint.example.com + port: 443 + - name: route-host-route + hostname: route-fallback.example.com + traffic: + healthCheck: + active: + timeout: 2s + interval: 5s + healthyThreshold: 1 + unhealthyThreshold: 3 + http: + host: "" + path: /healthz + method: GET + expectedStatuses: + - 200 + destination: + name: route-host-route-dest + settings: + - name: route-host-route-dest/backend/0 + addressType: FQDN + endpoints: + - host: backend-no-endpoint-host.example.com + port: 443 diff --git a/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.clusters.yaml new file mode 100644 index 0000000000..081c04ab7a --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.clusters.yaml @@ -0,0 +1,139 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + dnsRefreshRate: 30s + healthChecks: + - healthyThreshold: 1 + httpHealthCheck: + expectedStatuses: + - end: "201" + start: "200" + host: btp-health.example.com + method: GET + path: /healthz + interval: 5s + timeout: 2s + unhealthyThreshold: 3 + ignoreHealthOnHostRemoval: true + loadAssignment: + clusterName: btp-host-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: backend-address.example.com + portValue: 443 + hostname: backend-endpoint.example.com + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: btp-host-route-dest/backend/0 + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: btp-host-route-dest + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + dnsRefreshRate: 30s + healthChecks: + - healthyThreshold: 1 + httpHealthCheck: + expectedStatuses: + - end: "201" + start: "200" + host: backend-route.example.com + method: GET + path: /healthz + interval: 5s + timeout: 2s + unhealthyThreshold: 3 + ignoreHealthOnHostRemoval: true + loadAssignment: + clusterName: backend-host-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: backend-address.example.com + portValue: 443 + healthCheckConfig: + hostname: backend-endpoint.example.com + hostname: backend-endpoint.example.com + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: backend-host-route-dest/backend/0 + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: backend-host-route-dest + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + dnsRefreshRate: 30s + healthChecks: + - healthyThreshold: 1 + httpHealthCheck: + expectedStatuses: + - end: "201" + start: "200" + host: route-fallback.example.com + method: GET + path: /healthz + interval: 5s + timeout: 2s + unhealthyThreshold: 3 + ignoreHealthOnHostRemoval: true + loadAssignment: + clusterName: route-host-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: backend-no-endpoint-host.example.com + portValue: 443 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: route-host-route-dest/backend/0 + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: route-host-route-dest + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS diff --git a/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.endpoints.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.endpoints.yaml @@ -0,0 +1 @@ +[] diff --git a/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.listeners.yaml new file mode 100644 index 0000000000..a265e79d2a --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.listeners.yaml @@ -0,0 +1,35 @@ +- address: + socketAddress: + address: '::' + portValue: 10080 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: health-check-host-hierarchy-listener + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: health-check-host-hierarchy-listener + maxConnectionsToAcceptPerSocketEvent: 1 + name: health-check-host-hierarchy-listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.routes.yaml new file mode 100644 index 0000000000..98f5a1acaa --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/health-check-host-hierarchy.routes.yaml @@ -0,0 +1,36 @@ +- ignorePortInHostMatching: true + name: health-check-host-hierarchy-listener + virtualHosts: + - domains: + - btp-route.example.com + name: health-check-host-hierarchy-listener/btp-route_example_com + routes: + - match: + prefix: / + name: btp-host-route + route: + cluster: btp-host-route-dest + upgradeConfigs: + - upgradeType: websocket + - domains: + - backend-route.example.com + name: health-check-host-hierarchy-listener/backend-route_example_com + routes: + - match: + prefix: / + name: backend-host-route + route: + cluster: backend-host-route-dest + upgradeConfigs: + - upgradeType: websocket + - domains: + - route-fallback.example.com + name: health-check-host-hierarchy-listener/route-fallback_example_com + routes: + - match: + prefix: / + name: route-host-route + route: + cluster: route-host-route-dest + upgradeConfigs: + - upgradeType: websocket diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 331df07552..fd3acd40e9 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -12,6 +12,7 @@ new features: | bug fixes: | Fixed SecurityPolicy merge using the wrong policy as the owner for resource references and IR generation. + Fixed active HTTP health checks to use Backend endpoint hostnames before falling back to the effective Route hostname. # Enhancements that improve performance. performance improvements: | diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index ad782c4270..d2235779eb 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2942,7 +2942,7 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `hostname` | _string_ | false | | Hostname defines the HTTP host that will be requested during health checking.
Default: HTTPRoute or GRPCRoute hostname. | +| `hostname` | _string_ | false | | Hostname defines the HTTP Host header used for active HTTP health checks.
Host selection uses this order: this field, the associated Backend endpoint
hostname if available, then the effective Route hostname. | | `path` | _string_ | true | | Path defines the HTTP path that will be requested during health checking. | | `method` | _string_ | false | | Method defines the HTTP method used for health checking.
Defaults to GET | | `expectedStatuses` | _[HTTPStatus](#httpstatus) array_ | false | | ExpectedStatuses defines a list of HTTP response statuses considered healthy.
Defaults to 200 only | diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 9ebe32e3b9..2fa7a96b96 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -23198,8 +23198,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -28839,8 +28840,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -43176,8 +43178,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -44707,8 +44710,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -46425,8 +46429,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -48033,8 +48038,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -51105,8 +51111,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -52508,8 +52515,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -54190,8 +54198,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -55904,8 +55913,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/test/helm/gateway-crds-helm/e2e.out.yaml b/test/helm/gateway-crds-helm/e2e.out.yaml index 1c4ddb0c1a..49efed9ba9 100644 --- a/test/helm/gateway-crds-helm/e2e.out.yaml +++ b/test/helm/gateway-crds-helm/e2e.out.yaml @@ -1171,8 +1171,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -6812,8 +6813,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -21149,8 +21151,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -22680,8 +22683,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -24398,8 +24402,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -26006,8 +26011,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -29078,8 +29084,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -30481,8 +30488,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -32163,8 +32171,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -33877,8 +33886,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index 35d05311aa..95e41cc841 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -1171,8 +1171,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -6812,8 +6813,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -21149,8 +21151,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -22680,8 +22683,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -24398,8 +24402,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -26006,8 +26011,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -29078,8 +29084,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -30481,8 +30488,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -32163,8 +32171,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ @@ -33877,8 +33886,9 @@ spec: type: array hostname: description: |- - Hostname defines the HTTP host that will be requested during health checking. - Default: HTTPRoute or GRPCRoute hostname. + Hostname defines the HTTP Host header used for active HTTP health checks. + Host selection uses this order: this field, the associated Backend endpoint + hostname if available, then the effective Route hostname. maxLength: 253 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ From 075434ecb0ba3f444bcbf46a2b299f36df260cb8 Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Thu, 7 May 2026 18:24:39 -0700 Subject: [PATCH 07/12] fix(helm): propagate commonLabels to RBAC resources (#8818) * feat(helm): propagate commonLabels to RBAC resources Issue #8817 reported that 'helm template ... --set commonLabels.custom-label=custom-value' left ClusterRole, ClusterRoleBinding, Role, and RoleBinding resources unlabelled. The other resources in the chart already include 'eg.labels' in their metadata - which picks up 'commonLabels' via the helper at _helpers.tpl:43 - but envoy-gateway-rbac.yaml didn't set any labels block. Add 'labels: {{- include "eg.labels" . | nindent 4 }}' on every Role / RoleBinding / ClusterRole / ClusterRoleBinding declared in envoy-gateway-rbac.yaml. Matches the existing labels pattern used in certgen-rbac.yaml and envoy-gateway-deployment.yaml. Scopes are '$' inside the watched-namespaces 'range' and '.' at the template root, same rule the helper block inside the file already used. Verified locally with: helm dependency update charts/gateway-helm envsubst < charts/gateway-helm/values.tmpl.yaml > \ charts/gateway-helm/values.yaml helm template eg charts/gateway-helm \ --set commonLabels.custom-label=custom-value | yq ... All four RBAC resources now emit 'custom-label: custom-value' in their metadata.labels, matching the issue's repro steps. Cert-gen RBAC resources already carried it; this PR brings the core envoy-gateway RBAC set into parity. Fixes #8817 Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> * chore: regenerate helm-template snapshots for RBAC labels Run 'make helm-template.gateway-helm' to regenerate the snapshot fixtures after the envoy-gateway-rbac.yaml labels change. Adds the 'labels:' block to the RBAC resources in all 27 test cases. Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> * fix gen Signed-off-by: Huabing (Robin) Zhao * add release note Signed-off-by: Huabing (Robin) Zhao --------- Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Signed-off-by: Huabing (Robin) Zhao Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Huabing (Robin) Zhao Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- .../templates/envoy-gateway-rbac.yaml | 12 +++++++ release-notes/current.yaml | 2 +- .../gateway-helm/certgen-annotations.out.yaml | 12 +++++++ test/helm/gateway-helm/certgen-args.out.yaml | 12 +++++++ .../helm/gateway-helm/certgen-labels.out.yaml | 12 +++++++ .../certjen-custom-scheduling.out.yaml | 12 +++++++ test/helm/gateway-helm/common-labels.out.yaml | 20 +++++++++++ .../control-plane-with-pdb.out.yaml | 12 +++++++ .../helm/gateway-helm/default-config.out.yaml | 12 +++++++ .../deployment-annotations.out.yaml | 12 +++++++ .../deployment-custom-topology.out.yaml | 12 +++++++ .../gateway-helm/deployment-extraenv.out.yaml | 12 +++++++ .../deployment-images-config.out.yaml | 12 +++++++ .../deployment-priorityclass.out.yaml | 12 +++++++ .../deployment-repo-no-registry.out.yaml | 12 +++++++ .../deployment-securitycontext.out.yaml | 12 +++++++ .../deployment-volume-mounts.out.yaml | 12 +++++++ .../envoy-gateway-config.out.yaml | 12 +++++++ ...ay-gateway-namespace-config-watch.out.yaml | 36 +++++++++++++++++++ ...-gateway-gateway-namespace-config.out.yaml | 12 +++++++ ...teway-namespace-namespaceselector.out.yaml | 12 +++++++ .../global-images-config.out.yaml | 12 +++++++ ...l-pullsecrets-override-deployment.out.yaml | 12 +++++++ ...lobal-pullsecrets-override-global.out.yaml | 12 +++++++ ...obal-registry-override-deployment.out.yaml | 12 +++++++ .../global-registry-override-global.out.yaml | 12 +++++++ ...orizontal-pod-autoscaler-disabled.out.yaml | 12 +++++++ .../horizontal-pod-autoscaler.out.yaml | 12 +++++++ .../gateway-helm/namespace-override.out.yaml | 12 +++++++ .../service-customization.out.yaml | 12 +++++++ .../gateway-helm/webhook-disabled.out.yaml | 12 +++++++ 31 files changed, 393 insertions(+), 1 deletion(-) diff --git a/charts/gateway-helm/templates/envoy-gateway-rbac.yaml b/charts/gateway-helm/templates/envoy-gateway-rbac.yaml index fec98a8c83..82df678e26 100644 --- a/charts/gateway-helm/templates/envoy-gateway-rbac.yaml +++ b/charts/gateway-helm/templates/envoy-gateway-rbac.yaml @@ -18,6 +18,8 @@ metadata: creationTimestamp: null name: {{ include "eg.fullname" $ }}-envoy-gateway-role namespace: {{ $ns | quote }} + labels: + {{- include "eg.labels" $ | nindent 4 }} rules: {{ include "eg.rbac.namespaced" $ }} --- @@ -26,6 +28,8 @@ kind: RoleBinding metadata: name: {{ include "eg.fullname" $ }}-envoy-gateway-rolebinding namespace: {{ $ns | quote }} + labels: + {{- include "eg.labels" $ | nindent 4 }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role @@ -41,6 +45,8 @@ kind: ClusterRole metadata: creationTimestamp: null name: {{ include "eg.fullname" . }}-envoy-gateway-role + labels: + {{- include "eg.labels" . | nindent 4 }} rules: {{ include "eg.rbac.cluster" . }} --- @@ -48,6 +54,8 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: {{ include "eg.fullname" . }}-envoy-gateway-rolebinding + labels: + {{- include "eg.labels" . | nindent 4 }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -63,6 +71,8 @@ kind: ClusterRole metadata: creationTimestamp: null name: {{ include "eg.fullname" . }}-envoy-gateway-role + labels: + {{- include "eg.labels" . | nindent 4 }} rules: {{ include "eg.rbac.cluster" . }} {{ include "eg.rbac.namespaced" . }} @@ -71,6 +81,8 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: {{ include "eg.fullname" . }}-envoy-gateway-rolebinding + labels: + {{- include "eg.labels" . | nindent 4 }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/release-notes/current.yaml b/release-notes/current.yaml index fd3acd40e9..cc9b69ba8f 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -26,4 +26,4 @@ Other changes: | The maximum number of rules in a RateLimit policy is increased from 128 to 256. The maximum number of JWT providers allowed in `SecurityPolicy.spec.jwt.providers` is increased from 4 to 16. Added `runner_event_total` metric to track update and delete events in infrastructure and gateway API runners for improved observability. - + Added common Helm labels to Envoy Gateway RBAC resources. diff --git a/test/helm/gateway-helm/certgen-annotations.out.yaml b/test/helm/gateway-helm/certgen-annotations.out.yaml index 049aff9f27..7e7f07332e 100644 --- a/test/helm/gateway-helm/certgen-annotations.out.yaml +++ b/test/helm/gateway-helm/certgen-annotations.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/certgen-args.out.yaml b/test/helm/gateway-helm/certgen-args.out.yaml index 4cd3798b7b..15150f367b 100644 --- a/test/helm/gateway-helm/certgen-args.out.yaml +++ b/test/helm/gateway-helm/certgen-args.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/certgen-labels.out.yaml b/test/helm/gateway-helm/certgen-labels.out.yaml index 73b6373470..1978ae688f 100644 --- a/test/helm/gateway-helm/certgen-labels.out.yaml +++ b/test/helm/gateway-helm/certgen-labels.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml b/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml index 17801fc0d2..8ac8ee6871 100644 --- a/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml +++ b/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/common-labels.out.yaml b/test/helm/gateway-helm/common-labels.out.yaml index 01e8cbd5c6..d7176f5a26 100644 --- a/test/helm/gateway-helm/common-labels.out.yaml +++ b/test/helm/gateway-helm/common-labels.out.yaml @@ -66,6 +66,16 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/instance: custom-instance-name + app.kubernetes.io/name: custom-gateway-name + my-commonlabel-1: example-1 + my-commonlabel-2: example-2 rules: - apiGroups: - "" @@ -199,6 +209,16 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/instance: custom-instance-name + app.kubernetes.io/name: custom-gateway-name + my-commonlabel-1: example-1 + my-commonlabel-2: example-2 roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/control-plane-with-pdb.out.yaml b/test/helm/gateway-helm/control-plane-with-pdb.out.yaml index fce781862e..f22da7e4f9 100644 --- a/test/helm/gateway-helm/control-plane-with-pdb.out.yaml +++ b/test/helm/gateway-helm/control-plane-with-pdb.out.yaml @@ -73,6 +73,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -206,6 +212,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/default-config.out.yaml b/test/helm/gateway-helm/default-config.out.yaml index 1c2e624d78..51700736f6 100644 --- a/test/helm/gateway-helm/default-config.out.yaml +++ b/test/helm/gateway-helm/default-config.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/deployment-annotations.out.yaml b/test/helm/gateway-helm/deployment-annotations.out.yaml index a4dfc4f14e..c14f71c365 100644 --- a/test/helm/gateway-helm/deployment-annotations.out.yaml +++ b/test/helm/gateway-helm/deployment-annotations.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/deployment-custom-topology.out.yaml b/test/helm/gateway-helm/deployment-custom-topology.out.yaml index 60e4c0fe8b..8f945dedf6 100644 --- a/test/helm/gateway-helm/deployment-custom-topology.out.yaml +++ b/test/helm/gateway-helm/deployment-custom-topology.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/deployment-extraenv.out.yaml b/test/helm/gateway-helm/deployment-extraenv.out.yaml index 3e4047f321..f6b460c9c0 100644 --- a/test/helm/gateway-helm/deployment-extraenv.out.yaml +++ b/test/helm/gateway-helm/deployment-extraenv.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/deployment-images-config.out.yaml b/test/helm/gateway-helm/deployment-images-config.out.yaml index d38b1ef572..b744b95c41 100644 --- a/test/helm/gateway-helm/deployment-images-config.out.yaml +++ b/test/helm/gateway-helm/deployment-images-config.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/deployment-priorityclass.out.yaml b/test/helm/gateway-helm/deployment-priorityclass.out.yaml index 5c2f006c2e..20c6c8959e 100644 --- a/test/helm/gateway-helm/deployment-priorityclass.out.yaml +++ b/test/helm/gateway-helm/deployment-priorityclass.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/deployment-repo-no-registry.out.yaml b/test/helm/gateway-helm/deployment-repo-no-registry.out.yaml index be405b66af..73c08c129d 100644 --- a/test/helm/gateway-helm/deployment-repo-no-registry.out.yaml +++ b/test/helm/gateway-helm/deployment-repo-no-registry.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/deployment-securitycontext.out.yaml b/test/helm/gateway-helm/deployment-securitycontext.out.yaml index d9cee5ced7..c0ea913726 100644 --- a/test/helm/gateway-helm/deployment-securitycontext.out.yaml +++ b/test/helm/gateway-helm/deployment-securitycontext.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/deployment-volume-mounts.out.yaml b/test/helm/gateway-helm/deployment-volume-mounts.out.yaml index 1d734d9911..28dfdccac2 100644 --- a/test/helm/gateway-helm/deployment-volume-mounts.out.yaml +++ b/test/helm/gateway-helm/deployment-volume-mounts.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/envoy-gateway-config.out.yaml b/test/helm/gateway-helm/envoy-gateway-config.out.yaml index 555d7127cf..6f81297e94 100644 --- a/test/helm/gateway-helm/envoy-gateway-config.out.yaml +++ b/test/helm/gateway-helm/envoy-gateway-config.out.yaml @@ -60,6 +60,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -193,6 +199,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/envoy-gateway-gateway-namespace-config-watch.out.yaml b/test/helm/gateway-helm/envoy-gateway-gateway-namespace-config-watch.out.yaml index 7e16c14ee0..6f1b0f08e1 100644 --- a/test/helm/gateway-helm/envoy-gateway-gateway-namespace-config-watch.out.yaml +++ b/test/helm/gateway-helm/envoy-gateway-gateway-namespace-config-watch.out.yaml @@ -64,6 +64,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -123,6 +129,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -159,6 +171,12 @@ metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role namespace: "default" + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -261,6 +279,12 @@ metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role namespace: "app-ns" + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -606,6 +630,12 @@ kind: RoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding namespace: "default" + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: Role @@ -621,6 +651,12 @@ kind: RoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding namespace: "app-ns" + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/test/helm/gateway-helm/envoy-gateway-gateway-namespace-config.out.yaml b/test/helm/gateway-helm/envoy-gateway-gateway-namespace-config.out.yaml index 5df698eb80..3e4693e861 100644 --- a/test/helm/gateway-helm/envoy-gateway-gateway-namespace-config.out.yaml +++ b/test/helm/gateway-helm/envoy-gateway-gateway-namespace-config.out.yaml @@ -60,6 +60,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -261,6 +267,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/envoy-gateway-gateway-namespace-namespaceselector.out.yaml b/test/helm/gateway-helm/envoy-gateway-gateway-namespace-namespaceselector.out.yaml index 8cddcd3be7..dd4ce0c7b0 100644 --- a/test/helm/gateway-helm/envoy-gateway-gateway-namespace-namespaceselector.out.yaml +++ b/test/helm/gateway-helm/envoy-gateway-gateway-namespace-namespaceselector.out.yaml @@ -65,6 +65,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -285,6 +291,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/global-images-config.out.yaml b/test/helm/gateway-helm/global-images-config.out.yaml index 8d3d478756..7db956ec59 100644 --- a/test/helm/gateway-helm/global-images-config.out.yaml +++ b/test/helm/gateway-helm/global-images-config.out.yaml @@ -74,6 +74,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -207,6 +213,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/global-pullsecrets-override-deployment.out.yaml b/test/helm/gateway-helm/global-pullsecrets-override-deployment.out.yaml index d6e0603cad..1b32861684 100644 --- a/test/helm/gateway-helm/global-pullsecrets-override-deployment.out.yaml +++ b/test/helm/gateway-helm/global-pullsecrets-override-deployment.out.yaml @@ -62,6 +62,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -195,6 +201,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/global-pullsecrets-override-global.out.yaml b/test/helm/gateway-helm/global-pullsecrets-override-global.out.yaml index 75a837cef6..981cab8d3b 100644 --- a/test/helm/gateway-helm/global-pullsecrets-override-global.out.yaml +++ b/test/helm/gateway-helm/global-pullsecrets-override-global.out.yaml @@ -62,6 +62,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -195,6 +201,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/global-registry-override-deployment.out.yaml b/test/helm/gateway-helm/global-registry-override-deployment.out.yaml index 78f2e13f3e..1a6992ab20 100644 --- a/test/helm/gateway-helm/global-registry-override-deployment.out.yaml +++ b/test/helm/gateway-helm/global-registry-override-deployment.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/global-registry-override-global.out.yaml b/test/helm/gateway-helm/global-registry-override-global.out.yaml index c7e35a3df5..c8ca98a54f 100644 --- a/test/helm/gateway-helm/global-registry-override-global.out.yaml +++ b/test/helm/gateway-helm/global-registry-override-global.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/horizontal-pod-autoscaler-disabled.out.yaml b/test/helm/gateway-helm/horizontal-pod-autoscaler-disabled.out.yaml index 649a2461e3..eedac7153a 100644 --- a/test/helm/gateway-helm/horizontal-pod-autoscaler-disabled.out.yaml +++ b/test/helm/gateway-helm/horizontal-pod-autoscaler-disabled.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/horizontal-pod-autoscaler.out.yaml b/test/helm/gateway-helm/horizontal-pod-autoscaler.out.yaml index 56d6f25df7..98c68a8fab 100644 --- a/test/helm/gateway-helm/horizontal-pod-autoscaler.out.yaml +++ b/test/helm/gateway-helm/horizontal-pod-autoscaler.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/namespace-override.out.yaml b/test/helm/gateway-helm/namespace-override.out.yaml index 7124dd69c4..7b73ae5c1f 100644 --- a/test/helm/gateway-helm/namespace-override.out.yaml +++ b/test/helm/gateway-helm/namespace-override.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/service-customization.out.yaml b/test/helm/gateway-helm/service-customization.out.yaml index beb8f49542..3e3933c7ff 100644 --- a/test/helm/gateway-helm/service-customization.out.yaml +++ b/test/helm/gateway-helm/service-customization.out.yaml @@ -58,6 +58,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -191,6 +197,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/test/helm/gateway-helm/webhook-disabled.out.yaml b/test/helm/gateway-helm/webhook-disabled.out.yaml index 8f58e4cc08..759cc8f162 100644 --- a/test/helm/gateway-helm/webhook-disabled.out.yaml +++ b/test/helm/gateway-helm/webhook-disabled.out.yaml @@ -60,6 +60,12 @@ kind: ClusterRole metadata: creationTimestamp: null name: gateway-helm-envoy-gateway-role + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm rules: - apiGroups: - "" @@ -182,6 +188,12 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gateway-helm-envoy-gateway-rolebinding + labels: + helm.sh/chart: gateway-helm-v0.0.0-latest + app.kubernetes.io/name: gateway-helm + app.kubernetes.io/instance: gateway-helm + app.kubernetes.io/version: "latest" + app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole From 09fcd03e7d02b1bc2256dd34e888a2797b96600d Mon Sep 17 00:00:00 2001 From: Andrew Katsikas Date: Fri, 8 May 2026 02:29:55 +0000 Subject: [PATCH 08/12] fix(translator): set ListenerSet and listener Accepted:True for InvalidCertificateRef (#8871) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(translator): set ListenerSet and listener Accepted:True for InvalidCertificateRef When a ListenerSet listener has an unresolvable TLS certificate reference (InvalidCertificateRef or RefNotPermitted), Accepted: False was incorrectly set on both the listener and ListenerSet object. The Gateway API spec places InvalidCertificateRef exclusively under ResolvedRefs, not Accepted — a missing certificate is a reference resolution concern, not a structural one. Fixes #8870 Signed-off-by: apkatsikas * chore: fix gofumpt formatting in validateListenerConditions Signed-off-by: apkatsikas * fix(translator): separate RefNotPermitted from InvalidCertificateRef handling Unlike InvalidCertificateRef, RefNotPermitted should not set Accepted:True. Update unit test fixtures to match. Signed-off-by: apkatsikas * fix gen Signed-off-by: zirain --------- Signed-off-by: apkatsikas Signed-off-by: zirain Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- internal/gatewayapi/listenerset.go | 59 ++- ...policy-with-routing-type-listener.out.yaml | 5 + .../gateway-with-attached-routes.out.yaml | 5 + ...licting-listeners-one-invalid-ref.out.yaml | 5 + ...nvalid-multiple-tls-configuration.out.yaml | 5 + ...nfiguration-secret-does-not-exist.out.yaml | 5 + ...configuration-secret-is-not-valid.out.yaml | 5 + .../listenerset-conflict-listeners.out.yaml | 8 +- .../listenerset-cross-namespace.out.yaml | 8 +- .../testdata/listenerset-grpcroute.out.yaml | 8 +- .../testdata/listenerset-httproute.out.yaml | 4 +- ...tps-tls-misuses-gateway-namespace.out.yaml | 4 +- ...tls-mixed-valid-and-missing-secret.in.yaml | 112 ++++++ ...ls-mixed-valid-and-missing-secret.out.yaml | 340 ++++++++++++++++++ ...tenerset-https-tls-same-namespace.out.yaml | 4 +- ...et-https-tls-secret-does-not-exist.in.yaml | 73 ++++ ...t-https-tls-secret-does-not-exist.out.yaml | 210 +++++++++++ .../testdata/listenerset-invalid.out.yaml | 6 +- .../listenerset-no-maching-listener.out.yaml | 4 +- .../testdata/listenerset-tcproute.out.yaml | 4 +- .../testdata/listenerset-tlsroute.out.yaml | 4 +- .../testdata/listenerset-udproute.out.yaml | 4 +- internal/gatewayapi/validate.go | 27 +- release-notes/current.yaml | 1 + 24 files changed, 853 insertions(+), 57 deletions(-) create mode 100644 internal/gatewayapi/testdata/listenerset-https-tls-mixed-valid-and-missing-secret.in.yaml create mode 100644 internal/gatewayapi/testdata/listenerset-https-tls-mixed-valid-and-missing-secret.out.yaml create mode 100644 internal/gatewayapi/testdata/listenerset-https-tls-secret-does-not-exist.in.yaml create mode 100644 internal/gatewayapi/testdata/listenerset-https-tls-secret-does-not-exist.out.yaml diff --git a/internal/gatewayapi/listenerset.go b/internal/gatewayapi/listenerset.go index 68cdb575ed..03cbfebcac 100644 --- a/internal/gatewayapi/listenerset.go +++ b/internal/gatewayapi/listenerset.go @@ -113,48 +113,69 @@ func (t *Translator) ProcessListenerSetStatus(listenerSets []*gwapiv1.ListenerSe } // Calculate status based on listeners - allListenersValid := true - anyListenerValid := false + allListenersAccepted := true + anyListenerAccepted := false + allListenersProgrammed := true + anyListenerProgrammed := false for _, lStatus := range ls.Status.Listeners { accepted := false + programmed := false for _, cond := range lStatus.Conditions { if cond.Type == string(gwapiv1.ListenerEntryConditionAccepted) && cond.Status == metav1.ConditionTrue { accepted = true - break + } + if cond.Type == string(gwapiv1.ListenerConditionProgrammed) && cond.Status == metav1.ConditionTrue { + programmed = true } } - anyListenerValid = anyListenerValid || accepted - allListenersValid = allListenersValid && accepted + anyListenerAccepted = anyListenerAccepted || accepted + allListenersAccepted = allListenersAccepted && accepted + anyListenerProgrammed = anyListenerProgrammed || programmed + allListenersProgrammed = allListenersProgrammed && programmed } var ( lsAccepted bool - lsReason gwapiv1.ListenerSetConditionReason + lsAcceptedReason gwapiv1.ListenerSetConditionReason + lsAcceptedMsg string + lsProgrammed bool lsProgrammedReason gwapiv1.ListenerSetConditionReason - lsMsg string + lsProgrammedMsg string ) switch { - case allListenersValid: + case allListenersAccepted: lsAccepted = true - lsReason = gwapiv1.ListenerSetReasonAccepted - lsProgrammedReason = gwapiv1.ListenerSetReasonProgrammed - lsMsg = "All listeners are valid" - case anyListenerValid: // TODO: implement PartiallyInvalid conditions when Gateway API supports it + lsAcceptedReason = gwapiv1.ListenerSetReasonAccepted + lsAcceptedMsg = "All listeners are accepted" + case anyListenerAccepted: // TODO: implement PartiallyInvalid conditions when Gateway API supports it lsAccepted = true - lsReason = gwapiv1.ListenerSetReasonListenersNotValid - lsProgrammedReason = gwapiv1.ListenerSetReasonProgrammed - lsMsg = "Some listeners are invalid" + lsAcceptedReason = gwapiv1.ListenerSetReasonListenersNotValid + lsAcceptedMsg = "Some listeners are invalid" default: lsAccepted = false - lsReason = gwapiv1.ListenerSetReasonListenersNotValid + lsAcceptedReason = gwapiv1.ListenerSetReasonListenersNotValid + lsAcceptedMsg = "No listeners are accepted" + } + + switch { + case allListenersProgrammed: + lsProgrammed = true + lsProgrammedReason = gwapiv1.ListenerSetReasonProgrammed + lsProgrammedMsg = "All listeners are programmed" + case anyListenerProgrammed: + lsProgrammed = true + lsProgrammedReason = gwapiv1.ListenerSetReasonProgrammed + lsProgrammedMsg = "Some listeners are not programmed" + default: + lsProgrammed = false lsProgrammedReason = gwapiv1.ListenerSetReasonListenersNotValid - lsMsg = "All listeners are invalid" + lsProgrammedMsg = "No listeners are programmed" } - status.UpdateListenerSetStatusAccepted(ls, lsAccepted, lsReason, lsMsg) - status.UpdateListenerSetStatusProgrammed(ls, lsAccepted, lsProgrammedReason, lsMsg) + status.UpdateListenerSetStatusAccepted(ls, lsAccepted, lsAcceptedReason, lsAcceptedMsg) + status.UpdateListenerSetStatusProgrammed(ls, lsProgrammed, lsProgrammedReason, lsProgrammedMsg) } } diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml index 41827b1006..04c0af5b6d 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml @@ -126,6 +126,11 @@ gateways: reason: InvalidCertificateRef status: "False" type: ResolvedRefs + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener is invalid, see other Conditions for details. reason: Invalid diff --git a/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml b/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml index f11b451baf..430bf42173 100644 --- a/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml @@ -108,6 +108,11 @@ gateways: reason: InvalidCertificateRef status: "False" type: ResolvedRefs + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener is invalid, see other Conditions for details. reason: Invalid diff --git a/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml index 663bd2014f..67882951e3 100644 --- a/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml @@ -39,6 +39,11 @@ gateways: reason: InvalidCertificateRef status: "False" type: ResolvedRefs + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener is invalid, see other Conditions for details. reason: Invalid diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml index 82b7f2918d..69173449ba 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml @@ -97,6 +97,11 @@ gateways: reason: InvalidCertificateRef status: "False" type: ResolvedRefs + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener is invalid, see other Conditions for details. reason: Invalid diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml index fdf22c3ae1..e71962d4a8 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml @@ -27,6 +27,11 @@ gateways: reason: InvalidCertificateRef status: "False" type: ResolvedRefs + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener is invalid, see other Conditions for details. reason: Invalid diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml index 5ab341a973..84a07d67f8 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml @@ -27,6 +27,11 @@ gateways: reason: InvalidCertificateRef status: "False" type: ResolvedRefs + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener is invalid, see other Conditions for details. reason: Invalid diff --git a/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml b/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml index de19b641c4..c8ead033c5 100644 --- a/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml @@ -130,12 +130,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are invalid + message: No listeners are accepted reason: ListenersNotValid status: "False" type: Accepted - lastTransitionTime: null - message: All listeners are invalid + message: No listeners are programmed reason: ListenersNotValid status: "False" type: Programmed @@ -215,7 +215,7 @@ listenerSets: status: "True" type: Accepted - lastTransitionTime: null - message: Some listeners are invalid + message: Some listeners are not programmed reason: Programmed status: "True" type: Programmed @@ -300,7 +300,7 @@ listenerSets: status: "True" type: Accepted - lastTransitionTime: null - message: Some listeners are invalid + message: Some listeners are not programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-cross-namespace.out.yaml b/internal/gatewayapi/testdata/listenerset-cross-namespace.out.yaml index 22f5f6236c..3c2b82ad7a 100644 --- a/internal/gatewayapi/testdata/listenerset-cross-namespace.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-cross-namespace.out.yaml @@ -170,12 +170,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed @@ -227,12 +227,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-grpcroute.out.yaml b/internal/gatewayapi/testdata/listenerset-grpcroute.out.yaml index 7b44839908..512f312629 100644 --- a/internal/gatewayapi/testdata/listenerset-grpcroute.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-grpcroute.out.yaml @@ -198,12 +198,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed @@ -254,12 +254,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-httproute.out.yaml b/internal/gatewayapi/testdata/listenerset-httproute.out.yaml index 69aa62ae91..d80d3c20ce 100644 --- a/internal/gatewayapi/testdata/listenerset-httproute.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-httproute.out.yaml @@ -240,12 +240,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml index 25283fbf2c..f56dd359de 100644 --- a/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml @@ -128,12 +128,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are invalid + message: No listeners are accepted reason: ListenersNotValid status: "False" type: Accepted - lastTransitionTime: null - message: All listeners are invalid + message: No listeners are programmed reason: ListenersNotValid status: "False" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-mixed-valid-and-missing-secret.in.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-mixed-valid-and-missing-secret.in.yaml new file mode 100644 index 0000000000..5079af121a --- /dev/null +++ b/internal/gatewayapi/testdata/listenerset-https-tls-mixed-valid-and-missing-secret.in.yaml @@ -0,0 +1,112 @@ +namespaces: +- apiVersion: v1 + kind: Namespace + metadata: + name: gateway +- apiVersion: v1 + kind: Namespace + metadata: + name: xls + labels: + allow-xls: "true" +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: gateway + name: composite-gateway + spec: + gatewayClassName: envoy-gateway-class + allowedListeners: + namespaces: + from: Selector + selector: + matchLabels: + allow-xls: "true" + listeners: + - name: core-http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +listenerSets: +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + namespace: xls + name: https-xls + spec: + parentRef: + name: composite-gateway + namespace: gateway + listeners: + - name: extra-https-valid + protocol: HTTPS + port: 8443 + tls: + mode: Terminate + certificateRefs: + - group: "" + kind: Secret + name: tls-secret-1 + namespace: xls + allowedRoutes: + namespaces: + from: All + - name: extra-https-missing-cert + protocol: HTTPS + port: 8444 + tls: + mode: Terminate + certificateRefs: + - group: "" + kind: Secret + name: tls-secret-missing + namespace: xls + allowedRoutes: + namespaces: + from: All +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: route-valid + spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: ListenerSet + namespace: xls + name: https-xls + sectionName: extra-https-valid + rules: + - backendRefs: + - name: service-1 + port: 8080 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: route-missing-cert + spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: ListenerSet + namespace: xls + name: https-xls + sectionName: extra-https-missing-cert + rules: + - backendRefs: + - name: service-1 + port: 8080 +secrets: +- apiVersion: v1 + kind: Secret + metadata: + namespace: xls + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-mixed-valid-and-missing-secret.out.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-mixed-valid-and-missing-secret.out.yaml new file mode 100644 index 0000000000..c9cd6c9736 --- /dev/null +++ b/internal/gatewayapi/testdata/listenerset-https-tls-mixed-valid-and-missing-secret.out.yaml @@ -0,0 +1,340 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: composite-gateway + namespace: gateway + spec: + allowedListeners: + namespaces: + from: Selector + selector: + matchLabels: + allow-xls: "true" + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: core-http + port: 80 + protocol: HTTP + status: + attachedListenerSets: 1 + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: core-http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: route-valid + namespace: default + spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: ListenerSet + name: https-xls + namespace: xls + sectionName: extra-https-valid + rules: + - backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + group: gateway.networking.k8s.io + kind: ListenerSet + name: https-xls + namespace: xls + sectionName: extra-https-valid +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: route-missing-cert + namespace: default + spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: ListenerSet + name: https-xls + namespace: xls + sectionName: extra-https-missing-cert + rules: + - backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: There are no ready listeners for this parent ref + reason: NoReadyListeners + status: "False" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + group: gateway.networking.k8s.io + kind: ListenerSet + name: https-xls + namespace: xls + sectionName: extra-https-missing-cert +infraIR: + gateway/composite-gateway: + proxy: + listeners: + - name: gateway/composite-gateway/core-http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + - name: gateway/composite-gateway/xls/https-xls/extra-https-valid + ports: + - containerPort: 8443 + name: https-8443 + protocol: HTTPS + servicePort: 8443 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: composite-gateway + gateway.envoyproxy.io/owning-gateway-namespace: gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: gateway/composite-gateway + namespace: envoy-gateway-system +listenerSets: +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: https-xls + namespace: xls + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + name: extra-https-valid + port: 8443 + protocol: HTTPS + tls: + certificateRefs: + - group: "" + kind: Secret + name: tls-secret-1 + namespace: xls + mode: Terminate + - allowedRoutes: + namespaces: + from: All + name: extra-https-missing-cert + port: 8444 + protocol: HTTPS + tls: + certificateRefs: + - group: "" + kind: Secret + name: tls-secret-missing + namespace: xls + mode: Terminate + parentRef: + name: composite-gateway + namespace: gateway + status: + conditions: + - lastTransitionTime: null + message: All listeners are accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Some listeners are not programmed + reason: Programmed + status: "True" + type: Programmed + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted + name: extra-https-valid + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: 'No valid secrets exist: certificate refs 0: Secret xls/tls-secret-missing + does not exist.' + reason: InvalidCertificateRef + status: "False" + type: ResolvedRefs + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: ListenersNotValid + status: "False" + type: Programmed + name: extra-https-missing-cert + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +xdsIR: + gateway/composite-gateway: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-gateway-composite-gateway-acff6ccf + namespace: envoy-gateway-system + sectionName: "8080" + name: gateway/composite-gateway + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-gateway-composite-gateway-acff6ccf + namespace: envoy-gateway-system + sectionName: "8080" + name: gateway/composite-gateway + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + metadata: + kind: Gateway + name: composite-gateway + namespace: gateway + sectionName: core-http + name: gateway/composite-gateway/core-http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 8443 + hostnames: + - '*' + metadata: + kind: Gateway + name: composite-gateway + namespace: gateway + sectionName: extra-https-valid + name: gateway/composite-gateway/xls/https-xls/extra-https-valid + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8443 + routes: + - destination: + metadata: + kind: HTTPRoute + name: route-valid + namespace: default + name: httproute/default/route-valid/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/route-valid/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: route-valid + namespace: default + name: httproute/default/route-valid/rule/0/match/-1/* + tls: + alpnProtocols: null + certificates: + - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + name: xls/tls-secret-1 + privateKey: '[redacted]' + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-same-namespace.out.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-same-namespace.out.yaml index c4161ade75..781ab63b5a 100644 --- a/internal/gatewayapi/testdata/listenerset-https-tls-same-namespace.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-https-tls-same-namespace.out.yaml @@ -134,12 +134,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-secret-does-not-exist.in.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-secret-does-not-exist.in.yaml new file mode 100644 index 0000000000..493e6a6b9f --- /dev/null +++ b/internal/gatewayapi/testdata/listenerset-https-tls-secret-does-not-exist.in.yaml @@ -0,0 +1,73 @@ +namespaces: +- apiVersion: v1 + kind: Namespace + metadata: + name: gateway +- apiVersion: v1 + kind: Namespace + metadata: + name: xls + labels: + allow-xls: "true" +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: gateway + name: composite-gateway + spec: + gatewayClassName: envoy-gateway-class + allowedListeners: + namespaces: + from: Selector + selector: + matchLabels: + allow-xls: "true" + listeners: + - name: core-http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +listenerSets: +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + namespace: xls + name: https-xls + spec: + parentRef: + name: composite-gateway + namespace: gateway + listeners: + - name: extra-https + protocol: HTTPS + port: 8443 + tls: + mode: Terminate + certificateRefs: + - group: "" + kind: Secret + name: tls-secret-1 + namespace: xls + allowedRoutes: + namespaces: + from: All +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: route-extra-https + spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: ListenerSet + namespace: xls + name: https-xls + sectionName: extra-https + rules: + - backendRefs: + - name: service-1 + port: 8080 diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-secret-does-not-exist.out.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-secret-does-not-exist.out.yaml new file mode 100644 index 0000000000..bf0b1fa843 --- /dev/null +++ b/internal/gatewayapi/testdata/listenerset-https-tls-secret-does-not-exist.out.yaml @@ -0,0 +1,210 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: composite-gateway + namespace: gateway + spec: + allowedListeners: + namespaces: + from: Selector + selector: + matchLabels: + allow-xls: "true" + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: core-http + port: 80 + protocol: HTTP + status: + attachedListenerSets: 1 + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: core-http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: route-extra-https + namespace: default + spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: ListenerSet + name: https-xls + namespace: xls + sectionName: extra-https + rules: + - backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: There are no ready listeners for this parent ref + reason: NoReadyListeners + status: "False" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + group: gateway.networking.k8s.io + kind: ListenerSet + name: https-xls + namespace: xls + sectionName: extra-https +infraIR: + gateway/composite-gateway: + proxy: + listeners: + - name: gateway/composite-gateway/core-http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: composite-gateway + gateway.envoyproxy.io/owning-gateway-namespace: gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: gateway/composite-gateway + namespace: envoy-gateway-system +listenerSets: +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: https-xls + namespace: xls + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + name: extra-https + port: 8443 + protocol: HTTPS + tls: + certificateRefs: + - group: "" + kind: Secret + name: tls-secret-1 + namespace: xls + mode: Terminate + parentRef: + name: composite-gateway + namespace: gateway + status: + conditions: + - lastTransitionTime: null + message: All listeners are accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: No listeners are programmed + reason: ListenersNotValid + status: "False" + type: Programmed + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: 'No valid secrets exist: certificate refs 0: Secret xls/tls-secret-1 + does not exist.' + reason: InvalidCertificateRef + status: "False" + type: ResolvedRefs + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: ListenersNotValid + status: "False" + type: Programmed + name: extra-https + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +xdsIR: + gateway/composite-gateway: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-gateway-composite-gateway-acff6ccf + namespace: envoy-gateway-system + sectionName: "8080" + name: gateway/composite-gateway + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-gateway-composite-gateway-acff6ccf + namespace: envoy-gateway-system + sectionName: "8080" + name: gateway/composite-gateway + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + metadata: + kind: Gateway + name: composite-gateway + namespace: gateway + sectionName: core-http + name: gateway/composite-gateway/core-http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/listenerset-invalid.out.yaml b/internal/gatewayapi/testdata/listenerset-invalid.out.yaml index 449d97e743..e09a3482d6 100644 --- a/internal/gatewayapi/testdata/listenerset-invalid.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-invalid.out.yaml @@ -240,12 +240,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are invalid + message: No listeners are accepted reason: ListenersNotValid status: "False" type: Accepted - lastTransitionTime: null - message: All listeners are invalid + message: No listeners are programmed reason: ListenersNotValid status: "False" type: Programmed @@ -315,7 +315,7 @@ listenerSets: status: "True" type: Accepted - lastTransitionTime: null - message: Some listeners are invalid + message: Some listeners are not programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-no-maching-listener.out.yaml b/internal/gatewayapi/testdata/listenerset-no-maching-listener.out.yaml index 8c7309b61c..1dcf2f3339 100644 --- a/internal/gatewayapi/testdata/listenerset-no-maching-listener.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-no-maching-listener.out.yaml @@ -193,12 +193,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-tcproute.out.yaml b/internal/gatewayapi/testdata/listenerset-tcproute.out.yaml index bc69e734fb..efefe794c2 100644 --- a/internal/gatewayapi/testdata/listenerset-tcproute.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-tcproute.out.yaml @@ -92,12 +92,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-tlsroute.out.yaml b/internal/gatewayapi/testdata/listenerset-tlsroute.out.yaml index cb8d2b95bf..40d297c879 100644 --- a/internal/gatewayapi/testdata/listenerset-tlsroute.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-tlsroute.out.yaml @@ -116,12 +116,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/testdata/listenerset-udproute.out.yaml b/internal/gatewayapi/testdata/listenerset-udproute.out.yaml index 5339bbc54a..5e3287a6cd 100644 --- a/internal/gatewayapi/testdata/listenerset-udproute.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-udproute.out.yaml @@ -92,12 +92,12 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are valid + message: All listeners are accepted reason: Accepted status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are valid + message: All listeners are programmed reason: Programmed status: "True" type: Programmed diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index 528a0f03da..4332403a71 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -289,15 +289,24 @@ func (t *Translator) validateListenerConditions(listener *ListenerContext) { return } - // Edge case: only one condition which is ResolvedRefs=False, Reason=PartiallyInvalidCertificateRef - // In this case, we can still consider the listener as ready because we only program the listener using only the valid certificates. - if len(lConditions) == 1 && lConditions[0].Type == string(gwapiv1.ListenerConditionResolvedRefs) && - lConditions[0].Reason == string(status.ListenerReasonPartiallyInvalidCertificateRef) { - listener.SetCondition(gwapiv1.ListenerConditionAccepted, metav1.ConditionTrue, gwapiv1.ListenerReasonAccepted, - "Listener has been successfully translated") - listener.SetCondition(gwapiv1.ListenerConditionProgrammed, metav1.ConditionTrue, gwapiv1.ListenerReasonProgrammed, - "Sending translated listener configuration to the data plane") - return + onlyResolvedRefFailure := len(lConditions) == 1 && lConditions[0].Type == string(gwapiv1.ListenerConditionResolvedRefs) + if onlyResolvedRefFailure { + switch lConditions[0].Reason { + case string(status.ListenerReasonPartiallyInvalidCertificateRef): + // The listener is ready because we program it using only the valid certificates. + listener.SetCondition(gwapiv1.ListenerConditionAccepted, metav1.ConditionTrue, gwapiv1.ListenerReasonAccepted, + "Listener has been successfully translated") + listener.SetCondition(gwapiv1.ListenerConditionProgrammed, metav1.ConditionTrue, gwapiv1.ListenerReasonProgrammed, + "Sending translated listener configuration to the data plane") + return + case string(gwapiv1.ListenerReasonInvalidCertificateRef): + // The listener configuration is semantically valid, but the listener cannot serve traffic with an invalid certificate. + listener.SetCondition(gwapiv1.ListenerConditionAccepted, metav1.ConditionTrue, gwapiv1.ListenerReasonAccepted, + "Listener has been successfully translated") + listener.SetCondition(gwapiv1.ListenerConditionProgrammed, metav1.ConditionFalse, gwapiv1.ListenerReasonInvalid, + "Listener is invalid, see other Conditions for details.") + return + } } // Any condition on the listener apart from Programmed=true indicates an error. diff --git a/release-notes/current.yaml b/release-notes/current.yaml index cc9b69ba8f..55519c9f36 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -12,6 +12,7 @@ new features: | bug fixes: | Fixed SecurityPolicy merge using the wrong policy as the owner for resource references and IR generation. + Fixed ListenerSet and its listeners incorrectly setting `Accepted: False` for InvalidCertificateRef and RefNotPermitted, inconsistent with Gateway behavior and the Gateway API spec. Fixed active HTTP health checks to use Backend endpoint hostnames before falling back to the effective Route hostname. # Enhancements that improve performance. From 83a083bcd96acbcc013ab8a31f5a3715f1a9d5be Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Fri, 8 May 2026 10:59:40 +0800 Subject: [PATCH 09/12] fix: do not downgrade ALPN for only hostnames-overlapping listeners (#8934) fix: do not downgrade ALPN for overlapping hostnames withoug SANs overlapping Signed-off-by: Huabing (Robin) Zhao Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- internal/gatewayapi/listener.go | 7 +- internal/gatewayapi/listener_test.go | 15 +++ .../clienttrafficpolicy-http3.out.yaml | 12 +-- ...lapping-hostnames-merged-gateways.out.yaml | 10 +- ...steners-with-overlapping-hostnames.in.yaml | 11 --- ...teners-with-overlapping-hostnames.out.yaml | 93 +------------------ internal/ir/xds.go | 4 +- release-notes/current.yaml | 1 + 8 files changed, 27 insertions(+), 126 deletions(-) diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index a7bbc26957..da6b3f119c 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -508,14 +508,14 @@ func checkOverlappingHostnames(httpsListeners []*ListenerContext) { if gateway1.Name == gateway2.Name && gateway1.Namespace == gateway2.Namespace { message = fmt.Sprintf( - "The hostname %s overlaps with the hostname %s in listener %s. ALPN will default to HTTP/1.1 to prevent HTTP/2 connection coalescing, unless explicitly configured via ClientTrafficPolicy", + "The hostname %s overlaps with the hostname %s in listener %s.", overlappingListeners[i].hostname1, overlappingListeners[i].hostname2, overlappingListeners[i].listener2, ) } else { message = fmt.Sprintf( - "The hostname %s overlaps with the hostname %s in listener %s of gateway %s. ALPN will default to HTTP/1.1 to prevent HTTP/2 connection coalescing, unless explicitly configured via ClientTrafficPolicy", + "The hostname %s overlaps with the hostname %s in listener %s of gateway %s.", overlappingListeners[i].hostname1, overlappingListeners[i].hostname2, overlappingListeners[i].listener2, @@ -529,9 +529,6 @@ func checkOverlappingHostnames(httpsListeners []*ListenerContext) { gwapiv1.ListenerReasonOverlappingHostnames, message, ) - if listener.httpIR != nil { - listener.httpIR.TLSOverlaps = true - } } } } diff --git a/internal/gatewayapi/listener_test.go b/internal/gatewayapi/listener_test.go index 40094dfa6b..ca753c1bbf 100644 --- a/internal/gatewayapi/listener_test.go +++ b/internal/gatewayapi/listener_test.go @@ -385,6 +385,7 @@ func TestCheckOverlappingHostnames(t *testing.T) { for i := range tt.gateway.listeners { tt.gateway.listeners[i].listenerStatusIdx = i tt.gateway.listeners[i].gateway = tt.gateway + tt.gateway.listeners[i].httpIR = &ir.HTTPListener{} tt.gateway.Status.Listeners[i] = gwapiv1.ListenerStatus{ Name: tt.gateway.listeners[i].Name, Conditions: []metav1.Condition{}, @@ -420,6 +421,10 @@ func TestCheckOverlappingHostnames(t *testing.T) { t.Errorf("expected condition for listener %d, got nil or False", idx) } } + for idx, listener := range tt.gateway.listeners { + require.NotNil(t, listener.httpIR) + assert.False(t, listener.httpIR.TLSOverlaps, "hostname overlap must not trigger ALPN downgrade for listener %d", idx) + } if len(tt.expected) == 0 { if len(tt.gateway.Status.Listeners) != 0 { @@ -647,6 +652,7 @@ func TestCheckOverlappingCertificates(t *testing.T) { } gateway.listeners[i].listenerStatusIdx = i gateway.listeners[i].gateway = gateway + gateway.listeners[i].httpIR = &ir.HTTPListener{} } // Process overlapping certificates @@ -700,6 +706,15 @@ func TestCheckOverlappingCertificates(t *testing.T) { } } } + + expectedTLSOverlaps := map[string]bool{} + for _, expected := range tt.expectedStatus { + expectedTLSOverlaps[expected.listenerName] = true + } + for _, listener := range gateway.listeners { + require.NotNil(t, listener.httpIR) + assert.Equal(t, expectedTLSOverlaps[string(listener.Name)], listener.httpIR.TLSOverlaps, "unexpected TLSOverlaps for listener %s", listener.Name) + } }) } } diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-http3.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-http3.out.yaml index 62f58c8205..734d190a24 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-http3.out.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-http3.out.yaml @@ -92,8 +92,7 @@ gateways: type: ResolvedRefs - lastTransitionTime: null message: The hostname *.example.com overlaps with the hostname bar.example.com - in listener https-bar. ALPN will default to HTTP/1.1 to prevent HTTP/2 connection - coalescing, unless explicitly configured via ClientTrafficPolicy + in listener https-bar. reason: OverlappingHostnames status: "True" type: OverlappingTLSConfig @@ -122,8 +121,7 @@ gateways: type: ResolvedRefs - lastTransitionTime: null message: The hostname foo.example.com overlaps with the hostname *.example.com - in listener https-wildcard. ALPN will default to HTTP/1.1 to prevent HTTP/2 - connection coalescing, unless explicitly configured via ClientTrafficPolicy + in listener https-wildcard. reason: OverlappingHostnames status: "True" type: OverlappingTLSConfig @@ -152,8 +150,7 @@ gateways: type: ResolvedRefs - lastTransitionTime: null message: The hostname bar.example.com overlaps with the hostname *.example.com - in listener https-wildcard. ALPN will default to HTTP/1.1 to prevent HTTP/2 - connection coalescing, unless explicitly configured via ClientTrafficPolicy + in listener https-wildcard. reason: OverlappingHostnames status: "True" type: OverlappingTLSConfig @@ -304,7 +301,6 @@ xdsIR: privateKey: '[redacted]' maxVersion: "1.3" minVersion: "1.2" - tlsOverlaps: true - address: 0.0.0.0 externalPort: 443 hostnames: @@ -359,7 +355,6 @@ xdsIR: privateKey: '[redacted]' maxVersion: "1.3" minVersion: "1.2" - tlsOverlaps: true - address: 0.0.0.0 externalPort: 443 hostnames: @@ -414,7 +409,6 @@ xdsIR: privateKey: '[redacted]' maxVersion: "1.3" minVersion: "1.2" - tlsOverlaps: true readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames-merged-gateways.out.yaml b/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames-merged-gateways.out.yaml index b6c9580528..263d61190f 100644 --- a/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames-merged-gateways.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames-merged-gateways.out.yaml @@ -39,9 +39,7 @@ gateways: type: ResolvedRefs - lastTransitionTime: null message: The hostname foo.example.com overlaps with the hostname *.example.com - in listener https-1 of gateway gateway-2. ALPN will default to HTTP/1.1 - to prevent HTTP/2 connection coalescing, unless explicitly configured via - ClientTrafficPolicy + in listener https-1 of gateway gateway-2. reason: OverlappingHostnames status: "True" type: OverlappingTLSConfig @@ -102,9 +100,7 @@ gateways: type: ResolvedRefs - lastTransitionTime: null message: The hostname *.example.com overlaps with the hostname foo.example.com - in listener https-1 of gateway gateway-1. ALPN will default to HTTP/1.1 - to prevent HTTP/2 connection coalescing, unless explicitly configured via - ClientTrafficPolicy + in listener https-1 of gateway gateway-1. reason: OverlappingHostnames status: "True" type: OverlappingTLSConfig @@ -277,7 +273,6 @@ xdsIR: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNBQ0FRQXdEUVlKS29aSWh2Y05BUUVMQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkoKYm1NdU1SUXdFZ1lEVlFRRERBdGxlR0Z0Y0d4bExtTnZiVEFlRncweU5UQTBNakV3T1RFd05ETmFGdzB6TlRBMApNVGt3T1RFd05ETmFNRGN4RmpBVUJnTlZCQU1NRFNvdVpYaGhiWEJzWlM1amIyMHhIVEFiQmdOVkJBb01GR1Y0CllXMXdiR1VnYjNKbllXNXBlbUYwYVc5dU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0MKQVFFQXY0anl4TUh1YzQzMHdvWkk4M1JSMXVxU2gvbm9MVWVPdDZnMkNKaFVFYXNaeUNOMzN3bFRRRDE0SEhkSwpOb1k4SThWd1pOZFZCNGpjRzlnb3dDVmVQY3lqRzZPaGl1aUZNWnU2NzV6dWZEWnRlRTNEY3lTbFgrY2lSbVZZCkNuSmk3QkV3NlJMUUJ0bVV6WGxtYmRpVXE5djJwalVBL2R3ZnRLRHRZTHFrVytvTSt5MWg3cjRJV0JVK2RVcU0KcGtTem5VSCtKN1JoRkFsdytmRWlVSFRLemlCMkVtdjc3Mi91bS96NHdMWnJIeWNGbmc4L1FCM0JIUktXVTV4eQp3bWNTQ2xrVlMvWWNpMFVXcnR2eGhwck9wTUhQUGR2QkZ2M2NaWGNpUUJjb0ZNcGxsQzV0UURvdWJ0dEV1d3JpCi8rVktKWkUrSVl4ei9YeUd3Y3dJRnIzWG13SURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBU3VLaE8KcGtwL1VSclphbEU0OUlnc0xkN3hSTlBhREVkQ1RWZ3Qvc3praUhnSDB1NDBVaVV6KzVzaDRpdlJOazRqTm1zRwprb3FwQlBVS3pvVmtrSTcxUWQ4bHh1VzF2dkxZMXVvM0RIS2svdDFpUWVZWWpERlk3YzUxVG1BT015WUdKTlhxCi9EbW84UWgzaFB1RnI3a29kUjBLSkJyc0RsMEhoWVBjUnpWOW1sQ2lrU1B4THJGTUNwZGx0QUw2UEprSVpucUgKc1g5dEtVZk1uYW5jMkpHZTZVTDE1ODBEV2xQTUcrMU1qRElCVXdxWWYzaWNKb0NYclAwbzNmckRKcTE2VnpidApkalRtVGswakx1bGkvQ2JCZzh4dWp4emo4bmRPcVNkd05kd091OWoxSmZ2Q0I1RjZ4S0VTenowOVo5TzlOZUM5CjMrd1pLTlRSOXVEdDRKNksKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= name: envoy-gateway/tls-secret-example-com privateKey: '[redacted]' - tlsOverlaps: true - address: 0.0.0.0 externalPort: 443 hostnames: @@ -298,7 +293,6 @@ xdsIR: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNBQ0FRQXdEUVlKS29aSWh2Y05BUUVMQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkoKYm1NdU1SUXdFZ1lEVlFRRERBdGxlR0Z0Y0d4bExtTnZiVEFlRncweU5UQTBNakV3T1RFd05ETmFGdzB6TlRBMApNVGt3T1RFd05ETmFNRGN4RmpBVUJnTlZCQU1NRFNvdVpYaGhiWEJzWlM1amIyMHhIVEFiQmdOVkJBb01GR1Y0CllXMXdiR1VnYjNKbllXNXBlbUYwYVc5dU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0MKQVFFQXY0anl4TUh1YzQzMHdvWkk4M1JSMXVxU2gvbm9MVWVPdDZnMkNKaFVFYXNaeUNOMzN3bFRRRDE0SEhkSwpOb1k4SThWd1pOZFZCNGpjRzlnb3dDVmVQY3lqRzZPaGl1aUZNWnU2NzV6dWZEWnRlRTNEY3lTbFgrY2lSbVZZCkNuSmk3QkV3NlJMUUJ0bVV6WGxtYmRpVXE5djJwalVBL2R3ZnRLRHRZTHFrVytvTSt5MWg3cjRJV0JVK2RVcU0KcGtTem5VSCtKN1JoRkFsdytmRWlVSFRLemlCMkVtdjc3Mi91bS96NHdMWnJIeWNGbmc4L1FCM0JIUktXVTV4eQp3bWNTQ2xrVlMvWWNpMFVXcnR2eGhwck9wTUhQUGR2QkZ2M2NaWGNpUUJjb0ZNcGxsQzV0UURvdWJ0dEV1d3JpCi8rVktKWkUrSVl4ei9YeUd3Y3dJRnIzWG13SURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBU3VLaE8KcGtwL1VSclphbEU0OUlnc0xkN3hSTlBhREVkQ1RWZ3Qvc3praUhnSDB1NDBVaVV6KzVzaDRpdlJOazRqTm1zRwprb3FwQlBVS3pvVmtrSTcxUWQ4bHh1VzF2dkxZMXVvM0RIS2svdDFpUWVZWWpERlk3YzUxVG1BT015WUdKTlhxCi9EbW84UWgzaFB1RnI3a29kUjBLSkJyc0RsMEhoWVBjUnpWOW1sQ2lrU1B4THJGTUNwZGx0QUw2UEprSVpucUgKc1g5dEtVZk1uYW5jMkpHZTZVTDE1ODBEV2xQTUcrMU1qRElCVXdxWWYzaWNKb0NYclAwbzNmckRKcTE2VnpidApkalRtVGswakx1bGkvQ2JCZzh4dWp4emo4bmRPcVNkd05kd091OWoxSmZ2Q0I1RjZ4S0VTenowOVo5TzlOZUM5CjMrd1pLTlRSOXVEdDRKNksKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= name: envoy-gateway/tls-secret-example-com privateKey: '[redacted]' - tlsOverlaps: true - address: 0.0.0.0 externalPort: 443 hostnames: diff --git a/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames.in.yaml b/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames.in.yaml index 1ff5342871..e28cbebb25 100644 --- a/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames.in.yaml +++ b/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames.in.yaml @@ -22,17 +22,6 @@ gateways: protocol: HTTPS port: 443 hostname: "*.example.com" - allowedRoutes: - namespaces: - from: All - tls: - mode: Terminate - certificateRefs: - - name: tls-secret-example-com - - name: https-3 - protocol: HTTPS - port: 443 - hostname: "foo.bar.com" allowedRoutes: namespaces: from: All diff --git a/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames.out.yaml b/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames.out.yaml index ee1e4b38a5..002586dd3e 100644 --- a/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-multiple-https-listeners-with-overlapping-hostnames.out.yaml @@ -25,17 +25,6 @@ gateways: name: https-2 port: 443 protocol: HTTPS - tls: - certificateRefs: - - name: tls-secret-example-com - mode: Terminate - - allowedRoutes: - namespaces: - from: All - hostname: foo.bar.com - name: https-3 - port: 443 - protocol: HTTPS tls: certificateRefs: - name: tls-secret-foo-bar-com @@ -61,8 +50,7 @@ gateways: type: ResolvedRefs - lastTransitionTime: null message: The hostname foo.example.com overlaps with the hostname *.example.com - in listener https-2. ALPN will default to HTTP/1.1 to prevent HTTP/2 connection - coalescing, unless explicitly configured via ClientTrafficPolicy + in listener https-2. reason: OverlappingHostnames status: "True" type: OverlappingTLSConfig @@ -91,8 +79,7 @@ gateways: type: ResolvedRefs - lastTransitionTime: null message: The hostname *.example.com overlaps with the hostname foo.example.com - in listener https-1. ALPN will default to HTTP/1.1 to prevent HTTP/2 connection - coalescing, unless explicitly configured via ClientTrafficPolicy + in listener https-1. reason: OverlappingHostnames status: "True" type: OverlappingTLSConfig @@ -102,29 +89,6 @@ gateways: kind: HTTPRoute - group: gateway.networking.k8s.io kind: GRPCRoute - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: https-3 - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute httpRoutes: - apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -256,7 +220,6 @@ xdsIR: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNBQ0FRQXdEUVlKS29aSWh2Y05BUUVMQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkoKYm1NdU1SUXdFZ1lEVlFRRERBdGxlR0Z0Y0d4bExtTnZiVEFlRncweU5UQTBNakV3T1RFd05ETmFGdzB6TlRBMApNVGt3T1RFd05ETmFNRGN4RmpBVUJnTlZCQU1NRFNvdVpYaGhiWEJzWlM1amIyMHhIVEFiQmdOVkJBb01GR1Y0CllXMXdiR1VnYjNKbllXNXBlbUYwYVc5dU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0MKQVFFQXY0anl4TUh1YzQzMHdvWkk4M1JSMXVxU2gvbm9MVWVPdDZnMkNKaFVFYXNaeUNOMzN3bFRRRDE0SEhkSwpOb1k4SThWd1pOZFZCNGpjRzlnb3dDVmVQY3lqRzZPaGl1aUZNWnU2NzV6dWZEWnRlRTNEY3lTbFgrY2lSbVZZCkNuSmk3QkV3NlJMUUJ0bVV6WGxtYmRpVXE5djJwalVBL2R3ZnRLRHRZTHFrVytvTSt5MWg3cjRJV0JVK2RVcU0KcGtTem5VSCtKN1JoRkFsdytmRWlVSFRLemlCMkVtdjc3Mi91bS96NHdMWnJIeWNGbmc4L1FCM0JIUktXVTV4eQp3bWNTQ2xrVlMvWWNpMFVXcnR2eGhwck9wTUhQUGR2QkZ2M2NaWGNpUUJjb0ZNcGxsQzV0UURvdWJ0dEV1d3JpCi8rVktKWkUrSVl4ei9YeUd3Y3dJRnIzWG13SURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBU3VLaE8KcGtwL1VSclphbEU0OUlnc0xkN3hSTlBhREVkQ1RWZ3Qvc3praUhnSDB1NDBVaVV6KzVzaDRpdlJOazRqTm1zRwprb3FwQlBVS3pvVmtrSTcxUWQ4bHh1VzF2dkxZMXVvM0RIS2svdDFpUWVZWWpERlk3YzUxVG1BT015WUdKTlhxCi9EbW84UWgzaFB1RnI3a29kUjBLSkJyc0RsMEhoWVBjUnpWOW1sQ2lrU1B4THJGTUNwZGx0QUw2UEprSVpucUgKc1g5dEtVZk1uYW5jMkpHZTZVTDE1ODBEV2xQTUcrMU1qRElCVXdxWWYzaWNKb0NYclAwbzNmckRKcTE2VnpidApkalRtVGswakx1bGkvQ2JCZzh4dWp4emo4bmRPcVNkd05kd091OWoxSmZ2Q0I1RjZ4S0VTenowOVo5TzlOZUM5CjMrd1pLTlRSOXVEdDRKNksKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= name: envoy-gateway/tls-secret-example-com privateKey: '[redacted]' - tlsOverlaps: true - address: 0.0.0.0 externalPort: 443 hostnames: @@ -302,58 +265,6 @@ xdsIR: distinct: false name: "" prefix: / - tls: - alpnProtocols: null - certificates: - - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNBQ0FRQXdEUVlKS29aSWh2Y05BUUVMQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkoKYm1NdU1SUXdFZ1lEVlFRRERBdGxlR0Z0Y0d4bExtTnZiVEFlRncweU5UQTBNakV3T1RFd05ETmFGdzB6TlRBMApNVGt3T1RFd05ETmFNRGN4RmpBVUJnTlZCQU1NRFNvdVpYaGhiWEJzWlM1amIyMHhIVEFiQmdOVkJBb01GR1Y0CllXMXdiR1VnYjNKbllXNXBlbUYwYVc5dU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0MKQVFFQXY0anl4TUh1YzQzMHdvWkk4M1JSMXVxU2gvbm9MVWVPdDZnMkNKaFVFYXNaeUNOMzN3bFRRRDE0SEhkSwpOb1k4SThWd1pOZFZCNGpjRzlnb3dDVmVQY3lqRzZPaGl1aUZNWnU2NzV6dWZEWnRlRTNEY3lTbFgrY2lSbVZZCkNuSmk3QkV3NlJMUUJ0bVV6WGxtYmRpVXE5djJwalVBL2R3ZnRLRHRZTHFrVytvTSt5MWg3cjRJV0JVK2RVcU0KcGtTem5VSCtKN1JoRkFsdytmRWlVSFRLemlCMkVtdjc3Mi91bS96NHdMWnJIeWNGbmc4L1FCM0JIUktXVTV4eQp3bWNTQ2xrVlMvWWNpMFVXcnR2eGhwck9wTUhQUGR2QkZ2M2NaWGNpUUJjb0ZNcGxsQzV0UURvdWJ0dEV1d3JpCi8rVktKWkUrSVl4ei9YeUd3Y3dJRnIzWG13SURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBU3VLaE8KcGtwL1VSclphbEU0OUlnc0xkN3hSTlBhREVkQ1RWZ3Qvc3praUhnSDB1NDBVaVV6KzVzaDRpdlJOazRqTm1zRwprb3FwQlBVS3pvVmtrSTcxUWQ4bHh1VzF2dkxZMXVvM0RIS2svdDFpUWVZWWpERlk3YzUxVG1BT015WUdKTlhxCi9EbW84UWgzaFB1RnI3a29kUjBLSkJyc0RsMEhoWVBjUnpWOW1sQ2lrU1B4THJGTUNwZGx0QUw2UEprSVpucUgKc1g5dEtVZk1uYW5jMkpHZTZVTDE1ODBEV2xQTUcrMU1qRElCVXdxWWYzaWNKb0NYclAwbzNmckRKcTE2VnpidApkalRtVGswakx1bGkvQ2JCZzh4dWp4emo4bmRPcVNkd05kd091OWoxSmZ2Q0I1RjZ4S0VTenowOVo5TzlOZUM5CjMrd1pLTlRSOXVEdDRKNksKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= - name: envoy-gateway/tls-secret-example-com - privateKey: '[redacted]' - tlsOverlaps: true - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - foo.bar.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: https-3 - name: envoy-gateway/gateway-1/https-3 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 - routes: - - destination: - metadata: - kind: HTTPRoute - name: httproute-1 - namespace: envoy-gateway - name: httproute/envoy-gateway/httproute-1/rule/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8080 - metadata: - kind: Service - name: service-1 - namespace: envoy-gateway - sectionName: "8080" - name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 - protocol: HTTP - weight: 1 - hostname: foo.bar.com - isHTTP2: false - metadata: - kind: HTTPRoute - name: httproute-1 - namespace: envoy-gateway - name: httproute/envoy-gateway/httproute-1/rule/0/match/0/foo_bar_com - pathMatch: - distinct: false - name: "" - prefix: / tls: alpnProtocols: null certificates: diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 940996be35..54bf7096db 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -298,8 +298,8 @@ type HTTPListener struct { Hostnames []string `json:"hostnames" yaml:"hostnames"` // Tls configuration. If omitted, the gateway will expose a plain text HTTP server. TLS *TLSConfig `json:"tls,omitempty" yaml:"tls,omitempty"` - // TLSOverlaps indicates if the listener has TLS configuration that overlaps with other listeners. - // HTTP2 should be disabled if this is true to avoid the HTTP/2 Connection Coalescing issue (see https://gateway-api.sigs.k8s.io/geps/gep-3567/) + // TLSOverlaps indicates if the listener's certificate SANs overlap with another listener's certificate SANs. + // HTTP/2 should be disabled if this is true to avoid the HTTP/2 Connection Coalescing issue (see https://gateway-api.sigs.k8s.io/geps/gep-3567/) // We use a standalone field to avoid messing with the ClientTrafficPolicy ALPN config. TLSOverlaps bool `json:"tlsOverlaps,omitempty" yaml:"tlsOverlaps,omitempty"` // Routes associated with HTTP traffic to the service. diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 55519c9f36..4ed7cf3fa3 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -14,6 +14,7 @@ bug fixes: | Fixed SecurityPolicy merge using the wrong policy as the owner for resource references and IR generation. Fixed ListenerSet and its listeners incorrectly setting `Accepted: False` for InvalidCertificateRef and RefNotPermitted, inconsistent with Gateway behavior and the Gateway API spec. Fixed active HTTP health checks to use Backend endpoint hostnames before falling back to the effective Route hostname. + Fixed HTTPS listeners with overlapping hostnames but disjoint certificate SANs to preserve HTTP/2 ALPN by default. # Enhancements that improve performance. performance improvements: | From 6e4eaf86cfde4f8f7dbfdc6463a934bdc019e78c Mon Sep 17 00:00:00 2001 From: zirain Date: Fri, 8 May 2026 23:26:37 +0800 Subject: [PATCH 10/12] feat: enableDeferredCreationStats by default (#8937) * feat: enableDeferredCreationStats by default Signed-off-by: zirain Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- .../egctl/testdata/translate/out/default-resources.all.yaml | 4 ++++ .../testdata/translate/out/from-gateway-api-to-xds.all.json | 3 +++ .../testdata/translate/out/from-gateway-api-to-xds.all.yaml | 2 ++ .../translate/out/from-gateway-api-to-xds.bootstrap.yaml | 2 ++ .../out/jwt-single-route-single-match-to-xds.all.json | 3 +++ .../out/jwt-single-route-single-match-to-xds.all.yaml | 2 ++ .../out/jwt-single-route-single-match-to-xds.bootstrap.yaml | 2 ++ .../testdata/translate/out/no-service-cluster-ip.all.yaml | 2 ++ .../kubernetes/proxy/testdata/daemonsets/custom.yaml | 2 ++ .../kubernetes/proxy/testdata/daemonsets/default-env.yaml | 2 ++ .../kubernetes/proxy/testdata/daemonsets/default.yaml | 2 ++ .../proxy/testdata/daemonsets/disable-prometheus.yaml | 2 ++ .../kubernetes/proxy/testdata/daemonsets/extension-env.yaml | 2 ++ .../proxy/testdata/daemonsets/gateway-namespace-mode.yaml | 2 ++ .../testdata/daemonsets/override-labels-and-annotations.yaml | 2 ++ .../testdata/daemonsets/override-prometheus-annotations.yaml | 2 ++ .../kubernetes/proxy/testdata/daemonsets/patch-daemonset.yaml | 2 ++ .../proxy/testdata/daemonsets/shutdown-manager.yaml | 2 ++ .../kubernetes/proxy/testdata/daemonsets/volumes.yaml | 2 ++ .../proxy/testdata/daemonsets/with-annotations.yaml | 2 ++ .../kubernetes/proxy/testdata/daemonsets/with-extra-args.yaml | 2 ++ .../proxy/testdata/daemonsets/with-image-pull-secrets.yaml | 2 ++ .../kubernetes/proxy/testdata/daemonsets/with-name.yaml | 2 ++ .../proxy/testdata/daemonsets/with-node-selector.yaml | 2 ++ .../proxy/testdata/daemonsets/with-priority-class-name.yaml | 2 ++ .../testdata/daemonsets/with-topology-spread-constraints.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/custom-sa.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/custom.yaml | 2 ++ .../testdata/deployments/custom_with_initcontainers.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/default-env.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/default.yaml | 2 ++ .../proxy/testdata/deployments/disable-prometheus.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/dual-stack.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/extension-env.yaml | 2 ++ .../proxy/testdata/deployments/gateway-namespace-mode.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/ipv6.yaml | 2 ++ .../testdata/deployments/override-labels-and-annotations.yaml | 2 ++ .../testdata/deployments/override-prometheus-annotations.yaml | 2 ++ .../proxy/testdata/deployments/patch-deployment.yaml | 2 ++ .../proxy/testdata/deployments/shutdown-manager.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/volumes.yaml | 2 ++ .../proxy/testdata/deployments/with-annotations.yaml | 2 ++ .../proxy/testdata/deployments/with-empty-memory-limits.yaml | 2 ++ .../proxy/testdata/deployments/with-extra-args.yaml | 2 ++ .../proxy/testdata/deployments/with-image-pull-secrets.yaml | 2 ++ .../kubernetes/proxy/testdata/deployments/with-name.yaml | 2 ++ .../proxy/testdata/deployments/with-node-selector.yaml | 2 ++ .../proxy/testdata/deployments/with-priority-class-name.yaml | 2 ++ .../deployments/with-topology-spread-constraints.yaml | 2 ++ .../proxy/testdata/gateway-namespace-mode/deployment.yaml | 4 ++++ internal/xds/bootstrap/bootstrap.yaml.tpl | 2 ++ internal/xds/bootstrap/testdata/merge/default.out.yaml | 2 ++ .../bootstrap/testdata/merge/merge-user-bootstrap.out.yaml | 2 ++ .../xds/bootstrap/testdata/merge/patch-global-config.out.yaml | 2 ++ internal/xds/bootstrap/testdata/merge/stats_sinks.out.yaml | 2 ++ .../xds/bootstrap/testdata/render/custom-server-port.yaml | 2 ++ .../xds/bootstrap/testdata/render/custom-stats-matcher.yaml | 2 ++ .../xds/bootstrap/testdata/render/disable-prometheus.yaml | 2 ++ .../testdata/render/enable-prometheus-brotli-compression.yaml | 2 ++ .../testdata/render/enable-prometheus-gzip-compression.yaml | 2 ++ .../testdata/render/enable-prometheus-zstd-compression.yaml | 2 ++ internal/xds/bootstrap/testdata/render/enable-prometheus.yaml | 2 ++ internal/xds/bootstrap/testdata/render/ipv6.yaml | 2 ++ .../bootstrap/testdata/render/otel-metrics-backendref.yaml | 2 ++ .../xds/bootstrap/testdata/render/otel-metrics-custom-ca.yaml | 2 ++ .../testdata/render/otel-metrics-delta-temporality.yaml | 2 ++ .../xds/bootstrap/testdata/render/otel-metrics-headers.yaml | 2 ++ internal/xds/bootstrap/testdata/render/otel-metrics-tls.yaml | 2 ++ internal/xds/bootstrap/testdata/render/otel-metrics.yaml | 2 ++ .../bootstrap/testdata/render/topology-injector-disabled.yaml | 2 ++ .../bootstrap/testdata/render/topology-injector-enabled.yaml | 2 ++ .../bootstrap/testdata/render/with-max-heap-size-bytes.yaml | 2 ++ release-notes/current.yaml | 1 + 73 files changed, 151 insertions(+) diff --git a/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml b/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml index 9d2dc66515..41153fe438 100644 --- a/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml +++ b/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml @@ -23,6 +23,8 @@ envoyProxyForGatewayClass: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: @@ -568,6 +570,8 @@ xds: portValue: 19000 clusterManager: localClusterName: local_cluster + deferredStatOptions: + enableDeferredCreationStats: true dynamicResources: adsConfig: apiType: DELTA_GRPC diff --git a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.json b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.json index 45adf15015..ef6c2cdbc7 100644 --- a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.json +++ b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.json @@ -25,6 +25,9 @@ "clusterManager": { "localClusterName": "local_cluster" }, + "deferredStatOptions": { + "enableDeferredCreationStats": true + }, "dynamicResources": { "adsConfig": { "apiType": "DELTA_GRPC", diff --git a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.yaml b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.yaml index fe7f84b600..93486e9cf9 100644 --- a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.yaml +++ b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.yaml @@ -15,6 +15,8 @@ xds: portValue: 19000 clusterManager: localClusterName: local_cluster + deferredStatOptions: + enableDeferredCreationStats: true dynamicResources: adsConfig: apiType: DELTA_GRPC diff --git a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.bootstrap.yaml b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.bootstrap.yaml index ad785f5ff5..3a5582a922 100644 --- a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.bootstrap.yaml +++ b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.bootstrap.yaml @@ -14,6 +14,8 @@ xds: portValue: 19000 clusterManager: localClusterName: local_cluster + deferredStatOptions: + enableDeferredCreationStats: true dynamicResources: adsConfig: apiType: DELTA_GRPC diff --git a/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.json b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.json index 49e5ed4d0c..a05f7566c6 100644 --- a/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.json +++ b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.json @@ -25,6 +25,9 @@ "clusterManager": { "localClusterName": "local_cluster" }, + "deferredStatOptions": { + "enableDeferredCreationStats": true + }, "dynamicResources": { "adsConfig": { "apiType": "DELTA_GRPC", diff --git a/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.yaml b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.yaml index 9766fb1e7c..5a3619a007 100644 --- a/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.yaml +++ b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.yaml @@ -15,6 +15,8 @@ xds: portValue: 19000 clusterManager: localClusterName: local_cluster + deferredStatOptions: + enableDeferredCreationStats: true dynamicResources: adsConfig: apiType: DELTA_GRPC diff --git a/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.bootstrap.yaml b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.bootstrap.yaml index 47ec643913..2072db1fe5 100644 --- a/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.bootstrap.yaml +++ b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.bootstrap.yaml @@ -14,6 +14,8 @@ xds: portValue: 19000 clusterManager: localClusterName: local_cluster + deferredStatOptions: + enableDeferredCreationStats: true dynamicResources: adsConfig: apiType: DELTA_GRPC diff --git a/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml b/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml index c3a4473c6a..ff3d966c61 100644 --- a/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml +++ b/internal/cmd/egctl/testdata/translate/out/no-service-cluster-ip.all.yaml @@ -15,6 +15,8 @@ xds: portValue: 19000 clusterManager: localClusterName: local_cluster + deferredStatOptions: + enableDeferredCreationStats: true dynamicResources: adsConfig: apiType: DELTA_GRPC diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/custom.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/custom.yaml index 70994ff931..e44185cae5 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/custom.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/custom.yaml @@ -60,6 +60,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/default-env.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/default-env.yaml index fbce087da5..4ad641dc6c 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/default-env.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/default-env.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/default.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/default.yaml index 438eacd184..fd4ce3dbcf 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/default.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/default.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/disable-prometheus.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/disable-prometheus.yaml index a2a3143c77..9bcf2173de 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/disable-prometheus.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/disable-prometheus.yaml @@ -55,6 +55,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/extension-env.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/extension-env.yaml index b16624cfca..d1132cdd0d 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/extension-env.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/extension-env.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/gateway-namespace-mode.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/gateway-namespace-mode.yaml index 8dc2262e51..e2422e4fd6 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/gateway-namespace-mode.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/gateway-namespace-mode.yaml @@ -62,6 +62,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/override-labels-and-annotations.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/override-labels-and-annotations.yaml index 27491f7b93..5a98543e5a 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/override-labels-and-annotations.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/override-labels-and-annotations.yaml @@ -68,6 +68,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/override-prometheus-annotations.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/override-prometheus-annotations.yaml index 39dd56e6fa..568fc69cc3 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/override-prometheus-annotations.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/override-prometheus-annotations.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/patch-daemonset.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/patch-daemonset.yaml index e79d6f6497..70cfb128bf 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/patch-daemonset.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/patch-daemonset.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/shutdown-manager.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/shutdown-manager.yaml index 845409eee2..4ad7307a64 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/shutdown-manager.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/shutdown-manager.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/volumes.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/volumes.yaml index 3e6429df11..a565c83350 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/volumes.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/volumes.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-annotations.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-annotations.yaml index 063d9df6de..0b5cf0d9a3 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-annotations.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-annotations.yaml @@ -64,6 +64,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-extra-args.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-extra-args.yaml index 5d47039f22..c0fd41e168 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-extra-args.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-extra-args.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-image-pull-secrets.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-image-pull-secrets.yaml index b3bf334605..8a9f8ed1e0 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-image-pull-secrets.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-image-pull-secrets.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-name.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-name.yaml index a630bdb399..7b13bf1e99 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-name.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-name.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-node-selector.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-node-selector.yaml index 7359f093e3..32bff17024 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-node-selector.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-node-selector.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-priority-class-name.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-priority-class-name.yaml index 0ec1e349b0..1d9e731719 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-priority-class-name.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-priority-class-name.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-topology-spread-constraints.yaml b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-topology-spread-constraints.yaml index 1105ff9adc..65237ab496 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-topology-spread-constraints.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/daemonsets/with-topology-spread-constraints.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom-sa.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom-sa.yaml index f165dd6d49..42c8b0f3cb 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom-sa.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom-sa.yaml @@ -66,6 +66,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom.yaml index 98b4033ac7..b4490cd918 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom.yaml @@ -65,6 +65,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom_with_initcontainers.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom_with_initcontainers.yaml index cad31cfb09..e2743d6755 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom_with_initcontainers.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/custom_with_initcontainers.yaml @@ -65,6 +65,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/default-env.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/default-env.yaml index 0e5b2c5dbc..8aa34a75f6 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/default-env.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/default-env.yaml @@ -64,6 +64,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/default.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/default.yaml index f597fa03b9..4024d79708 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/default.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/default.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/disable-prometheus.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/disable-prometheus.yaml index c22da411c6..b4853096af 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/disable-prometheus.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/disable-prometheus.yaml @@ -59,6 +59,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/dual-stack.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/dual-stack.yaml index 3e26a3985e..75ddfe35a6 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/dual-stack.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/dual-stack.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/extension-env.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/extension-env.yaml index 6d28282d2f..b078c0570b 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/extension-env.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/extension-env.yaml @@ -64,6 +64,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/gateway-namespace-mode.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/gateway-namespace-mode.yaml index 91a3120c92..53bbde651e 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/gateway-namespace-mode.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/gateway-namespace-mode.yaml @@ -66,6 +66,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/ipv6.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/ipv6.yaml index 6e6ae6c4cd..cf94d2da00 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/ipv6.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/ipv6.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/override-labels-and-annotations.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/override-labels-and-annotations.yaml index 8370c9fc79..deefcec218 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/override-labels-and-annotations.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/override-labels-and-annotations.yaml @@ -72,6 +72,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/override-prometheus-annotations.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/override-prometheus-annotations.yaml index 707422a562..5504c9d47b 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/override-prometheus-annotations.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/override-prometheus-annotations.yaml @@ -65,6 +65,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/patch-deployment.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/patch-deployment.yaml index 3356ed26ec..bf061502a8 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/patch-deployment.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/patch-deployment.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/shutdown-manager.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/shutdown-manager.yaml index a177c6f2ea..be75b9f274 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/shutdown-manager.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/shutdown-manager.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/volumes.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/volumes.yaml index 0514b52039..d7303a8bf5 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/volumes.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/volumes.yaml @@ -64,6 +64,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-annotations.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-annotations.yaml index 3a26fa2de1..1e83e7f1c3 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-annotations.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-annotations.yaml @@ -68,6 +68,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-empty-memory-limits.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-empty-memory-limits.yaml index add627a94d..844d963a07 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-empty-memory-limits.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-empty-memory-limits.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-extra-args.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-extra-args.yaml index 09edcf4f4a..3af264c0ad 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-extra-args.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-extra-args.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-image-pull-secrets.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-image-pull-secrets.yaml index 98364ee759..cfea6aa343 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-image-pull-secrets.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-image-pull-secrets.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-name.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-name.yaml index 4700d9e6e7..46925304dd 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-name.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-name.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-node-selector.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-node-selector.yaml index 38ef7abdc8..b0bec4e69e 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-node-selector.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-node-selector.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-priority-class-name.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-priority-class-name.yaml index 21eb3abda9..c71e48c5a6 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-priority-class-name.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-priority-class-name.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-topology-spread-constraints.yaml b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-topology-spread-constraints.yaml index 2dac9e9eee..0a45dd3048 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-topology-spread-constraints.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/deployments/with-topology-spread-constraints.yaml @@ -63,6 +63,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/infrastructure/kubernetes/proxy/testdata/gateway-namespace-mode/deployment.yaml b/internal/infrastructure/kubernetes/proxy/testdata/gateway-namespace-mode/deployment.yaml index 7bedff6291..00f7165550 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/gateway-namespace-mode/deployment.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/gateway-namespace-mode/deployment.yaml @@ -66,6 +66,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: @@ -499,6 +501,8 @@ spec: node: locality: zone: $(ENVOY_SERVICE_ZONE) + deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/bootstrap.yaml.tpl b/internal/xds/bootstrap/bootstrap.yaml.tpl index 1c1c07ce53..3ce7131d88 100644 --- a/internal/xds/bootstrap/bootstrap.yaml.tpl +++ b/internal/xds/bootstrap/bootstrap.yaml.tpl @@ -15,6 +15,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/merge/default.out.yaml b/internal/xds/bootstrap/testdata/merge/default.out.yaml index 233616d086..e077a489cc 100644 --- a/internal/xds/bootstrap/testdata/merge/default.out.yaml +++ b/internal/xds/bootstrap/testdata/merge/default.out.yaml @@ -10,6 +10,8 @@ admin: port_value: 20000 cluster_manager: local_cluster_name: local_cluster +deferred_stat_options: + enable_deferred_creation_stats: true dynamic_resources: ads_config: api_type: DELTA_GRPC diff --git a/internal/xds/bootstrap/testdata/merge/merge-user-bootstrap.out.yaml b/internal/xds/bootstrap/testdata/merge/merge-user-bootstrap.out.yaml index ccb594eaad..c147788996 100644 --- a/internal/xds/bootstrap/testdata/merge/merge-user-bootstrap.out.yaml +++ b/internal/xds/bootstrap/testdata/merge/merge-user-bootstrap.out.yaml @@ -10,6 +10,8 @@ admin: port_value: 8080 cluster_manager: local_cluster_name: local_cluster +deferred_stat_options: + enable_deferred_creation_stats: true dynamic_resources: ads_config: api_type: DELTA_GRPC diff --git a/internal/xds/bootstrap/testdata/merge/patch-global-config.out.yaml b/internal/xds/bootstrap/testdata/merge/patch-global-config.out.yaml index 15d248b75b..c6baee4ed8 100644 --- a/internal/xds/bootstrap/testdata/merge/patch-global-config.out.yaml +++ b/internal/xds/bootstrap/testdata/merge/patch-global-config.out.yaml @@ -10,6 +10,8 @@ admin: port_value: 19000 cluster_manager: local_cluster_name: local_cluster +deferredStatOptions: + enableDeferredCreationStats: true dynamic_resources: ads_config: api_type: DELTA_GRPC diff --git a/internal/xds/bootstrap/testdata/merge/stats_sinks.out.yaml b/internal/xds/bootstrap/testdata/merge/stats_sinks.out.yaml index f03f95d6bc..6ebb53bcf7 100644 --- a/internal/xds/bootstrap/testdata/merge/stats_sinks.out.yaml +++ b/internal/xds/bootstrap/testdata/merge/stats_sinks.out.yaml @@ -10,6 +10,8 @@ admin: port_value: 19000 cluster_manager: local_cluster_name: local_cluster +deferred_stat_options: + enable_deferred_creation_stats: true dynamic_resources: ads_config: api_type: DELTA_GRPC diff --git a/internal/xds/bootstrap/testdata/render/custom-server-port.yaml b/internal/xds/bootstrap/testdata/render/custom-server-port.yaml index 2ee07fc73a..07c83680dd 100644 --- a/internal/xds/bootstrap/testdata/render/custom-server-port.yaml +++ b/internal/xds/bootstrap/testdata/render/custom-server-port.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/custom-stats-matcher.yaml b/internal/xds/bootstrap/testdata/render/custom-stats-matcher.yaml index dc1f6a4eb4..4449620532 100644 --- a/internal/xds/bootstrap/testdata/render/custom-stats-matcher.yaml +++ b/internal/xds/bootstrap/testdata/render/custom-stats-matcher.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/disable-prometheus.yaml b/internal/xds/bootstrap/testdata/render/disable-prometheus.yaml index 527784eb06..3fd0df98ff 100644 --- a/internal/xds/bootstrap/testdata/render/disable-prometheus.yaml +++ b/internal/xds/bootstrap/testdata/render/disable-prometheus.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/enable-prometheus-brotli-compression.yaml b/internal/xds/bootstrap/testdata/render/enable-prometheus-brotli-compression.yaml index 887846c1fc..c6b2f9124e 100644 --- a/internal/xds/bootstrap/testdata/render/enable-prometheus-brotli-compression.yaml +++ b/internal/xds/bootstrap/testdata/render/enable-prometheus-brotli-compression.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/enable-prometheus-gzip-compression.yaml b/internal/xds/bootstrap/testdata/render/enable-prometheus-gzip-compression.yaml index ae7bed5578..ba6377862f 100644 --- a/internal/xds/bootstrap/testdata/render/enable-prometheus-gzip-compression.yaml +++ b/internal/xds/bootstrap/testdata/render/enable-prometheus-gzip-compression.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/enable-prometheus-zstd-compression.yaml b/internal/xds/bootstrap/testdata/render/enable-prometheus-zstd-compression.yaml index b584011240..573a8b8970 100644 --- a/internal/xds/bootstrap/testdata/render/enable-prometheus-zstd-compression.yaml +++ b/internal/xds/bootstrap/testdata/render/enable-prometheus-zstd-compression.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/enable-prometheus.yaml b/internal/xds/bootstrap/testdata/render/enable-prometheus.yaml index 846533b79e..73aa82ea46 100644 --- a/internal/xds/bootstrap/testdata/render/enable-prometheus.yaml +++ b/internal/xds/bootstrap/testdata/render/enable-prometheus.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/ipv6.yaml b/internal/xds/bootstrap/testdata/render/ipv6.yaml index d9a1b966a1..714f65bc84 100644 --- a/internal/xds/bootstrap/testdata/render/ipv6.yaml +++ b/internal/xds/bootstrap/testdata/render/ipv6.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/otel-metrics-backendref.yaml b/internal/xds/bootstrap/testdata/render/otel-metrics-backendref.yaml index 8c250afc61..4723cbae86 100644 --- a/internal/xds/bootstrap/testdata/render/otel-metrics-backendref.yaml +++ b/internal/xds/bootstrap/testdata/render/otel-metrics-backendref.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/otel-metrics-custom-ca.yaml b/internal/xds/bootstrap/testdata/render/otel-metrics-custom-ca.yaml index 1ce524eb8b..0a81e308c9 100644 --- a/internal/xds/bootstrap/testdata/render/otel-metrics-custom-ca.yaml +++ b/internal/xds/bootstrap/testdata/render/otel-metrics-custom-ca.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/otel-metrics-delta-temporality.yaml b/internal/xds/bootstrap/testdata/render/otel-metrics-delta-temporality.yaml index d0457354e0..592e3a3d4a 100644 --- a/internal/xds/bootstrap/testdata/render/otel-metrics-delta-temporality.yaml +++ b/internal/xds/bootstrap/testdata/render/otel-metrics-delta-temporality.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/otel-metrics-headers.yaml b/internal/xds/bootstrap/testdata/render/otel-metrics-headers.yaml index 0b72c9fa0f..32d9e17500 100644 --- a/internal/xds/bootstrap/testdata/render/otel-metrics-headers.yaml +++ b/internal/xds/bootstrap/testdata/render/otel-metrics-headers.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/otel-metrics-tls.yaml b/internal/xds/bootstrap/testdata/render/otel-metrics-tls.yaml index dd58f54e80..43e07b5239 100644 --- a/internal/xds/bootstrap/testdata/render/otel-metrics-tls.yaml +++ b/internal/xds/bootstrap/testdata/render/otel-metrics-tls.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/otel-metrics.yaml b/internal/xds/bootstrap/testdata/render/otel-metrics.yaml index 8c250afc61..4723cbae86 100644 --- a/internal/xds/bootstrap/testdata/render/otel-metrics.yaml +++ b/internal/xds/bootstrap/testdata/render/otel-metrics.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/topology-injector-disabled.yaml b/internal/xds/bootstrap/testdata/render/topology-injector-disabled.yaml index 9791827250..62bbb840c0 100644 --- a/internal/xds/bootstrap/testdata/render/topology-injector-disabled.yaml +++ b/internal/xds/bootstrap/testdata/render/topology-injector-disabled.yaml @@ -11,6 +11,8 @@ admin: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/topology-injector-enabled.yaml b/internal/xds/bootstrap/testdata/render/topology-injector-enabled.yaml index 527784eb06..3fd0df98ff 100644 --- a/internal/xds/bootstrap/testdata/render/topology-injector-enabled.yaml +++ b/internal/xds/bootstrap/testdata/render/topology-injector-enabled.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/internal/xds/bootstrap/testdata/render/with-max-heap-size-bytes.yaml b/internal/xds/bootstrap/testdata/render/with-max-heap-size-bytes.yaml index 132da5aa46..3efccf6f50 100644 --- a/internal/xds/bootstrap/testdata/render/with-max-heap-size-bytes.yaml +++ b/internal/xds/bootstrap/testdata/render/with-max-heap-size-bytes.yaml @@ -13,6 +13,8 @@ cluster_manager: node: locality: zone: $(ENVOY_SERVICE_ZONE) +deferredStatOptions: + enableDeferredCreationStats: true stats_config: use_all_default_tags: true stats_tags: diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 4ed7cf3fa3..a2a4673618 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -18,6 +18,7 @@ bug fixes: | # Enhancements that improve performance. performance improvements: | + Enabled deferred stat creation to reduce CPU and memory overhead by creating only the subset of metrics that are actually used at runtime, instead of eagerly initializing all possible stats. More information can be found in the Envoy deferred stat creation [documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/bootstrap/v3/bootstrap.proto#config-bootstrap-v3-bootstrap-deferredstatoptions). # Deprecated features or APIs. deprecations: | From 883cb2e6b078e8adfef2ac539b79e7b6c740394f Mon Sep 17 00:00:00 2001 From: Rudrakh Panigrahi Date: Tue, 12 May 2026 16:04:48 +0530 Subject: [PATCH 11/12] fix: restore last transition time in merge status conditions (#8962) * fix: restore last transition time in merge status conditions Signed-off-by: Rudrakh Panigrahi * add release note Signed-off-by: Rudrakh Panigrahi --------- Signed-off-by: Rudrakh Panigrahi Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- internal/gatewayapi/status/conditions.go | 10 ++++++++-- internal/gatewayapi/status/conditions_test.go | 17 +++++++++++++++-- release-notes/current.yaml | 1 + 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/internal/gatewayapi/status/conditions.go b/internal/gatewayapi/status/conditions.go index 576281cb3a..6de6f4a92f 100644 --- a/internal/gatewayapi/status/conditions.go +++ b/internal/gatewayapi/status/conditions.go @@ -14,9 +14,10 @@ package status import ( - "reflect" "unicode" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -36,7 +37,7 @@ func MergeConditions(conditions []metav1.Condition, updates ...metav1.Condition) for j := range conditions { if conditions[j].Type == update.Type { add = false - if !reflect.DeepEqual(conditions[j], update) { + if conditionChanged(&conditions[j], &update) { conditions[j].Status = update.Status conditions[j].Reason = update.Reason conditions[j].Message = update.Message @@ -53,6 +54,11 @@ func MergeConditions(conditions []metav1.Condition, updates ...metav1.Condition) return conditions } +func conditionChanged(a, b *metav1.Condition) bool { + opts := cmpopts.IgnoreFields(metav1.Condition{}, "Type", "LastTransitionTime") + return !cmp.Equal(*a, *b, opts) +} + func newCondition(t string, status metav1.ConditionStatus, reason, msg string, og int64) metav1.Condition { return metav1.Condition{ Type: t, diff --git a/internal/gatewayapi/status/conditions_test.go b/internal/gatewayapi/status/conditions_test.go index b3ed1b2912..e43a7c7199 100644 --- a/internal/gatewayapi/status/conditions_test.go +++ b/internal/gatewayapi/status/conditions_test.go @@ -15,7 +15,6 @@ package status import ( "errors" - "reflect" "strings" "testing" @@ -41,6 +40,20 @@ func TestConditionChanged(t *testing.T) { a: metav1.Condition{}, b: metav1.Condition{}, }, + { + name: "condition LastTransitionTime should be ignored", + expected: false, + a: metav1.Condition{ + Type: string(gwapiv1.GatewayClassConditionStatusAccepted), + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.Unix(0, 0), + }, + b: metav1.Condition{ + Type: string(gwapiv1.GatewayClassConditionStatusAccepted), + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.Unix(1, 0), + }, + }, { name: "check condition reason differs", expected: true, @@ -70,7 +83,7 @@ func TestConditionChanged(t *testing.T) { } for _, tc := range testCases { - if got := !reflect.DeepEqual(tc.a, tc.b); got != tc.expected { + if got := conditionChanged(&tc.a, &tc.b); got != tc.expected { assert.Equal(t, tc.expected, got, tc.name) } } diff --git a/release-notes/current.yaml b/release-notes/current.yaml index a2a4673618..5c2c6edd30 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -15,6 +15,7 @@ bug fixes: | Fixed ListenerSet and its listeners incorrectly setting `Accepted: False` for InvalidCertificateRef and RefNotPermitted, inconsistent with Gateway behavior and the Gateway API spec. Fixed active HTTP health checks to use Backend endpoint hostnames before falling back to the effective Route hostname. Fixed HTTPS listeners with overlapping hostnames but disjoint certificate SANs to preserve HTTP/2 ALPN by default. + Fixed Gateway getting stuck at `Programmed=False` after its LoadBalancer Service IP was restored, by ignoring `LastTransitionTime` when comparing status conditions. # Enhancements that improve performance. performance improvements: | From 27f6d23f8fb453398b6162fcdc5be0df9e40156d Mon Sep 17 00:00:00 2001 From: jukie Date: Tue, 12 May 2026 20:56:20 -0600 Subject: [PATCH 12/12] [release/v1.8] v1.8.0 release notes Cherry-picked release-notes/v1.8.0.yaml and VERSION bump from #8942. Signed-off-by: jukie <10012479+jukie@users.noreply.github.com> --- VERSION | 2 +- release-notes/current.yaml | 12 ---- release-notes/v1.8.0.yaml | 113 +++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 13 deletions(-) create mode 100644 release-notes/v1.8.0.yaml diff --git a/VERSION b/VERSION index 828fcfc8b1..804a616da1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.8.0-rc.1 +v1.8.0 diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 5c2c6edd30..3271a4f907 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -2,7 +2,6 @@ date: Pending # Changes that are expected to cause an incompatibility with previous versions, such as deletions or modifications to existing APIs. breaking changes: | - Merged SecurityPolicy IR/xDS resource names (OIDC, BasicAuth, ExtAuth, JWT) now derive from the policy that contributes the field (parent or route) rather than always using the route-level policy. EnvoyPatchPolicy users who reference those generated names must update their patch targets. # Updates addressing vulnerabilities, security flaws, or compliance requirements. security updates: | @@ -11,23 +10,12 @@ security updates: | new features: | bug fixes: | - Fixed SecurityPolicy merge using the wrong policy as the owner for resource references and IR generation. - Fixed ListenerSet and its listeners incorrectly setting `Accepted: False` for InvalidCertificateRef and RefNotPermitted, inconsistent with Gateway behavior and the Gateway API spec. - Fixed active HTTP health checks to use Backend endpoint hostnames before falling back to the effective Route hostname. - Fixed HTTPS listeners with overlapping hostnames but disjoint certificate SANs to preserve HTTP/2 ALPN by default. - Fixed Gateway getting stuck at `Programmed=False` after its LoadBalancer Service IP was restored, by ignoring `LastTransitionTime` when comparing status conditions. # Enhancements that improve performance. performance improvements: | - Enabled deferred stat creation to reduce CPU and memory overhead by creating only the subset of metrics that are actually used at runtime, instead of eagerly initializing all possible stats. More information can be found in the Envoy deferred stat creation [documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/bootstrap/v3/bootstrap.proto#config-bootstrap-v3-bootstrap-deferredstatoptions). # Deprecated features or APIs. deprecations: | # Other notable changes not covered by the above sections. Other changes: | - Moved Envoy Gateway CRDs into a sub-chart to avoid the Helm release secret exceeding the 1MB size limit when adding new API fields. Upgrade/Install behavior is unchanged for users. - The maximum number of rules in a RateLimit policy is increased from 128 to 256. - The maximum number of JWT providers allowed in `SecurityPolicy.spec.jwt.providers` is increased from 4 to 16. - Added `runner_event_total` metric to track update and delete events in infrastructure and gateway API runners for improved observability. - Added common Helm labels to Envoy Gateway RBAC resources. diff --git a/release-notes/v1.8.0.yaml b/release-notes/v1.8.0.yaml new file mode 100644 index 0000000000..76f024062e --- /dev/null +++ b/release-notes/v1.8.0.yaml @@ -0,0 +1,113 @@ +date: May 12, 2026 + +# Changes that are expected to cause an incompatibility with previous versions, such as deletions or modifications to existing APIs. +breaking changes: | + The DirectResponse body in HTTPFilter now supports Envoy command operators for dynamic content. Existing configurations including the template syntax (%) will be interpolated. + The `0s` timeout in SecurityPolicy is now treated as infinite timeout instead of immediate timeout. + Fixed EnvoyProxy `samplingFraction` translation to correctly convert the Gateway API fraction into Envoy's percentage-based `random_sampling` field. Existing `samplingFraction` configurations will now sample 100x more frequently than in previous releases; divide previous values by 100 to preserve prior sampling rates. + The controller now uses production logging encoder config by default, which provides better output when using JSON encoder. + SecurityPolicy OIDC now generates a single native `envoy.filters.http.oauth2` HTTP filter in the HCM filter chain and moves route-specific OAuth2 configuration to route `typed_per_filter_config`. This can break existing EnvoyPatchPolicies and extension managers that depend on the previous per-route OAuth2 filter instances or on the old OAuth2 filter configuration shape in the HCM filter chain. + Merged SecurityPolicy IR/xDS resource names (OIDC, BasicAuth, ExtAuth, JWT) now derive from the policy that contributes the field (parent or route) rather than always using the route-level policy. EnvoyPatchPolicy users who reference those generated names must update their patch targets. + +# Updates addressing vulnerabilities, security flaws, or compliance requirements. +security updates: | + +# New features or capabilities added in this release. +new features: | + Added support for optional active health check configuration. + Added support for shadow mode in local rate limiting. + Added support for MergeType in SecurityPolicy to enable route-level policies to merge with parent Gateway/Listener policies, similar to BackendTrafficPolicy. + Added `egctl config envoy-gateway` commands to retrieve Envoy Gateway admin config dumps. + The DirectResponse body in HTTPFilter now supports Envoy command operators for dynamic content. See https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators for more details. + Added HTTP/2 connection keepalive support to ClientTrafficPolicy and BackendTrafficPolicy. + Added RoutingType field for BackendTrafficPolicy. + Added support for configuring weights for locality zones. + Added support for gRPC-Web settings in ClientTrafficPolicy. + Added support for Envoy Dynamic Modules. + Added support for weight in BackendRef API to enable traffic splitting for non-x-route resources. + Added support for removing headers based on matching criteria (Exact, Prefix, Suffix, RegularExpression) in ClientTrafficPolicy EarlyRequestHeaders and LateResponseHeaders. + Added support for priorityClassName in KubernetesPodSpec for Envoy Proxy pods. + Added support for Global rate limit shadow mode. + Added support for specifying both text (body) and attributes in access log format by making the type field optional. + Set warning status condition for deprecated fields in xPolicy CRDs. + Added support for URLRewrite filter on individual backendRefs. + Added support for custom headers on OTLP exports (metrics, tracing, access logs). + Added support for custom TLS configuration when pulling WASM code via HTTP or OCI in EnvoyExtensionPolicy. + Added support for gRPC stats settings in EnvoyProxy. + Added the PostEndpointsModify extension hook, allowing extensions to modify EDS ClusterLoadAssignments generated by Envoy Gateway before they are sent to Envoy. + Added support for stream idle timeout in BackendTrafficPolicy. + Added `namespaceOverride` support to gateway-helm chart. + Added support for configuring statusOnError in ExtAuth settings. + Added support for GeoIP-based authorization on HTTPRoute and GRPCRoute via `SecurityPolicy.spec.authorization.rules[*].principal.clientIPGeoLocations`, backed by shared GeoIP provider settings in `EnvoyProxy.spec.geoIP`. + Added support for retry budget in BackendTrafficPolicy. + Added support for BackendUtilization load balancing policy in BackendTrafficPolicy. + Added support for upstream access logs via the `Upstream` access log type in EnvoyProxy. + Added support for invert match in CIDR match RateLimit API. + Added support for ignoring HTTP/1.1 Upgrade requests in ClientTrafficPolicy via `http1.ignoredUpgradeTypes`. + Added support for OpenTelemetry sampler configuration for tracing. + Added support for multiple ExtensionManagers with sequential chaining via a new `extensionManagers` field in `EnvoyGateway` configuration. + Added support for default EnvoyProxy settings on EnvoyGatewaySpec that can be overridden by GatewayClass or Gateway-level EnvoyProxy configurations. A new MergeType field allows choosing between Replace (default), StrategicMerge, or JSONMerge strategies for combining configurations. + Added support for sending Envoy Gateway route metadata to external authorization backends via `SecurityPolicy.spec.extAuth.includeRouteMetadata`. + Added support for cross-namespace policy attachment for ClientTrafficPolicy, BackendTrafficPolicy, EnvoyExtensionPolicy, and SecurityPolicy. + Added `source` field to `responseOverride` rules in BackendTrafficPolicy, allowing rules to target only Envoy-generated responses (`Local`), only upstream responses (`Backend`), or both (`All`, the default). This enables overriding Envoy responses (e.g. auth/rate-limit failures) without affecting legitimate upstream responses with the same status code. + Added support for path override in ExtAuth HTTP service. + Added support for bandwidth limiting in BackendTrafficPolicy. + Added support for defining Envoy Proxy image, pullPolicy, and pullSecrets via the helm chart. Note that to merge these helm-configured values with EnvoyProxy resources, the EnvoyProxy must include `mergeType: StrategicMerge` or `mergeType: JSONMerge`. + Added support for Envoy Admission Control to BackendTrafficPolicy, enabling client-side load shedding based on historical upstream success rates using Envoy's admission control filter. + +bug fixes: | + Fixed local rate limit rules with identical sourceCIDR client selectors producing conflicting descriptors. + Rejected ClientTrafficPolicy if invalid TLS cipher suites are configured. + Fixed ClientTrafficPolicy to disable HTTP/3 and surface a warning on the policy when downstream client TLS validation is configured, instead of generating a rejected QUIC listener. + Fixed validation of XListenerSet certificateRefs. + Fixed XListenerSet not allowing xRoutes from the same namespace when configured to allow them. + Fixed API key authentication dropping non-first client IDs when credential Secrets contain multiple keys. + Fixed `X-ENVOY-ORIGINAL-HOST` not being set when `headers.enableEnvoyHeaders` is enabled and hostname rewrite is configured for DynamicResolver type of Backends. + Fixed standalone mode emitting non-actionable error logs for missing secrets and unsupported ratelimit deletion on every startup. + Fixed local object reference resolution from parent policy in merged BackendTrafficPolicies. + Fixed xPolicy resources being processed from all namespaces when NamespaceSelector watch mode is configured in the Kubernetes provider. + Fixed route and policy status aggregation across multiple GatewayClasses managed by the same controller, so resources preserve status from all relevant parents and ancestors instead of being overwritten by the last processed GatewayClass. + Fixed route status parent aggregation when the number of parents exceeds the Gateway API cap of 32. + Made ConnectionLimit.Value optional so users can configure MaxConnectionDuration, MaxRequestsPerConnection, or MaxStreamDuration without setting a max connections value. + Fixed endpoint hostname not being respected during active health checks. + Fixed ratelimit deployment missing metrics container port (19001), which prevented PodMonitor/ServiceMonitor from targeting the metrics endpoint. + Fixed ratelimit ServiceAccount missing standard Kubernetes app labels. + Fixed GRPCRoute RequestMirror filter backend not being indexed, causing "service not found" errors for mirror targets that exist in the cluster. + Fixed GRPCRoute not detecting conflicting RequestMirror and DirectResponse filters, which caused the mirror to be silently dropped. + Fixed BackendTrafficPolicy `requestBuffer` coexisting with route upgrades by disabling the default WebSocket upgrade on buffered routes and rejecting explicit `requestBuffer` + `httpUpgrade` combinations. + Fixed per-endpoint hostname override not working due to the auto-generated wildcard hostname. + Fixed Basic Authentication failing when htpasswd secrets use CRLF line endings by normalizing to LF before passing to Envoy. + Fixed BackendTLSPolicy being ignored when configuring TLS for telemetry backends (access logs, tracing, metrics). + Fixed client certificate secret never being delivered when exclusively referenced by a SecurityPolicy `extAuth`/`jwt`/`oidc` Backend. + Fixed xRoutes being incorrectly marked unaccepted when a RequestMirror filter referenced a backend with no endpoints; the route now remains accepted with `BackendsAvailable=False`, per Gateway API conformance. + Fixed `ws` and `wss` Backend appProtocols to force HTTP/1.1 upstream connections instead of negotiating HTTP/2, avoiding compatibility issues with WebSocket backends that do not support RFC 8441 extended CONNECT. + Fixed gateway-helm RBAC in GatewayNamespace mode with explicit `watch.namespaces` list by adding controller-namespace secret read permissions to infra-manager. + Fixed a control plane panic caused by concurrent Status mutation racing with the watchable Map coalesce goroutine. + Fixed BackendTrafficPolicy rate limit `requests` values above uint32 max (4294967295) being silently truncated modulo 2^32 by the rate limit service and Envoy token bucket. The field now rejects such values at admission time with a clear schema validation error. + Fixed status conditions not being updated when a route is rejected due to multiple errors. + Fixed spurious development-mode panic log from the gatewayapi translator. + Fixed SecurityPolicy merge using the wrong policy as the owner for resource references and IR generation. + Fixed ListenerSet and its listeners incorrectly setting `Accepted: False` for InvalidCertificateRef and RefNotPermitted, inconsistent with Gateway behavior and the Gateway API spec. + Fixed active HTTP health checks to use Backend endpoint hostnames before falling back to the effective Route hostname. + Fixed HTTPS listeners with overlapping hostnames but disjoint certificate SANs to preserve HTTP/2 ALPN by default. + Removed the spurious cross-namespace policy-attachment warning condition when a ReferenceGrant is missing (#8901). + Fixed an invalid first listener winning hostname/protocol precedence and causing a later valid listener on the same hostname/port to be marked HostnameConflict (#8577). + Increased `RateLimitSelectCondition.headers` MaxItems from 16 to 64, matching the existing `HTTPHeaderFilter` pattern (#8906). + Fixed Gateway getting stuck at `Programmed=False` after its LoadBalancer Service IP was restored, by ignoring `LastTransitionTime` when comparing status conditions. + +# Enhancements that improve performance. +performance improvements: | + Reduced chances of listener drain due to Lua policy updates by migrating to LuaPerRoute. + Reduced Kubernetes API server calls by reusing the cached controller-runtime client from the controller manager for infrastructure reconciliation. In GatewayNamespaceMode, this may slightly increase memory usage due to keeping the infrastructure resources in the cache. + Enabled deferred stat creation to reduce CPU and memory overhead by creating only the subset of metrics that are actually used at runtime, instead of eagerly initializing all possible stats. More information can be found in the Envoy deferred stat creation [documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/bootstrap/v3/bootstrap.proto#config-bootstrap-v3-bootstrap-deferredstatoptions). + +# Deprecated features or APIs. +deprecations: | + +# Other notable changes not covered by the above sections. +Other changes: | + Moved Envoy Gateway CRDs into a sub-chart to avoid the Helm release secret exceeding the 1MB size limit when adding new API fields. Upgrade/Install behavior is unchanged for users. + The maximum number of rules in a RateLimit policy is increased from 128 to 256. + The maximum number of JWT providers allowed in `SecurityPolicy.spec.jwt.providers` is increased from 4 to 16. + Added `runner_event_total` metric to track update and delete events in infrastructure and gateway API runners for improved observability. + Added common Helm labels to Envoy Gateway RBAC resources.