Jenkins can be an integral piece of software used to speed up development and deliver production services to customers. Because of this, security in Jenkins must be carefully implemented. This brief guide will walk a Jenkins sysadmin through setting up SSL for Jenkins.
- Create a Java Keystore
- Configure Jenkins to use SSL
- Configure iptables to port forward
- Verify SSL is running
- Cited references
- Advanced Resources
This guide assumes:
- Prior knowledge of public key infrastructure (PKI).
- RedHat or CentOS GNU/Linux for file paths. Jenkins specific knowledge translates across distros.
- The hosting server has a fully qualified domain name.
- You installed Jenkins via a system package.
- You’re using Jenkins Winstone (the Jenkins built-in web server) which is the default.
- You’re running Jenkins as a normal user (e.g.
jenkins). Normal users can’t listen on ports less than 1024 in Linux. Note: If you wish to use 443 instead of 8443 I recommend using
iptablesto forward ports.
Create a Java Keystore
Generating keys and obtaining signed certificates is outside of the scope of this article. What you need first:
- A private SSL key (
- An SSL certificate signed by a certificate authority (
- The SSL certificate of the certificate authority which did the signing
To generate a Java Keystore requires:
- Reference your SSL certificates and key (listed above).
- Convert the SSL certificates into an intermediate format (PKCS12 keystore).
- Convert the intermediate format into a Java Keystore (JKS keystore).
The following command will convert SSL certificates into the intermediate format (PKCS12).
openssl pkcs12 -export -out jenkins_keystore.p12 \ -passout 'pass:changeit' -inkey example.com.key \ -in example.com.crt -certfile ca.crt -name example.com
Then convert the intermediate format (PKCS12) to Java Keystore (JKS). This way Jenkins can use the JKS.
keytool -importkeystore -srckeystore jenkins_keystore.p12 \ -srcstorepass 'changeit' -srcstoretype PKCS12 \ -srcalias example.com -deststoretype JKS \ -destkeystore jenkins_keystore.jks -deststorepass 'changeit' \ -destalias example.com
-destaliasmust be the same as the domain name (e.g.
- The password for the PKCS12 store and the JKS store must be exactly the same. Jenkins will fail to start if it is not the case.
- You should probably use a different password than
changeit(which is conventional knowledge for Java keystores). It will protect you if the keystore is compromised and downloaded but the password is not known. Though, in a system breach, it is wise to revoke and request new certificates.
- The final keystore file is
Move the keystore to a place which can be referenced in Jenkins configuration.
mkdir -p /etc/jenkins cp jenkins_keystore.jks /etc/jenkins/ #configure permissions to secure your keystore chown -R jenkins: /etc/jenkins chmod 700 /etc/jenkins chmod 600 /etc/jenkins/jenkins_keystore.jks
Configure Jenkins to use SSL
/etc/sysconfig/jenkins and set the following variables.
#disable HTTP JENKINS_PORT="-1" #configure HTTPS JENKINS_HTTPS_PORT="8443" JENKINS_HTTPS_KEYSTORE="/etc/jenkins/jenkins_keystore.jks" JENKINS_HTTPS_KEYSTORE_PASSWORD="changeit" JENKINS_HTTPS_LISTEN_ADDRESS="127.0.0.1"
To learn more about these options you can execute (while Jenkins is running):
java -jar /usr/lib/jenkins/jenkins.war --help ps aux | grep 'jenkins\.war'
/var/log/jenkins/jenkins.log for potential troubleshooting.
Configure iptables to port forward
iptables can be used to forward port 443 to 8443. This provides a better user
experience since this is the standard port for HTTPS connections. To do this on
a RedHat system a few things must occur:
- The kernel must allow forwarding.
- iptables needs rules for forwarding.
- The recommendations are relevant to interface
eth0. Double check you’re using the correct interface for your system.
Configure kernel to allow port forwarding
To enable forwarding during runtime:
#allow forwarding sysctl -w net.ipv4.ip_forward=1 #allow forwarding to localhost on eth0 sysctl -w net.ipv4.conf.eth0.route_localnet=1
echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/conf/eth0/route_localnet
For forwarding settings to persist on reboot, add or change the following
net.ipv4.ip_forward = 1 net.ipv4.conf.eth0.route_localnet = 1
Depending on how
iptables is configured you may have to adapt how you insert
the rules into the runtime firewall. It may be simpler to write your rules in
/etc/sysconfig/iptables and reload the firewall.
#for remote connections iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:8443 iptables -A FORWARD -i eth0 -m state --state NEW -m tcp -p tcp -d 127.0.0.1 --dport 8443 -j ACCEPT #for localhost connections iptables -t nat -A OUTPUT -p tcp --dport 443 -d 127.0.0.1 -j DNAT --to-destination 127.0.0.1:8443
iptables-save to update
Verify SSL is running
Ensure a correct certificate chain order. The following command also accounts for Server Name Indication (SNI).
openssl s_client -connect example.com:443 -servername example.com < /dev/null
View certificate information of the remote service.
openssl s_client -connect example.com:443 -servername example.com < /dev/null | openssl x509 -text | less
By passing a null byte to stdin in the above commands,
openssl is signaling an
immediate close of the connection. For more information about the above
commands, see the man pages.
If you visit your secured Jenkins and find your browser is not showing a secure connection, then you’re likely missing the certificate authority certificate in your browser trust store.
These are some links I referred when doing my research to formalize and write up this post.
- Running Jenkins on Port 80 or 443 using iptables.
- RHEL Security Guide iptables forward.
- ServerFault: iptables port redirect not working for localhost.
- StackExchange: iptables redirect outside requests to 127.0.0.1.
These resources and scripts are intended for the initiated. I can do follow-up blog posts on any of them. Just ask in the comments.
- genSAN.sh - A script to generate a private key and a single domain or SAN certificate signing request (CSR) to be signed by a certificate authority.
- provision_jenkins.sh - A script to quickly play and provision Jenkins with ease.
- keystore.sh - My reference for converting X.509 certificates to JKS. It is a script I wrote quite a while ago when I was more familiar with the topic.
- repo.jenkins-ci.org - A Maven repository where the Jenkins
community publishes the Jenkins WAR file and plugin HPI files. Search
*jenkins*VERSION.warto download an exact version of Jenkins where
VERSIONis the version you’re running in production.