Configure Jira server to connect to MySQL via SSL
These instructions are tested on Ubuntu 20.04, and the general procedure is uniform across platforms.
However, depending on your distribution and the method you have used to install the software, the file locations may differ.
Please note that Atlassian Support will refer SSL support to the institution that issued the Certificate. We provide this documentation for reference.
Before we Begin
To complete this task, you will need the following:
- JIRA 8.5+
- MySQL 5.7+ with SSL support (most precompiled packages include this)
- openSSL 1.0+
These instructions are based upon the MySQL Documentation available here: link
These commands should be run as root or by using the sudo command.
Perform steps 1-3 on your MySQL server.
Whatever method you use to generate the certificate and key files, the Common Name value used for the server and client certificates/keys must each differ from the Common Name value used for the CA certificate. Otherwise, the certificate and key files will not work for servers compiled using OpenSSL
1. Generating your SSL keys
Ensure you have a clean workspace.
Terminal Inputrm -rf /etc/mysql/newcerts mkdir /etc/mysql/newcerts && cd /etc/mysql/newcerts
Create CA Certificate
Terminal Inputopenssl genrsa 2048 > ca-key.pem openssl req -new -x509 -nodes -days +365 -key ca-key.pem -out ca-cert.pem
Create Server Certificate, remove passphrase, and sign it
Terminal Inputopenssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-req.pem openssl rsa -in server-key.pem -out server-key.pem openssl x509 -req -in server-req.pem -days +365 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
Create Client Certificate, remove passphrase, and sign it
Terminal Inputopenssl req -newkey rsa:2048 -nodes -keyout client-key.pem -out client-req.pem openssl rsa -in client-key.pem -out client-key.pem openssl x509 -req -in client-req.pem -days +365 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
Verify your certificates to prevent surprises later
Terminal Inputopenssl verify -CAfile ca-cert.pem server-cert.pem client-cert.pem
2. Configure MySQL to accept SSL connections
These instructions are based upon the MySQL Documentation available here: link
Verify that your MySQL server includes SSL support
Terminal Inputmysql --ssl --help
The server will then list the SSL options available. If you receive this, instead:
mysqld --ssl --help 060525 14:18:52 [ERROR] mysqld: unknown option '--ssl'
then your MySQL package does not have SSL included. Selecting and installing the correct MySQL server is outside of the scope of this guide.
Open the /etc/mysql/my.cnf file in the editor of your choice and find the following section:
#ssl #ssl-ca=/etc/mysql/cacert.pem #ssl-cert=/etc/mysql/servercert.pem #ssl-key=/etc/mysql/serverkey.pem
Edit the file so it looks like this, using the file paths from Step 1:
ssl ssl-ca=/etc/mysql/newcerts/ca-cert.pem ssl-cert=/etc/mysql/newcerts/server-cert.pem ssl-key=/etc/mysql/newcerts/server-key.pem
3. Secure your JIRA user
This section is based on a server root username of 'root', a schema name of 'public', and a JIRA username of 'jira'. If this does not reflect your system, please adjust the statements.
Begin by entering the MySQL client CLI:
Terminal Inputmysql -uroot -p
Create (or change permissions for) JIRA user
If you have already created your JIRA user, you must first revoke privileges to prevent the server from accepting an unencrypted connection:
MySQL CLI InputREVOKE ALL on public from '<jira-user>'@'<jira-server-ip-address>';
MySQL CLI InputGRANT ALL on public.* to 'jira'@'<jira-server-ip-address>' identified by 'password' REQUIRE SSL;
- Check permissions by attempting to connect to your database from the specified machine with the specified user with the MySQL Client, MySQL Administrator, or other tool. You should not be able to connect without using the SSL certificate.
Perform steps 4 and 5 on your JIRA server
4. Import your keys to your .keystore
The Tomcat server uses the default password 'changeit'. If you would like to use a different password, declare that during the following step, and add the parameter "keystorePassword='password'" to your Tomcat connector.
- Copy the resulting *.pem files from your MySQL server to your home folder on your JIRA server.
Run the following command as root or using sudo:
keytool -import -alias mysqlclientcertificate -file client-cert.pem
- Your .keystore will be created in your home folder as ~/.keystore
5. Configure your JIRA server
- Stop JIRA if it is running.
- Find the file dbconfig.xml file in your <jira_home> folder.
Edit the section below:
<url>jdbc:mysql://<mysql-server-address>:3306/public?useUnicode=true&characterEncoding=UTF8&sessionVariables=storage_engine=InnoDB</url>
so that it looks like this:
<url>jdbc:mysql://<mysql-server-address>:3306/public?useUnicode=true&characterEncoding=UTF8&sessionVariables=storage_engine=InnoDB&useSSL=true&verifyServerCertificate=false</url>
- Find the server.xml file in your JIRA conf folder, typically /opt/atlassian/jira/conf
Uncomment the Connector section as seen below:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" maxHttpHeaderSize="8192" SSLEnabled="true" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" useBodyEncodingForURI="true" keystoreFile="/some/keystore/path/.keystore"/>
- Start JIRA.
Troubleshooting
Here are some troubleshooting tips if you are using a self-signed key created by keytool, as described above.
When you enter "https://localhost:8443" in your browser, if you get a message such as "Cannot establish a connection to the server at localhost:8443", look for error messages in your logs/catalina.out log file. Here are some possible errors with explanations:
Can't find the keystore
java.io.FileNotFoundException: /home/user/.keystore (No such file or directory)
This indicates that Tomcat cannot find the keystore. The keytool utility creates the keystore as a file called .keystore
in the current user's home directory. For Unix/Linux the home directory is likely to be /home/<username>
. For Windows it is likely to be C:\Documents And Settings\<UserName>
.
Make sure you are running JIRA as the same user who created the keystore. If this is not the case, or if you are running JIRA on Windows as a service, you will need to specify where the keystore file is in conf/server.xml
. Add the following attribute to the connector tag you uncommented:
keystoreFile="<location of keystore file>"
If you still see the error, your JIRA instance may be configured to run with the permissions of the user 'jira'. In that case, the keystore is in a folder that cannot be accessed by the user jira. Issue the following commands in your shell:
This step must be performed as the root user, or with the use of sudo
mkdir /home/jira
cp ~/.keystore home/jira/
Certificate reply and certificate in keystore are identical
keytool error: java.lang.Exception: Certificate reply and certificate in keystore are identical
This error will happen if you have identical names or fingerprints, which is the result of attempting to recreate the cert in your existing keystore. If you need to recreate or update the Cert, you may remove the existing keystore and creating a fresh, new keystore. In this case, creating a new keystore and adding the related certs will fix the issue. The default path for it in this documentation is $JAVA_HOME/jre/lib/security/cacerts
Incorrect password
java.io.IOException: Keystore was tampered with, or password was incorrect
You used a different password than "changeit". You must either use "changeit" for both the keystore password and for the key password for Tomcat, or if you want to use a different password, you must specify it using the keystorePass
attribute of the Connector tag, as described above.
Passwords don't match
java.io.IOException: Cannot recover key
You specified a different value for the keystore password and the key password for Tomcat. Both passwords must be the same.
Wrong certificate
javax.net.ssl.SSLException: No available certificate corresponds to the SSL cipher suites which are enabled.
If the Keystore has more than one certificate, Tomcat will use the first returned unless otherwise specified in the SSL Connector in conf/server.xml
.
Add the keyAlias
attribute to the Connector tag you uncommented, with the relevant alias, for example:
<Connector port="8443" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true" useBodyEncodingForURI="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="/opt/local/.keystore"
keystorePass="removed"
keyAlias="tomcat"/>
Using Apache Portable Runtime
APR uses a different SSL engine, and you will see an exception like this in your logs
SEVERE: Failed to initialize connector [Connector[HTTP/1.1-8443]]
LifecycleException: Protocol handler initialization failed: java.lang.Exception: No Certificate file specified or invalid file format
The reason for this is that the APR Connector uses OpenSSL and cannot use the keystore in the same way. You can rectify this in one of two ways:
Use the Http11Protocol to handle SSL connections
Edit the server.xml so that the SSL Connector tag you just uncommented specifies the Http11Protocol instead of the APR protocol
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxHttpHeaderSize="8192" SSLEnabled="true" keystoreFile="${user.home}/.keystore"
maxThreads="150" enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" useBodyEncodingForURI="true"/>
Configure the Connector to use the APR protocol
This is only possible if you have PEM encoded certificates and private keys. If you have used OpenSSL to generate your key, then you will have these PEM encoded files - in all other cases contact your certificate provider for assistance.
<Connector
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
SSLCertificateFile="${user.home}/certificate.pem"
SSLCertificateKeyFile="${user.home}/key.pem"
clientAuth="optional" SSLProtocol="TLSv1"/>