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

Filter out CA PrivateKeyEntry when creating a KeyManager #73807

Merged
merged 37 commits into from
Jul 8, 2021

Conversation

BigPandaToo
Copy link
Contributor

@BigPandaToo BigPandaToo commented Jun 6, 2021

In 8.0, with security on by default, we store the HTTP
layer CA PrivateKeyEntry in the http.ssl keystore (along
with the node certificate) so that it is available in our
Enrollment API transport actions.
When loading a keystore, the current behavior is that the
X509ExtendedKeyManager will iterate through the PrivateKeyEntry
objects and will return the first key/certificate that satisfies
the requirements of the client and the server configuration,
and lacks any additional logic/filters.
We need the KeyManager to deterministically pick the node
certificate/key in all cases as this is the intended entry to be
used for TLS on the HTTP layer.
This change introduces filtering when creating the in-memory
keystore the KeyManager is loaded with, so that it will not
include PrivateKeyEntry objects when:

  • there are more than 1 PrivateKeyEntry objects in the keystore
  • The leaf certificate associated with the PrivateKeyEntry is a
    CA certificate

Related: #75097

@BigPandaToo BigPandaToo marked this pull request as draft June 6, 2021 19:10
@BigPandaToo
Copy link
Contributor Author

@elasticmachine update branch

@BigPandaToo
Copy link
Contributor Author

@elasticmachine update branch

@BigPandaToo
Copy link
Contributor Author

@elasticmachine update branch

@BigPandaToo
Copy link
Contributor Author

@elasticmachine update branch

@BigPandaToo
Copy link
Contributor Author

@elasticmachine update branch

@BigPandaToo
Copy link
Contributor Author

@elasticmachine update branch

@BigPandaToo
Copy link
Contributor Author

@elasticmachine update branch

@jkakavas
Copy link
Member

jkakavas commented Jul 7, 2021

@BigPandaToo I looked into the failing tests and these are actually bugs in the enroll node and enroll kibana APIs that we missed originally because of lack of integration tests. I fixed them here instead of opening a new PR, let me know if you have any concerns with that

Copy link
Member

@jkakavas jkakavas left a comment

Choose a reason for hiding this comment

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

Can we also please change the PR title to something more appropriate and add a PR description that explains why we're adding this ?

client/rest-high-level/qa/ssl-enabled/build.gradle Outdated Show resolved Hide resolved
setting 'xpack.security.transport.ssl.enabled', 'true'
setting 'xpack.security.http.ssl.keystore.path', 'httpCa.p12'
setting 'xpack.security.transport.ssl.keystore.path', 'transport.p12'
setting 'xpack.security.transport.ssl.verification_mode', 'none'
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need verification mode to be none for transport ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it to certificate. The reason I didn't leave it to be full - this transport cert doesn't have SAN (which is required for the full verification mode). I think it is orthogonal to these test purposes.

Copy link
Member

Choose a reason for hiding this comment

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

Changed it to certificate.

This is what we will be configuring nodes with too, so it makes sense to have this to certificate instead of none.

The reason I didn't leave it to be full - this transport cert doesn't have SAN (which is required for the full verification mode).I think it is orthogonal to these test purposes.

We are using this cluster for Enrollment IT and our enrollment process will generate configuration that sets the transport verification mode to certificate so it's in our best interest to keep the test cluster config as close to what users will have as possible

@BigPandaToo BigPandaToo changed the title Handle a case of multiple keys in the same keystore. Security on by default: handle a situation when a keystore that is used for HTTPS contains more than one PrivateKeyEntry Jul 8, 2021
@BigPandaToo BigPandaToo requested a review from jkakavas July 8, 2021 02:08
@BigPandaToo
Copy link
Contributor Author

@elasticmachine update branch

assertThat(http_key, notNullValue());
assertThat(aliases.length, equalTo(1));
assertThat(aliases[0], equalTo("http"));
assertThat(certificates.length, equalTo(2));
Copy link
Member

@jkakavas jkakavas Jul 8, 2021

Choose a reason for hiding this comment

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

I think we can remove this assertion, it doesn't test something that we are interested in ( the certificate chain length of the non-ca certificate we happened to use in the test ) - same as below

Copy link
Contributor Author

@BigPandaToo BigPandaToo Jul 8, 2021

Choose a reason for hiding this comment

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

Just making sure we haven't deleted something we didn't mean to (like it happened before the last chage)

Copy link
Member

Choose a reason for hiding this comment

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

This the certificate chain length of a single certificate chain of a single PrivateKeyEntry. ( final X509Certificate[] certificates = keyManager.getCertificateChain("http"); )

We wouldn't have deleted one of the certificates in that chain before the last change.

Copy link
Member

Choose a reason for hiding this comment

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

I still think we don't need this, but won't block the PR on this

assertThat(aliases[0], equalTo("ca"));
assertThat(certificates.length, equalTo(1));
}

Copy link
Member

Choose a reason for hiding this comment

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

maybe quickly add one that contains a keystore with private key entries and trusted certificate entries and check the behavior there too ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean? A keystore with multiple not ca private key? Making sure nothing being deleted?

Copy link
Member

Choose a reason for hiding this comment

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

A keystore with a TrustedCertificate entry, a CA PrivateKeyEntry and a non-ca PrivateKeyEntry and make sure that we removed the CA PrivateKeyEntry only

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 that's what httpCa.p12 is in testCreateKeyManagerFromPKCS12ContainingCA

Copy link
Member

@jkakavas jkakavas left a comment

Choose a reason for hiding this comment

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

Thanks for the iteration @BigPandaToo . Let's fix the keystore checking for multiple entries and a couple minor things and it'd be good to be merged

@jkakavas
Copy link
Member

jkakavas commented Jul 8, 2021

Suggestion for PR Title : "Filter out CA PrivateKeyEntry when creating a KeyManager"

Suggestion for the description: ( It'd be nice to have diffs and suggested text as with code :/ but we don't so I add this below , feel free to pick any of the wording you might like )

In 8.0, with security on by default, we store ca
Private Key Entry used for node and Kibana
enrollment in http.sll keystore. This  keystore is
used for TLS. The current behavior is that the
KeyManager will iterate through the private key
entry and will return the first key/certificate it sees
fits, which lacking any additional logic/filters is any
of the PrivateKeyEntry. If it picks up ca Private
Key instead of the node' one TLS handshake will
fail. The solution is, when creating an in-memory
key store from filter our ca Private Key entry if

    this is http key store;
    there are more than 1 alises in the store (cover
    the case when ca is the node certificate).

----->

In 8.0, with security on by default, we store the HTTP
layer CA PrivateKeyEntry in the  http.ssl keystore (along
with the node certificate) so that it is available in our 
Enrollment API transport actions. 
When loading a keystore, the current behavior is that the
X509ExtendedKeyManager will iterate through the PrivateKeyEntry
objects and will return the first key/certificate that satisfies
the requirements of the client and the server configuration, 
and lacks any additional logic/filters.
We need the KeyManager to deterministically pick the node
certificate/key in all cases as this is the intended entry to be
used for TLS on the HTTP layer. 
This change introduces filtering when creating the in-memory
keystore the KeyManager is loaded with, so that it will not 
include PrivateKeyEntry objects when: 

- there are more than 1 PrivateKeyEntry objects in the keystore 
- The leaf certificate associated with the PrivateKeyEntry is a
CA certificate

@BigPandaToo BigPandaToo changed the title Security on by default: handle a situation when a keystore that is used for HTTPS contains more than one PrivateKeyEntry Filter out CA PrivateKeyEntry when creating a KeyManager Jul 8, 2021
@BigPandaToo BigPandaToo requested a review from jkakavas July 8, 2021 07:59
Copy link
Member

@jkakavas jkakavas left a comment

Choose a reason for hiding this comment

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

I have a couple of outstanding comments for your consideration but I don't want to hold the PR for more. See if you can address these if you agree, LGTM otherwise.

@BigPandaToo BigPandaToo merged commit 063a1f2 into elastic:master Jul 8, 2021
keyStore.load(in, keyStorePassword.getChars());
}
List<String> aliases = new ArrayList<>();
for (String s : Collections.list(keyStore.aliases())) {
Copy link
Member

Choose a reason for hiding this comment

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

we should not be filtering here. We should check that the aliases of all entries are 3 so that we can verify below that we do not remove non PrivateKeyEntry entries

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants