3. Настройка TLS (Transport Layer Security)

В наши дни использование TLS является практически обязательным. TLS реализует защитные функции конфиденциальности и целостности данных, а так же служит для поддержки аутентификации LDAP с использованием механизма SASL EXTERNAL. TLS определён в RFC4346.

Для настройки TLS на сервере нам понадобятся SSL сертификат и ключ. Сертификат должен быть подписан доверенным удостоверяющим центром (УЦ, Certificate Authority, CA) или собственным удостоверяющим центром (на основе «самоподписанного», self-signed, сертификата), если используется в тестовых целях.

С помощью OpenSSL мы создадим импровизированный удостоверяющий центр и затем настроим TLS.

Прямая цитата из Википедии:

Сертификаты, как правило, используются для обмена зашифрованными данными в больших сетях. Криптосистема с открытым ключом решает проблему обмена секретными ключами между участниками безопасного обмена, однако не решает проблему доверия к открытым ключам. Предположим, что Алиса, желая получать зашифрованные сообщения, генерирует пару ключей, один из которых (открытый) она публикует каким-либо образом. Любой, кто желает отправить ей конфиденциальное сообщение, имеет возможность зашифровать его этим ключом, и быть уверенным, что только она (так как только она обладает соответствующим секретным ключом) сможет это сообщение прочесть. Однако описанная схема ничем не может помешать злоумышленнику Давиду создать пару ключей, и опубликовать свой открытый ключ, выдав его за ключ Алисы. В таком случае Давид сможет расшифровывать и читать, по крайней мере, ту часть сообщений, предназначенных Алисе, которые были по ошибке зашифрованы его открытым ключом.

Идея сертификата — это наличие третьей стороны, которой доверяют две другие стороны информационного обмена. Предполагается, что таких третьих сторон немного, и их открытые ключи всем известны каким-либо способом, например, хранятся в операционной системе или публикуются в журналах. Таким образом, подлог открытого ключа третьей стороны легко выявляется.

Если Алиса сформирует сертификат со своим публичным ключом, и этот сертификат будет подписан третьей стороной (например, Трентом), любой, доверяющий Тренту, сможет удостовериться в подлинности открытого ключа Алисы. В централизованной инфраструктуре в роли Трента выступает удостоверяющий центр. В сетях доверия Трент может быть любым пользователем, и следует ли доверять этому пользователю, удостоверившему ключ Алисы, решает сам отправитель сообщения.

3.1 Удостоверяющий центр на основе самоподписанного сертификата с помощью OpenSSL

Где работаем: ldap-srv

Итак, мы создаём централизованную инфраструктуру открытых ключей (PKI) в миниатюре. Для этого сформируем пару закрытый ключ/корневой сертификат удостоверяющего центра. Причём сертификат будет подписан этим же закрытым ключом (т. е. станет «самоподписанным»).

Затем сгенерируем новый закрытый ключ для нашей службы каталогов и создадим для неё сертификат, подписанный закрытым ключом нашего удостоверяющего центра. При этом клиенские рабочие станции должны знать только корневой сертификат. Используя его они могут установить безопасное соединение с любым сервером, который имеет закрытый ключ и соответствующий ему сертификат, подписанный нашим УЦ.

Такие пары (ключ/сертификат) можно создавать для множества задач. Например, в разделе, посвященном репликации, мы создадим второй сервер каталогов, которому тоже понадобится такая пара.

Удостоверяющий центр желательно разворачивать на отдельной машине, не имеющей подключения к сети, но для простоты примера мы проделаем всю работу на ldap-srv.example.com.

Создадим каталог для нашего удостоверяющего центра (CA) и установим безопасные права доступа. Затем зададим значение umask таким, чтобы вновь создаваемые файлы имели права доступа чтения и записи только для создавшего их пользователя:

#  mkdir /root/CA
#  chmod u=rwx,g=,o= /root/CA
#  cd /root/CA
#  umask 066

В конфигурационном файле /etc/ssl/openssl.cnf в секции [ CA_default ] для удобства поменяем значение директивы dir = ./demoCA на dir = ./. В этом же разделе директивой default_days задаётся срок действия выпускаемых сертификатов. Можете поменять её значение по своему усмотрению.

Файлы index.txt и serial будут играть роль своеобразной базы данных, чтобы отслеживать статус выпущенных закрытых ключей и сертификатов.

Создадим структуру каталогов и файлов для своего удостоверяющего центра:

#  mkdir certs crl newcerts private
#  chmod 700 private
#  touch index.txt
#  echo 1000 > serial

Сгенерируем закрытый ключ удостоверяющего центра (длиной 4096 бит). Он должен хранится особенно бережно. Поэтому мы защитим его при помощи шифра AES. Вам будет предложено ввести пароль для доступа к новому закрытому ключу. Запомните его и не потеряйте. Это последний рубеж защиты от злоумышленника. Без пароля выпустить новые сертификаты не получится.

#  openssl genrsa -aes256 -out private/rootca.key 4096

Изменим права доступа к новому ключу, чтобы ненароком его не стереть:

#  chmod 400 private/rootca.key

Откройте конфигурационный файл OpenSSL (openssl.cnf) и найдите секции [ usr_cert ] и [ v3_ca ]. Убедитесь, что в них присутствуют следующие директивы:

[ usr_cert ]
# Эти расширения будут добавлены при подписывании запроса нашим УЦ.
basicConstraints=CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

[ v3_ca ]
# Расширения для типового УЦ
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = CA:true
keyUsage = cRLSign, keyCertSign

Сейчас мы можем выпустить корневой сертификат удостоверяющего центра, подписав его закрытым ключом rootca.key. Так как это сертификат УЦ, используем расширение v3_ca:

#  openssl req -sha256 -new -x509 -days 3650 -extensions v3_ca \
 -key private/rootca.key -out certs/rootca.crt \
 -subj /C=RU/ST=Moscow/L=Moscow/O=ExampleInc/OU=ITdept/CN=ca-server/emailAddress=support@example.com
#  chmod 444 certs/rootca.crt

В качестве алгоритма хэширования мы используем SHA-2 (подвид SHA-256). Стоимость атаки на SHA-1 стремительно падает, а о практическом применении новоявленного SHA-3 говорить пока рано. Почему мы выбрали именно SHA-256, а не SHA-512? С сертификатом, использующим SHA-512, Вы сможете запустить демон slapd, но не сможете к нему подключиться. Увидите лишь такую многозначную ошибку:

can't connect: A TLS packet with unexpected length was received...

Мы так же указываем количество дней, в течении которых сертификат будет действителен. Десять лет — достаточно большой срок.

С помощью модификатора subj заносим в сертификат информацию:

Можем посмотреть содержимое сертификата следующей командой:

#  openssl x509 -in certs/rootca.crt -noout -text

Удостоверяющий центр готов к выпуску сертификатов.

3.2 Выпуск сертификата для сервера службы каталогов

Где работаем: ldap-srv

Как правило, закрытые ключи клиентов УЦ не должны хранится в самом УЦ. Клиент может сам сформировать ключевую пару и прислать в УЦ лишь запрос на подпись (Certificate Signing Request, CSR). Запрос содержит открытый ключ. Однако мы будем создавать все ключи и хранить их в одном месте. В организации, которая серьёзно подходит к проблемам безопасности такой процесс работы может быть неприемлемым.

Продолжаем в том же каталоге /root/CA. Создадим закрытый ключ для сервера службы каталогов:

#  openssl genrsa -out private/ldap-srv.example.com.key 4096
#  chmod 400 private/ldap-srv.example.com.key

Сгенерируем запрос на подпись сертификата. Наименование организации (ExampleInc) должно совпадать с наименованием в корневом сертификате УЦ. В качестве Common Name укажем FQDN нашего сервера:

#  openssl req -sha256 -new \
        -key private/ldap-srv.example.com.key -out certs/ldap-srv.example.com.csr \
        -subj /C=RU/ST=Moscow/L=Moscow/O=ExampleInc/OU=ITdept/CN=ldap-srv.example.com/emailAddress=support@example.com

Следующим шагом должно быть подписание запроса CSR существующим доверенным удостоверяющим центром (например, VeriSign) в обмен на деньги. Но нам не хочется платить за эту услугу, или у нас нет своего (корпоративного) CA, или это просто тестовая конфигурация, а может нам просто всё равно. Поэтому мы подпишем его с помощью своего собственного CA:

#  openssl ca -extensions usr_cert -notext -md sha256 \
 -keyfile private/rootca.key -cert certs/rootca.crt \
 -in certs/ldap-srv.example.com.csr -out certs/ldap-srv.example.com.crt
#  chmod 444 certs/ldap-srv.example.com.crt

Создадим каталог для ключевой информации нашего сервера и поместим туда получившиеся у нас файлы:

#  mkdir /etc/ldap/ssl
#  chown openldap:openldap /etc/ldap/ssl
#  chmod 0500 /etc/ldap/ssl
#  cp certs/ldap-srv.example.com.crt private/ldap-srv.example.com.key /etc/ldap/ssl

Установим права доступа для ключевой информации:

#  chown openldap:openldap /etc/ldap/ssl/{ldap-srv.example.com.crt,ldap-srv.example.com.key}
#  chmod 0400 /etc/ldap/ssl/{ldap-srv.example.com.crt,ldap-srv.example.com.key}

Поместим корневой сертификат в каталог с сертификатами операционной системы и зададим для него права доступа:

#  cp certs/rootca.crt /etc/ssl/certs/
#  chmod 0644 /etc/ssl/certs/rootca.crt

В заключение можем удалить запрос CSR, он нам больше не нужен:

#  rm -rf certs/ldap-srv.example.com.csr

Каталог /root/CA теперь выполняет роль удостоверяющего центра. Аналогичным образом его можно создать на другой машине, тогда надо будет копировать секретные ключи и подписанные сертификаты по сети с помощью scp или через съёмный носитель. Неплохой идеей будет хранить этот каталог на отдельном носителе и монтировать его только для выпуска новых сертификатов. Сам носитель можно, например, положить в сейф. Процесс создания новых пар ключ-сертификат в будущем будет состоять из трёх этапов:

  1. Генерация секретного ключа и запроса на подписание сертификата;
  2. Подписание сертификата с помощью закрытого ключа нашего CA (rootca.key);
  3. Перемещение новых секретного ключа и подписанного сертификата в каталоги, где они будут использоваться.

3.3 Настройка конфигурации TLS

Где работаем: ldap-srv

Вернёмся во временный каталог:

$ cd ~/ldap

Создадим LDIF-файл 3.2-tls-config.ldif для внесения в каталог конфигурации TLS и запишем в него:

dn: cn=config
add: olcTLSVerifyClient
olcTLSVerifyClient: never
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/ssl/ldap-srv.example.com.crt
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap-srv.example.com.key
-
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/rootca.crt

Этими записи говорят демону slapd, где лежит его сертификат и ключ, где лежит корневой сертификат УЦ и что от клиентов требовать наличие сертификата не нужно. Чтобы окончательно всё запутать, мы могли бы создать сертификаты для всех клиентов. В реальной жизни такая аутентификация клиента принесёт небольшое усиление защиты за счёт большого увеличения работы по сопровождению всех этих сертификатов. Тем более далее в этом руководстве мы опишем механизмы аутентификации Kerberos.

Загрузим конфигурацию TLS в наш каталог:

#  ldapmodify -QY EXTERNAL -H ldapi:/// -f 3.2-tls-config.ldif
modifying entry "cn=config"

Теперь наш сервер OpenLDAP должен поддерживать расширения TLS. Перепроверим, что всё в порядке:

#  ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b cn=config -s base | grep -i tls
olcTLSCertificateFile: /etc/ldap/ssl/ldap-srv.example.com.crt
olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap-srv.example.com.key
olcTLSCACertificateFile: /etc/ssl/certs/rootca.crt
olcTLSVerifyClient: never

Вновь отредактируем конфигурационный файл /etc/ldap/ldap.conf и включим поддержку TLS:

BASE            dc=example,dc=com
URI             ldap://ldap-srv.example.com
TLS_CACERT      /etc/ssl/certs/rootca.crt
TLS_REQCERT     demand
TIMELIMIT       15
TIMEOUT         20

Обычно для конфигурации cn=config перезагрузка службы не требуется, но чтобы созданная нами ключевая информация «подхватилась», придётся это сделать:

#  service slapd restart
 * Stopping OpenLDAP slapd  [ OK ]
 * Starting OpenLDAP slapd  [ OK ]

Проверьте соединение с сервером с использованием TLS (модификатор -ZZ). На этот раз мы выполним запрос с использованием DN нашего администратора:

$  ldapsearch -xZZLLLWD cn=admin,dc=example,dc=com -b cn=config -s base
Enter LDAP Password:
dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcPidFile: /var/run/slapd/slapd.pid
olcTLSCACertificateFile: /etc/ssl/certs/rootca.crt
olcTLSCertificateFile: /etc/ldap/ssl/ldap-srv.example.com.crt
olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap-srv.example.com.key
olcTLSVerifyClient: never

Обратите внимание, что в запросе ldapsearch нам не пришлось указывать имя хоста (-H ldap://ldap-srv.example.com).  Всё потому что оно указано в файле /etc/ldap/ldap.conf. Что касается TLS, то во время инициирования соединения клиент (на данном этапе клиентский запрос выполняет сам сервер) получает от сервера его подписанный сертификат (ldap-srv.example.com.crt). Клиент может ничего не знать о сервере, но у него есть сертификат CA (rootca.crt), с помощью которого и проверяется сервер.

3.4 Создание CRL и отзыв сертификатов

Где работаем: ldap-srv

Сертификаты не вечны. Во-первых при создании задаётся его срок действия. При этом частота обновления сертификатов — баланс между безопасностью и удобством. Во-вторых он может быть скомпрометирован, если скомпрометирован его закрытый ключ. Как во втором случае оповестить субъектов доступа, что сертификат более не действителен? Для этого и служит Certificate Revocation List (CRL). Он представляет собой список серийных номеров отозванных сертификатов, подписанный УЦ, который их выпустил.

Вернёмся в каталог удостоверяющего центра:

#  cd /root/CA

Прежде чем мы сможем сгенерировать CRL, надо создать файл crlnumber. Он нужен openssl, чтобы отслеживать номер следующего CRL:

#  echo 1000 > crlnumber

В стандартной конфигурации openssl использует CRL V1. Раскомментируйте строку

crl_extensions = crl_ext
в /etc/ssl/openssl.cnf, чтобы переключиться на CRL V2. Это хорошая идея, за исключением тех случаев, когда надо использовать именно CRL V1 (например, при использовании сильно устаревшего браузера). Создаём CRL:

#  openssl ca -keyfile private/rootca.key -cert certs/rootca.crt  -gencrl -out crl/rootca.crl

Посмотреть результат можно так:

#  openssl crl -in crl/rootca.crl -text

Предположим, что закрытый ключ сервера ldap-srv был скомпрометирован. Чтобы оповестить об этом клиентские машины, надо отозвать сертификат  этого сервера, создать CRL, а затем — распространить CRL среди клиентов.

Отзываем сертификат:

#  openssl ca -keyfile private/rootca.key -cert certs/rootca.crt -revoke certs/ldap-srv.example.com.crt

Заглянем в index.txt. Начало записи с нашим сертификатом теперь изменилось с V на R:

# cat index.txt
R 160116072355Z 150119081313Z 1000 unknown /C=RU/ST=Moscow/O=ExampleInc/OU=ITdept/CN=ldap-srv.example.com/emailAddress=support@example.com

Обратите внимание, что копии новых сертификатов так же содержатся в каталоге newcerts. При этом имя файла содержит серийный номер сертификата. Когда отзываете сертификаты, вместо файлов в каталоге certs Вы можете пользоваться каталогом newcerts. Результат будет идентичен. Например:

#  openssl ca -keyfile private/rootca.key -cert certs/rootca.crt -revoke newcerts/1000.pem

Обновим CRL:

#  openssl ca -keyfile private/rootca.key -cert certs/rootca.crt -gencrl -out crl/rootca.crl

Взглянём на содержимое CRL:

#  openssl crl -in crl/rootca.crl -text

Вы должны увидеть нечто подобное:

...
Revoked Certificates:
    Serial Number: 1000
        Revocation Date: ...

Поместим CRL в каталог, где его увидит клиентское ПО:

#  cp crl/rootca.crl /etc/ssl

Осталось только распространить этот CRL среди клиентов. Мы делаем это простым путём — копированием файлов по сети вручную.

Где работаем: ldap-client

На каждой клиентской машине надо будет запустиь:

#  scp user@ldap-srv.example.com:/etc/ssl/certs/rootca.crt /etc/ssl/certs
#  scp user@ldap-srv.example.com:/etc/ssl/rootca.crl /etc/ssl/

Настроим клиентскую конфигурацию в /etc/ldap/ldap.conf и укажем, где хранится CRL:

BASE  dc=example,dc=com
URI  ldap://ldap-srv.example.com
TLS_CACERT /etc/ssl/certs/rootca.crt
TLS_REQCERT demand
TLS_CRLFILE /etc/ssl/rootca.crl
TIMELIMIT 15
TIMEOUT  20

И попробуем получить доступ к серверу каталогов:

$  ldapsearch -xZZLLLWD cn=admin,dc=example,dc=com -b cn=config -s base dn
ldap_start_tls: Connect error (-11)
        additional info: (unknown error code)

Наш CRL работает. Но к slapd теперь не подключиться. Надо выпустить новый сертификат для сервера.

Где работаем: ldap-srv

Сделаем это простой последовательностью команд. Мы повторяем пройденное, комментарии излишни:

#  cd /root/CA
#  openssl genrsa -out private/ldap-srv.example.com.key 4096
#  chmod 400 private/ldap-srv.example.com.key
#  openssl req -sha256 -new \
        -key private/ldap-srv.example.com.key -out certs/ldap-srv.example.com.csr \
        -subj /C=RU/ST=Moscow/L=Moscow/O=ExampleInc/OU=ITdept/CN=ldap-srv.example.com/emailAddress=support@example.com
#  openssl ca -extensions usr_cert -notext -md sha256 \
 -keyfile private/rootca.key -cert certs/rootca.crt \
 -in certs/ldap-srv.example.com.csr -out certs/ldap-srv.example.com.crt
#  chmod 444 certs/ldap-srv.example.com.crt
#  cp certs/ldap-srv.example.com.crt private/ldap-srv.example.com.key /etc/ldap/ssl
#  chown openldap:openldap /etc/ldap/ssl/{ldap-srv.example.com.crt,ldap-srv.example.com.key}
#  chmod 0400 /etc/ldap/ssl/{ldap-srv.example.com.crt,ldap-srv.example.com.key}

Перезупустим демон slapd и убедимся, что к серверу можно подключиться:

#  service slapd restart
$  ldapsearch -xZZLLLWD cn=admin,dc=example,dc=com -b cn=config -s base dn
Enter LDAP Password:
dn: cn=config

В целом по отзыву сертификатов... Иногда в реальных условиях лучше применить другой подход. Намного удобней, когда клиентские машины самостоятельно выясняют у сервера, действителен конкретный сертификат или нет. В выпускаемые сертификаты можно вносить запись CRL Distribution Points. Она заставит клиентов самих периодически скачивать новый CRL. Или можно использовать OCSP. Но эта тема выходит за рамки данного руководства.

Pro-LDAP.ru 2015 г. Последнее изменение страницы — 3 мая 2015 г. Вопросы и предложения принимаются на форуме проекта.