Adding SSL to your Jira

Well, I’ve been avoiding this topic for a while. It’s not that I don’t believe in having a certificate on your service – quite the opposite. This topic can be a bit of a rabbit hole and one that I’m wary of. That being said, this is important…and more importantly, it’s the only thing on my backlog that looks interesting today! So let’s dig into setting up Jira to be accessed securely by assigning it an SSL Certificate.

Why do you need one

So, in the early internet, they prioritized access over security. Considering the HTTP protocol was initially designed to share research materials across the early network, this does make sense. Simply put, they never imagined a situation where you would be using this tool to send passwords, company secrets, and banking information across the network.

By default, Jira is configured to use the unencrypted HTTP protocol out of the box. This is likely fine for a test instance you only need for a few days, but if you are setting this up for Production use, you should be accessing Jira via the encrypted HTTPS protocol. By doing so, you will deny anyone sitting between you and the Jira Server access to read whatever you are sending back and forth (see aforementioned passwords and company secrets). Today I won’t go into how HTTPS works in any detail – if you want to know that, I recommend this article by Cloudflare.  Instead, I will be talking about the practicalities of setting up your Jira instance to use SSL Certs.

Different files associated with the Certificate

Before we get too far down the rabbit hole, let’s take a moment to talk about the different files that you will need as you generate and install your Certificate. Most certificate authorities will have guides to generate these different files (and if they don’t, I won’t give them my money), so I won’t go into detail about getting them.  

Private Key

The Private Key is the entire game. This key is the file you need to keep secure to maintain security. It is the only file that can decrypt requests sent to your server, and if hackers get it, they can pretend to be you. 

CSR

This file is generated simultaneously as your key and will be what you use to communicate the details of your certificate request to the certificate authority. After you generate your request, you won’t need it again, but it is a critical part of the process.  

Certificate

The Certificate is the public key in your key pair – and is what browsers will use to encrypt and decrypt data coming from your system. This Certificate is usually a single file onto itself and will be called out specifically in your configuration. 

Chain Certs

So, question. How does your Browser know the Certificate a site is using is who they claim to be? This question was the principal problem they were trying to solve when Netscape first dreamed up HTTPS.  

Their solution: Have someone you trust to vouch for them. This is done because your Certificate will be signed by a Certificate Authority who says they have confirmed you are who you say you are. There are several schemes to do this – but it usually comes down to you proving you own the domain one way or another. The two most popular ways I’ve seen this done by a) providing some challenge string you have to add to your Domain’s DNS as a TXT record or b) answering some response sent to the admin email at that domain. 

But how do you trust that Certificate Authority? Well, you go up a chain until you get to Root Certificate – which is the highest authority whose recognition is built-in to modern browsers. But, it is your server’s responsibility to provide all the intermediary certificates that connect your Cert up to the Root Certificate.

This is where the Chain Certificates come in. In your configuration, you will specify the Certificates between you and the Root Certificate, and these are provided by your CA when you purchase your Certificate.  

Installing your Certificate directly to the Jira Service

So, you have all these files, and now you need to set them up to be used in Jira. There are two options here: Plug the information directly into Jira and have it handle SSL, or use a program to sit in between Jira and the Users to handle SSL translation for Jira. These programs and called Proxies and are just specially configured Web Servers.  

To be clear, I will go over the method for setting up Jira to serve SSL translation itself, but this is not the recommended method. Jira is not as good at SSL encryption/decryption as Proxies are, so there will be enough of a performance hit for users to notice. It won’t be the end of the world if you have a hard requirement, but it’s still not preferred.

Generate the Java KeyStore

The first step will be to put your Certificate into a form Jira’s JVM will understand. So our first step will be to convert both the key and the complete Certificate chain into a p12 file. We can do this with the following command.

openssl pkcs12 -export -in my.crt -inkey my.key -chain -CAfile ca-certs.pem -name "my-domain.com" -out my.p12

It will ask you to enter a password – remember this, as we will need it to convert this into the final Keystore. When done, it should look like this.

Using this command, we will now use your java keytool to convert this p12 file into the final Java Keystore. 

$JAVA_HOME/bin/keytool -importkeystore -deststorepass MY-KEYSTORE-PASS -destkeystore /opt/atlassian/jira/jira.jks -srckeystore my.p12 -srcstoretype PKCS12

Running this command will ask for the password you used in the previous step. A successful run should look like this:

And we’ll make one more chance to verify and fix the permissions of the file.

chown jira:jira /opt/atlassian/jira/jira.jks
$JAVA_HOME/bin/keytool -list -alias "my-domain.com" -keystore /opt/atlassian/jira/jira.jks

The -alias command should match whatever you entered for the domain in the OpenSSL command. A successful run should look like this:

Now that we have our file as a JKS, we can configure Jira to use it. Back up and Open up your <Jira_INSTALL>/conf/server.xml file in the text editor of your choice. Then modify your connector to look like this. Be sure to change the location of your keystoreFile, your keyAlias, and your keystorePass.

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
              maxHttpHeaderSize="8192" SSLEnabled="true"
              maxThreads="150" minSpareThreads="25"
              enableLookups="false" disableUploadTimeout="true"
              relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`&quot;&lt;&gt;"
              acceptCount="100" scheme="https" secure="true"
              sslEnabledProtocols="TLSv1.2,TLSv1.3"
              clientAuth="false" useBodyEncodingForURI="true"
              keyAlias="my-domain.com" keystoreFile="<Jira_HOME>/jira.jks" keystorePass="changeit" keystoreType="JKS"/>

Now we add a redirect to move users from port 8080 to port 8443 automatically.

<Connector acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" enableLookups="false" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" port="8080" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`&quot;&lt;&gt;" />

This should leave you with a final server.xml that looks like this. Save your work and exit this document.

Now we will open <Jira_INSTALL>/atlassian-jira/WEB-INF/web.xml and finalize the redirect. Add the right before </web-app> near the bottom of the file. 

<security-constraint>
	<web-resource-collection>
		<web-resource-name>all-except-attachments</web-resource-name>
		<url-pattern>*.jsp</url-pattern>
		<url-pattern>*.jspa</url-pattern>
		<url-pattern>/browse/*</url-pattern>
		<url-pattern>/issues/*</url-pattern>
	</web-resource-collection>
	<user-data-constraint>
		<transport-guarantee>CONFIDENTIAL</transport-guarantee>
	</user-data-constraint>
</security-constraint>

Save this file too and restart Jira. It might help to monitor <Jira_INSTALL>/log/catalina.out to look for any problems with the new config. Once your system is up, try connecting to port 8443 using HTTPS to do a final test.

Using a “Proxy”

As I stated, the above is functional, but you will have much better performance using a Proxy. Nginx is the preferred tool of choice for this, but honestly – I’m an old Linux Admin, so I’m more familiar with Apache – which is why it’s my Go-to. So I will go over what you need to do to get the proxy working in both. Either way, you will need to configure Jira with the new proxy URL and port to know how to communicate with itself, which we will also cover.

The next most significant benefit of using a proxy is using the default SSL and HTTP ports (443 and 80, respectively). These will make accessing your Jira instance a much smoother experience. 

Apache

As I know Apache best, I’ll start with that first. This is the configuration I have used and re-used for many applications to secure them, so I’d like to think it works. It does manage both HTTP redirection and HTTPS Proxy. Here is the config file.

<VirtualHost _default_:80>
        ServerName <Jira URL>

        <Location /server-status>
                SetHandler server-status
                Order deny,allow
                Allow from 127.0.0.1/8
        </Location>


        RewriteEngine On

        RewriteCond %{HTTPS} off
        RewriteCond %{REQUEST_URI} !^/server-status
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</VirtualHost>


<VirtualHost _default_:443>
        ServerName <Jira URL>

        #ErrorLog logs/ssl_error_log
        #TransferLog logs/ssl_access_log
        LogLevel warn

        SSLEngine on
        SSLProtocol TLSv1.2
        SSLHonorCipherOrder on
        SSLCipherSuite "!EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM !EECDH+ECDSA+SHA384 !EECDH+ECDSA+SHA256 !EECDH+aRSA+SHA384 !EECDH+aRSA+SHA256 !EECDH+aRSA+RC4 EECDH !EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"


        SSLCertificateFile /path/to/certs/<Cert File>.pem
        SSL CertificateChainFile /path/to/certs/<Chain 1>.pem
        SSLCertificateKeyFile /path/to/keys/<Private Key>.key

        <Files ~ "\.(cgi|shtml|phtml|php3?)$">
                SSLOptions +StdEnvVars
        </Files>

        <Directory "/var/www/cgi-bin">
                SSLOptions +StdEnvVars
        </Directory>

        ProxyRequests On

        <Proxy *>
                Require all granted
        </Proxy>
        <Location /server-status>
                SetHandler server-status
                Order deny,allow
                Allow from 127.0.0.1/8
        </Location>

        BrowserMatch "MSIE [2-5]" \
                nokeepalive ssl-unclean-shutdown \
                downgrade-1.0 force-response-1.0

        #CustomLog logs/ssl_request_log \
        #        "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"


        ProxyPass /server-status !

        ProxyPreserveHost On
        ProxyPass / http://<Jira_URL>:8080/
        ProxyPassReverse / http://<Jira_URL>:8080/
</VirtualHost>

I should note you can add as many SSLCertificateChainFile parameters as you need – I only needed one, so I only have one.  

You will either put this in the /etc/apache2/sites-available/ folder if you are on a Debian based OS, or in the /etc/httpd/conf.d/ for RedHat based OSes. I like to name the file after the site it’s for, so I’d name this 10-jira.conf, for example.

If you are on a Debian-based system, you will also need to enable the site with a2ensite 10-jira.conf. 

You will also need to make sure the following apache modules are installed and enabled:

  1. ssl
  2. proxy
  3. proxy_http
  4. rewrite

Nginx

Like Apache, this file will also handle both HTTP redirection and the proxy for Jira. It’s a much simpler file than Apache – but I’m set in my ways.

server {
        listen  80 default_server;
        listen  [::]:80 default_server ipv6only=on;
        server_name <Jira URL>;
        return  301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate /path/to/signed_cert_plus_intermediates;
    ssl_certificate_key /path/to/private_key;
    server_name <Jira URL>:443;
    location / {
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_pass http://<Jira URL>:8080/;
        client_max_body_size 10M;
    }
}

 

Here you have to combine your chain certs and your main certificate file into one file. An easy way to do this is to use this command:

cat www.example.com.crt bundle.crt > www.example.com.chained.crt

You will install this file at /etc/nginx/sites-available/10-jira.conf, then enable it with the following command:

ln -s /etc/nginx/sites-available/10-jira.conf /etc/nginx/sites-enabled/

While you are at it, make sure the default file is no longer enabled:

rm -rf /etc/nginx/sites-enabled/default

Then restart the Nginx process, and your new config will be active.

sudo systemctl restart nginx

Additional Steps on Jira

Your last step will be to configure Jira to let it know what its actual URL is. This is because both the Jira Process and client browsers will make return calls to Jira, and they need to know how to access it like any browser.

To do this, open up <Jira Install>/conf/server.xml. Then, on your connector, add the following parameters:

proxyName="<Jira URL>" proxyPort="443" scheme="https"

It should look something like this:

The scheme parameter may already be present, but you must update it to be “https.” If you are using a self-signed cert, you will also need to import it into Jira’s Keystore. The process is similar to what we would do if Jira were doing SSL translation itself, but your Keystore will be $JAVA_HOME/lib/security/cacerts, and your Keystore password will be “changeit”. (Not making that up!)

Once you have the changes to your server.xml file, you can restart Jira and load up your Jira site. Congrats, you now have SSL on your Jira instance!

So…yeah.

This article is a day late. I hate doing that, but I really wanted to double check the work before I posted it. During the process, I found several pages in Atlassian’s docs that were outdated.

However, I can say that next week’s article will not be late. As a Community leader, I get regularly invited to events from Atlassian – and this past week I got to attend an “AMA” (Ask Me Anything) from Atlassian’s CRO Cameron Deatsch, who answered everything from when can we expect the next Data Center LTS release, to what are the chances Team ’22 will actually be live. I have the transcript now and I am already working to convert this into next week’s post.

But until next time, my name is Rodney, asking, “Have you updated your Jira issues today?”

7 Comments

  1. I am trying to use SSL without proxy server. I followed instruction to change /atlassian-jira/WEB-INF/web.xml file. But jira failed to start. If I use original web.xml file, jira will start but ssl will not work. Can you help to point out what is wrong?

    Thank you.

    Like

      1. Thank you very much. Your article on SSL is a great help for me. You are the guru in jira field. Unfortunately, I have given up on Atlassian’s instruction on ssl and jira. With the help of my other teammates, they have setup load balancer as proxy for my SSL, SSL is working. We want get rid of reverse proxy since it caused jira gadget to fail in title and other area: https://confluence.atlassian.com/jirakb/fix-gadget-titles-showing-as-__msg_gadget-in-jira-server-813697086.html
        I have tried every fix in their article without any success. I am working on my next big adventure: get jira to work with SSO and PingFederate without IIS and reverse proxy.

        We can’t update to jira cloud since it is not Fed Ramped. We are stuck in server or data center. Atlassian support is so weak. I can’t believe they can still charge that of money for their software. Imaging you have to pay the price of a Lamborghini for a Ford Escort. 😦

        Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.