Skip to content
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

Refresh Certs every X minutes #3568

Merged
merged 7 commits into from
Feb 18, 2019
Merged

Refresh Certs every X minutes #3568

merged 7 commits into from
Feb 18, 2019

Conversation

jai1
Copy link
Contributor

@jai1 jai1 commented Feb 11, 2019

Motivation

If certs are refreshed on the file system we need to refresh the certs and recreate the TLS Channel.

Modifications

  • Created a class SslContextRefresher.java which uses java.nio.file.WatchEvents to detect file system changes and refresh the certs.
  • As soon as the java.nio.file.WatchEvents detects file system changes it will refresh the sslcontext

@jai1
Copy link
Contributor Author

jai1 commented Feb 11, 2019

rerun java8 tests

Copy link
Contributor

@merlimat merlimat left a comment

Choose a reason for hiding this comment

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

This seems to be targeting only discovery service, while it should also be in broker, proxy and client lib

this.sslContext = sslContext;
}

public SslContext get() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of using a background thread, couldn't we just check a timestamp here to check whether the cached context is still valid?

Copy link
Contributor

Choose a reason for hiding this comment

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

We could even just check the stat of the file each time, without having to configure a caching time. If the file hasn't changed since last time, then reuse context.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed - will make the changes accordingly.

for (String file : files) {
LOG.info("File {}", file);
Path p = Paths.get(file).getParent();
WatchService watchService = p.getFileSystem().newWatchService();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why to do we need to poll if we're using a "watch-service"? Isn't this supposed to notify when the files are changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe Watch service doesn't have a callback, it just has a polling mechanism.
https://docs.oracle.com/javase/8/docs/api/java/nio/file/WatchService.html

Copy link
Contributor

@merlimat merlimat left a comment

Choose a reason for hiding this comment

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

Left a comment on the caching part. Also I think the same logic should be done in client lib

*
* @return a Client Certificate File Path, or null if data is not available
*/
default String getCertFilePath() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, I don't think it's a good option to have these 2 here, since the auth data provider is not specific to TLS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added refresh() instead

@jai1 jai1 force-pushed the expiry branch 2 times, most recently from 810cf2e to c55ac9b Compare February 14, 2019 07:29
* Refresh Authentication Data.
*
*/
default void refresh() {
Copy link
Contributor

Choose a reason for hiding this comment

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

But shouldn't this be dealt internally by implementations? Why should we triggering it from outside?

For example: when reading token credential you have different ways to refresh the token data (eg: passing a Supplier<String> or by refreshing the token file).

The implementation will have more information about when it has to refresh, so it would be better to leave the decision inside there.

My point is that TLS plugin should do the caching in its own implementation, for example by checking the last modified of cert file when client lib calls getTlsCertificates()

@jai1
Copy link
Contributor Author

jai1 commented Feb 18, 2019

@merlimat and @rdhabalia - Can you review this?

Copy link
Contributor

@rdhabalia rdhabalia left a comment

Choose a reason for hiding this comment

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

LGTM.. few minor comments.

}
}

@Override
protected void initChannel(SocketChannel ch) throws Exception {
if (serverSslCtx != null) {
ch.pipeline().addLast(TLS_HANDLER, serverSslCtx.newHandler(ch.alloc()));
if (this.enableTls) {
Copy link
Contributor

Choose a reason for hiding this comment

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

can we check null for serverSslCtxRefresher to avoid NPE in future.

}
}

@Override
protected void initChannel(SocketChannel ch) throws Exception {
if (sslCtx != null) {
ch.pipeline().addLast(TLS_HANDLER, sslCtx.newHandler(ch.alloc()));
if (this.enableTls) {
Copy link
Contributor

Choose a reason for hiding this comment

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

same here.. can we add null check for sslCtxRefresher.get()

FileTime newLastModifiedTime = updateLastModifiedTime();
if (newLastModifiedTime != null && !newLastModifiedTime.equals(lastModifiedTime)) {
this.lastModifiedTime = newLastModifiedTime;
ret = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

instead having boolean var, can we just return true here and return false in the next line.

try {
return Files.getLastModifiedTime(p);
} catch (IOException e) {
LOG.error("Unable to fetch lastModified time for file {}: ", fileName, e);
Copy link
Contributor

Choose a reason for hiding this comment

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

instead catching exception, should we log and throw up to top level and let it be handled at caller?

tlsCiphers, tlsProtocols, tlsRequireTrustedClientCertOnConnect);
}

public SslContext get() {
Copy link
Contributor

Choose a reason for hiding this comment

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

do we need this method thread-safe?

@jai1
Copy link
Contributor Author

jai1 commented Feb 18, 2019

rerun integration tests

}
}

@Override
protected void initChannel(SocketChannel ch) throws Exception {
if (sslCtx != null) {
ch.pipeline().addLast(TLS_HANDLER, sslCtx.newHandler(ch.alloc()));
if (this.enableTls) {
Copy link
Contributor

Choose a reason for hiding this comment

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

can you also add null check for sslCtxRefresher here.

Copy link
Contributor

@rdhabalia rdhabalia left a comment

Choose a reason for hiding this comment

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

👍 LGTM.

@jai1 jai1 merged commit a0f7661 into apache:master Feb 18, 2019
@jai1 jai1 deleted the expiry branch February 18, 2019 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants