Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/provider/kubernetes/indexers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,7 @@ func secretRouteFilterIndexFunc(rawObj client.Object) []string {
if filter.Spec.CredentialInjection != nil {
secretReferences = append(secretReferences,
types.NamespacedName{
Namespace: filter.Namespace,
Namespace: gatewayapi.NamespaceDerefOr(filter.Spec.CredentialInjection.Credential.ValueRef.Namespace, filter.Namespace),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Load the referenced namespace for HRF secrets

When CredentialInjection.Credential.ValueRef.Namespace is set, this index now makes the remote Secret pass validateSecretForReconcile, but the reconcile path still fetches the credential from the HTTPRouteFilter namespace in internal/provider/kubernetes/filters.go:112 and only inserts that namespace into the resource tree. As a result, a cross-namespace credential Secret change is enqueued but the translator still cannot see the remote Secret, so the configuration remains stale or invalid despite the new cross-namespace test expectation.

Useful? React with 👍 / 👎.

Name: string(filter.Spec.CredentialInjection.Credential.ValueRef.Name),
}.String(),
)
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/kubernetes/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func (r *gatewayAPIReconciler) isHTTPRouteFilterReferencingSecret(nsName *types.
return true
}

return true
return false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor credential ValueRef namespaces before skipping reconcile

When an HTTPRouteFilter credentialInjection valueRef.namespace points at a Secret in another namespace, this new false path skips reconciliation for that Secret because secretRouteFilterIndexFunc indexes HTTPRouteFilters under filter.Namespace instead of ValueRef.Namespace. The generated CRD explicitly allows cross-namespace valueRef.namespace with a ReferenceGrant, and the translator calls validateSecretRef(true, ...), so rotating that cross-namespace credential will no longer enqueue a reconcile and Envoy can keep using stale credentials until some unrelated event occurs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the modification in internal/provider/kubernetes/indexers.go should take care of that cross namespace stuff, is it enough ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex review

}

func (r *gatewayAPIReconciler) isBackendTLSPolicyReferencingSecret(nsName *types.NamespacedName) bool {
Expand Down
57 changes: 57 additions & 0 deletions internal/provider/kubernetes/predicates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,61 @@ func TestValidateSecretForReconcile(t *testing.T) {
secret: test.GetSecret(types.NamespacedName{Namespace: "default", Name: "secret"}),
expect: true,
},
{
name: "secret not referenced by any HTTPRouteFilter",
configs: []client.Object{
test.GetGatewayClass("test-gc", egv1a1.GatewayControllerName, nil),
},
secret: test.GetSecret(types.NamespacedName{Namespace: "default", Name: "unrelated-secret"}),
expect: false,
},
{
name: "secret referenced by HTTPRouteFilter CredentialInjection",
configs: []client.Object{
test.GetGatewayClass("test-gc", egv1a1.GatewayControllerName, nil),
&egv1a1.HTTPRouteFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "credential-filter",
Namespace: "default",
},
Spec: egv1a1.HTTPRouteFilterSpec{
CredentialInjection: &egv1a1.HTTPCredentialInjectionFilter{
Credential: egv1a1.InjectedCredential{
ValueRef: gwapiv1.SecretObjectReference{
Name: "credential-secret",
},
},
},
},
},
},
secret: test.GetSecret(types.NamespacedName{Namespace: "default", Name: "credential-secret"}),
expect: true,
},
{
name: "secret in another namespace referenced by HTTPRouteFilter CredentialInjection",
configs: []client.Object{
test.GetGatewayClass("test-gc", egv1a1.GatewayControllerName, nil),
&egv1a1.HTTPRouteFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "credential-filter",
Namespace: "default",
},
Spec: egv1a1.HTTPRouteFilterSpec{
CredentialInjection: &egv1a1.HTTPCredentialInjectionFilter{
Credential: egv1a1.InjectedCredential{
ValueRef: gwapiv1.SecretObjectReference{
Name: "credential-secret",
Namespace: gatewayapi.NamespacePtr("other-ns"),
},
},
},
},
},
},
secret: test.GetSecret(types.NamespacedName{Namespace: "other-ns", Name: "credential-secret"}),
expect: true,
},
}

// Create the reconciler.
Expand All @@ -877,6 +932,7 @@ func TestValidateSecretForReconcile(t *testing.T) {
spCRDExists: true,
epCRDExists: true,
eepCRDExists: true,
hrfCRDExists: true,
envoyGateway: &egv1a1.EnvoyGateway{
EnvoyGatewaySpec: egv1a1.EnvoyGatewaySpec{
ExtensionAPIs: &egv1a1.ExtensionAPISettings{
Expand All @@ -895,6 +951,7 @@ func TestValidateSecretForReconcile(t *testing.T) {
WithIndex(&egv1a1.EnvoyProxy{}, secretEnvoyProxyIndex, secretEnvoyProxyIndexFunc).
WithIndex(&egv1a1.EnvoyExtensionPolicy{}, secretEnvoyExtensionPolicyIndex, secretEnvoyExtensionPolicyIndexFunc).
WithIndex(&egv1a1.Backend{}, secretBackendIndex, secretBackendIndexFunc).
WithIndex(&egv1a1.HTTPRouteFilter{}, secretHTTPRouteFilterIndex, secretRouteFilterIndexFunc).
Build()
t.Run(tc.name, func(t *testing.T) {
res := r.validateSecretForReconcile(tc.secret)
Expand Down
Loading