Application: "389 Administration & Directory Server v.1.3.7", "OpenSSL".
Задача: защитить клиент-серверные соединения LDAP-инстанса "389-DS" и сервера администрирования "389-AS" SSL/TLS-шифрованием с последующим отключением небезопасного протокола доступа.
Сервисы "389-DS" могут обслуживать клиентов как в открытом виде, так и в защищённом SSL/TLS-шифрованием соединении, при этом поддерживается три режима работы:
1. Open LDAP, TCP:389 - передача данных в открытом виде.
2. LDAP with StartTLS, TCP:389 - включение шифрования данных по требованию клиента.
3. LDAPS with SSL/TLS, TCP:636 - обязательное шифрование передаваемых данных.
2. LDAP with StartTLS, TCP:389 - включение шифрования данных по требованию клиента.
3. LDAPS with SSL/TLS, TCP:636 - обязательное шифрование передаваемых данных.
Таким образом, при подключении к LDAP-сервису клиент может выбрать, насколько защищённое соединение ему устанавливать, в зависимости от секретности задачи.
Зачем применять шифрование клиентских соединения при работе с LDAP, внутри которого пользовательские пароли хранятся в виде "хешей"? На удивление многие считают, что если пароль на стороне сервера "хеширован", то и на этапе аутентификации при подключении он не будет раскрыт. Налицо отсутствие причинно-следственной связи, но не всем это понятно без демонстрации доказательств.
Посмотрим, что можно выловить из сетевых пакетов простейшего запроса выборки атрибутов одной записи, с предварительной аутентификацией, разумеется:
$ ldapsearch -x -v -H ldap://ldap0.example.net -D "uid=userOne,ou=People,dc=example,dc=net" -w password -b uid=userOne,ou=People,dc=example,dc=net
На компьютере, откуда исходят запросы (это непринципиально - трафик можно прослушивать и на транзитных узлах), запускаем "tcpdump":
# tcpdump -nn -A -q -l -i eth0 dst ldap0.example.net && port 389
....
...&uid=userOne,ou=People,dc=example,dc=net..password
....
...&uid=userOne,ou=People,dc=example,dc=net..password
....
В аналогичных условиях запускаем "tshark" (более умелая утилита - "terminal-based Wireshark" - способная структурировать трафик по патернам, в нашем случае LDAP):
# tshark -i vnet0 -f "dst ldap0.example.net && port 389" -n -O ldap -Y "ldap.protocolOp == 0"
....
Transmission Control Protocol, Src Port: 57418, Dst Port: 389, Seq: 1, Ack: 1, Len: 56
Lightweight Directory Access Protocol
LDAPMessage bindRequest(1) "uid=userOne,ou=People,dc=example,dc=net" simple
messageID: 1
protocolOp: bindRequest (0)
bindRequest
version: 3
name: uid=userOne,ou=People,dc=example,dc=net
authentication: simple (0)
simple: password
Transmission Control Protocol, Src Port: 57418, Dst Port: 389, Seq: 1, Ack: 1, Len: 56
Lightweight Directory Access Protocol
LDAPMessage bindRequest(1) "uid=userOne,ou=People,dc=example,dc=net" simple
messageID: 1
protocolOp: bindRequest (0)
bindRequest
version: 3
name: uid=userOne,ou=People,dc=example,dc=net
authentication: simple (0)
simple: password
Очевидно, что "простой (simple)" метод аутентификации LDAP без инкапсуляции в SSL/TLS должен стать запретным для всех областей применения, кроме демонстрации возможностей на тестовом стенде.
Считаю разумным вообще запретить подключения к LDAP-сервису извне по незащищённому протоколу LDAP, что мы и сделаем в дальнейшем, после настройки SSL/TLS для серверов "389-AS/DS".
Последовательность дальнейших действий такова:
1. Генерируем сертификаты.
2. Настраиваем LDAPS для "389-DS".
3. Методика возврата к предыдущим настройкам "389-DS".
4. Проверка работы клиента с "389-DS" через SSL/TLS.
5. Настраиваем SSL/TLS для "389-AS".
6. Методика возврата к предыдущим настройкам "389-AS".
7. Деактивируем поддержку устаревшего SSLv3.
8. Опционально переводим "389-AS/DS" на IPv4.
9. Закрываем доступ извне к незащищённому LDAP.
2. Настраиваем LDAPS для "389-DS".
3. Методика возврата к предыдущим настройкам "389-DS".
4. Проверка работы клиента с "389-DS" через SSL/TLS.
5. Настраиваем SSL/TLS для "389-AS".
6. Методика возврата к предыдущим настройкам "389-AS".
7. Деактивируем поддержку устаревшего SSLv3.
8. Опционально переводим "389-AS/DS" на IPv4.
9. Закрываем доступ извне к незащищённому LDAP.
Генерируем сертификаты.
В качестве SSL-сертификата в "389-AS/DS" применяется классический "x509". Можно попробовать использовать обычный SSL-сертификат, вроде тех, которыми обеспечивают HTTPS для web-сайтов. Можно воспользоваться инфраструктурой локального удостоверяющего (сертификационного) центра, если таковой на предприятии уже функционирует, и создать для LDAP-сервиса сертификат, подписанный всей цепочкой доверенных узлов. А можно создать и применить "самоподписанный" сертификат, особенно если сервис не публичный, предприятие небольшое и блюсти красоту нет необходимости или возможности.
Воспользуемся документацией от разработчиков: для "RHDS" и для "FDS" (немного старого).
Следуя правильным путём, мы бы средствами "389-DS" сформировали запрос на выпуск сертификата для целевого LDAP-инстанса, отправили его в центр сертификации предприятия, получили в ответ готовый сертификат и уже его импортировали в "NSS-базу сертификатов" LDAP-инстанса.
Но мы здесь разбираем вариант с применением "самоподписанного" корневого сертификата, так что просто создаём его, потом создаём подписанные им сертификаты компонентов и размещаем их NSS-хранилищах.
Заготовим место в файловой системе условно основного LDAP-сервера, где будем создавать и хранить сертификаты всех участников схемы:
# mkdir -p /etc/ssl/dirsrv
# cd /etc/ssl/dirsrv
# cd /etc/ssl/dirsrv
Заготовим файл с "цифровым шумом", который потребуется в полуавтоматизированных процедурах создания сертификатов:
# openssl rand -out /root/.rnd -hex 256
Создаём закрытую и открытую часть корневого сертификата ("самоподписанного"):
# openssl req \
-subj "/C=RU/ST=State/L=City/O=Example, Inc./OU=IT/CN=Self-Signed Root CA certificat" \
-newkey rsa:4096 -nodes -keyout ./ss-rootCA.key \
-x509 -days 3650 -out ./ss-rootCA.crt
-subj "/C=RU/ST=State/L=City/O=Example, Inc./OU=IT/CN=Self-Signed Root CA certificat" \
-newkey rsa:4096 -nodes -keyout ./ss-rootCA.key \
-x509 -days 3650 -out ./ss-rootCA.crt
Теперь мы располагаем двумя частями "самоподписанного" корневого сертификата: публичной "ss-rootCA.crt" и секретной "ss-rootCA.key", используемой только для подписания других сертификатов.
Далее создаём простейший сертификат для LDAP-инстанса, заверяя его "самоподписанным" корневым сертификатом (в три этапа, с "закрытым" ключём, CSR-запросом, и затем подписанным сертификатом):
# openssl genrsa -out ./ldap0.example.net.key 4096
# openssl req -new \
-subj "/OU=389 Administration\/Directory Server/CN=ldap0.example.net" \
-key ./ldap0.example.net.key \
-out ./ldap0.example.net.csr
# openssl x509 -req \
-in ./ldap0.example.net.csr \
-CA ./ss-rootCA.crt -CAkey ./ss-rootCA.key -CAcreateserial \
-days 3650 -out ./ldap0.example.net.crt
# openssl req -new \
-subj "/OU=389 Administration\/Directory Server/CN=ldap0.example.net" \
-key ./ldap0.example.net.key \
-out ./ldap0.example.net.csr
# openssl x509 -req \
-in ./ldap0.example.net.csr \
-CA ./ss-rootCA.crt -CAkey ./ss-rootCA.key -CAcreateserial \
-days 3650 -out ./ldap0.example.net.crt
Просмотр содержимого сертификата - всех трёх его компонентов:
# openssl rsa -noout -text -in ./ldap0.example,net.key | less
# openssl req -noout -text -in ./ldap0.example.net.csr | less
# openssl x509 -noout -text -in ./ldap0.example.net.crt | less
# openssl req -noout -text -in ./ldap0.example.net.csr | less
# openssl x509 -noout -text -in ./ldap0.example.net.crt | less
Компонуем приватную и публичную части сертификата в PFX-контейнер - в таком виде они удобнее импортируются впоследствии в NSS-хранилище LDAP-инстанса (конечно же, не забываем пароль, которым будет защищён контейнер с сертифкатом):
# openssl pkcs12 -export -name "(AS/DS) ldap0.example,net" -out ./ldap0.example.net.p12 -inkey ./ldap0.example.net.key -in ./ldap0.example.net.crt
Очевидно, что такие наборы из "приватного" ключа, CSR-запроса, итогового сертификата и PXF-контейнера нужно создать для всех LDAP-инстансов и серверов администрирования настраиваемой схемы, запускаемых на отдельных сетевых узлах.
Обращаю внимание на то, что все наборы сертификатов, подписываемых одним корневым сертификатом, очень желательно генерировать в одном месте, например выделенном для хранения "приватного" ключа корневого сертификата. Дело в том, что при каждом создании и подписании нового сертификата в рабочей директории создаётся и обновляется файл "ss-rootCA.srl", содержащий случайный набор символов с присоединённым в конце шестнадцатеричным порядковым номером очередного сертификата (простая последовательность: 01,02,03,...). Так вот, если генерировать и подписывать сертификаты в разных местах, то у них могут оказаться одинаковые номера, что впоследствии будет замечено чутким клиентским приложением, которое откажется принимать такие сертификаты.
# chown -R root:root /etc/ssl/dirsrv
# chmod -R go-rwx /etc/ssl/dirsrv
# chmod -R go-rwx /etc/ssl/dirsrv
Настраиваем LDAPS для "389-DS".
Теперь настроим поддержку SSL/TLS LDAP-инстанса. Его "база сертификатов" располагается в файловой директории с настройками "/etc/dirsrv/slapd-ldap0-example-net".
Для простоты и краткости дальнейших команд переходим в директорию конфигурации LDAP-инстанса и будем работать уже там:
# cd /etc/dirsrv/slapd-ldap0-example-net
Первым делом есть смысл запросить посредством утилиты "certutil" из набора "libnss3" перечень возможно уже имеющихся сертификатов:
# certutil -d . -L
Если LDAP-сервис свежеустановленный, то "NSS-база сертификатов" для него отсутствует или неактивированна. Создадим зашифрованное и защищённое отдельным паролем (не забываем его) хранилище SSL-сертификатов (файлы "key3.db", "cert8.db" & "secmod.db"):
# certutil -d . -N
В процессе создания "NSS-базы сертификатов" задаётся пароль доступа к таковой. В дальнейшем потребуется вводить этот пароль для доступа к хранилищу сертификатов и это доставит некоторые неудобства - дело в том, что даже сам сервер "389-DS" не сможет запуститься без процедуры ввода пароля для доступа к SSL/TLS-сертификатам, которыми он должен шифровать соединения клиентов - в дальнейшем ещё придётся обходить это ограничение, а пока будим вводить пароль вручную.
Сразу импортируем публичную часть корневого сертификата (он у нас "самоподписанный") в NSS-хранилище, объявив его доверенным узлом - удостоверяющим центром (это важная для сетевой связности участников схемы репликации процедура, хотя SSL-сервис запустится и без неё):
# certutil -A -d . -n "Self-Signed Root CA certificat" -t "CT,," -a -i /etc/ssl/dirsrv/ss-rootCA.crt
Импортируем заготовленный ранее контейнер с "приватной" и публичной частями сертификата LDAP-инстанса:
# pk12util -d . -n "(AS/DS) ldap0.example,net" -i /etc/ssl/dirsrv/ldap0.example.net.p12
Ненужные сертификаты легко удалить, указав в качестве идентификатора их наименование:
# certutil -D -d . -n "Instance certificate"
После создания сертификатов включаем функционал поддержки шифрования клиентских соединений:
В GUI "389 Console" это выглядит так:
DS Console -> Configuration -> "ldap0.example.net" -> Encryption:
Enable SSL for this server: on
Use this cipher family RSA
Security Device: internal
Certificate: (AS/DS) ldap0.example.net
Client Authentication:
# Перед нами не стоит задача аутентификации клиентов посредством сертификатов (мы только защищаем трафик шифрованием), потому явно отключаем это функционал.
Do not allow client authentication
# (до перевода на SSL сервера "389-AS" нет смысла переключать на SSL GUI-утилиту "389-console")
Use SSL in Console: off
Save.
Enable SSL for this server: on
Use this cipher family RSA
Security Device: internal
Certificate: (AS/DS) ldap0.example.net
Client Authentication:
# Перед нами не стоит задача аутентификации клиентов посредством сертификатов (мы только защищаем трафик шифрованием), потому явно отключаем это функционал.
Do not allow client authentication
# (до перевода на SSL сервера "389-AS" нет смысла переключать на SSL GUI-утилиту "389-console")
Use SSL in Console: off
Save.
На этом настройка поддержки SSL/TLS-шифрования для "389-DS" завершена и нужно будет перезагрузить LDAP-инстанс. Вот здесь в полной мере проявится неудобство от обязательной защиты "NSS-базы сертификатов" паролем, который вводится только интерактивно - при запуске сервер "389-DS" обратится к сервису хранилища сертификатов, который запросит посредством метода "tty-ask-password" ввести пароль:
....
Please enter password with the systemd-tty-ask-password-agent tool!
Enter PIN for Internal (Software) Token: ***
Please enter password with the systemd-tty-ask-password-agent tool!
Enter PIN for Internal (Software) Token: ***
Не вдаваясь в детали реализации, сразу приведу решение автоматизации. Используемый для запроса пароля сервис "systemd-tty-ask-password-agent" принимает таковой их простого текстового файла с зарезервированным именем "pin.txt", размещаемого в одной директории с целевой "NSS-базой":
# vi /etc/dirsrv/slapd-ldap0-example-net/pin.txt
Internal (Software) Token:<passoword>
Обращаю внимание - текстовая конструкция в примере выше должна быть такой с точностью до символа, а между двоеточием и паролем пробелы недопустимы.
Разумеется, файл с паролем закрываем от посторонних:
# chown dirsrv:dirsrv /etc/dirsrv/slapd-ldap0-example-net/pin.txt
# chmod go-rwx /etc/dirsrv/slapd-ldap0-example-net/pin.txt
# chmod go-rwx /etc/dirsrv/slapd-ldap0-example-net/pin.txt
Теперь можно перезапускать LDAP-инстанс:
# stop-dirsrv ldap0-example-net && start-dirsrv ldap0-example-net
Проверяем, прослушивает ли сервис теперь и TCP:636 - порт для SSL/TLS-соединений:
# netstat -apn | grep -i "^tcp" | grep -i listen | grep -i "ns-slapd"
tcp ... 0.0.0.0:636 0.0.0.0:* LISTEN .../ns-slapd
tcp ... 0.0.0.0:389 0.0.0.0:* LISTEN .../ns-slapd
tcp ... 0.0.0.0:389 0.0.0.0:* LISTEN .../ns-slapd
После настройки функционала поддержки SSL/TLS-шифрования также станет возможна аутентификация пользователей посредством выдаваемых им индивидуальных SSL-сертификатов, но это необязательный функционал - главное, чего мы сейчас добиваемся, так это защита клиент-серверного трафика от прослушивания посторонними.
Методика возврата к предыдущим настройкам "389-DS".
Если что-то пошло не так, и потребуется быстро отключить поддержку SSL/TLS в "389-DS":
$ ldapmodify -h 127.0.0.1 -p 389 -D "cn=Directory Manager" -W
dn: cn=config
changetype: modify
replace: nsslapd-security
nsslapd-security: off
dn: cn=RSA,cn=encryption,cn=config
changetype: modify
replace: nsSSLActivation
nsSSLActivation: off
^d
changetype: modify
replace: nsslapd-security
nsslapd-security: off
dn: cn=RSA,cn=encryption,cn=config
changetype: modify
replace: nsSSLActivation
nsSSLActivation: off
^d
# stop-dirsrv ldap0-example-net && start-dirsrv ldap0-example-net
Проверка работы клиента с "389-DS" через SSL/TLS.
Легко проверить, готов ли LDAP-сервер принимать SSL/TLS-соединения.
Пробуем соединиться через порт для LDAP, поддерживающий "StartTLS":
$ echo QUIT | openssl s_client -starttls ldap -connect ldap0.example.net:389 | less
Пробуем соединиться и запросить сертификат через выделенный только для SSL-порт:
$ echo QUIT | openssl s_client -connect ldap0.example.net:636 | openssl x509 -noout -text | less
$ echo QUIT | openssl s_client -connect ldap0.example.net:636 | less
$ echo QUIT | openssl s_client -connect ldap0.example.net:636 | less
CONNECTED(00000005)
depth=1 CN = Self-Signed Root CA cert
verify error:num=19:self signed certificate in certificate chain
....
depth=1 CN = Self-Signed Root CA cert
verify error:num=19:self signed certificate in certificate chain
....
В журнале событий LDAP-сервера будут фиксироваться эти попытки, с указанием протокола шифрования.
В сообщениях утилиты "openssl" выше было видно, что проверить действительность сертификата невозможно, так как он "самоподписанный". Из-за этого большинство приложений не будут подключаться к LDAP-серверу без явного указания игнорировать результаты проверки подлинности сертификата:
$ ldapsearch -x -v -H ldaps://ldap0.example.net -D "uid=app0,ou=Services,dc=example,dc=net" -W -b uid=userOne,ou=People,dc=example,dc=net
ldap_initialize( ldaps://ldap0.example.net:636/??base )
Enter LDAP Password:
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
Enter LDAP Password:
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
Тот же принцип и для соединения через порт TCP:389, предназначенный для открытой передачи данных, с запросом шифрования посредством "StartTLS" - использование "самоподписанного" сертификата по умолчанию недопустимо:
$ ldapsearch -x -v -ZZ -H ldap://ldap0.example.net -D "uid=app0,ou=Services,dc=example,dc=net" -W -b uid=userOne,ou=People,dc=example,dc=net
ldap_initialize( ldap://ldap0.example.net:389/??base )
ldap_start_tls: Connect error (-11)
additional info: (unknown error code)
ldap_start_tls: Connect error (-11)
additional info: (unknown error code)
Выяснить, что конкретно не срабатывает при подключении к LDAP-серверу, помогает включение режима отладки (ключ "-d") - в данном случае видно, что клиентское приложение не может проверить валидность цепи доверия сертификатов:
$ ldapsearch -d 1 -x -v -H ldaps://ldap0.example.net -D "uid=app0,ou=Services,dc=example,dc=net" -W -b uid=userOne,ou=People,dc=example,dc=net
....
ldap_initialize( ldaps://ldap0.example.net:636/??base )
....
connect success
....
TLS: peer cert untrusted or revoked (0x42)
TLS: can't connect: (unknown error code).
....
ldap_initialize( ldaps://ldap0.example.net:636/??base )
....
connect success
....
TLS: peer cert untrusted or revoked (0x42)
TLS: can't connect: (unknown error code).
....
Специальным параметром, передаваемым здесь в переменной окружения, укажем утилите "ldapsearch" не запрашивать проверку валидности SSL/TLS-сертификата сервера:
$ LDAPTLS_REQCERT=allow ldapsearch -x -v -H ldaps://ldap0.example.net -D "uid=app0,ou=Services,dc=example,dc=net" -W -b uid=userOne,ou=People,dc=example,dc=net
Теперь соединение должно пройти успешно.
Настраиваем LDAPS для "389-AS".
Настройка поддержки SSL для сервера администрирования "389-AS" во многом аналогична тому, как это делается для LDAP-инстанса, с той только разницей, что в итоге "389-AS" полностью переключается на SSL/TLS.
Переходим в директорию с конфигурацией сервера администрирования, проверяем наличие возможно имеющихся сертификатов и опционально создаём хранилище сертификатов (если оно не инициализировано ранее):
# cd /etc/dirsrv/admin-serv
# certutil -d . -L
# certutil -d . -N
# certutil -d . -L
# certutil -d . -N
Сразу импортируем публичную часть корневого сертификата (он у нас "самоподписанный") в NSS-хранилище, объявив его доверенным узлом - удостоверяющим центром (это очень важная для сетевой связности участников схемы администрирования процедура):
# certutil -A -d . -n "Self-Signed Root CA certificat" -t "CT,," -a -i /etc/ssl/dirsrv/ss-rootCA.crt
Импортируем заготовленный ранее контейнер с "приватной" и публичной частями сертификата LDAP-инстанса (если FQDN сервисов "389-DS" и "389-AS" одинаковый, то и сертификат можно использовать один и тот же):
# pk12util -d . -n "(AS/DS) ldap0.example.net" -i /etc/ssl/dirsrv/ldap0.example.net.p12
В GUI "389 Console" в обязательном порядке сразу указываем, что к хранилищу конфигурации сервера администрирования теперь нужно подключаться с использованием SSL (важно понимать, что сервер администрирования "389-AS" хранит свою конфигурацию в одном из инстансов "389-DS" - а ранее мы его уже перевели на SSL):
DS Console -> Configuration -> Administration Server -> Configuration DS:
LDAP Host: ldap0.example.net
LDAP Port: 636
Secure Connection: on
Save.
LDAP Host: ldap0.example.net
LDAP Port: 636
Secure Connection: on
Save.
В GUI "389 Console" указываем, что к основному управляемому LDAP-инстансу "389-DS" теперь нужно подключаться с использованием SSL (ранее мы его перевели на SSL):
DS Console -> Configuration -> Administration Server -> User DS:
Set User Directory:
LDAP Host and Port: ldap0.example.net:636
Secure Connection: on
User Directory Subtree: dc=example,dc=net
Bind DN: cn=Directory Manager
Bind Password: ***
Save.
Set User Directory:
LDAP Host and Port: ldap0.example.net:636
Secure Connection: on
User Directory Subtree: dc=example,dc=net
Bind DN: cn=Directory Manager
Bind Password: ***
Save.
В GUI "389 Console" включаем шифрование соединений к самому серверу администрирования:
DS Console -> Configuration -> Administration Server -> Encryption:
Enable SSL for this server: on
Use this cipher family RSA
Security Device: internal
Certificate: (AS/DS) ldap0.example.net
Disable Client Authentication
Save.
Enable SSL for this server: on
Use this cipher family RSA
Security Device: internal
Certificate: (AS/DS) ldap0.example.net
Disable Client Authentication
Save.
В GUI "389 Console" переключаем соединения от этой самой консоли на SSL:
DS Console -> Configuration -> "ldap0.example.net" -> Encryption:
Enable SSL for this server: on
....
Use SSL in Console: on
Save.
Enable SSL for this server: on
....
Use SSL in Console: on
Save.
В процессе включения LDAPS для "389-DS" я уже упоминал о "хитром скоке", которым мы сообщаем сервису пароль для доступа к его же NSS-базе сертификатов. Так вот у сервиса "389-AS" подход примерно такой же.
В конфигурационном файле NSS-подсистемы указываем не запрашивать пароль интерактивно, а считывать его из текстового файла:
# vi /etc/dirsrv/admin-serv/nss.conf
....
#Pass Phrase Dialog:
NSSPassPhraseDialog file://etc/dirsrv/admin-serv/pin.txt
....
#Pass Phrase Dialog:
NSSPassPhraseDialog file://etc/dirsrv/admin-serv/pin.txt
....
Пароль к NSS-базе сертификатов указываем в текстовом файле (посимвольно следуем примеру, без кавычек, не допуская между двоеточием и паролем пробелов):
# vi /etc/dirsrv/admin-serv/pin.txt
internal (software):<password>
Файл с паролем закрываем от доступа посторонних:
# chown dirsrv:dirsrv /etc/dirsrv/admin-serv/pin.txt
# chmod go-rwx /etc/dirsrv/admin-serv/pin.txt
# chmod go-rwx /etc/dirsrv/admin-serv/pin.txt
Несмотря на то, что в GUI "389 Console" мы включили режим шифрования соединений сервера администрирования, в ряде случаев в конфигурационном файле сервиса, принимающего запросы, оказывается не указан перечень допустимых SSL-протоколов, без которого сервис не стартует - исправляем это:
# vi /etc/dirsrv/admin-serv/console.conf
....
NSSProtocol TLSv1.0,TLSv1.1,TLSv1.2
....
NSSProtocol TLSv1.0,TLSv1.1,TLSv1.2
....
Так же будет полезно помочь web-серверу определиться, на каком FQDN ему принимать запросы:
# vi /etc/dirsrv/admin-serv/httpd.conf
....
ServerName ldap0.example.net:9830
....
ServerName ldap0.example.net:9830
....
Теперь последовательно перезапускаем "389-DS" и "389-AS":
# stop-ds-admin
# stop-dirsrv ldap0-example-net && start-dirsrv ldap0-example-net
# start-ds-admin
# stop-dirsrv ldap0-example-net && start-dirsrv ldap0-example-net
# start-ds-admin
Как минимум, для начала, сервис должен прослушивать один TCP-порт - всё тот же, что раньше без шифрования - теперь он принимает только SSL/TLS-запросы:
# netstat -apn | grep -i "^tcp" | grep -i listen | grep -i "apache"
Проверка должна показать, что "389-AS" принимает соединения с новым сертификатом:
$ echo QUIT | openssl s_client -connect ldap0.example.net:9830 | openssl x509 -noout -text | less
Теперь подключение к серверу администрирования возможны только через HTTPS (например с URL "https://ldap0.example.net:9830") - как в очень скромном web-интерфейсе "389 Administration Express", так и через "389 Console".
Методика возврата к предыдущим настройкам "389-AS".
При анализе проблем подключения к серверу администрирования "389-AS" прежде всего стоит обратить внимание на поведение используемой для этого GUI-утилиты "389 Console".
Включите прослушивание трафика между клиентом и сервером, на порту TCP:8930 - иногда, в то время, как утилита "389-console" заявляет о невозможности подключения к серверу, сведений о посылаемых пакетах нет - то есть это java-приложение сбоит само себе внутри и сервер тут не при чём.
Стоит помнить о возможности запустить "389-console" в режиме отладки с ключём "-D 9", что даст возможность изучить её внутренний мир и понять, в какую сторону копать дальше. На практике утилита удивляет капризами и тому будет посвящена отдельная публикация.
Если что-то пошло совсем не так, то следующими шагами возвращаем "389-AS" к работе на незащищённом HTTP.
Обязательно останавливаем сервер администрирования:
# stop-ds-admin
Параметрами с говорящими именами отключаем поддержку SSL/TLS в конфигурационном файле сервиса:
# vi /etc/dirsrv/admin-serv/local.conf
....
configuration.nsAdminAccessHosts: *
....
configuration.nsServerSecurity: off
....
configuration.encryption.RSA.nsSSLActivation: off
....
configuration.nsAdminAccessHosts: *
....
configuration.nsServerSecurity: off
....
configuration.encryption.RSA.nsSSLActivation: off
....
Указываем "389-AS" не обращаться к NSS-базе сертификатов:
# vi /etc/dirsrv/admin-serv/console.conf
....
NSSEngine off
....
NSSEngine off
....
Ищем, где точно располагаются опции конфигурирования сервера администрирования в иерархии LDAP-сервиса:
$ ldapsearch -x -LLL -h 127.0.0.1 -D "cn=Directory Manager" -W -b "o=NetscapeRoot" "(objectclass=nsAdminConfig)" dn
dn: cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
Деактивируем ограничения по доступу и поддержку SSL/TLS для "389-AS":
$ ldapmodify -h 127.0.0.1 -D "cn=Directory Manager" -W
dn: cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: nsAdminAccessHosts
nsAdminAccessHosts: *
dn: cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: nsServerSecurity
nsServerSecurity: off
^d
changetype: modify
replace: nsAdminAccessHosts
nsAdminAccessHosts: *
dn: cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: nsServerSecurity
nsServerSecurity: off
^d
Запускаем сервер администрирования:
# start-ds-admin
Деактивируем поддержку устаревшего SSLv3.
В "Linux Ubuntu 18 LTS" случилось так, что из применяемого в ней современного "OpenSSL" уже вырезана поддержка "SSLv3", а компоненты "389-AS/DS" ещё пытаются этот метод шифрования использовать, засыпая журнал событий предупреждениями о невозможности активировать часть функционала.
Есть смысл явно отключить во всех компонентах "389-AS/DS" устаревший протокол "SSLv3" и указать, какие впредь следует использовать:
# vi /etc/dirsrv/admin-serv/local.conf
....
configuration.encryption.nsSSL3: off
....
configuration.encryption.nsSSL3: off
....
# vi /etc/dirsrv/admin-serv/adm.conf
....
sslVersionMin: TLS1.0
sslVersionMax: TLS1.1
sslVersionMin: TLS1.0
sslVersionMax: TLS1.1
$ ldapmodify -h 127.0.0.1 -D "cn=Directory Manager" -W
dn: cn=encryption,cn=config
changetype: modify
replace: nsSSL3
nsSSL3: off
dn: cn=encryption,cn=config
changetype: modify
replace: nsTLS1
nsTLS1: on
dn: cn=encryption,cn=config
changetype: modify
replace: sslVersionMin
sslVersionMin: TLS1.0
dn: cn=encryption,cn=config
changetype: modify
replace: sslVersionMax
sslVersionMax: TLS1.2
^d
changetype: modify
replace: nsSSL3
nsSSL3: off
dn: cn=encryption,cn=config
changetype: modify
replace: nsTLS1
nsTLS1: on
dn: cn=encryption,cn=config
changetype: modify
replace: sslVersionMin
sslVersionMin: TLS1.0
dn: cn=encryption,cn=config
changetype: modify
replace: sslVersionMax
sslVersionMax: TLS1.2
^d
$ ldapmodify -h 127.0.0.1 -D "cn=Directory Manager" -W
dn: cn=encryption,cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: nsSSL3
nsSSL3: off
dn: cn=encryption,cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: nsTLS1
nsTLS1: on
dn: cn=encryption,cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: sslVersionMin
sslVersionMin: TLS1.0
dn: cn=encryption,cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: sslVersionMax
sslVersionMax: TLS1.2
^d
changetype: modify
replace: nsSSL3
nsSSL3: off
dn: cn=encryption,cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: nsTLS1
nsTLS1: on
dn: cn=encryption,cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: sslVersionMin
sslVersionMin: TLS1.0
dn: cn=encryption,cn=configuration,cn=admin-serv-ldap0,cn=389 Administration Server,cn=Server Group,cn=ldap0.example.net,ou=local,o=NetscapeRoot
changetype: modify
replace: sslVersionMax
sslVersionMax: TLS1.2
^d
# stop-ds-admin
# stop-dirsrv ldap0-example-net && start-dirsrv ldap0-example-net
# start-ds-admin
# stop-dirsrv ldap0-example-net && start-dirsrv ldap0-example-net
# start-ds-admin
Опрос сетевым сканером покажет, что сервер отвечает только современным методам шифрования:
$ nmap --script ssl-enum-ciphers -p 9830 ldap0.example.net
....
| ssl-enum-ciphers:
| TLSv1.0:
....
| TLSv1.1:
....
| TLSv1.2:
....
| ssl-enum-ciphers:
| TLSv1.0:
....
| TLSv1.1:
....
| TLSv1.2:
....
Опционально переводим "389-AS/DS" на IPv4.
По умолчанию "389-DS" запускается в режиме прослушивания IPv4 и IPv6, а "389-AS" - только IPv4. Возможны неполадки связи (например из-за отсутствия разрешения имён в DNS для IPv6), потому можно явно перевести оба сервиса на IPv4:
$ ldapmodify -h 127.0.0.1 -D "cn=Directory Manager" -W
dn: cn=config
changetype: modify
replace: nsslapd-listenhost
nsslapd-listenhost: 0.0.0.0
dn: cn=config
changetype: modify
replace: nsslapd-securelistenhost
nsslapd-securelistenhost: 0.0.0.0
^d
changetype: modify
replace: nsslapd-listenhost
nsslapd-listenhost: 0.0.0.0
dn: cn=config
changetype: modify
replace: nsslapd-securelistenhost
nsslapd-securelistenhost: 0.0.0.0
^d
# stop-ds-admin
# stop-dirsrv ldap0-example-net && start-dirsrv ldap0-example-net
# start-ds-admin
# stop-dirsrv ldap0-example-net && start-dirsrv ldap0-example-net
# start-ds-admin
# netstat -apn | grep -i "^tcp" | grep -i listen | grep -iE "(ns-slap|apache)"
tcp ... 0.0.0.0:636 0.0.0.0:* LISTEN .../ns-slapd
tcp ... 0.0.0.0:389 0.0.0.0:* LISTEN .../ns-slapd
tcp ... 0.0.0.0:9830 0.0.0.0:* LISTEN .../apache2
tcp ... 0.0.0.0:389 0.0.0.0:* LISTEN .../ns-slapd
tcp ... 0.0.0.0:9830 0.0.0.0:* LISTEN .../apache2
Закрываем доступ извне к незащищённому LDAP.
В отличии от "OpenLDAP" в конфигурации "389-AS/DS" нет возможности указать комбинации вариантов, откуда и кому разрешены подключения к тому или иному порту. Можно лишь включить или полностью выключить обслуживание запросов клиентов на сетевом порту.
Следуя жёсткому курсу недопущения утечки конфиденциальных данных надо бы вообще выключить незащищённый LDAP-сервис, оставив только LDAPS - но с "самоподписанными" сертификатами это может вызвать проблемы связности компонентов, а потому лучше оставить себе возможность оперативно разрешить соединения без шифрования хотя бы на локальной сетевой петле.
В итоге, проще всего запретить не-SSL доступ снаружи средствами сетевого защитного экрана несущей операционной системы:
# iptables -t filter -L INPUT -n -v --line-numbers
# iptables -A INPUT -p TCP --dport 389 -j REJECT -m comment --comment "Forbidden connect to insecure LDAP"
# iptables -A INPUT -p TCP --dport 389 -j REJECT -m comment --comment "Forbidden connect to insecure LDAP"
Опционально можно организовать подключение к закрытому небезопасному порту для внутренних сервисов (только через локальную сетевую петлю, например), добавлением разрешительного правила непосредственно перед запретительным:
# iptables -I INPUT 1 -i lo -p TCP --dport 389 -j ACCEPT -m comment --comment "Allow use insecure LDAP only from localhost"
При необходимости правила легко избирательно удалить:
# iptables -t filter -L INPUT -n -v --line-numbers
# iptables -D INPUT 1
# iptables -D INPUT 1
Устанавливаем сервис для автоматического сохранения правил "iptables" и применения таковых при запуске операционной системы:
# aptitude install iptables-persistent
Сохраняем текущее состояние конфигурации "сетевого фильтра":
# netfilter-persistent save
Как вариант, правила можно сохранить утилитой из дистрибутивного набора "iptables" (подобным образом можно наладить их активацию при запуске системы, но это уже ручная работа):
# iptables-save > /etc/iptables/rules.v4