-
Notifications
You must be signed in to change notification settings - Fork 41
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
#67 add TLS support #80
Conversation
9fe3664
to
21e26e2
Compare
Could please one of the maintainers review this PR? BTW, I cannot link the corresponding issue, could you please take care of that as well? |
Hi @j3t! |
0780f75
to
a4e984e
Compare
Thanks @multani! I have added some more tests. |
@@ -335,7 +399,8 @@ public Node call() throws Exception { | |||
|
|||
// Support for Jenkins security | |||
String jnlpSecret = ""; | |||
if (Jenkins.get().isUseSecurity()) { | |||
if (Jenkins.get().isUseSecurity() || template.isDockerDriver()) { |
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'm not sure about this condition at all. It depends very much on how the agent.jar is executed. When java -cp is used then the secret is mandatory but when -jar is used then it's optional I guess. It probably makes sense to refactor this part in the future so that either the cp or the jar approach is used but not both.
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 don't see how this is relevant to adding TLS to talk with the Nomad agent though?
Can you simply remove this and address it in a different issue?
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.
@j3t Thanks for the PR!
Disclaimer: I'm not familiar at all with the Java PKI APIs.
I had a look and tested locally, the only issue I found was the "Test connection" in doTestConnection
failed to report the TLS connection couldn't be established. Could you update it to return something useful if the plugin , without TLS correctly configured, tries to connect to a TLS-enabled Nomad server?
I quickly hacked something like this:
Response response = clientBuilder.build().newCall(request).execute();
ResponseBody body = response.body();
String content ="";
if (body != null) {
content = body.string();
body.close();
}
if (response.code() != 200) {
throw new Exception("HTTP Status " + response.code() + ": " + content);
}
Apart from that, if I understood your PR correctly, you made the client certificate mandatory but not the server certificate / CA.
Also, not having the server certificate/CA doesn't validate the server identity, right?
If this is the case, you should flip around the setup you proposed then:
- The server certificate must be fully validated, instead of being optional. I think this one is the most important: if you bother to build up a PKI and enable TLS on Nomad, you must have a way to validate the client->server TLS communications.
- The client certificate should be optional: verification of the client certificate can be disabled on the server's side, so this is not strictly mandatory. It's pretty cool that you build it up in the PR in the first place, so keep it 👍
Also, I'd like the README to be extended a bit in the future (it's almost useless as it is, and it's actually not easy to get started with the plugin). Would you mind adding a small section on what would be possible when this gets merged and how to configure TLS with the plugin?
@@ -335,7 +399,8 @@ public Node call() throws Exception { | |||
|
|||
// Support for Jenkins security | |||
String jnlpSecret = ""; | |||
if (Jenkins.get().isUseSecurity()) { | |||
if (Jenkins.get().isUseSecurity() || template.isDockerDriver()) { |
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 don't see how this is relevant to adding TLS to talk with the Nomad agent though?
Can you simply remove this and address it in a different issue?
} | ||
|
||
/** | ||
* Checks that mutual TLS is working as expected (client proves the identity of the server and vise versa). |
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.
* Checks that mutual TLS is working as expected (client proves the identity of the server and vise versa). | |
* Checks that mutual TLS is working as expected (client proves the identity of the server and vice versa). |
} | ||
|
||
/** | ||
* Checks that one way TLS is working as expected (server proves the identity of the client but not vise versa). |
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.
* Checks that one way TLS is working as expected (server proves the identity of the client but not vise versa). | |
* Checks that one way TLS is working as expected (server proves the identity of the client but not vice versa). |
Like I said above, not proving the identity of the server is a bit awkward at best: if you rely on TLS to protect your communication but not authenticating who you are talking to, you can send sensitive information to a rogue server that just has TLS enabled.
Actually, if the connection can't fully validate the TLS connection, I would fail the connection altogether.
} | ||
|
||
/** | ||
* Checks that one way TLS is working as expected (client proves the identity of the server but not vise versa). |
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.
* Checks that one way TLS is working as expected (client proves the identity of the server but not vise versa). | |
* Checks that one way TLS is working as expected (client proves the identity of the server but not vice versa). |
<f:entry title="Client certificate password (optional)" > | ||
<f:password field="clientPassword" /> | ||
</f:entry> | ||
<f:entry title="Server certificate path (optional)" description="Path to the PKCS12 server certificate (aka Truststore). Usually a common authority or a public key."> |
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.
It should be worth mentioning that not setting this will not validate the certificate from the server.
I'd would even say not having this configure should not even be a valid configuration: if you have TLS enabled, you must validate the full TLS setup, otherwise it's a bit pointless.
What do you think?
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 my opinion we have to support the following use cases
- mutual TLS (client proves the identity of the server and vice versa)
- client auth only (server proves the identity of the client)
- server auth only (client proves the identity of the server)
The current solution supports them but is not clear. What is the expectation when TLS is enabled and both certificate fields are empty?
Suggestion: Differentiate between enable TLS (client-auth)
and enable TLS (server-auth)
. Then the certificate is not optional anymore.
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 server-auth is only important when the server is using self-signed certificates. Providing a server certificate, overrides JVM's default truststore.
} | ||
|
||
/** | ||
* Checks that TLS in general is working as expected (client not proves the identity of the server and vise versa). |
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.
* Checks that TLS in general is working as expected (client not proves the identity of the server and vise versa). | |
* Checks that TLS in general is working as expected (client not proves the identity of the server and vice versa). |
@@ -162,12 +207,12 @@ void stopWorker(String workerName, String nomadToken) { | |||
args.add(cloud.getJenkinsUrl()); | |||
} | |||
|
|||
if (!cloud.getJenkinsTunnel().isEmpty()) { | |||
if (cloud.getJenkinsTunnel() != null && !cloud.getJenkinsTunnel().isEmpty()) { |
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 not relevant to your PR.
args.add("-tunnel"); | ||
args.add(cloud.getJenkinsTunnel()); | ||
} | ||
|
||
if (!template.getRemoteFs().isEmpty()) { | ||
if (template.getRemoteFs() != null && !template.getRemoteFs().isEmpty()) { |
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 not relevant to your PR.
@@ -180,7 +225,7 @@ void stopWorker(String workerName, String nomadToken) { | |||
|
|||
String prefixCmd = template.getPrefixCmd(); | |||
// If an addtional command is defined - prepend it to jenkins worker invocation | |||
if (!prefixCmd.isEmpty()) { | |||
if (prefixCmd != null && !prefixCmd.isEmpty()) { |
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 not relevant to your PR.
* Provides an {@link OkHttpClient} instance. The existing client is reused. <b>Note</b> The client initialization is synchronized | ||
* which means this method is thread safe and can be called from different threads in parallel. |
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 think this is enough:
* Provides an {@link OkHttpClient} instance. The existing client is reused. <b>Note</b> The client initialization is synchronized | |
* which means this method is thread safe and can be called from different threads in parallel. | |
* Provides an {@link OkHttpClient} instance. Create a new client or reuse the existing one. | |
* This method is threadsafe. |
a4e984e
to
bae6927
Compare
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 your valuable comments! I have improved the description for the client and server path and I also adjusted the test setup a little bit. Now, tests are separated by the client trust-store (Default CA and Custom CA). I hope that makes things more clear.
<f:entry title="Client certificate password (optional)" > | ||
<f:password field="clientPassword" /> | ||
</f:entry> | ||
<f:entry title="Server certificate path (optional)" description="Path to the PKCS12 server certificate (aka Truststore). Usually a common authority or a public key."> |
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 my opinion we have to support the following use cases
- mutual TLS (client proves the identity of the server and vice versa)
- client auth only (server proves the identity of the client)
- server auth only (client proves the identity of the server)
The current solution supports them but is not clear. What is the expectation when TLS is enabled and both certificate fields are empty?
Suggestion: Differentiate between enable TLS (client-auth)
and enable TLS (server-auth)
. Then the certificate is not optional anymore.
<f:entry title="Client certificate password (optional)" > | ||
<f:password field="clientPassword" /> | ||
</f:entry> | ||
<f:entry title="Server certificate path (optional)" description="Path to the PKCS12 server certificate (aka Truststore). Usually a common authority or a public key."> |
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 server-auth is only important when the server is using self-signed certificates. Providing a server certificate, overrides JVM's default truststore.
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 finally took some time to give it another look. It looks quite cool on my side, there were a few more things to fix and I tested them and comited them in the branch directly (some typos, a security fix to prevent d451234 from happening again, some doc, etc.)
@j3t If you are good with the change, I'm OK to merge this and create a new release 👍
src/main/resources/org/jenkinsci/plugins/nomad/NomadCloud/config.jelly
Outdated
Show resolved
Hide resolved
Hi @multani, that's great! Unfortunately, I don't have time this week to test it manually but it looks good to me what I have seen so far. So, I would say it's fine. 👍 |
Just a small adjusted so that NomadApiClientTLSTest is not failing on my local machine and a typo. I have also tested it manually against our Nomad environment. It is working as expected. 👍 |
@j3t Awesome! Let me merge this and prepare a new release just after that 👍 This is a fine addition to the plugin ❤️ |
It's out in v0.8.0 🎉 Note that's there some issues with Jenkins infrastructure at the moment, so I haven't been able to release it fully. |
It's now released, it should be available through the Update Center soon. |
I have added TLS support so that NomadServer which are secured by client/server certificates can used as well.
corresponding Issue: #67