среда, 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 сервер. При импорте будет запрошен пароль - один раз если он такой же как на хранилище, и два раза если пароли хранилища и сертификата разные.
Импорт на внешнем сервере делается аналогично.

пятница, 17 февраля 2012 г.

Как включить Relay на Exchange 2007 или 2010

Как обычно пишу сюда решения по достаточно актуальным вопросам, которые часто требуются, но приходится "покопать" просторы Инета, чтобы их обнаружить.
Краткая предистория... В моей организации развернут Exchange 2007, поскольку организация небольшая (не много пользователей почтового сервиса), то практически все роли на одном сервере, кроме Edge, конечно. Edge отдельный сервер в DMZ, как завещает нам всем MS.
ВНЕЗАПНО потребовалось сделать так, чтобы с определенных серверов можно было отправлять почту не только внутри организации, но и внешнему подрядчику... Сразу получил отлуп по Relay denied. Чуть погуглив нашел корректное описание того, как делается Relay для Exchange 2007, а заодно и 2010.
Привожу текст as is (учим английскую мову, оригинал всей статьи здесь):

Allow relaying: The easy way

With the new IP address added to the Exchange server – let’s say it is 192.168.1.17, and your app server, device or copier that needs to relay is 192.168.1.100, fire up Exchange shell and use the following command:

New-ReceiveConnector -Name RelayConnector -usage Custom -Bindings ’192.168.1.17:25′ -fqdn server.domain.com -RemoteIPRanges 192.168.1.100 -server MYEXCHANGESERVER -permissiongroups ExchangeServers -AuthMechanism ‘TLS, ExternalAuthoritative’

What this does:

  • Creates a new Receive Connector called RelayConnector
  • Specifies the usage type Custom
  • Binds the Receive Connector to port 25 on IP address 192.168.1.17
  • Gives it the FQDN of server.domain.com
  • Allows only the host with the IP address 192.168.1.100 to connect to it (specified by the RemoteIPRanges parameter)
Additionally, and most importantly, it assigns the ExchangeServers permission group to it, and disables authentication. When you select ExternalAuthoritative for authentication, you’re telling Exchange that you completely trust the IP address(es) or subnets specified in the RemoteIPRanges parameter (192.168.1.100) and you have another authentication mechanism outside of Exchange, such as IPSec, to authenticate.
This also bypasses all security for messages received from that IP address. Because Exchange treats all hosts specified in RemoteIPRanges as trusted, it doesn’t apply anti-spam filters, doesn’t enforce message size limits, resolves P2 headers, and allows sending on behalf of users. Going back to Exchange Server 2003, this is somewhat similar to adding the sending host’s address to Connection Filtering‘s Global Accept list.

A better, more secure way to allow relaying

If you want it to be more secure, you can create a Receive Connector with PermissionGroups set to AnonymousUsers:

New-ReceiveConnector -Name RelayConnector -usage Custom -Bindings ’192.168.1.17:25′ -fqdn server.domain.com -RemoteIPRanges 192.168.1.100 -server MYEXCHANGESERVER -permissiongroups AnonymousUsers

Notice, we’ve left out the AuthMechanism parameter in the above command. However, we’re still restricting it to a particular IP address— 192.168.1.100. The big difference from the previous approach is we’re not treating the host as trusted.
Next, allow anonymous users to relay. This is done by allowing anonymous users the extended right ms-Exch-SMTP-Accept-Any-Recipient for this Connector:

Get-ReceiveConnector RelayConnector | Add-ADPermission -User “NT AUTHORITY\ANONYMOUS LOGON” -ExtendedRights “ms-Exch-SMTP-Accept-Any-Recipient”

Сделал оба варианта, проверил - работает! Если что-то не работает - пишем, будем разбираться почему.