Сборка openssh с поддержкой авторизации через LDAP

На прошлых выходных вышла новая версия дистрибутива Debian 8 (Jessie), нового там много, поэтому впереди довольно много обновлений систем предстоит. В связи с этим решил заранее собрать версию ssh сервера, которая у меня используется в разных местах — она умеет работать с пользователями из LDAP. В этой статье я коснусь только самого процесса сборки, сам процесс настройки системы под подобную авторизацию я как-нибудь опишу позже. А сейчас о том как быстро и безболезненно пропатчить openssh-server на Debian 8 с патчем LPK.

Сам патч разработан давно в рамках LPK progect — http://code.google.com/p/openssh-lpk/ , есть несколько форков и продолжений этого патча под разные версии openssh. Я воспользовался одним из этих форков для предыдущего патча на Debian 7, когда пришло время я взял его же. Скачать его можно по ссылке https://github.com/takkeybook/openssh-lpk. Небольшую сложность, которая заключается в том что он для openssh-6.6p1 не так сложно обойти. Итак, предполагается что у вас уже есть среда с Debian 8 где вы будете проводить сбору. Выкачиваем исходники:

cd /usr/src ; apt-get source openssh-server

Скачиваем патч:

git clone https://github.com/takkeybook/openssh-lpk.git

Переименуем его для удобства и положим к остальным патчам для пакета:

cp openssh-lpk-6.6p1-0.3.14.patch /usr/src/openssh-6.7p1/debian/patches/openssh-lpk-6.7p1-0.3.14.patch

Добавляем в /usr/src/openssh-6.7p1/debian/patches/series этот патч

В самом патче меняем все упоминания 6.6p1 на 6.7p1. После этого пушим изменения о новых патчах

cd /usr/src/openssh-6.7p1/ ; quilt push ; quilt refresh

Доставляем необходимые пакеты для сборки если они не были установлены до этого:

apt-get build-dep openssh-server

Прописываем изменения в changelog чтобы у вас получился новый пакет с изменениями. Для этого воспользуемся утилиткой dch.

dch -i

Пишем, что-нибудь про изменения которые были внесены чтобы не забыть, например

Add LPK patch for working with LDAP

Теперь можно собирать пакет:

dpkg-buildpackage -us -uc

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

Настройка OpenVPN с авторизацией через LDAP

Данная небольшая статья поведает как настроить openvpn, да не просто так, а с авторизацией через LDAP. Раз уж я рассказывал до этого как настраивать LDAP, то пришла пора его для чего-то применить. Вот одно их полезных моментов куда его можно применить в целях организации закрытой инфраструктуры изолированной от попадания того кого не нужно. OpenVpn в этом деле незаменимая вещь, позволяющая давать доступ тому кому надо, а кого не надо оставлять за бортом. Ну а LDAP предельно упрощает предоставление таких прав нужным людям.

Для начала приведу общий конфиг для openvpn остановивлюсь на тех вещах которые нужны именно для нормальной работы opnevpn+ldap

tmp-dir /tmp
local 142.2.44.55
port 2000
proto tcp-server
tcp-queue-limit 256
bcast-buffers 4096
duplicate-cn
dev tun0
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/local.crt
client-cert-not-required
username-as-common-name
key /etc/openvpn/keys/local.key
dh /etc/openvpn/keys/dh2048.pem
server 10.30.0.0 255.255.255.0
push "route 10.11.0.0 255.255.0.0"
push "dhcp-option DNS 10.11.0.1"
push "dhcp-option DOMAIN example.local"
push "sndbuf 393216"
push "rcvbuf 393216"
tls-server
tls-auth /etc/openvpn/keys/ta.key 0
tls-timeout 120
auth MD5
cipher AES-256-CBC
keepalive 10 120
max-clients 100
user nobody
group nogroup
persist-key
persist-tun
script-security 3 execve
status /var/log/openvpn/openvpn-status.log
log /var/log/openvpn/openvpn.log
verb 4
plugin /usr/lib/openvpn/openvpn-auth-ldap.so "auth-ldap.conf"

В целом все как при обычном конфигурировании openvpn, есть небольшие только отличия

username-as-common-name — меняет авторизацию по common name из сертификата на авторизацию по логину и паролю, то что именно нам и надо.

plugin /usr/lib/openvpn/openvpn-auth-ldap.so «auth-ldap.conf» — подключает в качестве плагина openvpn-auth-ldap.so, который даест возможность вытаскивать из LDAP данные пользователя и использовать их для прохождения авторизации. На дебиане он ставиться довольно просто:

apt-get install openvpn-auth-ldap

В основном конфиге все, более добавлять ничего не надо. Есть еще дополнительный конфиг auth-ldap.conf где и осуществляется вся магия авторизации через LDAP.



URL ldap://10.11.0.2
BindDN cn=user,dc=example
Password pass
Timeout 15


BaseDN "ou=people,dc=example"
SearchFilter "(&(uid=%u)(attr1=vpn))"
RequireGroup false


Тут указаны данные к какому LDAP серверу подсоединяться

URL ldap://10.11.0.2

с какими правами работать

BindDN cn=user,dc=example , Password pass

и в какой директории искать

BaseDN «ou=people,dc=example»

Так же указан фильтр по которому будет производиться выборка

SearchFilter «(&(uid=%u)(attr1=vpn))»

это значит что будет проводиться поиск по указанному пользователю и если у него есть атрибут attr1=vpn, что позволяет ограничить в директории пользователей на тех кому нужен доступ по VPN и кому нет, так же можно разграничить доступ по разным VPN.

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



URL ldap://10.11.0.2
BindDN cn=user,dc=example
Password pass
Timeout 15


BaseDN "ou=people,dc=example"
SearchFilter "(uid=%u)"
RequireGroup true

BaseDN "cn=openvpn,ou=groups,dc=example"
SearchFilter "(cn=openvpn)"
MemberAttribute memberUid


Добавляется секция с поиском в группе указанного пользователя. Теперь для предоставления прав на доступ достаточно добавить пользователя в указанную группу или удалить если он там больше не нужен. Вот в общем и все, надеюсь эта статья будет вам полезна.

Настройка TLS для LDAP

Не так давно я описал в статье настройку репликации LDAP серверов по схеме multimaster. В данной заметке я опишу как настроить работу LDAP по зашифрованному каналу в том числе и для репликации. Понадобиться это может в довольно большом количестве случаев, например если вам надо прокинуть реплику куда-то во вне защищенной сети или если ваша сеть публичная. В общем зашифровать данные никогда не бывает лишним. В LDAP это делается довольно просто. Итак, исходные данные такие же как и в предыдущей статье, будем считать, что та схема уже сделана и нормально функционирует, и просто к ней в дополнение организовываем шифрование.

Как и прежде, все настройки мы храним с самом LDAP и реплицируем между всем серверами реплики. В качестве ключей будем использовать самоподписные ключи сгенерированные с помощью утилит из набора GNU TLS. Ключи сделанные через openssl работать не будут, так что пользоваться придется certtool, что совсем не сложно. Для начала установим набор утилит:

apt-get install gnutls-bin

Теперь можно сгенерировать корневые сертификаты для нашего самоподписного сертификата, пока я этого не сделал, получал подобную ошибку:

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

Поэтому делаем набор ключ и сертификат для корневого сертификата и им подписываем сертификат для непосредственно рабочей пары:

certtool --generate-privkey --outfile ca.key
certtool --generate-self-signed --load-privkey ca.key --outfile ca.crt

Генерим рабочую пару:

certtool --generate-privkey --outfile ldap.prod.local.key
certtool --generate-certificate --load-privkey ldap.prod.local.key --outfile ldap.prod.local.crt --load-ca-certificate ca.crt --load-ca-privkey ca.key

Кладем все полученные сертификаты и приватный ключик в папочку где они будут доступны для сервера, например в /etc/ldap/ssl. Добавляем владельца и группу:

chown -R openldap:openldap /etc/ldap/ssl

Вносим изменения в конфиг, добавляя туда информацию о ключах с помощью следующих строчек

dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/ssl/ca.crt
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap.prod.local.key
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/ssl/ldap.prod.local.crt

Теперь можно перезапустить сервер с работой по шифрованному протоколу, для этого идем в /etc/default/slapd и в строчке

SLAPD_SERVICES="ldap://server1.prod.local ldapi:///"

Добавляем еще один биндинг

ldaps://server1.prod.local, так чтобы полная строчка стала выглядеть так:

SLAPD_SERVICES="ldap://server1.prod.local ldapi:/// ldaps://server1.prod.local"

Делаем это на каждом из серверов и перезапускаем службу:

/etc/init.d/slapd restart

Теперь демон будет, помимо 389 порта, еще доступен на 636 порту, не забудьте открыть его в файерволе. Для того чтобы помимо обычных запросов, шифровались и запросы по реплике, то при конфигурировании реплики надо указывать ключик starttls=yes, при этом остальные параметры остаются без изменений, в общем конфиг для репликации конфигов будет выглядеть таким вот образом:

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=001 provider=ldap://server1.prod.local binddn="cn=admin,cn=config"
bindmethod=simple credentials=ck3u8gj3
searchbase="cn=config" type=refreshAndPersist
retry="5 5 300 5" timeout=1 starttls=yes
olcSyncRepl: rid=002 provider=ldap://server2.prod.local binddn="cn=admin,cn=config"
bindmethod=simple credentials=ck3u8gj3
searchbase="cn=config" type=refreshAndPersist
retry="5 5 300 5" timeout=1 starttls=yes
-
add: olcMirrorMode
olcMirrorMode: TRUE

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

Настройка репликации LDAP Multimaster

В какой-то момент понадобилось старую схему LDAP с одиноким сервисом переделать в что-то более надежное и устойчивое, способное выдерживать сбои и держать большую нагрузку. После недолгих изысканий было принято решение реализовать схему мастер-мастер. Удобство данной схемы в равноценности всех серверов в реплике и возможность вносить изменения на любом сервере. Устанавливать буду на сервера с Debian Linux тут это довольно просто делается. Конфиги будут хранится в самом LDAP и тоже будут реплицироваться между серверами. Сервера будут server1.prod.local и server2.prod.local. Итак, поехали.

Устанавливаем необходимые пакеты

apt-get install slapd ldap-utils

Далее начинаем прописывать конфиги, конфиги будут храниться в самом LDAP так что будем все конфигурить через ldiff с помощью команды

ldapmodify -Y EXTERNAL -H ldapi:/// -f 1.ldiff

На обоих серверах прописываем ID — ServerID (у каждого сервера свой) следующим ldiff

dn: cn=config
changetype: modify
add: olcServerID
olcServerID: 1

Добавляем пароль для сервиса репликации конфигов на обоих серверах

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: jcb8332jf30

Включаем модуль для репликации syncprov на обоих серверах

dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: {1}syncprov.la

На обоих серверах прописываем сервера с которыми у нас будет проходить репликация

dn: cn=config
changetype: modify
add: olcServerID
olcServerID: 1 ldap://server1.prod.local
olcServerID: 2 ldap://server2.prod.local

Добавляем оверлей на обоих серверах чтобы пошла репликация

dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov

Включаем репликацию конфигов, это тоже делаем на обоих серверах

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=001 provider=ldap://server1.prod.local binddn="cn=admin,cn=config"
bindmethod=simple credentials=ck3u8gj3
searchbase="cn=config" type=refreshAndPersist
retry="5 5 300 5" timeout=1
olcSyncRepl: rid=002 provider=ldap://server2.prod.local binddn="cn=admin,cn=config"
bindmethod=simple credentials=ck3u8gj3
searchbase="cn=config" type=refreshAndPersist
retry="5 5 300 5" timeout=1
-
add: olcMirrorMode
olcMirrorMode: TRUE

Теперь репликация конфигов работает и все остальные действия можно выполнять на одном из серверов.
Далее нужно включить репликацию для нашей основной базы где у нас содержаться или будут содержаться все данные, база у нас пусть называется prod.
Для начала создадим пользователя для репликации, т.к. создаваться он должен в самой базе, то создавать его надо командой

ldapmodify -vvvvv -D "cn=admin,dc=prod" -W -H ldapi:/// -f sync.diff

dn: cn=sync,dc=prof
changetype: add
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: sync
description: Syncrepl user for mirrormode operation
userPassword: {SSHA}n+8YKycr9Q/GpuCf4sDfSOQ+zg3csv3Ae

Прописываем тем же способом acl

dn: olcDatabase={1}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=proxy,dc=prod" read by dn="cn=manager,dc=prod" write by dn="cn=sync,dc=prod" read by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=prod" write by * read

Включаем репликацию

dn: olcDatabase={1}hdb,cn=config
changeType: modify
add: olcSyncrepl
olcSyncrepl: rid=003 provider=ldap://server1.prod.local bindmethod=simple binddn="cn=sync,dc=fs" credentials=vkj48gfj searchbase="dc=prod" schemachecking=on type=refreshAndPersist retry="5 5 300 5" timeout=1
olcSyncRepl: rid=004 provider=ldap://server1.prod.local binddn="cn=sync,dc=prod" bindmethod=simple credentials=vkj48gfj searchbase="dc=prod" schemachecking=on type=refreshAndPersist retry="5 5 300 5" timeout=1
-
add: olcMirrorMode
olcMirrorMode: TRUE

Добавляем индексы на нужные поля

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: objectClass eq
olcDbIndex: cn eq
olcDbIndex: gidNumber eq
olcDbIndex: memberUid eq
olcDbIndex: uid eq
olcDbIndex: uidNumber eq
olcDbIndex: uniqueMember eq
olcDbIndex: accessTo eq
olcDbIndex: entryUUID eq

После этого нужно выключить сервер slapd (/etc/init.d/slapd stop) и выполнить команду

slapindex

Которая создаст необходимые индексы для базы. И включить сервер. Это надо сделать на обоих серверах
Добавляем лимиты чтобы все работало без ошибок даже при большом количестве полей

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcLimits
olcLimits: dn.exact="cn=sync,dc=prod" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited
-
add: olcSizeLimit
olcSizeLimit: 10000
-
replace: olcDbConfig
olcDbConfig: {0}set_cachesize 0 209715200 1
olcDbConfig: {1}set_lk_max_objects 1024000
olcDbConfig: {2}set_lk_max_locks 10240
olcDbConfig: {3}set_lk_max_lockers 10240

В целом конфигурация основных моментов закончена, репликация баз где конфиги и базы где хранятся данные уже работает.

Настраиваем бекап, бекап делается через простой скриптик

backup.sh
#!/bin/sh
YMD=`date +%Y.%m.%d-%HHours`;
slapcat > /etc/ldap/ldap.ldiff;
cd /root/ldap-backup/files;
tar c /etc/ldap/ >$YMD-server1-ldap-etc.tar; gzip $YMD-server1-ldap-etc.tar;

В случае необходимости восстановиться из бекапа делаем это так

restore.sh
#!/bin/sh
/etc/init.d/slapd stop;
rm /var/lib/ldap/*;
rm /root/ldap-backup/etc -rf;
slapadd -l /root/ldap-backup/etc/ldap/ldap.ldiff;
chown openldap:openldap /var/lib/ldap -R

/etc/init.d/slapd start;

 

Добавил статью про настройку TLS для соединения с LDAP