-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OCPBUGS-33958: secret re-creation scenario for externalCertificate with active informer #614
base: master
Are you sure you want to change the base?
Conversation
Skipping CI for Draft Pull Request. |
@chiragkyal: This pull request references Jira Issue OCPBUGS-33958, which is invalid:
Comment The bug has been updated to refer to the pull request using the external bug tracker. In response to this: Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
41a1750
to
f51a3f2
Compare
/jira refresh |
@chiragkyal: This pull request references Jira Issue OCPBUGS-33958, which is valid. 3 validation(s) were run on this bug
Requesting review from QA contact: In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
70121a3
to
f655bd2
Compare
@chiragkyal: This pull request references Jira Issue OCPBUGS-33958, which is invalid:
Comment In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
/assign |
/assign @alebedev87 |
/jira refresh |
@chiragkyal: This pull request references Jira Issue OCPBUGS-33958, which is valid. 3 validation(s) were run on this bug
Requesting review from QA contact: In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
to vendor openshift/library-go#1740 go get github.com/openshift/library-go@0119d1ed45b58f8e7b180370b4cfe933846f9a91 Signed-off-by: chiragkyal <[email protected]>
* RemoveRoute should not delete the informer (deletion will be handled by the plugin) * utilize old secret name for modified event Signed-off-by: chiragkyal <[email protected]>
Signed-off-by: chiragkyal <[email protected]>
Signed-off-by: chiragkyal <[email protected]>
8c31094
to
441b12f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some questions and nit picks.
// since secret re-creation will not trigger the apiserver route admission, | ||
// we need to rely on the router controller for this validation. | ||
if err := p.validate(route); err != nil { | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we fail here, will the fact that the deletedSecrets
has been cleaned already cause any problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we fail here, then there are two choices
- Delete that secret which will re-populate
deletedSecrets
; and then re-create it - Update that secret
Both choices will only work after fixing the issue which had caused the validation to fail.
Of we fail here, will the fact that the deletedSecrets has been cleaned already cause any problem?
So, it should not cause any problem.
Signed-off-by: chiragkyal <[email protected]>
// TODO always creating a new `secretHandler` ensures that there are no stale route specs | ||
// in the next plugin chain, especially when the referenced secret is updated or deleted. | ||
// This prevents sending outdated routes to subsequent plugins, preserving expected functionality. | ||
// TODO: Refer https://github.com/openshift/router/pull/565#discussion_r1596441128 for possible ways to improve the logic. | ||
// TODO : we might need to add RouteLister() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to use RouteLister()
inside all ResourceEventHandlerFuncs
of generateSecretHandler()
to avoid sending stale route object in the next plugin chain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed during the sync call, the problem statement is valid - the route state is captured at the time of the handler registration which may lead to the update of the route to the older state. The solution which gets the route state from the controller-runtime cache may be problematic as it breaks out of the single source of truth for routes - route controller. Alternative solutions:
- when the secret manager detects a secret recreation the corresponding route should be re-synced by the route controller forcing it to go through the plugin chain (preferred).
- when a route is registered into the secret manager its whole state can be passed as an additional parameter forming a dedicated cache of routes with external certificates. When the secret manager detects a secret recreation it can get the latest route state from this cache.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when the secret manager detects a secret recreation the corresponding route should be re-synced by the route controller forcing it to go through the plugin chain (preferred).
If we can send some event (maybe forcefully) to the Shared RouteInformer from the secret handlerFuncs without updating the actual route object, then that would be great.
when a route is registered into the secret manager its whole state can be passed as an additional parameter forming a dedicated cache of routes with external certificates. When the secret manager detects a secret recreation it can get the latest route state from this cache.
A route is registered only once with the secret manager. We're removing the logic of always doing re-registration of route for every plugin chain call in this PR to have the informer active. So, if we want to keep a dedicated cache of routes, it has to be part of RouteSecretManager
rather than SecretManager
(exists in library-go)
/retest-required |
@alebedev87 Apart from #614 (comment) discussion, is this PR lgtm from your side? |
Signed-off-by: chiragkyal <[email protected]>
@chiragkyal: The following test failed, say
Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took at look at the latest changes so I could leave some quick feedback and questions about recent changes. I still need to go back and re-review the older changes.
// entire plugin chain again. Without re-validating the external certificate | ||
// and re-syncing the secret here, the route could incorrectly transition | ||
// back to an "active" state and start serving the default certificate | ||
// even though its spec still references an external certificate. | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would the router use the default certificate for the route? Why wouldn't it continue to use the route's old external certificate?
This point is central to my concern about the secret manager's setting Admitted=False
. I'm fine with setting Admitted=False
in these two cases:
- The secret was deleted.
- A new secret was created after the old one had been deleted (which means that the route should already have
Admitted=False
).
In other words, the secret manager can set Admitted=False
in any sequence of events that includes deleting the secret that the route references. However, I still don't understand the necessity of setting Admitted=False
in the case where the secret was updated. We do need to force the controller to revalidate the route, but is it really necessary to mark the route as rejected in the meantime?
Does setting Admitted=False
when the secret is updated imply that rotating certificates necessarily causes downtime when using an external certificate? ...Hm, maybe not, as you only call p.plugin.HandleRoute(watch.Deleted, route)
in the delete case, and not in the update case; does that mean we report that the route is rejected but continue serving it unless revalidation re-rejects it?
In comparison, if the route has an inline certificate, the route can be updated with a new certificate, and the router continues using the old certificate until it observes the update; once the router does observe the update, it switches to the new certificate without rejecting the route and without any interruption to service. I don't understand why the experience should or must be different when using an external certificate.
// the same, the router needs to be aware of the events when the content of | ||
// the secret is updated or the secret is recreated, to re-validate and | ||
// fetch the new TLS data. Note: These events won't trigger the apiserver | ||
// route admission, hence we need to rely on the router controller for this validation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean we rely on the controller to trigger re-validation, right? Or are you saying that this scenario requires the controller to perform some validation steps that would otherwise be handled by the admission plugin?
// route admission, hence we need to rely on the router controller for this validation. | |
// route admission, hence we need to rely on the router controller to trigger this validation. |
// - AddFunc: | ||
// - Invoked when a new secret is added. | ||
// - Handles secret recreation: If a secret is recreated (created after being | ||
// deleted), it fetches the latest route object associated with it using the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if multiple routes reference the same secret?
|
||
// The route should *remain* rejected until it's re-evaluated | ||
// by all the plugins (including this plugin). Once passes, the route will become active again. | ||
p.recorder.RecordRouteRejection(route, "ExternalCertificateSecretReCreated", msg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p.recorder.RecordRouteRejection(route, "ExternalCertificateSecretReCreated", msg) | |
p.recorder.RecordRouteRejection(route, "ExternalCertificateSecretRecreated", msg) |
} | ||
}, | ||
|
||
UpdateFunc: func(old interface{}, new interface{}) { | ||
secretOld := old.(*kapi.Secret) | ||
secretNew := new.(*kapi.Secret) | ||
log.V(4).Info("secret updated for route", "namespace", route.Namespace, "secret", secretNew.Name, "old-version", secretOld.ResourceVersion, "new-version", secretNew.ResourceVersion, "route", route.Name) | ||
key := generateKey(namespace, routeName) | ||
msg := fmt.Sprintf("secret %q updated for route %q : old-version %q new-version %q", secretNew.Name, key, secretOld.ResourceVersion, secretNew.ResourceVersion) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
msg := fmt.Sprintf("secret %q updated for route %q : old-version %q new-version %q", secretNew.Name, key, secretOld.ResourceVersion, secretNew.ResourceVersion) | |
msg := fmt.Sprintf("secret %q updated for route %q (old resourceVersion=%v, new resourceVersion=%v)", secretNew.Name, key, secretOld.ResourceVersion, secretNew.ResourceVersion) |
This PR:
Handles secret re-creation scenarios for externalCertificate where a previously deleted secret is added again.
Introduces a
deletedSecrets
map inRouteSecretManager
to track routes for which the associated secret was deleted. This helps differentiate between new secret creation and recreation of a previously deleted secret.Refactors secret handling logic in
generateSecretHandler
to address these changes.AddFunc
handles the secret recreations. Upon detecting a recreated secret, it revalidates the route, updates its TLS configuration, and triggers aModified
event for the next plugins.DeleteFunc
does not callUnregisterRoute()
, instead tracks deleted secrets.Improves the logic for handling
Modified
events for routes with externalCertificate to avoid blindly unregistering and re-registrations with the secret manager.UnregisterRoute()
, which leads to the stopping of the informer.Makes stopping of the informer self-contained to the
RouteSecretManager
plugin.RemoveRoute
(templateRouter
) should not callUnregisterRoute()
to avoid removal of informer whenRouteSecretManager
calls the next plugin chain withwatch.Deleted
event.externalCertificate
field is removedexternalCertificate
field is changed to a new secret name. [Old secret name is cached insideSecretManager
'sregisteredHandlers
map.Adds unit tests to cover the new logic and scenarios.
New Helper Functions:
validate()
to encapsulate the externalCertificate validation logic.populateRouteTLSFromSecret()
to update a route's in-memory TLS configuration from the referenced secret.unregister()
to remove the route's registration with the secret manager and clean up references indeletedSecrets
.Part of : https://issues.redhat.com//browse/OCPBUGS-33958