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

Remove duplicate ssl setup in sql/qa projects #57319

Merged
merged 21 commits into from
Jun 4, 2020

Conversation

breskeby
Copy link
Contributor

@breskeby breskeby commented May 28, 2020

This is follow up on #57197 as we run ssl cert certification for each with-ssl subproject with identical parameters. This PR introduces an elasticsearch.test-with-ssl plugin that configures projects to use pregenerated certificates for testing that are shipped with buildSrc.

  • Removes duplicate code from with-ssl test projects
  • Removes expensive duplicate dynamic creation of ssl certificate generation during precommit run
  • Documents how the certificates can be recreated
  • Used certs are static and not generated dynamically anymore

Here's a comparison of running precommit locally before(https://gradle-enterprise.elastic.co/s/lhoqf5yix5g24/performance/build) and after(https://gradle-enterprise.elastic.co/s/djogrpm6ci7fs/performance/build)

@breskeby breskeby self-assigned this May 28, 2020
@breskeby breskeby added :Delivery/Build Build or test infrastructure Team:Core/Infra Meta label for core/infra team v7.7.2 v7.8.1 v7.9.0 v8.0.0 labels May 28, 2020
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (:Core/Infra/Build)

@breskeby breskeby marked this pull request as draft May 28, 2020 21:45
Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

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

One general comment is I wonder why we are still generating these files on the fly. In other projects (eg :x-pack:qa:smoke-test-plugins-ssl) we have moved away from generating the ssl support files and instead check them in. What if we were to move them to a shared location in buildSrc and have a plugin that copies them into projects and does the configuration. That would also mean the sql projects here could support fips testing, which I believe is why we moved to static files in the first place.

cc @jkakavas

}
}

tasks.withType(org.elasticsearch.gradle.testclusters.TestClustersAware){
Copy link
Member

Choose a reason for hiding this comment

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

Won't this aggressively realize all tasks? I think we need configureEach?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch. 👀 . Fixed

@jkakavas
Copy link
Member

One general comment is I wonder why we are still generating these files on the fly. In other projects (eg :x-pack:qa:smoke-test-plugins-ssl) we have moved away from generating the ssl support files and instead check them in.

The reason is that the SQL client doesn't yet support to be configured with certificate/key material in PEM format and thus we can handle this in the same way we do in other qa projects. That's why we have this :

integTest.runner {
  dependsOn(importClientCertificateInNodeKeyStore)
  onlyIf {
    // Do not attempt to form a cluster in a FIPS JVM, as doing so with a JKS keystore will fail.
    // TODO Revisit this when SQL CLI client can handle key/certificate instead of only Keystores.
    // https://github.com/elastic/elasticsearch/issues/32306
    BuildParams.inFipsJvm == false
  }
}

What if we were to move them to a shared location in buildSrc and have a plugin that copies them into projects and does the configuration. That would also mean the sql projects here could support fips testing, which I believe is why we moved to static files in the first place.

This is a step in the right direction IMHO, but we can always defer that to when we will be able to actually use the key/cert material in the SQL projects

@breskeby
Copy link
Contributor Author

One general comment is I wonder why we are still generating these files on the fly. In other projects (eg :x-pack:qa:smoke-test-plugins-ssl) we have moved away from generating the ssl support files and instead check them in. What if we were to move them to a shared location in buildSrc and have a plugin that copies them into projects and does the configuration. That would also mean the sql projects here could support fips testing, which I believe is why we moved to static files in the first place.

cc @jkakavas

From what I can see there are two dynamic variables in this generation:

  1. san(SubjectAlternativeName)
  2. dname(Distinguished Name).

At least dname seems to possible to be made a fixed string I think. for san I'm not sure how it is used and I honestly don't know if this can be removed or alternated to be static so we could generate them once and ship as you described. Would be great if we can. as generating those files is like ~3-4s on each execution (and part of precommit atm)

@breskeby
Copy link
Contributor Author

@jkakavas so I wonder is this dynamic in the creation of those files as described here: #57319 (comment) required or could we remove that so we can have those files generate once, checked in and reused in all environments (local devs, ci, etc)?

@jkakavas
Copy link
Member

No, we don't need to generate those dynamically. We can use catch-all SANs that would work for all

 X509v3 Subject Alternative Name: 
                DNS:localhost, DNS:localhost.localdomain, DNS:localhost4, DNS:localhost4.localdomain4, DNS:localhost6, DNS:localhost6.localdomain6, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1

We have README files in most(wanted to say all but I noticed I didn't put one in :x-pack:qa:smoke-test-plugins-ssl ) of the places we use pre-generated keys and certificates describing how these were generated , i.e. : https://github.com/jkakavas/elasticsearch/blob/75a5a64427bed323f76f055050b42d5b05c3a5a7/x-pack/plugin/security/qa/tls-basic/src/test/resources/ssl/README.asciidoc

We also have an issue open to clean these up and do deduplication: #41646

@breskeby
Copy link
Contributor Author

@jkakavas perfect. That should make things simpler and we can remove the overhead on every build run. I look into this.

@breskeby
Copy link
Contributor Author

@elasticsearchmachine test this please

1 similar comment
@breskeby
Copy link
Contributor Author

breskeby commented Jun 2, 2020

@elasticsearchmachine test this please

@breskeby breskeby force-pushed the remove-duplicate-ssl-setup-in-qa branch from 4a77c93 to 86c96e6 Compare June 2, 2020 08:26
@breskeby breskeby force-pushed the remove-duplicate-ssl-setup-in-qa branch from 86c96e6 to 63aea79 Compare June 2, 2020 09:23
@breskeby breskeby marked this pull request as ready for review June 3, 2020 10:25
@breskeby breskeby requested a review from jkakavas June 3, 2020 10:26
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 love this, it will help us untangle much of the setup in the security tests. I added some comments and questions on whether we can make this plugin slightly more generic so that it can handle other test use cases

File keyStoreDir = new File(project.getBuildDir(), "keystore");
TaskProvider<ExportElasticsearchBuildResourcesTask> exportKeyStore = project.getTasks()
.register("copyTestCertificates", ExportElasticsearchBuildResourcesTask.class, (t) -> {
t.copy("test/ssl/test-client.cert");
Copy link
Member

Choose a reason for hiding this comment

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

nit: It doesn't really matter but can we rename the suffices to crt instead ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

t.copy("test/ssl/test-client.cert");
t.copy("test/ssl/test-client.jks");
t.copy("test/ssl/test-node.cert");
t.copy("test/ssl/test-node.jks");
Copy link
Member

Choose a reason for hiding this comment

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

Can we also get the private keys into test/ssl/test-X.pem ? In general , given the applicability that this plugin has in so many projects in our security and core tests, I wonder if we can do a little more up front:

  • Setup a CA key and certificate
  • Generate test-node private key and certificate signed by that CA
  • Generate test-client private key and certificate signed by that CA
  • Make all the above available as PEM files ( x.crt and x.key ) and in JKS / PKCS12 keystores
  • Copy all of them as extra config files

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jkakavas I think we should be able to do that. Can you raise a separate issue for this? I'd like to keep this PR small and focussed.

Copy link
Member

Choose a reason for hiding this comment

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

raised #57606

.getByName(TestClustersPlugin.EXTENSION_NAME);
clusters.all(c -> {
// ceremony to set up ssl
c.setting("xpack.security.transport.ssl.keystore.path", "test-node.jks");
Copy link
Member

Choose a reason for hiding this comment

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

Can I override/overwrite this in the build.gradle file of a subproject where I use this new plugin ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, you can override them in the build script after applying the plugin

The certificates are generated using catch-all SAN in the following procedure:

1. Generate the node's keystore:
`keytool -genkey -alias test-node -keystore test-node.jks -keyalg RSA -keysize 2048 -validity 712 -dname CN="Elasticsearch Build Test Infrastructure" -keypass keypass -storepass keypass -ext san=dns:localhost,dns:localhost.localdomain,dns:localhost4,dns:localhost4.localdomain4,dns:localhost6,dns:localhost6.localdomain6,ip:127.0.0.1,ip:0:0:0:0:0:0:0:1`
Copy link
Member

Choose a reason for hiding this comment

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

I think we can go with something closer to 10 years here instead of 2. We don't gain anything by shorter lifetime. Maybe also add a note in the README with the date these certificates expire so that is more probable someone catches this and updates them before they expire and tests start failing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

NamedDomainObjectContainer<ElasticsearchCluster> clusters = (NamedDomainObjectContainer<ElasticsearchCluster>) project
.getExtensions()
.getByName(TestClustersPlugin.EXTENSION_NAME);
clusters.all(c -> {
Copy link
Member

Choose a reason for hiding this comment

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

Could we also have a conditional here that if we are inFipsJvm() it would use key and certificate PEM files to set up TLS instead of keystores so that it can work even when the subproject that uses this plugin is running tests in fips mode ? i.e.

*.ssl.key
*.ssl.secure_key_passphrase
*.ssl.certificate

instead of

*.ssl.keystore.path
*.ssl.keystore.secure_password

and

*.ssl.certificate_authorities

instead of

*.ssl.keystore.path

or

*.ssl.truststore.path

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jkakavas same as above. Would like to tackle this in a separate story

Copy link
Member

Choose a reason for hiding this comment

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

I'm fine with that as long as we don't apply this plugin to any other subproject until we have the fips handling because it will start failing in CI. ( sql is fine because we mute the tests in fips eitherway )

breskeby added 2 commits June 3, 2020 16:17
- make them valid for 10 years
- Add note to readme about date of expiration
buildSrc/build.gradle Outdated Show resolved Hide resolved
NamedDomainObjectContainer<ElasticsearchCluster> clusters = (NamedDomainObjectContainer<ElasticsearchCluster>) project
.getExtensions()
.getByName(TestClustersPlugin.EXTENSION_NAME);
clusters.all(c -> {
Copy link
Member

Choose a reason for hiding this comment

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

I'm fine with that as long as we don't apply this plugin to any other subproject until we have the fips handling because it will start failing in CI. ( sql is fine because we mute the tests in fips eitherway )

@breskeby
Copy link
Contributor Author

breskeby commented Jun 3, 2020

@elasticmachine test this please

Copy link
Contributor

@mark-vieira mark-vieira left a comment

Choose a reason for hiding this comment

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

Man this is about 1000% better. 👍

t.setOutputDir(keyStoreDir);
});

project.getPlugins().withType(StandaloneRestTestPlugin.class).configureEach(restTestPlugin -> {
Copy link
Contributor

Choose a reason for hiding this comment

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

How does this compare to project.getPluginManager().withPlugin()?

Copy link
Contributor Author

@breskeby breskeby Jun 3, 2020

Choose a reason for hiding this comment

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

getPluginManager() doesn't allow configuration by plugin type (class) which I usually prefer when coding. also depending on your environment it used to be better when doing safer when refactorings etc instead of relying on plugin ids. PluginManager provides access to AppliedPlugin which we do not need here.


project.getPlugins().withType(StandaloneRestTestPlugin.class).configureEach(restTestPlugin -> {
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
SourceSet testSourceSet = sourceSets.getByName("test");
Copy link
Contributor

Choose a reason for hiding this comment

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

We can use Util.getJavaTestSourceSet().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

testSourceSet.compiledBy(exportKeyStore);

project.getTasks()
.withType(org.elasticsearch.gradle.testclusters.TestClustersAware.class)
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 have to use the fully qualified name here? Can we add an import?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


// Tell the tests we're running with ssl enabled
project.getTasks()
.withType(RestIntegTestTask.class)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should instead configure all tasks of RestTestRunnerTask type. There can be instances where we create these directly w/o creating a RestIntegTestTask. Also, the latter will hopefully dissapear soon.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, would we not want this for unit tests as well? Or is this very specific to integration tests?

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 to use RestTestRunnerTask. So far I don't think we have unit tests for this kind of testing. I don't see how this would look like tbh.

@breskeby breskeby merged commit 78cb9fa into elastic:master Jun 4, 2020
breskeby added a commit to breskeby/elasticsearch that referenced this pull request Jun 4, 2020
* Remove duplicate ssl setup in sql/qa projects
* Fix enforcement of task instances
* Use static data for cert generation
* Move ssl testing logic into a plugin
* Document test cert creation
breskeby added a commit to breskeby/elasticsearch that referenced this pull request Jun 4, 2020
* Remove duplicate ssl setup in sql/qa projects
* Fix enforcement of task instances
* Use static data for cert generation
* Move ssl testing logic into a plugin
* Document test cert creation
breskeby added a commit to breskeby/elasticsearch that referenced this pull request Jun 4, 2020
* Remove duplicate ssl setup in sql/qa projects
* Fix enforcement of task instances
* Use static data for cert generation
* Move ssl testing logic into a plugin
* Document test cert creation
@breskeby breskeby deleted the remove-duplicate-ssl-setup-in-qa branch June 4, 2020 08:36
breskeby added a commit that referenced this pull request Jun 4, 2020
* Remove duplicate ssl setup in sql/qa projects
* Fix enforcement of task instances
* Use static data for cert generation
* Move ssl testing logic into a plugin
* Document test cert creation
breskeby added a commit that referenced this pull request Jun 4, 2020
* Remove duplicate ssl setup in sql/qa projects
* Fix enforcement of task instances
* Use static data for cert generation
* Move ssl testing logic into a plugin
* Document test cert creation
breskeby added a commit that referenced this pull request Jun 4, 2020
* Remove duplicate ssl setup in sql/qa projects
* Fix enforcement of task instances
* Use static data for cert generation
* Move ssl testing logic into a plugin
* Document test cert creation
@mark-vieira mark-vieira added Team:Delivery Meta label for Delivery team and removed Team:Core/Infra Meta label for core/infra team labels Nov 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Delivery/Build Build or test infrastructure Team:Delivery Meta label for Delivery team v7.7.2 v7.8.1 v7.9.0 v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants