41

I have a Fedora server running Jenkins which I install via yum. Everything is okay, I can access it with http://ci.mydomain.com.

But now, I want to access it with https://ci.mydomain.com so the login with username and password is encrypted.

How can I do this?

The following is my /etc/sysconfig/jenkins file. Starting Jenkins works, but I can not access Jenkins with the webbrowser with https://ci.mydomain.com or http://ci.mydomain.com:443, ...

## Path:        Development/Jenkins
## Description: Configuration for the Jenkins continuous build server
## Type:        string
## Default:     "/var/lib/jenkins"
## ServiceRestart: jenkins
#
# Directory where Jenkins store its configuration and working
# files (checkouts, build reports, artifacts, ...).
#
JENKINS_HOME="/var/lib/jenkins"

## Type:        string
## Default:     ""
## ServiceRestart: jenkins
#
# Java executable to run Jenkins
# When left empty, we'll try to find the suitable Java.
#
JENKINS_JAVA_CMD=""

## Type:        string
## Default:     "jenkins"
## ServiceRestart: jenkins
#
# Unix user account that runs the Jenkins daemon
# Be careful when you change this, as you need to update
# permissions of $JENKINS_HOME and /var/log/jenkins.
#
JENKINS_USER="jenkins"

## Type:        string
## Default:     "-Djava.awt.headless=true"
## ServiceRestart: jenkins
#
# Options to pass to java when running Jenkins.
#
JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true"

## Type:        integer(0:65535)
## Default:     8080
## ServiceRestart: jenkins
#
# Port Jenkins is listening on.
#
JENKINS_PORT="8080"

## Type:        integer(1:9)
## Default:     5
## ServiceRestart: jenkins
#
# Debug level for logs -- the higher the value, the more verbose.
# 5 is INFO.
#
JENKINS_DEBUG_LEVEL="5"

## Type:        yesno
## Default:     no
## ServiceRestart: jenkins
#
# Whether to enable access logging or not.
#
JENKINS_ENABLE_ACCESS_LOG="no"

## Type:        integer
## Default:     100
## ServiceRestart: jenkins
#
# Maximum number of HTTP worker threads.
#
JENKINS_HANDLER_MAX="100"

## Type:        integer
## Default:     20
## ServiceRestart: jenkins
#
# Maximum number of idle HTTP worker threads.
#
JENKINS_HANDLER_IDLE="20"

## Type:        string
## Default:     ""
## ServiceRestart: jenkins
#
# Pass arbitrary arguments to Jenkins.
# Full option list: java -jar jenkins.war --help
#
JENKINS_ARGS="--httpsPort=443 --httpsKeyStore=/root/.keystore --httpsKeyStorePassword=MYPASSWORD"
gunr2171
  • 103
  • 5
Tim
  • 600
  • 2
  • 8
  • 15
  • you can use authbind to use any port below 1000 and still run jenkins as non-root. –  Jan 03 '15 at 18:04

4 Answers4

21

Just in case you're using Nginx and not Apache, you might want to use proxy_redirect http:// https://; to rewrite the Location header as the response comes back from Jenkins.

A complete nginx setup where SSL is terminated with Nginx and proxied internally to Jenkins using 8080 might look like this:

upstream jenkins {
  server 127.0.0.1:8080 fail_timeout=0;
}

server {
  listen 80 default;
  server_name 127.0.0.1 *.mydomain.com;
  rewrite ^ https://$server_name$request_uri? permanent;
}

server {
  listen 443 default ssl;
  server_name 127.0.0.1 *.mydomain.com;

  ssl_certificate           /etc/ssl/certs/my.crt;
  ssl_certificate_key       /etc/ssl/private/my.key;

  ssl_session_timeout  5m;
  ssl_protocols  SSLv3 TLSv1;
  ssl_ciphers HIGH:!ADH:!MD5;
  ssl_prefer_server_ciphers on;

  # auth_basic            "Restricted";
  # auth_basic_user_file  /home/jenkins/htpasswd;

  location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_redirect http:// https://;

    add_header Pragma "no-cache";

    proxy_pass http://jenkins;
  }
}
emm
  • 211
  • 2
  • 2
17

This page should help you set it up behind Apache (which would handle HTTPS): https://wiki.eclipse.org/Hudson-ci/Running_Hudson_behind_Apache

Apart from being a "normal" reverse-proxy, you'll need this (as shown on that page):

Header edit Location ^http://www.example.com/hudson/ https://www.example.com/hudson/
Bruno
  • 4,069
  • 1
  • 20
  • 37
  • 2
    Thanks for the reply. I do not have Apache up and running, I only have the Linux server with Jenkins. – Tim Jun 07 '11 at 13:32
  • 3
    In this case, create a keystore with your certificate and use `httpsPort` (and related parameters): http://groups.google.com/group/jenkinsci-users/browse_thread/thread/80491952f543d91a/c015c6bf8ddd172b – Bruno Jun 07 '11 at 13:40
  • Okay, I have my own certificate added into the keystore. But what should I call now? Where should I do this? `In any case: if I put only --httpsPort=8443 or i put --httpsKeyStore=/ path/to/keystore --httpsKeyStorePassword=myPassowrd in my HUDSON_ARGS`? – Tim Jun 07 '11 at 14:22
  • Put all the required parameters (port, store location and password). Then, start Jenkins and point your browser to `http://yourhostname:8443/`. – Bruno Jun 07 '11 at 14:25
  • Where should I put these parameters? And then I want to call https://ci.mydomain.com/ – Tim Jun 07 '11 at 15:55
  • You should have the file /etc/default/jenkins (at least there is under Debian, don't know if it's the same on Fedora). There you have the variable JENKINS_ARGS, where already httpPort etc. is specified. There you put httpsPort and httpsKeyStore etc. – dunni Jun 07 '11 at 18:33
  • I found the file and I pasted the content in my question. The problem is that Jenkins will start, but is not accessible https or any other portnumber. – Tim Jun 08 '11 at 09:21
  • You keystore seems to be in `/root/.keystore`, but you're running Jenkins under user `jenkins`. Make sure that file is readable by that user (so in a directory that can be executed by that user). – Bruno Jun 08 '11 at 09:53
  • I did this and I did a `chown` and `chgrp` to `jenkins` and moved the `.keystore` to `/var/lib/jenkins/`. On startup with `/etc/init.d/jenkins restart` I get this error in the Jenkins logfile: `[Winstone 2011/06/08 14:07:46] - Error during HTTPS listener init or shutdown java.net.BindException: Permission denied at java.net.PlainSocketImpl.socketBind(Native Method) at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:353) at java.net.ServerSocket.bind(ServerSocket.java:336) at ... [Winstone 2011/06/08 14:07:46] - HTTPS Listener shutdown successfully` – Tim Jun 08 '11 at 12:12
  • This error I get if I have `--httpsPort=443` and `JENKINS_PORT="8080"`. If I use `--httpsPort=8080` instead of `--httpsPort=443`, I get another error message: `Error during HTTPS listener init or shutdown javax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled. at sun.security.ssl.SSLServerSocketImpl.checkEnabledSuites(SSLServerSocketImpl.java:327) ... HTTPS Listener shutdown successfully`. – Tim Jun 08 '11 at 12:19
  • You can't use port 443 as it's a privileged port (you'd need to be root). There are way to go around this, but that's a different question. ServerFault would be a better place to ask all this anyway. – Bruno Jun 08 '11 at 12:22
  • For the other problem, it looks like you haven't generated your keystore properly. I'd suggest you look a bit more about these issues, there's plenty on the topic on the web. – Bruno Jun 08 '11 at 12:25
  • Okay, I understand this with port 443. But the other error seems to be a problem with the certificate. I have a signed certificate and I did this: `keytool -import -v -trustcacerts -alias myjenkins -file MyDomainValidation-CA.pem` Then I entered the password twice which I use for `--httpsKeyStorePassword=...`. So what is the problem? Oh, okay, ServerFault, so I should better open a new question there or do you know the problem and I can close this? – Tim Jun 08 '11 at 12:29
  • You need to import the private key with the certificate. You're not trying to import a CA cert (trustcacerts) here, but the private key and the certificate for your server. – Bruno Jun 08 '11 at 13:01
  • Yes, I think here is the problem. I did this: `keytool -import -alias root -keystore /var/lib/jenkins/.keystore -trustcacerts -file DomainValidation.pem` So this is the certificate of the CA and its content: `-----BEGIN CERTIFICATE----- MII... -----END CERTIFICATE-----` Then I have to import something with this command `keytool -import -alias jenkins -keystore /var/lib/jenkins/.keystore -file ???` but I only have a .crt and a .key file and both tell me that it is not a valid X.509 certificate. – Tim Jun 08 '11 at 13:24
  • The .crt file `Bag Attributes localKeyID: 01 00 00 00 friendlyName: *.mydomain.com subject=/C=COM/OU=Domain Control Validated/O=*.mydomain.com/CN=*.mydomain.com issuer=/C=BE/OU=Domain Validation CA/O=GlobalSign nv-sa/CN=GlobalSign Domain Validation CA -----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----` The .key file: `-----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY-----` So if I list the keystore, I get `Keystore-Typ: JKS Keystore-Provider: SUN Keystore contains 1 entry. my_ca, 08.06.2011, trustedCertEntry, ... (MD5): D5:E8:D3:6E:AB...` So no needed `keyEntry`. – Tim Jun 08 '11 at 13:25
  • I solved it. I used this tutorial and I needed to import it with JavaImport java class: http://wiki.eclipse.org/Generating_a_Private_Key_and_a_Keystore But the last problem is the root user. I changed `JENKINS_USER="jenkins"` to `JENKINS_USER="root"` then it works with port 443, but this is probably not the best solution. I only want that the user jenkins can use port 443 and not granted to be root. – Tim Jun 08 '11 at 14:42
  • There are a few options for this, one of them is to use `iptables`. That's the sort of question that's probably already been answered on serverfault. – Bruno Jun 08 '11 at 17:42
  • This link is broken as on 25 April 2018 – Umesh .A Bhat Apr 25 '18 at 10:04
  • 1
    @Umesh.ABhat It should be fixed now. – Bruno Apr 25 '18 at 16:47
15

Note that (as of sometime?) Jenkins can generate the key for you, all you need to do is set the --httpsPort=(portnum) parameter in JENKINS_ARGS.

In my case I set JENKINS_PORT="-1" (disable http) and set --httpsPort=8080 which worked well for my own purposes.

Just note that any port below 1000 generally requires root access, so pick a port higher than that...

(Link for more info)

Adam Rofer
  • 251
  • 2
  • 3
  • 3
    https://wiki.jenkins-ci.org/display/JENKINS/Starting+and+Accessing+Jenkins is the official documentation for this, by the way. – Jesse Glick Jan 15 '13 at 15:55
  • 3
    It'd be nice if that page had any mention about generating its own key - unfortunately you have to infer this capability by noticing that usang an "existing certificate" requires different steps than the default (which uses its own self-generated one) – Adam Rofer Jan 16 '13 at 02:24
  • 1
    Warning: that's easy enough for self-generated keys; however, I tried using those instructions with a real certificate, and setting up the keystore was a huge pain (since keystores have two password and the standard tools are really not transparent about this). – Blaisorblade May 29 '15 at 17:37
  • 1
    Note: This doesn't work with OpenJDK, only with the Oracle JRE, because [it relies on `sun.security.x509.CertAndKeyGen`](https://issues.jenkins-ci.org/browse/JENKINS-25333). Also, it was [broken with Java 8](https://issues.jenkins-ci.org/browse/JENKINS-25333) until very recently (Jenkins 2.38 fixed that). Worse though, the changelog for that release says [`This option is deprecated and will be removed in a future release. We strongly recommend you create self-signed certificates yourself and use --httpsKeyStore`](https://jenkins.io/changelog/). – nh2 Jan 26 '17 at 20:16
10

For an Ubuntu server (assuming you installed with apt-get install jenkins):

You'll want to edit /etc/default/jenkins at the bottom of the file, edit Jenkins_args. In my args, I've disabled http access (using -1) and put SSL on the default Jenkins port (8080). The most important part here is that you sent an httpsPort and certificate/key (if you have one, otherwise you can leave those off for the self generated one). I place the crts in apache and then use them for both, but you could put them anywhere.

JENKINS_ARGS="--webroot=/var/cache/jenkins/war --httpsPort=$HTTP_PORT --httpPort=-1 --httpsCertificate=/etc/apache2/ssl.crt/CERT.crt --httpsPrivateKey=/etc/apache2/ssl.key/KEY.key --ajp13Port=$AJP_PORT"

In some cases, you'll have to use a Java Key Store. First, convert your keys:

openssl pkcs12 -inkey /var/lib/jenkins/jenkins.key.pem -in /var/lib/jenkins/jenkins.crt.pem  -export -out keys.pkcs12

keytool -importkeystore -srckeystore keys.pkcs12 -srcstoretype pkcs12 -destkeystore jenkins.jks

Now use Jenkins args like

JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpsPort=$HTTP_PORT --httpPort=-1 --httpsKeyStore=/etc/apache2/ssl.crt/jenkins.jks --httpsKeyStorePassword=thePassword --ajp13Port=$AJP_PORT"

Also, see https://serverfault.com/a/569898/300544

Loren
  • 233
  • 2
  • 8
  • 1
    Ensure that the export password you supply to `openssl` matches the "source keystore password" requested by `keytool`. Further, the password cannot be blank. – bishop Jul 28 '17 at 15:28