Jenkins over HTTPS with JNLP slaves

     

So you install Jenkins and also deploy Nginx over it. Eventually you also enable, or even enforce SSL. Later, you may get really cocky and also setup required protocol versions and ciphers suites. And that’s where the shit may hit the fan. So here’s a rather strict Nginx SSL configuration excerpt:

ssl_protocols TLSv1.2;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_prefer_server_ciphers on;
ssl_ciphers 'AES256+EECDH:AES256+EDH';

# generate this with
# openssl dhparam -out dh4096.pem 4096
ssl_dhparam dh4096.pem;

ssl_stapling on;
ssl_stapling_verify on;
resolver 208.67.222.222 208.67.220.220 valid=300s;
resolver_timeout 10s;

#limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
#limit_req zone=one burst=10 nodelay;

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header X-Content-Type-Options nosniff;

# This will prevent certain click-jacking attacks, but will prevent
# other sites from framing your site, so delete or modify as necessary!
#add_header X-Frame-Options SAMEORIGIN;
add_header X-Frame-Options DENY;

This is great and all, but then you wanna re-connect the JNLP slaves and boom:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
        at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2011)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1113)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)
        at hudson.remoting.Launcher.parseJnlpArguments(Launcher.java:269)
        at hudson.remoting.Launcher.run(Launcher.java:219)
        at hudson.remoting.Launcher.main(Launcher.java:192)

That’s not looking good. Then you read it up and figure that JDK 8 uses TLS 1.2 as default but Perfect Forward Secrecy is not enabled by default.

Then you open the Jenkins site with Firefox which is nice enough to tell you the cipher suite:

So then you modify the JNLP slave launcher like this:

java -Dhttp.cipherSuites=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA -jar slave.jar -jnlpUrl $jnlpurl -secret $secret -jar-cache cache

But guess what, it still doesn’t work. At all.

Then you stumble upon some random bullcr@p about Unlimited Strength Jurisdiction Policy Files. You deploy them to the slaves, and what do you get?

Apr 24, 2015 3:11:01 PM hudson.remoting.jnlp.Main createEngine
INFO: Setting up slave: windows-vs2008
Apr 24, 2015 3:11:01 PM hudson.remoting.jnlp.Main$CuiListener 
INFO: Jenkins agent is running in headless mode.
Apr 24, 2015 3:11:01 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Locating server among [https://jenkins.foobar.net/]
Apr 24, 2015 3:11:01 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Connecting to jenkins.foobar.net:54321
Apr 24, 2015 3:11:01 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Handshaking
Apr 24, 2015 3:11:01 PM hudson.remoting.jnlp.Main$CuiListener status
INFO: Connected

And that’s it! You don’t even need http.cipherSuites, just the policy files. Problem solved.