Инструменты пользователя

Инструменты сайта


www:jira-tomcat-ssl

Настраиваем SSL на Tomcat (JIRA) и предотвращаем Logjam уязвимость

Введение

По работе приходится использовать и обслуживать стек приложений от Atlassian - JIRA, Confluence, Stash, Bamboo, FishEye. Как правило, все они стоят за reverse proxy серверами - apache/nginx и никаких проблем с устранением уязвимостей вроде POODLE там нет. Но недавно пришлось столкнуться с нетипичной настройкой - терминировать SSL надо было средствами самого Tomcat, даже не смотря на то, что сам Atlassian не оказывает поддержку таких конфигураций

Atlassian applications allow the use of SSL within our products, however Atlassian Support does not provide assistance for configuring it. Consequently, Atlassian cannot guarantee providing any support for it

Но мы ведь не ищем легких путей. Итак, приступаем.

Настройка SSL в Tomcat. JSEE.

Согласно официальной документации настраивается все просто. Нам нужно создать свой т.н. keystore и поместить в него наши сертификаты и закрытый ключ. Казалось бы, что может быть проще, но тут я столкнулся с первой проблемой. В сети есть масса примеров как это делается, но все они, как правило приведены с учетом создания само подписанного сертификата, как корневого, так и сертификата для сервиса. Но у нас ситуация немного другая, в нашем распоряжении есть:

  • jira.example.net.crt - сертификат
  • jira.example.net.key - соответствующий закрытый ключ
  • ca.pem - корневой сертификат StartSSL
  • sub.class1.server.ca.pem - Промежуточный сертификат StartSSL

А так как по дефолту JIRA предлагает использовать т.н. блокирующий коннектор (blocking Java connector), который не понимает x509 сертификаты, а использует свой формат - JKS, то нам придется преобразовать наши сертификаты и сохранить их в JKS хранилище. Собственно NIO (non blocking Java connector) тоже требует JKS.

Итак, для начала объединяем все наши сертификаты. Хочу обратить ваше внимание, что порядок имеет значение! Если у вас есть корневой и промежуточные сертификаты вашего центра сертификации, то последовательность должна быть следующей:

root -> intermediate(s) -> domain
# cat rootca.crt > chain.pem
# cat sub.class1.server.ca.crt >> chain.pem
# cat jira.example.net.crt >> chain.pem

Проверяем нашу цепочку

# openssl verify chain.pem
chain.pem: OK

Если все нормально, то преобразовываем наши сертификаты и закрытый ключ в формат pkcs#12

В криптографии PKCS#12 — один из стандартов семейства Public-Key Cryptography Standards (PKCS), опубликованных RSA Laboratories. Он определяет формат файла, используемый для хранения и/или транспортировки закрытого ключа (en:Private key), цепочки доверия от сертификата пользователя до корневого сертификата удостоверяющего центра и списка отзыва сертификатов (CRL). В файлах PKCS#12 хранятся одновременно и закрытый ключ, и сертификат (разумеется в зашифрованном виде).
# openssl pkcs12 -export -in chain.pem -inkey jira.example.net.key > jira.example.net.p12
Enter Export Password: **********
Verifying - Enter Export Password: **********
Даже не смотря на то, что можно не вводить пароль, а оставить его пустым, вам придется задать пароль, иначе позже на этапе импорта pkcs12 в хранилище JKS утилита keytool откажется выполнять импорт!!!

А теперь импортируем нашу цепочку и закрытый ключ и на их основе создаем свой keystore

# keytool -importkeystore -srckeystore jira.example.net.p12 -destkeystore jira.example.net.jks -srcstoretype pkcs12            
Enter destination keystore password: **********
Re-enter new password: **********
Enter source keystore password: **********
Entry for alias 1 successfully imported. **********
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Проверяем полученное хранилище

$ keytool -list -keystore jira.example.net.jks
Enter keystore password:

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

1, Jun 24, 2015, PrivateKeyEntry,
Certificate fingerprint (SHA1): F2:CE:0D:6F:D7:71:DF:57:41:96:A9:48:EB:CA:6C:94:C9:C5:4E:F0

Теперь у нас все готово к настройке SSL. Для этого редактируем JIRA-INSTALL-DIR/conf/server.xml, в нем есть секция отвечающая за SSL, по умолчанию она закоментирована.

Все действия в данной статье производятся с учетом следующего

JIRA-HOME=/opt/projects/alpha/application-data
JIRA-INSTALL-DIR=/opt/projects/alpha/jira
<Connector protocol="org.apache.coyote.http11.Http11Protocol"
   SSLEnabled="true"
   port="443" scheme="https" secure="true"
   useBodyEncodingForURI="true"
   maxHttpHeaderSize="8192"
   maxThreads="150" minSpareThreads="25"
   enableLookups="false" disableUploadTimeout="true"
   acceptCount="100"
   clientAuth="false"
   sslProtocol="TLS"
   keystoreFile="/etc/pki/jira/jira.example.net.jks" keystorePass="7654321" keystoreType="JKS"
/>

Запускаем JIRA и смотрим логи: JIRA-INSTALL-DIR/logs/catalina.out

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0
Jul 02, 2015 10:20:02 AM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
Jul 02, 2015 10:20:03 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-443"]
Jul 02, 2015 10:20:03 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1619 ms
Jul 02, 2015 10:20:03 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Jul 02, 2015 10:20:03 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.55
2015-07-02 10:20:17,902 localhost-startStop-1 INFO      [atlassian.jira.startup.JiraStartupLogger]

****************
JIRA starting...
****************

...
...
...

Jul 02, 2015 10:21:42 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-443"]
Jul 02, 2015 10:21:42 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 98546 ms
2015-07-02 10:21:45,345 Modification Check:thread-1 INFO      [atlassian.jira.startup.JiraStartupLogger]

___ Modifications ___________________________

     Modified Files                                : jira-application.properties, WEB-INF/web.xml
     Removed Files                                 : None

log4j:WARN No appenders could be found for logger (com.amazonaws.jmx.spi.SdkMBeanRegistry).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

Как видим Tomcat у нас запустился, так что производим проверку на SSLLABS

Не очень утешительная оценка. Отправляемся к чтению документации и после осмысления добавляем следующие строки

<Connector protocol="org.apache.coyote.http11.Http11Protocol"
   SSLEnabled="true"
   port="443" scheme="https" secure="true"
   useBodyEncodingForURI="true"
   maxHttpHeaderSize="8192"
   maxThreads="150" minSpareThreads="25"
   enableLookups="false" disableUploadTimeout="true"
   acceptCount="100"
   clientAuth="false"
   sslProtocol="TLS"
   keystoreFile="/etc/pki/jira/jira.example.net.jks" keystorePass="7654321" keystoreType="JKS"
   sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2"
   сiphers="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
            TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
            TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
            TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
            TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
            TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
            TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
            TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
            TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
            TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
            TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
            TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"
/>

Перезапускаем JIRA и снова производим тестирование

После этого можно идти и пить кофе. Единственный нюанс - BIO коннектор поддерживает Secure Client-Initiated Renegotiation, что может быть не безопасным, поэтому лучше использовать неблокирующий коннектор NIO. Для этого достаточно заменить значение в параметре protocol на новое

<Connector protocol="org.apache.coyote.http11.Http11NioProtocol"
Так как настройка SSL в реализациях JSSE (см выше) и APR (см ниже) сильно отличается, то лучше явно указывать тип коннектора и не полагаться на автоопределение.

Так же хочу заметить, что значение 90 в Cipher Strength удалось получить благодаря использованию Java Cryptography Extension (JCE), данное расширение можно бесплатно скачать с сайта oracle. Все что нужно сделать, это скопировать два jar файла (local_policy.jar/US_export_policy.jar) из архива в папку JIRA-INSTALL-DIR/jre/lib/security. Без JCE Cipher Strength получается 80.

Если же хочется достичь полной нирваны и просветления, т.е. получить Cipher Strength 100, то вы можете поиграться со значением параметра сiphers. Но это я оставляю в виде домашнего задания.

Настройка SSL в Tomcat. APR.

Если внимательно посмотреть на логи запуска JIRA, то в самом начале можно заметить следующие строки

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0
Jul 02, 2015 10:20:02 AM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib

Собственно обращаем внимание на строку - «The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found». Здесь речь идет о данной библиотеке. APR коннектор так же как и NIO является не блокирующим, а для SSL/TLS функционала используется openssl. Так же есть поддержка FIPS 140-2.

Ниже привожу содержимое server.xml для запуска APR

<Connector port="443" protocol="org.apache.coyote.http11.Http11AprProtocol"
   scheme="https"
   secure="true"
   clientAuth="false"
   useBodyEncodingForURI="true"

   SSLEnabled="true"
   SSLHonorCipherOrder="true"
   SSLDisableCompression="true"
   SSLCertificateFile="/etc/pki/jira/jira.example.net.crt"
   SSLCertificateKeyFile="/etc/pki/jira/jira.example.net.key"
   SSLCACertificateFile="/etc/pki/jira/ca.pem"
   SSLCertificateChainFile="/etc/pki/jira/sub.class1.server.ca.pem"
   SSLCipherSuite="kEECDH+AES128:kEECDH:kEDH:-3DES:kRSA+AES128:kEDH+3DES:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv2"
   SSLProtocol="TLSv1+TLSv1.1+TLSv1.2"
/>

Те, кто настраивал SSL в apache сразу узнает знакомые названия параметров.

В составе JIRA уже идут исходники tomcat native, их можно найти в JIRA-INSTALL-DIR/bin/tomcat-native.tar.gz. Но к сожалению она не подойдет нам, так как согласно changelog поддержка TLSv1.2 и TLSv1.1 появилась только в 1.1.33. Иначе при попытке запуска вы будете получать подобные ошибки

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0
Jul 03, 2015 5:28:47 AM org.apache.catalina.core.AprLifecycleListener init
INFO: Loaded APR based Apache Tomcat Native library 1.1.31 using APR version 1.3.9.
Jul 03, 2015 5:28:47 AM org.apache.catalina.core.AprLifecycleListener init
INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
Jul 03, 2015 5:28:48 AM org.apache.catalina.core.AprLifecycleListener initializeSSL
INFO: OpenSSL successfully initialized (OpenSSL 1.0.1e 11 Feb 2013)
...
...
...
SEVERE: Failed to initialize end point associated with ProtocolHandler ["http-apr-443"]
java.lang.Exception: An invalid value [TLSv1+TLSv1.1+TLSv1.2] was provided for the SSLProtocol attribute
        at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:490)
...
...
...
Jul 03, 2015 5:28:48 AM org.apache.catalina.core.StandardService initInternal
SEVERE: Failed to initialize connector [Connector[HTTP/1.1-443]]
org.apache.catalina.LifecycleException: Failed to initialize component [Connector[HTTP/1.1-443]]

А забегая немного наперед сразу скажу, что и версия 1.1.33 нас не спасет, точнее она не позволит избежать Logjam уязвимости. Поэтому нам надо использовать 1.1.34, но на момент написания статьи, а это начало июля, эта версия доступна только в транке.

Скачиваем исходники

# cd /root/rpmbuild/BUILD/
# svn co https://svn.apache.org/repos/asf/tomcat/native/branches/1.1.x/ tcnative-1.1.34
A    tcnative-1.1.34/jnirelease.sh
A    tcnative-1.1.34/KEYS
A    tcnative-1.1.34/README.txt
A    tcnative-1.1.34/build.properties.default
A    tcnative-1.1.34/build.xml
...
...
...
A    tcnative-1.1.34/java/org/apache/tomcat/jni/Stdlib.java
A    tcnative-1.1.34/java/org/apache/tomcat/jni/SSLExt.java
A    tcnative-1.1.34/java/org/apache/tomcat/jni/Status.java
Checked out external at revision 1659384.

Checked out revision 1688981.

Но так как это trunk, то там отсутствует файл configure и нам придется его сгенерировать, но для этого понадобятся исходники самой apr

# rpm -ivh http://vault.centos.org/6.6/os/Source/SPackages/apr-1.3.9-5.el6_2.src.rpm
# cd /root/rpmbuild/SPECS/
# rpmbuild -bp --target=x86_64 apr.spec
Building target platforms: x86_64
Building for target x86_64
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.tThAuX
+ umask 022
+ cd /root/rpmbuild/BUILD
+ LANG=C
+ export LANG
...
...
...
+ echo 'Patch #11 (apr-1.2.7-fnmatch.patch):'
Patch #11 (apr-1.2.7-fnmatch.patch):
+ /usr/bin/patch -p1 -b --suffix .fnmatch --fuzz=0
+ /bin/cat /root/rpmbuild/SOURCES/apr-1.2.7-fnmatch.patch
patching file strings/apr_fnmatch.c
+ exit 0

Теперь у нас все готово для сборки самой библиотеки

# cd /root/rpmbuild/BUILD/tcnative-1.1.34/native/
# sh buildconf --with-apr=/root/rpmbuild/BUILD/apr-1.3.9
Looking for apr source in /root/rpmbuild/BUILD/apr-1.3.9
Creating configure ...
Generating 'make' outputs ...
rebuilding rpm spec file

# ./configure --with-ssl --with-apr=/usr/bin/apr-1-config --with-java-home=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.79.x86_64
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking target system type... x86_64-unknown-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
checking for working mkdir -p... yes
Tomcat Native Version: 1.1.34
checking for chosen layout... tcnative
checking for APR... yes
configure: APR 1.3.9 detected.
...
...
...
checking OpenSSL library version >= 0.9.8m... ok
checking for OpenSSL DSA support... yes
  setting TCNATIVE_LDFLAGS to "-lssl -lcrypto"
  adding "-DHAVE_OPENSSL" to CFLAGS
  setting TCNATIVE_LIBS to ""
  setting TCNATIVE_LIBS to " /usr/lib64/libapr-1.la  -lpthread"
checking for apr_pool_pre_cleanup_register in -lapr-1... yes
  adding "-DHAVE_POOL_PRE_CLEANUP" to CFLAGS
configure: creating ./config.status
config.status: creating tcnative.pc
config.status: creating Makefile
config.status: executing default commands

# make

В результате в папке .libs должны появится следующие файлы

# ls -la
total 2512
drwxr-xr-x. 2 root root    4096 Jul  3 06:12 .
drwxr-xr-x. 9 root root    4096 Jul  3 06:12 ..
-rw-r--r--. 1 root root 1631390 Jul  3 06:12 libtcnative-1.a
lrwxrwxrwx. 1 root root      19 Jul  3 06:12 libtcnative-1.la -> ../libtcnative-1.la
-rw-r--r--. 1 root root    1025 Jul  3 06:12 libtcnative-1.lai
lrwxrwxrwx. 1 root root      23 Jul  3 06:12 libtcnative-1.so -> libtcnative-1.so.0.1.34
lrwxrwxrwx. 1 root root      23 Jul  3 06:12 libtcnative-1.so.0 -> libtcnative-1.so.0.1.34
-rwxr-xr-x. 1 root root  921921 Jul  3 06:12 libtcnative-1.so.0.1.34

Нас интересуют so модули. Копируем их в папку /usr/lib64 и перезапускаем JIRA. И снова получаем туже ошибку! А всему виной вот это баг, который был исправлен в tomcat-7.0.57, а в последней Jira, а именно 6.4.7 идет 7.0.55.

Скачиваем apache-tomcat-7.0.57 и копируем содержимое папки lib в JIRA-INSTALL-DIR/lib с заменой. Запускаем JIRA и смотрим логи

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0
Jul 03, 2015 6:43:47 AM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
INFO: Loaded APR based Apache Tomcat Native library 1.1.34 using APR version 1.3.9.
Jul 03, 2015 6:43:47 AM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
Jul 03, 2015 6:43:47 AM org.apache.catalina.core.AprLifecycleListener initializeSSL
INFO: OpenSSL successfully initialized (OpenSSL 1.0.1e 11 Feb 2013)
Jul 03, 2015 6:43:47 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-apr-443"]
Jul 03, 2015 6:43:47 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1051 ms
Jul 03, 2015 6:43:47 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Jul 03, 2015 6:43:47 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.57
2015-07-03 06:43:59,014 localhost-startStop-1 INFO      [atlassian.jira.startup.JiraStartupLogger]

****************
JIRA starting...
****************

Обращаем внимание на версию APR и Tomcat. Запускаем тест на SSLLABS

Теперь уж точно все и можно смело идти отдыхать.

P.S. Я создал соответствующий запрос на предмет обновления версии tomcat в составе JIRA хотя бы до 7.0.57.

Полезные ссылки

www/jira-tomcat-ssl.txt · Последние изменения: 2016/01/26 11:03 — root