Proof of Concept
PoC Overview
- This PoC demonstrates how the pre-fix behavior could allow an attacker to influence which TLS certificate is used for a Gateway listener by ordering multiple certificateRefs and providing an attacker-controlled Secret in a namespace the controller might not properly restrict.
- The fix adds per-ref permission checks and per-ref TLS loading, preventing unauthorized Secret references from being used for TLS termination.
Prerequisites (Kubernetes cluster with Traefik Gateway provider installed in a test environment):
- A GatewayClass named my-gateway-class backed by traefik.io/gateway-controller
- A Gateway in namespace default with a listener using HTTPS/TLS and two certificateRefs
- Two Secrets containing TLS data: one legitimate (allowed) and one attacker-controlled (potentially disallowed)
Files to apply (placeholders for cert data; replace with real test certs in a safe testing environment):
1) Attacker-controlled TLS secret ( attacker-secret in namespace attacker-ns )
---
apiVersion: v1
kind: Secret
metadata:
name: attacker-secret
namespace: attacker-ns
type: kubernetes.io/tls
stringData:
tls.crt: |-
-----BEGIN CERTIFICATE-----
MIIBtjCCAVugAwIBAgIJAO7Z... (test cert for attacker example)
-----END CERTIFICATE-----
tls.key: |-
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMG... (test key for attacker example)
-----END PRIVATE KEY-----
2) Legitimate TLS secret ( legitimate-secret in namespace default )
---
apiVersion: v1
kind: Secret
metadata:
name: legitimate-secret
namespace: default
type: kubernetes.io/tls
stringData:
tls.crt: |-
-----BEGIN CERTIFICATE-----
MIIBlTCCATugAwIBAgIJAO9t... (legitimate test cert)
-----END CERTIFICATE-----
tls.key: |-
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMG... (legitimate test key)
-----END PRIVATE KEY-----
3) Gateway resource ordering attacker-ref first (default namespace) to illustrate misconfiguration risk
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: test-gw
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
certificateRefs:
- kind: Secret
name: attacker-secret
namespace: attacker-ns
group: ""
- kind: Secret
name: legitimate-secret
namespace: default
group: ""
allowedRoutes:
namespaces:
from: Same
4) HTTPRoute to complete configuration (optional for PoC) – routes from gateway to a sample service
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-app-1
namespace: default
spec:
parentRefs:
- name: test-gw
kind: Gateway
group: gateway.networking.k8s.io
hostnames:
- "example.local"
rules:
- matches:
- path:
type: Exact
value: /bar
backendRefs:
- name: whoami
port: 80
weight: 1
kind: Service
group: ""
What to observe:
- Before fix (or if the controller ignores per-ref permissions): The Gateway listener could load attacker-secret (attacker-secret) as the TLS certificate for TLS termination if attacker-secret is listed first, potentially presenting an attacker-controlled certificate to clients connecting to https://example.local. This could enable misconfiguration exposure, info disclosure, or downgrade risks if clients reject the certificate or trust mismatch occurs.
- After fix (as implemented by this commit): The Gateway controller validates each certificateRef per the namespace/gateway permissions. If an attacker-controlled secret is referenced in a way that is not permitted, the code marks the TLS reference as invalid (ListenerConditionResolvedRefs with a reason like RefNotPermitted/InvalidCertificateRef) and will not load that TLS certificate, preventing unauthorized TLS termination.
How to test manually:
1) Deploy the resources with a test CA-signed certificate for legitimate-secret and a self-signed or differently issued certificate for attacker-secret.
2) Apply the Gateway manifest with attacker-secret first in certificateRefs.
3) Observe the Gateway status via kubectl describe gateway/test-gw -n default. Before the fix it may continue to serve the attacker cert if permissions are not enforced. After the fix you should see a ResolvedRefs condition false with a reason such as RefNotPermitted or InvalidCertificateRef.
4) Attempt an TLS handshake to the gateway. If the attacker-secret was incorrectly trusted, you may observe a certificate presented that does not match the expected domain. With the fix in place, TLS termination should not proceed using the unauthorized certificate, and the listener may be marked as not accepted until a valid, permitted certificateRef is provided.
Notes:
- This PoC uses intentionally attacker-controlled TLS secrets and an attacker-first reference order to illustrate the risk of not validating per-ref permissions for TLS certificateRefs. In real deployments, proper RBAC and Gateway API permissions should prevent cross-namespace references unless explicitly allowed.
- Replace the placeholder certificate data with real-test certificates in a safe, isolated test environment.
Code Diff
diff --git a/pkg/provider/kubernetes/gateway/fixtures/httproute/with_multiple_certificaterefs.yml b/pkg/provider/kubernetes/gateway/fixtures/httproute/with_multiple_certificaterefs.yml
new file mode 100644
index 0000000000..4766f554bd
--- /dev/null
+++ b/pkg/provider/kubernetes/gateway/fixtures/httproute/with_multiple_certificaterefs.yml
@@ -0,0 +1,78 @@
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: supersecret
+ namespace: default
+
+data:
+ tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
+ tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
+
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: supersecret2
+ namespace: default
+
+data:
+ tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
+ tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
+
+---
+kind: GatewayClass
+apiVersion: gateway.networking.k8s.io/v1
+metadata:
+ name: my-gateway-class
+spec:
+ controllerName: traefik.io/gateway-controller
+
+---
+kind: Gateway
+apiVersion: gateway.networking.k8s.io/v1
+metadata:
+ name: my-gateway
+ namespace: default
+spec:
+ gatewayClassName: my-gateway-class
+ listeners:
+ - name: https
+ protocol: HTTPS
+ port: 443
+ tls:
+ certificateRefs:
+ - kind: Secret
+ name: supersecret
+ group: ""
+ - kind: Secret
+ name: supersecret2
+ group: ""
+ allowedRoutes:
+ namespaces:
+ from: Same
+
+---
+kind: HTTPRoute
+apiVersion: gateway.networking.k8s.io/v1
+metadata:
+ name: http-app-1
+ namespace: default
+spec:
+ parentRefs:
+ - name: my-gateway
+ kind: Gateway
+ group: gateway.networking.k8s.io
+ hostnames:
+ - "foo.com"
+ rules:
+ - matches:
+ - path:
+ type: Exact
+ value: /bar
+ backendRefs:
+ - name: whoami
+ port: 80
+ weight: 1
+ kind: Service
+ group: ""
diff --git a/pkg/provider/kubernetes/gateway/fixtures/httproute/with_multiple_certificaterefs_one_missing.yml b/pkg/provider/kubernetes/gateway/fixtures/httproute/with_multiple_certificaterefs_one_missing.yml
new file mode 100644
index 0000000000..7fa32e0c60
--- /dev/null
+++ b/pkg/provider/kubernetes/gateway/fixtures/httproute/with_multiple_certificaterefs_one_missing.yml
@@ -0,0 +1,67 @@
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: supersecret
+ namespace: default
+
+data:
+ tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
+ tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
+
+---
+kind: GatewayClass
+apiVersion: gateway.networking.k8s.io/v1
+metadata:
+ name: my-gateway-class
+spec:
+ controllerName: traefik.io/gateway-controller
+
+---
+kind: Gateway
+apiVersion: gateway.networking.k8s.io/v1
+metadata:
+ name: my-gateway
+ namespace: default
+spec:
+ gatewayClassName: my-gateway-class
+ listeners:
+ - name: https
+ protocol: HTTPS
+ port: 443
+ tls:
+ certificateRefs:
+ - kind: Secret
+ name: supersecret
+ group: ""
+ - kind: Secret
+ name: missing-secret
+ group: ""
+ allowedRoutes:
+ namespaces:
+ from: Same
+
+---
+kind: HTTPRoute
+apiVersion: gateway.networking.k8s.io/v1
+metadata:
+ name: http-app-1
+ namespace: default
+spec:
+ parentRefs:
+ - name: my-gateway
+ kind: Gateway
+ group: gateway.networking.k8s.io
+ hostnames:
+ - "foo.com"
+ rules:
+ - matches:
+ - path:
+ type: Exact
+ value: /bar
+ backendRefs:
+ - name: whoami
+ port: 80
+ weight: 1
+ kind: Service
+ group: ""
diff --git a/pkg/provider/kubernetes/gateway/kubernetes.go b/pkg/provider/kubernetes/gateway/kubernetes.go
index cd7c9ad2e7..7910dc4534 100644
--- a/pkg/provider/kubernetes/gateway/kubernetes.go
+++ b/pkg/provider/kubernetes/gateway/kubernetes.go
@@ -428,7 +428,7 @@ func (p *Provider) loadConfigurationFromGateways(ctx context.Context) *dynamic.C
}
func (p *Provider) loadGatewayListeners(ctx context.Context, gateway *gatev1.Gateway, conf *dynamic.Configuration) []gatewayListener {
- tlsConfigs := make(map[string]*tls.CertAndStores)
+ tlsCerts := make(map[string]*tls.CertAndStores)
allocatedListeners := make(map[string]struct{})
gatewayListeners := make([]gatewayListener, len(gateway.Spec.Listeners))
@@ -529,30 +529,22 @@ func (p *Provider) loadGatewayListeners(ctx context.Context, gateway *gatev1.Gat
// TLS
if listener.Protocol == gatev1.HTTPSProtocolType || listener.Protocol == gatev1.TLSProtocolType {
- if listener.TLS == nil || (len(listener.TLS.CertificateRefs) == 0 && listener.TLS.Mode != nil && *listener.TLS.Mode != gatev1.TLSModePassthrough) {
- // update "Detached" status with "UnsupportedProtocol" reason
+ if listener.TLS == nil {
gatewayListeners[i].Status.Conditions = append(gatewayListeners[i].Status.Conditions, metav1.Condition{
Type: string(gatev1.ListenerConditionAccepted),
Status: metav1.ConditionFalse,
ObservedGeneration: gateway.Generation,
LastTransitionTime: metav1.Now(),
Reason: "InvalidTLSConfiguration", // TODO check the spec if a proper reason is introduced at some point
- Message: fmt.Sprintf("No TLS configuration for Gateway Listener %s:%d and protocol %q",
- listener.Name, listener.Port, listener.Protocol),
+ Message: fmt.Sprintf("No TLS configuration for Gateway Listener %s:%d and protocol %q", listener.Name, listener.Port, listener.Protocol),
})
-
continue
}
- var tlsModeType gatev1.TLSModeType
- if listener.TLS.Mode != nil {
- tlsModeType = *listener.TLS.Mode
- }
-
- isTLSPassthrough := tlsModeType == gatev1.TLSModePassthrough
+ tlsMode := ptr.Deref(listener.TLS.Mode, gatev1.TLSModeTerminate)
+ isTLSPassthrough := tlsMode == gatev1.TLSModePassthrough
if isTLSPassthrough && len(listener.TLS.CertificateRefs) > 0 {
- // https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.GatewayTLSConfig
log.Ctx(ctx).Warn().Msg("In case of Passthrough TLS mode, no TLS settings take effect as the TLS session from the client is NOT terminated at the Gateway")
}
@@ -560,7 +552,7 @@ func (p *Provider) loadGatewayListeners(ctx context.Context, gateway *gatev1.Gat
// Protocol TLS -> Passthrough -> TLSRoute
// Protocol TLS -> Terminate -> TLSRoute
// Protocol HTTPS -> Terminate -> HTTPRoute
- if listener.Protocol == gatev1.HTTPSProtocolType && isTLSPassthrough {
+ if isTLSPassthrough && listener.Protocol == gatev1.HTTPSProtocolType {
gatewayListeners[i].Status.Conditions = append(gatewayListeners[i].Status.Conditions, metav1.Condition{
Type: string(gatev1.ListenerConditionAccepted),
Status: metav1.ConditionFalse,
@@ -569,13 +561,11 @@ func (p *Provider) loadGatewayListeners(ctx context.Context, gateway *gatev1.Gat
Reason: string(gatev1.ListenerReasonUnsupportedProtocol),
Message: "HTTPS protocol is not supported with TLS mode Passthrough",
})
-
continue
}
if !isTLSPassthrough {
if len(listener.TLS.CertificateRefs) == 0 {
- // update "ResolvedRefs" status true with "InvalidCertificateRef" reason
gatewayListeners[i].Status.Conditions = append(gatewayListeners[i].Status.Conditions, metav1.Condition{
Type: string(gatev1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
@@ -584,74 +574,73 @@ func (p *Provider) loadGatewayListeners(ctx context.Context, gateway *gatev1.Gat
Reason: string(gatev1.ListenerReasonInvalidCertificateRef),
Message: "One TLS CertificateRef is required in Terminate mode",
})
-
continue
}
- // TODO Should we support multiple certificates?
- certificateRef := listener.TLS.CertificateRefs[0]
-
- if certificateRef.Kind == nil || *certificateRef.Kind != "Secret" ||
- certificateRef.Group == nil || (*certificateRef.Group != "" && *certificateRef.Group != groupCore) {
- // update "ResolvedRefs" status true with "InvalidCertificateRef" reason
- gatewayListeners[i].Status.Conditions = append(gatewayListeners[i].Status.Conditions, metav1.Condition{
- Type: string(gatev1.ListenerConditionResolvedRefs),
- Status: metav1.ConditionFalse,
- ObservedGeneration: gateway.Generation,
- LastTransitionTime: metav1.Now(),
- Reason: string(gatev1.ListenerReasonInvalidCertificateRef),
- Message: fmt.Sprintf("Unsupported TLS CertificateRef group/kind: %s/%s", groupToString(certificateRef.Group), kindToString(certificateRef.Kind)),
- })
+ var errCertConditions []metav1.Condition
+ listenerTLSCerts := make(map[string]*tls.CertAndStores)
+ for _, certificateRef := range listener.TLS.CertificateRefs {
+ if certificateRef.Kind == nil || *certificateRef.Kind != "Secret" || certificateRef.Group == nil || (*certificateRef.Group != "" && *certificateRef.Group != groupCore) {
+ errCertConditions = append(errCertConditions, metav1.Condition{
+ Type: string(gatev1.ListenerConditionResolvedRefs),
+ Status: metav1.ConditionFalse,
+ ObservedGeneration: gateway.Generation,
+ LastTransitionTime: metav1.Now(),
+ Reason: string(gatev1.ListenerReasonInvalidCertificateRef),
+ Message: fmt.Sprintf("Unsupported TLS CertificateRef group/kind: %s/%s", groupToString(certificateRef.Group), kindToString(certificateRef.Kind)),
+ })
+ continue
+ }
- continue
- }
+ certificateNamespace := string(ptr.Deref(certificateRef.Namespace, gatev1.Namespace(gateway.Namespace)))
+ if err := p.isReferenceGranted(kindGateway, gateway.Namespace, groupCore, "Secret", string(certificateRef.Name), certificateNamespace); err != nil {
+ errCertConditions = append(errCertConditions, metav1.Condition{
+ Type: string(gatev1.ListenerConditionResolvedRefs),
+ Status: metav1.ConditionFalse,
+ ObservedGeneration: gateway.Generation,
+ LastTransitionTime: metav1.Now(),
+ Reason: string(gatev1.ListenerReasonRefNotPermitted),
+ Message: fmt.Sprintf("Cannot reference CertificateRef %s/%s: %s", certificateNamespace, certificateRef.Name, err),
+ })
+ continue
+ }
- certificateNamespace := gateway.Namespace
- if certificateRef.Namespace != nil && string(*certificateRef.Namespace) != gateway.Namespace {
- certificateNamespace = string(*certificateRef.Namespace)
+ configKey := certificateNamespace + "/" + string(certificateRef.Name)
+ if _, tlsExists := listenerTLSCerts[configKey]; !tlsExists {
+ tlsCert, err := p.getTLSCert(certificateRef.Name, certificateNamespace)
+ if err != nil {
+ errCertConditions = append(errCertConditions, metav1.Condition{
+ Type: string(gatev1.ListenerConditionResolvedRefs),
+ Status: metav1.ConditionFalse,
+ ObservedGeneration: gateway.Generation,
+ LastTransitionTime: metav1.Now(),
+ Reason: string(gatev1.ListenerReasonInvalidCertificateRef),
+ Message: fmt.Sprintf("Cannot load CertificateRef %s/%s: %s", certificateNamespace, certificateRef.Name, err),
+ })
+ continue
+ }
+ listenerTLSCerts[configKey] = tlsCert
+ }
}
- if err := p.isReferenceGranted(kindGateway, gateway.Namespace, groupCore, "Secret", string(certificateRef.Name), ce
... [truncated]