среда, 12 декабря 2012 г.

Как я ставил сертификаты на GlassFish

Довольно давно ничего не заносил сюда, хотя парочка дел этого и заслуживала - к сожалению, времени.НЕТ.
Попробую частично исправить эту ситуацию, тем более, что информация для данного поста собиралась "на ходу" и "по крупицам".
Приступим!
Задача: есть 2 сервера - один в Public Internet, второй - в DMZ зоне предприятия. Оба сервера работают под CentOS 6.3, на обоих установлен GlassFish+JDK крайней версии, на момент установки и написания сего поста. Внешний сервер является сервером веб-форм, предоставляющим доступ к приложению, которое развернуто на сервере расположенном в DMZ. Для обеспечения безопасности работа с вэб-формами в Интернете осуществляется только по шифрованному каналу, используя SSL. Связь между серверами тоже зашифрована SSL-ем.
Установку и настройку ОС, GlassFish и внутреннего СА в данной статье я рассматривать не буду - с одной стороны ничего сложного нет, кроме некоторых нюансов настройки GlassFish касаемых имени сервера в файле host.
Как известно, для организации шифрованного канала между клиентом и сервером с использованием SSL необходим сертификат, как минимум на сервере, а если настроена взаимная проверка с использованием сертификатов, то и на клиенте - тоже. Второй случай (все должны быть с сертификатами) я рассматривать не буду, ибо тем, кому это необходимо либо сами знают многое про PKI, либо - имея много денег, готовы нанять знающих людей.
Рассматриваем стандартный вариант - клиент идет на сервер веб-форм, который его принудительно переводит на HTTPS у меня на стандартном 443 порту. Поясню почему я делал именно так. При использовании нестандартного порта для SSL вы можете подложить "свинью" тем, кто будет обращаться к вашему серверу из-за такого чудесного прокси, как ISA server или TMG. Проблема для этих прокси достаточно хорошо известна и при наличии не глупого админа решаема, но не факт, что у клиента такой есть, либо ему - админу - потребуется какое-то время на решение задачи, которую вы ему подкинули, сделав SSLна нестандартном порту. Исходя из этого я решил не "усугублять" и поставил "по умолчанию".
Здесь маленькая ремарка - у GlassFish SSL для клиентов (не админка) "по умолчанию" стоит на порту 8181! Не стоит об этом забывать.
Теперь переходим к сути. У GlassFish, которая использует Java, для управления ключами и сертификатами ничего собственного НЕТ. Поэтому используется стандартная утилита Java - keytool. Подробное описание можно найти с помощью Google или иных поисковиков, я приведу только одну ссылку, на мой взгляд наиболее полно отражающую, что это такое.
Вначале нам нужно создать запрос сертификата в СА. Можно конечно пользоваться самоподписанным - это зависит от того, кто будет обращаться на сервер веб-форм. Если только свои и в организации развернут свой СА - то можно выписать сертификат через него. Если же будут сторонние пользователи, то я крайне рекомендую немного разориться на сертификат от внешнего СА, который знают большинство систем/браузеров. Стоимость самого простого начинается в среднем от 100 $ для организаций за годовой сертификат, что на мой взгляд является весьма гумманной ценой.
НО! Прежде чем начинать делать запрос, я КРАЙНЕ рекомендую сменить пароли на хранилища как собственных сертификатов домена GlassFish, так и доверенных СА этого же домена. По умолчанию, пароль к keystore.jks и cacerts.jks - changeit - перевод не требуется. Что ж, просят поменять - надо уважить. И вот здесь поджидает первый нюанс. (Замечу, пишу не для гурО, а для себя и тех, кто с GlassFish не сталкивался!) В самой утилите keytool есть возможность (параметр) поменять пароль как на хранилище своих сертификатов (keystore.jks), так и на хранилище доверенных СА (cacerts.jks) - НЕ ИСПОЛЬЗОВАТЬ! Иначе получите большой геморрой в дальнейшем. См. ссылку здесь
Итак, меняем мастер-пароль командой:

# ./asadmin change-master-password --savemasterpassword=true yours_domain1
После сей процедуры начинаем делать запрос для СА примерно такой командой из директории Java, где есть данная утилита:
# keytool -keysize 2048 -genkey -alias yours_alias1 -keyalg RSA -dname "CN=my.domain.com,O=My Organization,OU=My department,L=My_City,S=My_region,C=My_Country"  -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/keystore.jks 
Параметры этой команды можете сами уточнить прочитав информацию из первой ссылки. При выполнении этой команды вас попросят ввести пароль от вашего keystore.jks (введите тот, на который вы поменяли стандартный), а затем поступит запрос на ввод пароля для данного сертификата. Рекомендация - если вы не параноик и нет особых задач, то просто нажимайте ввод и пароль сертификата будет соответствовать паролю хранилища. В дальнейшем это упрощает его использование, т.к. при разных паролях (на хранилище и сертификат) вам потребуется указывать пароль от сертификата в дополнительных настройках подключения, иначе, опять будет геморрой.
После выполнения данной команды в keystore.jks появляется алиас, связанный с Private key сертификата, но самого сертификата нет - там пока только запрос. Чтобы появился сертификат нам нужно получить ответ от СА. Для этого нам потребуется выгрузить запрос сертификата в отдельный файл. Выполняем команду:

# keytool -certreq -alias yours_alias1  -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/keystore.jks -file you_filename1.csr
Полученный файл будет в известной кодировке Base64 (RFC1421), начинается с -----BEGIN и оканчивается на -----END.
Кстати, вот хорошая ссылка, чтобы проверить правильный ли запрос в СА получился: https://ssl-tools.verisign.com/#home  (требуется JAVA =)) )

Возвращаюсь к Задаче. Для внешнего сервера запрос во внешний СА у нас уже должен был получится. Переходим к серверу в  DMZ. C ним будет чуток веселее, т.к. у меня есть собственный СА, который я и собираюсь использовать для получения сертификата для данного сервера. Генерируем запрос, но прежде, небольшая ремарка:
У моего сервера в DMZ два DNS имени - одно из внешнего пространства, а другое - из внутреннего. Если у вас нет собственного СА, и/или вы планируете использовать на сервере в DMZ сертификат от внешнего СА, тогда для уменьшения стоимости сертификата стоит использовать только одно имя - внешнее. И все, что ниже - точно не для вас. Если только для информации...
Итак, запрос во внутренний СА, с указанием SAN (subjectAlternetiveName)
# keytool -keysize 2048 -genkey -alias yours_alias2 -keyalg RSA -dname "CN=my.domain.com,O=My Organization,OU=My department,L=My_City,S=My_region,C=My_Country" -ext san=DNS:my.domain.com,DNS:my-ANOTHER.domen-ANOTHER.com-ANOTHER -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/keystore.jks
Вводим запрошенные пароли, выполняем запрос на получение сертификата с маленьким дополнением к первому:
# keytool -certreq -alias yours_alias2 -ext san=DNS:my.domain.com,DNS:my-ANOTHER.domen-ANOTHER.com-ANOTHER  -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/keystore.jks -file you_filename2.csr
Получаем второй файлик csr. Проверяем полученный файлик с помощью verisigh-ой программки, обращаем внимание, что в самом низу должны быть как минимум 2 SAN имени: одно должно соответствовать CN-у, второе - то, какое требуется дополнительно.
Сейчас у меня есть два файла с запросами в СА: you_filename1.csr и you_filename2.csr. Первый я отправляю во внешний СА и жду ответа... Второй - быстро обрабатываю в своем СА и получаю сертификат you_filename2.crt.

Переходим к импорту сертификатов на сервера.
В самом начале я говорил о том, какие 2 типа хранилищ и для чего использует GlassFish, поэтому дальше просто то, что и куда надо импортировать. У кого есть вопрос "ПОЧЕМУ?" советую обратиться к мануалу.

Вначале делаем импорт сертификата своего корневого СА, а в моем случае еще и выдающего сервера в хранилище cacerts.jks примерно такой командой (следующие действия я проделал и с публичным сервером вэб-форм, т.к. для соединения обоих серверов используется SSL на сертификате, выданном моим собственным СА, а внешний сервер таки ничего не знает про мой СА):
# keytool -import -alias you_alias_CAroot -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/cacerts.jks -file you_filename_CAroot.crt
В моем случае придется делать дважды:
# keytool -import -alias you_alias_CAissue -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/cacerts.jks -file you_filename_CAissue.crt
То же самое требуется выполнить и в хранилище keystore.jks. Дело в том, что GlassFish не может самостоятельно построить цепочку сертификатов - ей надо все "разжевывать". Я сталкивался со статьями, которые объясняли как из цепочки сделать отдельные сертификаты, чтобы импортировать полученные отдельные сертификаты в хранилища...
# keytool -import -alias you_alias_CAroot -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/keystore.jks -file you_filename_CAroot.crt
И в этом случае придется делать дважды:
# keytool -import -alias you_alias_CAissue -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/keystore.jks -file you_filename_CAissue.crt
 Я не совсем уверен, что на публичном сервере стоило добавлять корневой и выдающий сертификат в keystore.jks, но лучше пересолить чем получить "веселые" ошибки при связки внешнего и внутреннего сервера (тем более, это общедоступные сертификаты).
Осталось провести импорт полученных от СА сертификатов. Для этого используется примерно следующая команда:
# keytool -import -alias you_alias2 -keystore /[...]/glassfish/glassfish/domains/yours_domain1/config/keystore.jks -file you_filename2.crt
Этой командой я импортирую полученный ответ СА на свой DMZ сервер. При импорте будет запрошен пароль - один раз если он такой же как на хранилище, и два раза если пароли хранилища и сертификата разные.
Импорт на внешнем сервере делается аналогично.

Комментариев нет:

Отправить комментарий