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
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ require (
github.com/gocarina/gocsv v0.0.0-20190927101021-3ecffd272576
github.com/google/go-cmp v0.7.0
github.com/haproxytech/config-parser/v4 v4.0.0-rc1
github.com/openshift/api v0.0.0-20251120145848-32e27fc232a9
github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235
github.com/openshift/api v0.0.0-20260212193555-c06ab675261f
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13
github.com/openshift/library-go v0.0.0-20251021141706-f489e811f030
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_model v0.6.2
Expand Down Expand Up @@ -117,3 +117,5 @@ require (
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)

replace github.com/openshift/library-go => github.com/bentito/library-go v0.0.0-20260316154701-200e1ee46963
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/bcicen/go-haproxy v0.0.0-20180203142132-ff5824fe38be h1:7b8/p7wJ3N/OjXbZmwJdyR9eOoCla5SbUIe18WHio5s=
github.com/bcicen/go-haproxy v0.0.0-20180203142132-ff5824fe38be/go.mod h1:MxVpaKTkNjZu5awzzr6mk6CIKaZYUFGxbmNwMvyVfeM=
github.com/bentito/library-go v0.0.0-20260316154701-200e1ee46963 h1:jhARqaZphAvzRd1htPKPSLHAMEg01p9/CgmrNvqLLxM=
github.com/bentito/library-go v0.0.0-20260316154701-200e1ee46963/go.mod h1:K3FoNLgNBFYbFuG+Kr8usAnQxj1w84XogyUp2M8rK8k=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
Expand Down Expand Up @@ -180,12 +182,10 @@ github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/openshift/api v0.0.0-20251120145848-32e27fc232a9 h1:oof7rtwtidp0ktq759ahPvuexk7nppGWTJo0ubXuupo=
github.com/openshift/api v0.0.0-20251120145848-32e27fc232a9/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235 h1:9JBeIXmnHlpXTQPi7LPmu1jdxznBhAE7bb1K+3D8gxY=
github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235/go.mod h1:L49W6pfrZkfOE5iC1PqEkuLkXG4W0BX4w8b+L2Bv7fM=
github.com/openshift/library-go v0.0.0-20251021141706-f489e811f030 h1:dbv8ZYDWIl22A5WBjQJTKeENM08f8HwMBuv8glDXO/0=
github.com/openshift/library-go v0.0.0-20251021141706-f489e811f030/go.mod h1:OlFFws1AO51uzfc48MsStGE4SFMWlMZD0+f5a/zCtKI=
github.com/openshift/api v0.0.0-20260212193555-c06ab675261f h1:l1IgsK48Ym/nED30yfaCTF4MtswO1eOoyfXgh2rEmdw=
github.com/openshift/api v0.0.0-20260212193555-c06ab675261f/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13 h1:6rd4zSo2UaWQcAPZfHK9yzKVqH0BnMv1hqMzqXZyTds=
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13/go.mod h1:YvOmPmV7wcJxpfhTDuFqqs2Xpb3M3ovsM6Qs/i2ptq4=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
Expand Down
2 changes: 2 additions & 0 deletions pkg/router/controller/contention.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ var (
ExtCrtStatusReasonSecretRecreated,
ExtCrtStatusReasonSecretUpdated,
ExtCrtStatusReasonSecretDeleted,
ExtCrtStatusReasonSARCompleted,
ExtCrtStatusReasonSecretLoaded,
)
)

Expand Down
60 changes: 57 additions & 3 deletions pkg/router/controller/route_secret_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const (
ExtCrtStatusReasonSecretUpdated = "ExternalCertificateSecretUpdated"
ExtCrtStatusReasonSecretDeleted = "ExternalCertificateSecretDeleted"
ExtCrtStatusReasonGetFailed = "ExternalCertificateGetFailed"
ExtCrtStatusReasonSARCompleted = "ExternalCertificateSARCompleted"
ExtCrtStatusReasonSecretLoaded = "ExternalCertificateSecretLoaded"
)

// RouteSecretManager implements the router.Plugin interface to register
Expand Down Expand Up @@ -260,6 +262,7 @@ func (p *RouteSecretManager) generateSecretHandler(namespace, routeName string)
AddFunc: func(obj interface{}) {
secret := obj.(*kapi.Secret)
log.V(4).Info("Secret added for route", "namespace", namespace, "secret", secret.Name, "route", routeName)
routeapihelpers.InvalidateAsyncSARCache(namespace, secret.Name)

// Secret re-creation scenario
// Check if the route key exists in the deletedSecrets map, indicating that the secret was previously deleted for this route.
Expand All @@ -281,6 +284,23 @@ func (p *RouteSecretManager) generateSecretHandler(namespace, routeName string)
// by all the plugins (including this plugin). Once passes, the route will become active again.
msg := fmt.Sprintf("secret %q recreated for route %q", secret.Name, key)
p.recorder.RecordRouteRejection(route, ExtCrtStatusReasonSecretRecreated, msg)
return
}

// Async secret load scenario
// When the secret completes its initial cache sync, we need to trigger the router
// controller to evaluate this route again. We use RecordRouteRejection to keep the route
// pending until the full plugin chain evaluates and admits it.
route, err := p.routelister.Routes(namespace).Get(routeName)
if err != nil {
log.Error(err, "failed to get route", "namespace", namespace, "route", routeName)
return
}
msg := fmt.Sprintf("secret %q loaded for route %q", secret.Name, key)
if isRouteAdmittedTrue(route.DeepCopy(), p.routerName) {
p.recorder.RecordRouteUpdate(route, ExtCrtStatusReasonSecretLoaded, msg)
} else {
p.recorder.RecordRouteRejection(route, ExtCrtStatusReasonSecretLoaded, msg)
}
},

Expand All @@ -289,6 +309,7 @@ func (p *RouteSecretManager) generateSecretHandler(namespace, routeName string)
secretNew := new.(*kapi.Secret)
key := generateKey(namespace, routeName)
log.V(4).Info("Secret updated for route", "namespace", namespace, "secret", secretNew.Name, "oldSecretVersion", secretOld.ResourceVersion, "newSecretVersion", secretNew.ResourceVersion, "route", routeName)
routeapihelpers.InvalidateAsyncSARCache(namespace, secretNew.Name)

// Ensure fetching the updated route
route, err := p.routelister.Routes(namespace).Get(routeName)
Expand All @@ -309,10 +330,23 @@ func (p *RouteSecretManager) generateSecretHandler(namespace, routeName string)
},

DeleteFunc: func(obj interface{}) {
secret := obj.(*kapi.Secret)
secret, ok := obj.(*kapi.Secret)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
log.Error(nil, "Couldn't get object from tombstone", "obj", obj)
return
}
secret, ok = tombstone.Obj.(*kapi.Secret)
if !ok {
log.Error(nil, "Tombstone contained object that is not a secret", "obj", tombstone.Obj)
return
}
}
key := generateKey(namespace, routeName)
msg := fmt.Sprintf("secret %q deleted for route %q", secret.Name, key)
log.V(4).Info(msg)
routeapihelpers.InvalidateAsyncSARCache(namespace, secret.Name)

// keep the secret monitor active and mark the secret as deleted for this route.
p.deletedSecrets.Store(key, true)
Expand All @@ -338,8 +372,28 @@ func (p *RouteSecretManager) generateSecretHandler(namespace, routeName string)
// by reading the "tls.crt" and "tls.key" added by populateRouteTLSFromSecret.
func (p *RouteSecretManager) validate(route *routev1.Route) error {
fldPath := field.NewPath("spec").Child("tls").Child("externalCertificate")
if err := routeapihelpers.ValidateTLSExternalCertificate(route, fldPath, p.sarClient, p.secretsGetter).ToAggregate(); err != nil {
log.Error(err, "skipping route due to invalid externalCertificate configuration", "namespace", route.Namespace, "route", route.Name)

onComplete := func(namespace, secretName string) {
// Ensure fetching the updated route
latestRoute, err := p.routelister.Routes(namespace).Get(route.Name)
if err != nil {
log.Error(err, "failed to get route for SAR completion callback", "namespace", namespace, "route", route.Name)
return
}

msg := fmt.Sprintf("SAR check completed for secret %q", secretName)
log.V(4).Info(msg, "namespace", namespace, "route", route.Name)

// Update the route status to notify plugins, including this plugin, for re-evaluation.
if isRouteAdmittedTrue(latestRoute.DeepCopy(), p.routerName) {
p.recorder.RecordRouteUpdate(latestRoute, ExtCrtStatusReasonSARCompleted, msg)
} else {
p.recorder.RecordRouteRejection(latestRoute, ExtCrtStatusReasonSARCompleted, msg)
}
}

if err := routeapihelpers.ValidateTLSExternalCertificate(route, fldPath, p.sarClient, p.secretsGetter, onComplete).ToAggregate(); err != nil {
log.Error(err, "skipping route due to invalid externalCertificate configuration (or pending SAR check)", "namespace", route.Namespace, "route", route.Name)
p.recorder.RecordRouteRejection(route, ExtCrtStatusReasonValidationFailed, err.Error())
p.plugin.HandleRoute(watch.Deleted, route)
return err
Expand Down
Loading