-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Support certificates hot reload #918
Comments
@sbordet Do you means this is the recommended solution also for the future? |
@Horcrux7, no I just meant to gather together references to the same problem. |
I have a similar situation with Jetty using short lived certificates. In my case I am not using ACME directly as it is an internal private CA for service to service mutual authentication. I have control over the client portion and can deal with short lived certificates but the Jetty server portion needs a solution. I have dynamic keystores that update the key/certificate and can make a callback call when they are ready to use. What I am missing is a mechanism for the callback to notify Jetty listeners to reinitialize the SSLContext. |
@Horcrux7 for Jetty implementing the ACME protocol I think it's overkill. We are not in that business, and Let's Encrypt has already provided tools that people can use alongside with Jetty to implement the certificate renewal/revocation. The idea is that you will install Jetty and a certificate management agent (as defined by Let's Encrypt); the latter will take care of the ACME part and generate the new keystore. We will improve Jetty's This will allow new connections to use the new key material, while older connections will continue to use the old key material until closed. I think this will cover @fhossain use case, as well as the original poster on the mailing list (thread referenced above), and with a bit of glue code, also @Horcrux7 use case. |
Introduced SslContextFactory.reload(Consumer) to perform atomic reload of SslContextFactory.
Introduced There is a gotcha, though. The JDK by default supports TLS session resumption. A new connection established by the client will use session resumption; the client will also check that the certificate received by the server is equal to the certificate that it cached previously. Turns out that the JDK chokes if this check fails, and throws a On the other hand, browsers are perfectly capable of handling this case by falling back to the full TLS handshake instead of the fast one that uses session resumption. @gregw has already verified that the JDK offers no API to disable the caching of TLS sessions (see #519). In summary:
I would appreciate if people can test this new feature and report their feedback. Thanks ! |
@sbordet Sounds you should open a bug report/feature request for Java by Oracle. |
@sbordet thanks for addressing it. I have tested it out and it works like a charm. I am using this inside SpringFramework and have wired it to use both Keystore from disk as well as use SslStoreProvider() which allows me to have in memory version of Keystore. They both work great. I tested with standard HttpsURLConnection but could not reproduce the problem you mentioned. I ran a loop with System.setProperty("http.keepAlive", "false"); on the client with -Dssl.debug=true -Djavax.net.debug=ssl:handshake. I can see repeated calls with logs like %% Try resuming [Session-1, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384] from port 61259. In each round the port number seems to change but not the Session number. However, after a SslContextFactory.reload(...) I can see the client session number going up by one. The exception seems to be handled transparently from the client side without any exception propagated to the client. Let me know if you think I made any mistakes in my testing. Otherwise, everything LGTM 👍 |
@fhossain, glad it works for you. It is strange that the TLS session number goes up by one: it should be a random-like number every time it is generated by the server. Can you share your code that uses HttpsURLConnection ? Other testers ? |
Here is the gut of my test.
|
What happens if you uncomment con.setRequestProperty("Connection", "close"); ? |
It behaves the same as using System.setProperty("http.keepAlive", "false");. In both cases the session re-establish is successful until the certificate is updated. Upon which the session count goes up by one. I think the actual session number might be random but the debug printout sanitized it for readability. |
Could the server invalidate all TLS session IDs whenever the certificate changes? |
@johngmyers there's no API to either purge the TLS session ID cache, set it to 0 entries, or to access the list of sessions and invalidate each. If you know of a way, let us know. |
@sbordet wanted to know if we can have the same functionality in 9.2.x release also as version 9.3.x requires JDK 8. |
No, we won't backport this to 9.2.x because Jetty 9.2.x is End-Of-Life. |
@sbordet , I couldn't get this work for me, I could see log in at INFO level of SslContextFactory for change in X509 for my SslContextFactory, but browser wasn't able to detect change in certs, is there anything else needs to be done |
So the server did the right thing, but the browser did not. |
well, actually its working perfectly fine...! |
To make things easier I also cleaned up and combined server and service. jetty/jetty.project#918 https://github.com/eclipse/jetty.project/blob/b22c0b196f856fb61ba41a853c4a0b4664019f7e/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java#L1860
To make things easier I also cleaned up and combined server and service. jetty/jetty.project#918 https://www.eclipse.org//lists/jetty-users/msg07259.html https://github.com/eclipse/jetty.project/blob/b22c0b196f856fb61ba41a853c4a0b4664019f7e/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java#L1860
Hi all, cc: @ramtaneja @sbordet , When I am checking using the curl Please find the code and suggest me if any.
|
Note: Jetty 9.x is at End of Community Support as of June 2022 You should be using Jetty 10, Jetty 11, or Jetty 12 at this point in time. Also note that Jetty 10 and Jetty 11 has started it's Sunsetting and will be at End of Community Support in January 2025 |
Hi @joakime , |
@nagarjunabattula The browses cache the displayed certificate infos in standard mode. The certificate what you see is not the used certificate. Use the |
Also note that existing connections are not closed, so they will continue to use the old certificate. Only new connections established after the reload will use the new certificate. Depending on the HTTP protocol version used, this may take a long time (typically longer in HTTP/2 than in HTTP/1). |
@sbordet |
@Horcrux7 |
Yes, I means the private mode. |
It is not a good idea to close the connections, as requests may be in progress. They will eventually close, and the new ones will use the new certificate. |
yeah tested but its still showing old cer |
then what could be the alternative? Was there any flaw in my code? |
@ramtaneja |
The code you posted is not enough to say anything, sorry. We have tests in If you can replicate the issue in a small project with very few or no other dependencies, then open a new issue, attach the reproducer project so that we can try it out, and we will continue the discussion there. |
Only if the example small project is on a supported version of Jetty. |
CertificateUtil is a very simple one, downloadcerts will download certs using an API, and copycerts will just copy from the download location to the certs location. As it has some confidential APIs so only I didn't share them. |
@sbordet Do I need to use [SSLSocket|SSLEngine].getSession().invalidate()? |
@sbordet |
@sbordet
Now when we change this to the following code we are not getting SSLHandshake exception.
|
Go ask the Apache HttpClient folks how their client handles certificate renewals for active connections. Since curl, Jetty HttpClient, and the new Java java.net.htt.HttpClient all work correctly this is no longer a Jetty issue or question, but a question for your chosen Http Client library. |
ok. |
One more thing, now when I am reloading and without reloading the internal API call getting succeeded with out error and i saw the following line now However, in non-embedded situations (i.e. Jetty started using java start.jar), it requires the creation of a custom module and a jar file that will include the fairly straightforward code that will trigger the reload. As I am using Jetty standalone and I am not using anything mentioned, could you please let me know what is custom module and what jar I need to use here? |
In Jetty 12 (the only supported version of Jetty right now) the |
Hi @joakime , But I am not getting this instead call is getting succeeded. and client-side code is the following.
Here in getResponse call when I am printing certificate info but i am getting an error while getting server or client certs. So, I am unable to figure out whether the issue is with server reload or client-side
FYI Also on the client side when I am using printCertificate to print the certs I am always getting exceptions is this expected how should we know which cert the httpclientconnection using? |
Note: Jetty 12 is the only supported version of Jetty at the moment. And use the keyStoreScanner = new KeyStoreScanner(sslContextFactory);
keyStoreScanner.setScanInterval(0); // how frequently to scan for changes (in seconds)
server.addBean(keyStoreScanner); Don't use Since you are on Java 11 now, use Always use Also, keep in mind that you are now in the world of up to date SSL/TLS specs. |
Ok let me change. |
Disable hostname verification will accept the untrusted certificate right, No it should still pass with the proper certificate only. and |
Because certificates from Let's Encrypt has a lifetime of 90 days only a automatic renew is required without a server restart. This should be handle from Jetty server self.
A generic implementation of the ACME protocol should be the best solution. There are Java client libraries for the ACME protocol.
The minimum is a dynamic replacement of the current used certificate.
The text was updated successfully, but these errors were encountered: