-
Notifications
You must be signed in to change notification settings - Fork 24.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
Update "ssl-config" to support X-Pack features #74887
Update "ssl-config" to support X-Pack features #74887
Conversation
This commit upgrades the existing SSPL licensed "ssl-config" library to include additional features that are supported by the X-Pack SSL library. This commit does not make any changes to X-Pack to use these new features - it introduces them in preparation for their future use by X-Pack. The reindex module is updated to reflect API changes in ssl-config
Pinging @elastic/es-security (Team:Security) |
I've labelled this as |
/** | ||
* A TrustConfiguration that merges trust anchors from a number of other trust configs to produce a single {@link X509ExtendedTrustManager}. | ||
*/ | ||
public class CompositeTrustConfig implements SslTrustConfig { |
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.
In X-Pack, specifying a keystore, but no truststore gives you a set of trust anchors that support everything in your JDK trust, and all the trust anchors in your keystore.
This class was added so we can also support that behaviour from ssl-config.
@@ -51,6 +53,11 @@ | |||
this.trustStorePassword = trustStorePassword; | |||
} | |||
|
|||
@Override | |||
public boolean isSystemDefault() { | |||
return true; |
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.
This method needed for the PKI realm - it will not trust the JDK default issuers.
@@ -31,7 +31,7 @@ | |||
* Based on https://github.com/groovenauts/jmeter_oauth_plugin/blob/master/jmeter/src/ | |||
* main/java/org/apache/jmeter/protocol/oauth/sampler/PrivateKeyReader.java | |||
*/ | |||
final class DerParser { | |||
public final class DerParser { |
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.
The RestrictedTrustConfig in X-Pack needs to be able to use this parser.
|
||
/** | ||
* A variety of utility methods for working with or constructing {@link KeyStore} instances. | ||
*/ | ||
final class KeyStoreUtil { | ||
public final class KeyStoreUtil { |
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 of these methods have been made public because X-Pack will need to call them.
} | ||
|
||
static Stream<KeyStoreEntry> stream(KeyStore keyStore, | ||
Function<GeneralSecurityException, ? extends RuntimeException> exceptionHandler) { |
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.
This method and the class below were added to support stream-based iteration over keystore entires.
} catch (GeneralSecurityException e) { | ||
throw new SslConfigException("cannot load ssl private key file [" + key.toAbsolutePath() + "]", e); | ||
throw SslFileUtil.securityException(KEY_FILE_TYPE, List.of(path), e); |
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.
Lots of exception handling has been unified. See comments in SslFileUtil
/** | ||
* Utility methods for common file handling in SSL configuration | ||
*/ | ||
final class SslFileUtil { |
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.
This is a new class, mostly to handle generating exceptions for particular file related problems.
return ioException(fileType, paths, cause, null); | ||
} | ||
|
||
static SslConfigException ioException(String fileType, List<Path> paths, IOException cause, String detail) { |
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.
One of the big things we did to try and make X-Pack SSL setup easier was write clear & explicit error messages for all the common problems that people run into:
- File not found
- File permissions wrong
- File in wrong directory
- Missing password
- Wrong password
This class replicates those messages into ssl-config and centralises them.
Some of the messages already existed in this library, but the X-Pack ones are encountered more frequently, and have been better turned for readability.
That said, I did try and improve some of them along the way.
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
public abstract class SslKeystoreConfig implements SslKeyConfig { |
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.
This is a base class for PKCS#11 and File-Keystore (JKS, PKCS#12) support.
The X-Pack model of having 1 class that handled both was really fragile - we often wrote code that assume that the file
was non-null.
* Information about a certificate that is locally stored.It includes a reference to the {@link X509Certificate} itself, | ||
* as well as information about where it was loaded from. | ||
*/ | ||
public class StoredCertificate { |
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.
This is used for the _ssl/certificates
API.
That API uses a CertificateInfo
which depends on ToXContent
etc, which isn't available inside this library. So this class is a lightweight representation of the information needed for that API, and X-Pack will convert from this class to the X-Pack class.
@elasticmachine update branch |
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 added a couple of nit comments.
LGTM otherwise
@@ -91,9 +91,10 @@ static KeyStore buildKeyStore(Collection<Certificate> certificateChain, PrivateK | |||
|
|||
/** | |||
* Construct an in-memory keystore with multiple trusted cert entries. | |||
* |
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.
nit: extra line?
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 wouldn't say so.
Everything in that file has blank line between the method description & the parameters, so this format is consistent with the rest of the code.
libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslKeystoreConfig.java
Outdated
Show resolved
Hide resolved
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.
Thanks for taking the time to add comments for things that would most probably raise questions, that was very helpful. Added some suggestions and comments, mostly nits
* @param keyPassword Password for the private key (or empty is the key is not encrypted) | ||
* @param configBasePath The base directory from which config files should be read (used for diagnostic exceptions) | ||
*/ | ||
public PemKeyConfig(String certificate, String key, char[] keyPassword, Path configBasePath) { |
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.
nit for readability
public PemKeyConfig(String certificate, String key, char[] keyPassword, Path configBasePath) { | |
public PemKeyConfig(String certificatePath, String key, char[] keyPassword, Path configBasePath) { |
boolean first = true; | ||
for (Certificate cert : certificates) { | ||
if (cert instanceof X509Certificate) { | ||
info.add(new StoredCertificate((X509Certificate) cert, this.certificate, "PEM", null, first)); |
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.
is it safe to assume that certificate points to a file where if multiple certs are included, the leaf is always the first one?
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.
Probably not - but that's what X-Pack currently does.
It should be - if the certificate path points to a PEM file with multiple certificates, then they should be a chain ordered from leaf to issuer to root - but there's no guarantee that it's true.
However, other things will break if it's not. When we build a keystore we will assume the certificates that we read form a valid chain, and Keystore.setKeyEntry
will throw an exception if they're not.
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 added a test to show that createKeyManager
fails if the chain is in the wrong order. I think that is sufficient for the assumption in this method.
We do have a "private key" for the leaf (first element) certificate. It might be the wrong key (none of the config classes check that in this method), but we have one.
And the core functionality of the config (building a key manager) will fail.
libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/KeyStoreUtil.java
Show resolved
Hide resolved
libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/KeyStoreUtil.java
Show resolved
Hide resolved
final Path trustStorePath = resolveSetting(TRUSTSTORE_PATH, basePath::resolve, null); | ||
protected SslTrustConfig buildTrustConfig(Path basePath, SslVerificationMode verificationMode, SslKeyConfig keyConfig) { | ||
final List<String> certificateAuthorities = resolveListSetting(CERTIFICATE_AUTHORITIES, Function.identity(), null); | ||
final String trustStorePath = resolveSetting(TRUSTSTORE_PATH, Function.identity(), null); |
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.
:+1
if (cause.getMessage() != null) { | ||
message += " (" + cause.getMessage() + ")"; | ||
} | ||
if (detail != null) { |
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.
is it worth adding the hint about UnrecoverableKeyException ? ( maybe only if detail is null )
/** | ||
* @return A collection of {@link X509Certificate certificates} used by this config. | ||
*/ | ||
Collection<? extends StoredCertificate> getConfiguredCertificates(); |
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.
Do we foresee exteding StoredCertificate ? Can we make the return type non generic for now ?
List<Tuple<PrivateKey, X509Certificate>> getKeys(); | ||
|
||
/** | ||
* @return A collection of {@link X509Certificate certificates} used by this config. |
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.
nit: update javadoc with corret return type
if (certificates.isEmpty()) { | ||
return List.of(); | ||
} | ||
final Certificate certificate = certificates.get(0); |
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.
nit: rename certificate here for readability ( vs this.certificate)
|
||
if (cause.getCause() instanceof UnrecoverableKeyException) { | ||
message += " - this is usually caused by an incorrect password"; | ||
} else if (cause != null && cause.getMessage() != null) { |
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.
cause can't be null here, otherwise we'd have thrown an NPE in cause.getCause() above. We can check that cause is not null above and not go into this conditional at all
- Remove PKCS#11 - Improve exception messages - Simplify return types
PemKeyConfig.getConfiguredCertificates relies on the certificate file containing a chain from leaf -> issuer -> .. -> root This commit adds a test to ensure that createKeyManager will fail if that order is not correct, and therefore the assumption in getConfiguredCertificates is acceptable
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.
LGTM
This commit upgrades the existing SSPL licensed "ssl-config" library to include additional features that are supported by the X-Pack SSL library. This commit does not make any changes to X-Pack to use these new features - it introduces them in preparation for their future use by X-Pack. The reindex module is updated to reflect API changes in ssl-config
This commit upgrades the existing SSPL licensed "ssl-config" library to include additional features that are supported by the X-Pack SSL library. This commit does not make any changes to X-Pack to use these new features - it introduces them in preparation for their future use by X-Pack. The reindex module is updated to reflect API changes in ssl-config
This commit upgrades the existing SSPL licensed "ssl-config" library
to include additional features that are supported by the X-Pack SSL
library.
This commit does not make any changes to X-Pack to use these new
features - it introduces them in preparation for their future use by
X-Pack.
The reindex module is updated to reflect API changes in ssl-config