3.1 Практическое занятие. Права доступа. Атрибуты файла. POSIX ACL
Управление доступом с помощью классических битов защиты
При листинге директорий с помощью команды ls -l будет получена информация о дискреционном разграничении доступа к файлам.
Например, следующий вывод:
mpyrev@debian-kb:~$ ls -l
total 44
drwxr-xr-x 3 mpyrev mpyrev 4096 Mar 10 18:29 Desktop
drwxr-xr-x 2 mpyrev mpyrev 4096 Mar 7 10:28 Documents
drwxr-xr-x 2 mpyrev mpyrev 4096 Mar 7 10:28 Downloads
-rwxr--r-x 1 root root 10 Mar 7 19:37 mk123.sh
drwxr-xr-x 2 mpyrev mpyrev 4096 Mar 7 10:28 Music
drwxr-xr-x 2 mpyrev mpyrev 4096 Mar 7 10:28 Pictures
drwxr-xr-x 2 mpyrev mpyrev 4096 Mar 7 10:28 Public
-rwxr-xr-x 1 root root 79 Mar 7 13:09 script.sh
drwxr-xr-x 2 mpyrev mpyrev 4096 Mar 7 10:28 Templates
drwx-w-rwx 2 user1 user1 4096 Mar 7 18:59 test
drwxr-xr-x 2 mpyrev mpyrev 4096 Mar 7 10:28 Videos
В левой части вывода напротив каждого вывода представляется строка вида:
PERMIT LINKS USER GROUP
drwxrwxrwx 1 root root
В поле PERMIT указывается информация о типе файла и разрешения разделенные по логике user:group:others или u:g:o. В поле USER указывается владелец файла, в поле GROUP группа владельцев файла. В обозначение others входят все остальные пользователи, которые не являются владельцем или членом группы владельцев.
В unix-системах существуют семь типов файлов:
- — обычный файл (regular file)
d — каталог (directory)
p — именованный канал (named pipe)
l — символическая ссылка (soft link)
c и b — символьные и блочные файлы устройств (device file)
s — сокет (socket)
D — дверь (door)
Биты разрешений могут принимать значения r w x, что означает:
read — чтение
write — запись
execute — выполнение
Изменение классических битов и смена владельца и группы владельцев файла
Изменение классических битов
При необходимости, возможно изменить стандартно назначаемые биты защиты, путем ввода команды:
chmod o+rwx mk123.sh
Данная команда может быть выполнена суперпользователем, администратором с использованием sudo или владельцем файла.
Синтаксис команды:
chmod [u|g|o][+|-][rwxst] [FILE]
В данном синтаксисе представлены биты s и t, которые рассмотрены ниже.
Кроме того, биты могут быть записаны в восьмеричном значении:
1 - x
2 - w
4 - r
Таким образом, при необходимости определить все права на файл (например, полные права пользователю, чтение и исполнение группе и только исполнение всем остальным), можно записать в следующем виде (по октетам):
chmod 731 mk123.sh
Смена владельца и группы владельцев файла
Если требуется сменить владельца файла или группы владельцев необходимо воспользоваться следующей командой:
chown mpyrev:root mk123.sh
Синтаксис команды:
chown [u]:[g] [FILE]
Данная команда может быть выполнена только суперпользователем или администратором с использованием sudo
Специальные разрешения файлов в Linux (SetUID, SetGID, Sticky bit)
SetUID, SetGID
SetUID – это бит разрешения, который позволяет пользователю запускать исполняемый файл с правами владельца этого файла. Другими словами, использование этого бита позволяет нам поднять привилегии пользователя в случае, если это необходимо.
Принцип работы SetGID очень похож на setuid с отличием, что файл будет запускаться пользователем от имени группы, которая владеет файлом.
chmod g+s mk123.sh
ls -l mk123.sh
-rwxrwr-x 1 root root 10 Mar 7 19:37 mk123.sh
В случае, если бит на выполнение был удален, бит SetUID или SetGID становится заглавным.
chmod g-x mk123.sh
ls -l mk123.sh
-rwxrwr-x 1 root root 10 Mar 7 19:37 mk123.sh
SetUID и SetGID биты действуют только на бинарные файлы, на любых других скриптах игнорируются.
Необходимо с осторожностью назначать SetUID и SetGID биты, так как утилиты могут иметь функции по исполнению команд.
Например, с помощью команды:
find . -exec /bin/sh -p ; -quit
При наличии на бинарном файле /usr/bin/find SUID бита, команда выведет консоль от имени суперпользователя.
Sticky bit
В случае, если этот бит установлен для папки, то файлы в этой папке могут быть удалены только их владельцем. Пример использования этого бита в операционной системе это системная папка /tmp . Эта папка разрешена на запись любому пользователю, но удалять файлы в ней могут только пользователи, являющиеся владельцами этих файлов.
ls -ld /tmp
drwxrwxrw 8 root root 4096 Mar 25 10:22 /tmp
При отсутствии бита на исполнение, sticky bit отображается заглавной буквой:
chmod o-x /tmp
ls -ld /tmp
drwxrwxrw 8 root root 4096 Mar 25 10:22 /tmp
Данная команда может быть выполнена только суперпользователем или администратором с использованием sudo
При назначении данного атрибута, даже суперпользователь не в праве изменить данный файл
Если потребуется создать файл, который является лог-файлом (нельзя изменять, но возможно дописывать), то необходимо добавить атрибут +a
pyrev@debian-kb:~$ cd test/
mpyrev@debian-kb:~/test$ ls
1
mpyrev@debian-kb:~/test$ cat 1
test
test
mpyrev@debian-kb:~/test$ ls -la
total 12
drwx-w-rwx 2 user1 user1 4096 Mar 7 18:59 .
drwxr-xr-x 16 mpyrev mpyrev 4096 Apr 3 16:37 ..
-rw-r--r-- 1 mpyrev mpyrev 10 Mar 7 20:22 1
mpyrev@debian-kb:~/test$ chattr +a 1
mpyrev@debian-kb:~/test$ echo "hello" > 1
bash: 1: Operation not permitted
mpyrev@debian-kb:~/test$ echo "hello" >> 1
mpyrev@debian-kb:~/test$ cat 1
test
test
hello
mpyrev@debian-kb:~/test$ lsattr 1
-----a--------e------- 1
POSIX ACL
ACL (Access control lists) — более сложный, но гибкий инструмент управления правами доступа. Он позволяет сегментировать категорию «other» и разрешить работу с файлом/директорией нескольким конкретным пользователям и группам.
В данном случае, помимо добавленных разрешений появилась маска. По умолчанию, составляется как дизъюнкция всех разрешений, кроме владельца. Данная маска необходима для определения максимально возможных прав доступа отличных от владельца пользователям. Например, при маске -wx, будет отображено следующее:
Предварительная настройка разрешения доменных имен
Для практического занятия потребуются две виртуальные машины (ВМ) Debian.
Далее будет использоваться Debian 11 "bullseye". Однако одна ВМ будет настроена без графической оборочки, далее - Debian Server. ВМ с графической оболочкой - Debian Client.
При установке рекомендуется сразу указать домен, к примеру - .
Таким образом hostname ВМ будут выглядеть следующим образом: server.kb.edu и client.kb.edu.
В файл /etc/hosts на server.kb.edu необходимо добавить информацию об IP-адресах клиента и сервера. В реальной инфраструктуре данная информация вносится в DNS-сервер.
root@server:~# cat /etc/hosts
127.0.0.1 localhost
#127.0.1.1 server.kb.edu server
192.168.3.139 server.kb.edu server
192.168.3.140 client.kb.edu client
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
В файл /etc/hosts на client.kb.edu также необходимо добавить информацию об IP-адресах клиента и сервера.
Также рекомендуется проверить наличие ping при запросе по имени:
root@client:~# ping server
PING server.kb.edu (192.168.3.139) 56(84) bytes of data.
64 bytes from server.kb.edu (192.168.3.139): icmp_seq=1 ttl=64 time=0.449 ms
64 bytes from server.kb.edu (192.168.3.139): icmp_seq=2 ttl=64 time=0.269 ms
64 bytes from server.kb.edu (192.168.3.139): icmp_seq=3 ttl=64 time=0.978 ms
64 bytes from server.kb.edu (192.168.3.139): icmp_seq=4 ttl=64 time=1.20 ms
^C
--- server.kb.edu ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3094ms
rtt min/avg/max/mdev = 0.269/0.723/1.199/0.378 ms
root@client:~# ping client
PING client.kb.edu (192.168.3.140) 56(84) bytes of data.
64 bytes from client.kb.edu (192.168.3.140): icmp_seq=1 ttl=64 time=0.037 ms
64 bytes from client.kb.edu (192.168.3.140): icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from client.kb.edu (192.168.3.140): icmp_seq=3 ttl=64 time=0.085 ms
64 bytes from client.kb.edu (192.168.3.140): icmp_seq=4 ttl=64 time=0.047 ms
^C
--- client.kb.edu ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3072ms
rtt min/avg/max/mdev = 0.037/0.058/0.085/0.018 ms
Установка OpenLDAP
Где работаем: server
Мы сразу устанавливаем krb5-kdc-ldap, даже несмотря на то, что настроим их позже. Идея заключается в том, чтобы сразу получить необходимые схемы наборов данных OpenLDAP.
Создадим пустой каталог для нашей новой конфигурации:
root@server:~# mkdir /etc/ldap/slapd.d
Создадим файл init-config.ldif с новой конфигурацией и запишем в него:
Здесь и далее рекомендуется писать конфигурацию вручную или производить копирование c заменой знаков табуляции вначале каждой строки, если такие имеются
В этом файле первым делом мы определяем корневую запись DIT (Directory Information Tree), cn=config. С помощью директив olcPidFile и olcArgsFile мы указали, куда необходимо записать ID процесса службы каталогов и аргументы его запуска соответственно.
Во втором разделе задаём служебную базу данных конфигурации cn=config. Мы так же добавили правило доступа (ACL, Access Control List), разрешающее манипулировать ей от имени пользователя root (uid=0, gid=0) с помощью механизма SASL EXTERNAL и идентификационной сущности IPC. Помните, что в конце каждого ACL, если не задан модификатор break, подразумевается наличие правила by * none . То есть остальной доступ к объекту в условии to — запрещён.
Последним разделом мы добавляем в конфигурацию контейнер для наборов схем данных.
Разрешим нашей службе каталогов использовать только IPv4. Для этого установим SLAPD_OPTIONS="-4" в файле /etc/default/slapd. В остальном конфигурация стандартная:
Настроим rsyslog, чтобы он писал события службы каталогов в отдельный файл. Для этого достаточно добавить три строки в его конфигурацию после глобальных директив /etc/rsyslog.conf:
$ModLoad imuxsock # provides support for local system logging
$ModLoad imklog # provides kernel logging support
$KLogPermitNonKernelFacility on
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
$RepeatedMsgReduction on
$FileOwner syslog
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022
$PrivDropToUser syslog
$PrivDropToGroup syslog
$WorkDirectory /var/spool/rsyslog
$IncludeConfig /etc/rsyslog.d/*.conf
# Пишем журнал демона slapd в /var/log/slapd.log
if $programname == 'slapd' then /var/log/slapd.log
& ~
Создадим файл для журнала службы каталогов и зададим для него права доступа. Затем перезапустим rsyslog, чтобы изменения вступили в силу:
Заметьте, что slapadd (из предыдущего пункта) добавил в наш каталог описание служебной базы данных frontend (в ней можно определить опции, которые будут применяться ко всем базам данных в текущей конфигурации OLC). Однако, если те же самые опции (в том числе правила ACL) определены в конкретной базе данных, то будут применяться именно они.
Подключение динамических модулей
Где работаем: server
Для работы нам понадобится два модуля. Один — для механизма базы данных mdb. На данный момент он рассматривается как основной для нормальных баз данных и должен прийти на сменуbdb и hdb. Второй модуль — monitor, для создания и динамической поддержки ветки с информацией о текущем статусе демона slapd.
Чтобы их подключить нам понадобится всего один короткий LDIF-файл и специальная запись cn=module,cn=config. Назовём файл add-modules.ldif и запишем в него:
На просторах сети был найден несложный скрипт для преобразования файлов schema в формат LDIF. Немного откорректируем его (для универсальности) и сохраним в том же каталоге ~/ldap под именем schema-ldif.sh:
#!/bin/bash
SCHEMAD=~/ldap
tmpd=`mktemp -d`
pushd ${tmpd} >>/dev/null
echo '' > convert.dat
for schema in ${SCHEMAS} ; do
echo include ${SCHEMAD}/${schema} >> convert.dat
done
slaptest -f convert.dat -F .
if [ $? -ne 0 ] ; then
echo "slaptest conversion failed"
exit
fi
for schema in ${SCHEMAS} ; do
fullpath=${SCHEMAD}/${schema}
schema_name=`basename ${fullpath} .schema`
schema_dir=`dirname ${fullpath}`
ldif_file=${schema_name}.ldif
find . -name *${schema_name}.ldif -exec mv '{}' ./${ldif_file} \;
sed -i "/dn:/ c dn: cn=${schema_name},cn=schema,cn=config" ${ldif_file}
sed -i "/cn:/ c cn: ${schema_name}" ${ldif_file}
sed -i '/structuralObjectClass/ d' ${ldif_file}
sed -i '/entryUUID/ d' ${ldif_file}
sed -i '/creatorsName/ d' ${ldif_file}
sed -i '/createTimestamp/ d' ${ldif_file}
sed -i '/entryCSN/ d' ${ldif_file}
sed -i '/modifiersName/ d' ${ldif_file}
sed -i '/modifyTimestamp/ d' ${ldif_file}
sed -i '/^ *$/d' ${ldif_file}
mv ${ldif_file} ${schema_dir}
done
popd >>/dev/null
rm -rf $tmpd
Сделаем его исполняемым и запустим, передав через переменную SCHEMAS имя файла конвертируемого набора схем:
Последней строчкой мы указали получившийся в результате конвертации набор схем kerberos.ldif.
Добавим наши наборы схем:
root@server:~# ldapadd -QY EXTERNAL -H ldapi:/// -f add-schemas.ldif
adding new entry "cn=core,cn=schema,cn=config"
adding new entry "cn=cosine,cn=schema,cn=config"
adding new entry "cn=inetorgperson,cn=schema,cn=config"
adding new entry "cn=collective,cn=schema,cn=config"
adding new entry "cn=corba,cn=schema,cn=config"
adding new entry "cn=duaconf,cn=schema,cn=config"
adding new entry "cn=openldap,cn=schema,cn=config"
adding new entry "cn=dyngroup,cn=schema,cn=config"
adding new entry "cn=java,cn=schema,cn=config"
adding new entry "cn=misc,cn=schema,cn=config"
adding new entry "cn=nis,cn=schema,cn=config"
adding new entry "cn=ppolicy,cn=schema,cn=config"
adding new entry "cn=kerberos,cn=schema,cn=config"
Инициализация базы данных
Где работаем: server
Вот мы и подошли к созданию базы данных, в которой будем хранить нашу рабочую информацию.
Для начала создадим пароль администратора. Утилита slappasswd генерирует посоленный хэш вводимого нами пароля:
root@server:~# slappasswd -h '{SSHA}'
New password:
Re-enter new password:
{SSHA}RMjrfsi7NkpBMR+NQHTDk4iddvo/2le+
Сформируем конфигурационный LDIF-файл для нашей базы данных db.ldif и запишем получившийся хэш в атрибут olcRootPW:
dn: olcDatabase=mdb,cn=config
objectClass: olcMdbConfig
olcDatabase: mdb
olcSuffix: dc=kb,dc=edu
olcDbDirectory: /var/lib/ldap
olcDbMaxsize: 1073741824
olcRootDN: cn=admin,dc=kb,dc=edu
olcRootPW: {SSHA}RMjrfsi7NkpBMR+NQHTDk4iddvo/2le+
olcAccess: {0}to *
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
by * break
olcAccess: {1}to attrs=userPassword
by self write
by anonymous auth
olcAccess: {2}to *
by self read
dn: olcDatabase=monitor,cn=config
objectClass: olcDatabaseConfig
olcDatabase: monitor
И вновь несколько комментариев...
В качестве механизма манипуляции данными выбираем ранее подключенный модуль mdb.
В качестве суффикса (корневой записи) создаваемого DIT (Directory Information Tree) обычно используется имя домена DNS. Но это не является обязательным. Для примера мы задали суффикс dc=kb,dc=edu.
В атрибуте olcDbDirectory мы указали путь к каталогу бузы данных. Атрибут обязательный и требует существование каталога на момент загрузки в базу данных.
Механизм mdb требует указания максимального размера базы данных. Он задается в байтах и должен быть больше её ожидаемого размера, даже с учётом прироста. В файловой системе должно быть достаточно свободного места для размещения базы данных такого размера.
В атрибут olcRootDN мы записываем DN администратора нашей базы данных.
Для пользователя, указанного в атрибуте olcRootDN, задавать правило в ACL не нужно, он обладает полным доступом к данным в вашей базе. Поэтому постарайтесь сохранить его пароль в надежном месте (например, используя keepass или gpg).
Добавляем три правила доступа для базы данных mdb:
Доступ ко всей базе данных:
Разрешить доступ пользователю root с использованием механизма SASL EXTERNAL.
Продолжить анализ ACL, если нет совпадений с субъектами доступа, указанными с помощью директивы by.
Доступ к атрибуту userPassword:
Разрешить доступ для смены пароля самим пользователем.
root@server:~# ldapadd -QY EXTERNAL -H ldapi:/// -f db.ldif
adding new entry "olcDatabase=mdb,cn=config"
adding new entry "olcDatabase=monitor,cn=config"
Определим RootDN для доступа к конфигурации службы каталогов. Он будет ссылаться на RootDN, находящийся в нашей БД. Эта запись желательна только при первоначальной настройке или в тестовой конфигурации. Не оставляйте её в боевой системе! Для {-1}frontend зададим минимально необходимые права для доступа к RootDSE. Создадим LDIF-файл acl-mod.ldif, модифицирующий права доступа:
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootDN
olcRootDN: cn=admin,dc=kb,dc=edu
dn: olcDatabase={-1}frontend,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to *
by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
by * break
olcAccess: {1}to dn.base=""
by * read
olcAccess: {2}to dn.base="cn=subschema"
by * read
Убедимся, что учётная запись администратора имеет доступ к нашей службе каталогов:
root@server:~# ldapwhoami -WD cn=admin,dc=kb,dc=edu
Enter LDAP Password:
dn:cn=admin,dc=kb,dc=edu
Отлично! Теперь у нас есть работающий сервер OpenLDAP.
Отредактируем файл /etc/ldap/ldap.conf. Это нужно только для того, чтобы немного упростить себе жизнь и меньше печатать в дальнейшем. В BASE подставьте свой суффикс, а в URI — FQDN Вашего сервера OpenLDAP:
#
# LDAP Defaults
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
BASE dc=kb,dc=edu
URI ldap://server.kb.edu
#SIZELIMIT 12
TIMELIMIT 15
TIMEOUT 20
#DEREF never
# TLS certificates (needed for GnuTLS)
#TLS_CACERT /etc/ssl/certs/ca-certificates.crt
С настройкой TLS мы разберемся в следующем разделе.
И последний штрих. Добавим демон нашей службы каталогов в автозагрузку:
root@server:~# update-rc.d slapd defaults
Удостоверяющий центр на основе самоподписанного сертификата с помощью OpenSSL
Где работаем: server
Итак, мы создаём централизованную инфраструктуру открытых ключей (PKI) в миниатюре. Для этого сформируем пару закрытый ключ/корневой сертификат удостоверяющего центра. Причём сертификат будет подписан этим же закрытым ключом (т. е. станет самоподписанным).
Затем сгенерируем новый закрытый ключ для нашей службы каталогов и создадим для неё сертификат, подписанный закрытым ключом нашего удостоверяющего центра. При этом клиенские рабочие станции должны знать только корневой сертификат. Используя его они могут установить безопасное соединение с любым сервером, который имеет закрытый ключ и соответствующий ему сертификат, подписанный нашим УЦ.
Удостоверяющий центр желательно разворачивать на отдельной машине, не имеющей подключения к сети, но для простоты примера мы проделаем всю работу на server.kb.edu.
Создадим каталог для нашего удостоверяющего центра (CA) и установим безопасные права доступа. Затем зададим значение umask таким, чтобы вновь создаваемые файлы имели права доступа чтения и записи только для создавшего их пользователя:
В конфигурационном файле /etc/ssl/openssl.cnf в секции [ CA_default ] для удобства поменяем значение директивы dir = ./demoCA на dir = ./. В этом же разделе директивой default_days задаётся срок действия выпускаемых сертификатов. Можете поменять её значение по своему усмотрению.
Файлы index.txt и serial будут играть роль своеобразной базы данных, чтобы отслеживать статус выпущенных закрытых ключей и сертификатов.
Создадим структуру каталогов и файлов для своего удостоверяющего центра:
Сгенерируем закрытый ключ удостоверяющего центра (длиной 4096 бит). Он должен хранится особенно бережно. Поэтому мы защитим его при помощи шифра AES. Вам будет предложено ввести пароль для доступа к новому закрытому ключу. Запомните его и не потеряйте. Это последний рубеж защиты от злоумышленника. Без пароля выпустить новые сертификаты не получится.
Изменим права доступа к новому ключу, чтобы ненароком его не стереть:
root@server:~# chmod 400 private/rootca.key
Откройте конфигурационный файл OpenSSL /etc/ssl/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:
В качестве алгоритма хэширования мы используем 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 заносим в сертификат информацию:
C - Country Name (страна) - RU
ST - State or Province Name (штат или провинция) - Sverdlovskaya
L - Locality Name (город) - Ekaterinburg
O - Organization Name (наименование организации) - UrFU
OU - Organizational Unit Name (наименование подразделения) - KB
CN - Common Name (имя субъекта или FQDN сервера) - ca-server
emailAddress - Email Address (адрес электронной почты) - support@kb.edu
Удостоверяющий центр готов к выпуску сертификатов.
Выпуск сертификата для сервера службы каталогов
Где работаем: server
Как правило, закрытые ключи клиентов УЦ не должны хранится в самом УЦ. Клиент может сам сформировать ключевую пару и прислать в УЦ лишь запрос на подпись (Certificate Signing Request, CSR). Запрос содержит открытый ключ. Однако мы будем создавать все ключи и хранить их в одном месте. В организации, которая серьёзно подходит к проблемам безопасности такой процесс работы может быть неприемлемым.
Продолжаем в том же каталоге /root/CA. Создадим закрытый ключ для сервера службы каталогов:
Сгенерируем запрос на подпись сертификата. Наименование организации (UrFU) должно совпадать с наименованием в корневом сертификате УЦ. В качестве Common Name укажем FQDN нашего сервера:
Следующим шагом должно быть подписание запроса CSR существующим доверенным удостоверяющим центром (например, VeriSign) в обмен на деньги. Но нам не хочется платить за эту услугу, или у нас нет своего (корпоративного) CA, или это просто тестовая конфигурация, а может нам просто всё равно. Поэтому мы подпишем его с помощью своего собственного CA:
В заключение можем удалить запрос CSR, он нам больше не нужен:
root@server:~# rm -rf certs/server.kb.edu.csr
Каталог /root/CA теперь выполняет роль удостоверяющего центра. Аналогичным образом его можно создать на другой машине, тогда надо будет копировать секретные ключи и подписанные сертификаты по сети с помощью scp или через съёмный носитель. Неплохой идеей будет хранить этот каталог на отдельном носителе и монтировать его только для выпуска новых сертификатов. Сам носитель можно, например, положить в сейф. Процесс создания новых пар ключ-сертификат в будущем будет состоять из трёх этапов:
Генерация секретного ключа и запроса на подписание сертификата;
Подписание сертификата с помощью закрытого ключа нашего CA (rootca.key);
Перемещение новых секретного ключа и подписанного сертификата в каталоги, где они будут использоваться.
Настройка конфигурации TLS
Где работаем: server
Вернёмся во временный каталог:
root@server:~# cd ~/ldap
Создадим LDIF-файл tls-config.ldif для внесения в каталог конфигурации TLS и запишем в него:
Этими записи говорят демону slapd, где лежит его сертификат и ключ, где лежит корневой сертификат УЦ и что от клиентов требовать наличие сертификата не нужно. Чтобы окончательно всё запутать, мы могли бы создать сертификаты для всех клиентов. В реальной жизни такая аутентификация клиента принесёт небольшое усиление защиты за счёт большого увеличения работы по сопровождению всех этих сертификатов. Тем более, далее, на этой практике мы настроим механизмы аутентификации Kerberos.
Вновь отредактируем конфигурационный файл /etc/ldap/ldap.conf и включим поддержку TLS:
#
# LDAP Defaults
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
BASE dc=kb,dc=edu
URI ldap://server.kb.edu
#SIZELIMIT 12
TIMELIMIT 15
TIMEOUT 20
#DEREF never
# TLS certificates (needed for GnuTLS)
#TLS_CACERT /etc/ssl/certs/ca-certificates.crt
TLS_CACERT /etc/ssl/certs/rootca.crt
TLS_REQCERT demand
Обычно для конфигурации cn=config перезагрузка службы не требуется, но чтобы созданная нами ключевая информация подхватилась, придётся это сделать:
root@server:~# service slapd restart
Проверьте соединение с сервером с использованием TLS (модификатор -ZZ). На этот раз мы выполним запрос с использованием DN нашего администратора:
root@server:~# ldapsearch -xZZLLLWD cn=admin,dc=kb,dc=edu -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/server.kb.edu.crt
olcTLSCertificateKeyFile: /etc/ldap/ssl/server.kb.edu.key
olcTLSVerifyClient: never
Обратите внимание, что в запросе ldapsearch нам не пришлось указывать имя хоста (-H ldap://server.kb.edu). Всё потому что оно указано в файле /etc/ldap/ldap.conf. Что касается TLS, то во время инициирования соединения клиент (на данном этапе клиентский запрос выполняет сам сервер) получает от сервера его подписанный сертификат (server.kb.edu.crt). Клиент может ничего не знать о сервере, но у него есть сертификат CA (rootca.crt), с помощью которого и проверяется сервер.
Создание CRL и отзыв сертификатов
Где работаем: server
Сертификаты не вечны. Во-первых при создании задаётся его срок действия. При этом частота обновления сертификатов — баланс между безопасностью и удобством. Во-вторых он может быть скомпрометирован, если скомпрометирован его закрытый ключ. Как во втором случае оповестить субъектов доступа, что сертификат более не действителен? Для этого и служит Certificate Revocation List (CRL). Он представляет собой список серийных номеров отозванных сертификатов, подписанный УЦ, который их выпустил.
Вернёмся в каталог удостоверяющего центра:
root@server:~# cd /root/CA
Прежде чем мы сможем сгенерировать CRL, надо создать файл crlnumber. Он нужен openssl, чтобы отслеживать номер следующего CRL:
root@server:~# echo 1000 > crlnumber
В стандартной конфигурации openssl использует CRL V1.
Раcкомментируйте строку crl_extensions = crl_ext в /etc/ssl/openssl.cnf, чтобы переключиться на CRL V2. Это хорошая идея, за исключением тех случаев, когда надо использовать именно CRL V1 (например, при использовании сильно устаревшего браузера). Создаём CRL:
root@server:~# openssl ca -keyfile private/rootca.key -cert certs/rootca.crt -gencrl -out crl/rootca.crl
Предположим, что закрытый ключ сервера server был скомпрометирован. Чтобы оповестить об этом клиентские машины, надо отозвать сертификат этого сервера, создать CRL, а затем — распространить CRL среди клиентов.
Отзываем сертификат:
root@server:~# openssl ca -keyfile private/rootca.key -cert certs/rootca.crt -revoke certs/server.kb.edu.crt
Заглянем в index.txt. Начало записи с нашим сертификатом теперь изменилось с V на R:
root@server:~# cat index.txt
R 160116072355Z 150119081313Z 1000 unknown /C=RU/ST=Sverdlovskaya/O=UrFU/OU=KB/CN=server.kb.edu/emailAddress=support@kb.edu
Обратите внимание, что копии новых сертификатов так же содержатся в каталоге newcerts. При этом имя файла содержит серийный номер сертификата. Когда отзываете сертификаты, вместо файлов в каталоге certs Вы можете пользоваться каталогом newcerts. Результат будет идентичен. Например:
root@server:~# openssl ca -keyfile private/rootca.key -cert certs/rootca.crt -revoke newcerts/1000.pem
Обновим CRL:
root@server:~# openssl ca -keyfile private/rootca.key -cert certs/rootca.crt -gencrl -out crl/rootca.crl
Настроим клиентскую конфигурацию в /etc/ldap/ldap.conf и укажем, где хранится CRL:
#
# LDAP Defaults
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
BASE dc=kb,dc=edu
URI ldap://server.kb.edu
#SIZELIMIT 12
TIMELIMIT 15
TIMEOUT 20
#DEREF never
# TLS certificates (needed for GnuTLS)
#TLS_CACERT /etc/ssl/certs/ca-certificates.crt
TLS_CACERT /etc/ssl/certs/rootca.crt
TLS_REQCERT demand
TLS_CRLFILE /etc/ssl/rootca.crl
Для следующей команды потребуется установить на клиенте утилиты ldap:
Перезапустим демон slapd и убедимся, что к серверу можно подключиться.
root@server:~# service slapd restart
Где работаем: client
root@client:~# ldapsearch -xZZLLLWD cn=admin,dc=kb,dc=edu -b cn=config -s base dn
Enter LDAP Password:
dn: cn=config
В целом по отзыву сертификатов... Иногда в реальных условиях лучше применить другой подход. Намного удобней, когда клиентские машины самостоятельно выясняют у сервера, действителен конкретный сертификат или нет. В выпускаемые сертификаты можно вносить записьCRL Distribution Points. Она заставит клиентов самих периодически скачивать новый CRL. Или можно использоватьOCSP. Но эта тема выходит за рамки данной практики.
Управление пользователями и группами в OpenLDAP
Где работаем: server
На данном этапе у нас есть пустой каталог OpenLDAP. Мы можем проверить это, просто попытавшись извлечь из него информацию:
root@server:~# ldapsearch -xZZLLLWD cn=admin,dc=kb,dc=edu -b dc=kb,dc=edu
Enter LDAP Password:
No such object (32)
Если Вам интересно, коды ошибок LDAP описаны в RFC 4511, в приложении A Результирующие коды LDAP. В случае ошибки 32 сервер информирует нас, что запрашиваемый объект dc=kb,dc=edu не найден. Но такую же ошибку можно получить, если ACL сервера запрещают доступ.
Для работы нашего каталога понадобится создать корневой суффикс базы данных и добавить в него две организационных единицы (Organizational Unit, OU) для хранения пользователей и групп. Создадим LDIF-файл users+groups.ldif, в котором опишем эту информацию:
dn: dc=kb,dc=edu
dc: kb
objectClass: top
objectClass: domain
dn: ou=users,dc=kb,dc=edu
ou: Users
objectClass: top
objectClass: organizationalUnit
description: Central location for UNIX users
dn: ou=groups,dc=kb,dc=edu
ou: Groups
objectClass: top
objectClass: organizationalUnit
description: Central location for UNIX groups
dn: ou=services,dc=kb,dc=edu
ou: Services
objectClass: top
objectClass: organizationalUnit
description: Group all services under this OU
Добавим эту информацию в наш каталог:
root@server:~# ldapmodify -a -xZZWD cn=admin,dc=kb,dc=edu -f users+groups.ldif
Enter LDAP Password:
adding new entry "dc=kb,dc=edu"
adding new entry "ou=users,dc=kb,dc=edu"
adding new entry "ou=groups,dc=kb,dc=edu"
adding new entry "ou=services,dc=kb,dc=edu"
Можем удостовериться в том, что информация добавлена:
root@server:~# ldapsearch -xZZLLLWD cn=admin,dc=kb,dc=edu
Enter LDAP Password:
dn: dc=kb,dc=edu
dc: kb
objectClass: top
objectClass: domain
dn: ou=users,dc=kb,dc=edu
ou: Users
objectClass: top
objectClass: organizationalUnit
description: Central location for UNIX users
dn: ou=groups,dc=kb,dc=edu
ou: Groups
objectClass: top
objectClass: organizationalUnit
description: Central location for UNIX groups
dn: ou=services,dc=kb,dc=edu
ou: Services
objectClass: top
objectClass: organizationalUnit
description: Group all services under this OU
Теперь давайте добавим несколько групп:
sysadmin, для объединения системных администраторов Linux;
nssproxy, которая будет использоваться для опроса сервера, чтобы не делать анонимный опрос;
test.group, для тестирования различных частей архитектуры PAM и LDAP.
Этот список не окончательный и может быть дополнен, чтобы соответствовать нуждам Вашей организации.
Для добавления групп в каталог создадим новый LDIF groups.ldif:
dn: cn=sysadmin,ou=groups,dc=kb,dc=edu
cn: sysadmin
objectClass: top
objectClass: posixGroup
gidNumber: 1100
description: UNIX systems administrators
dn: cn=nssproxy,ou=groups,dc=kb,dc=edu
cn: nssproxy
objectClass: top
objectClass: posixGroup
gidNumber: 801
description: Network Service Switch Proxy
dn: cn=test.group,ou=groups,dc=kb,dc=edu
cn: test.group
objectClass: top
objectClass: posixGroup
gidNumber: 1101
description: Test Group
Загрузим LDIF в наш каталог:
root@server:~# ldapmodify -a -xZZWD cn=admin,dc=kb,dc=edu -f groups.ldif
Enter LDAP Password:
adding new entry "cn=sysadmin,ou=groups,dc=kb,dc=edu"
adding new entry "cn=nssproxy,ou=groups,dc=kb,dc=edu"
adding new entry "cn=test.group,ou=groups,dc=kb,dc=edu"
Настало время создать несколько пользователей. И вновь отмечаем, что список может быть расширен в соответствии с потребностями Вашей организации:
mpyrev - персональный пользователь.
nssproxy, который будет использоваться для опроса сервера, чтобы не делать опрос от анонимного пользователя.
test.user - как и тестовая группа, этот пользователь будет использоваться для проверки наших настроек.
Создадим LDIF-файл users.ldif для добавления пользователей. Пока не беспокойтесь о паролях, мы сейчас к ним вернёмся:
Пользователи связаны с группами через атрибут gidNumber. Для того, чтобы добавить в группу других пользователей, в запись группы необходимо добавить атрибут memberUID, перечислив в нём UID пользователей через запятую. Например, это может выглядеть вот так:
dn: cn=sysadmin,ou=groups,dc=kb,dc=edu
cn: sysadmin
objectClass: top
objectClass: posixGroup
gidNumber: 1100
description: UNIX systems administrators
memberUID: 801,1101
Добавьте пользователей в каталог:
root@server:~# ldapmodify -a -xZZWD cn=admin,dc=kb,dc=edu -f users.ldif
Enter LDAP Password:
adding new entry "cn=mpyrev,ou=users,dc=kb,dc=edu"
adding new entry "cn=nssproxy,ou=users,dc=kb,dc=edu"
adding new entry "cn=test.user,ou=users,dc=kb,dc=edu"
Теперь установим пароли для пользователей. Повторите нижеследующую команду для всех пользователей. Обратите внимание, что сначала Вам будет предложено дважды ввести пароль изменяемой записи, а затем — пароль записи cn=admin,dc=kb,dc=edu:
root@server:~# ldappasswd -xZZWD cn=admin,dc=kb,dc=edu -S cn=nssproxy,ou=users,dc=kb,dc=edu
New password:
Re-enter new password:
Enter LDAP Password:
Если заглянуть в журнал /var/log/slapd.log, то можно увидеть строки, говорящие об изменении записи:
slapd[5319]: conn=1022 op=1 PASSMOD id="cn=nssproxy,ou=users,dc=kb,dc=edu" new
slapd[5319]: conn=1022 op=1 RESULT oid= err=0 text=
Для того, чтобы пользователь nssproxy имел доступ к информации нашего каталога, необходимо поправить ACL базы данных с пользователями и группами. Но какое у этой базы DN? Давайте вспомним:
В разделе Инициализация базы данных мы дали нашей учетной записи администратора очень широкие права, поэтому он может заглянуть в конфигурацию cn=config.
Теперь мы знаем, что требуется отредактировать ACL записи olcDatabase={1}mdb,cn=config.
Давайте проверим, какие ACL настроены для данного DN (вывод отформатирован):
root@server:~# ldapsearch -xZZLLLWD cn=admin,dc=kb,dc=edu -b olcDatabase={1}mdb,cn=config olcAccess
Enter LDAP Password:
dn: olcDatabase={1}mdb,cn=config
olcAccess: {0}to *
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external ,cn=auth" manage
by * break
olcAccess: {1}to attrs=userPassword
by self write
by anonymous auth
olcAccess: {2}to *
by self read
Мы должны немного изменить ACL, чтобы предоставить доступ пользователю nssproxy на чтение атрибутов учётных записей. Для этого создадим LDIF-файл nssproxy.acl.ldif:
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to *
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external ,cn=auth" manage
by * break
-
add: olcAccess
olcAccess: {1}to attrs=userPassword
by self write
by anonymous auth
-
add: olcAccess
olcAccess: {2}to *
by self read
by dn.base="cn=nssproxy,ou=users,dc=kb,dc=edu" read
Проверим, можем ли мы просматривать информацию в каталоге от имени пользователя nssproxy. Для этого выполним запрос с использованием его учётных данных. Результатом запроса должно быть всё DIT (Directory Information Tree). Опустим его, для краткости:
При установке нам будут предложены некоторые настройки . Далее мы всё равно внесём в конфигурацию изменения, но это нужно сделать, чтобы все пакеты нормально установились:
URI сервера LDAP: ldap://server.kb.edu;
База поиска сервера LDAP: dc=kb,dc=edu;
Имена настраиваемых служб: passwd,group,shadow,netgroup.
Прежде чем делать запросы к LDAP-серверу, проверим параметры клиента в /etc/ldap/ldap.conf:
#
# LDAP Defaults
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
BASE dc=kb,dc=edu
URI ldap://server.kb.edu
#SIZELIMIT 12
TIMELIMIT 15
TIMEOUT 20
#DEREF never
# TLS certificates (needed for GnuTLS)
#TLS_CACERT /etc/ssl/certs/ca-certificates.crt
TLS_CACERT /etc/ssl/certs/rootca.crt
TLS_REQCERT demand
TLS_CRLFILE /etc/ssl/rootca.crl
Конечно, для того, чтобы всё заработало, сертификат нашего Certificate Authority (rootca.crt) и CRL-файл (rootca.crl) должны быть на месте.
Проверим работоспособность простым запросом. Результат опустим (Вы должны увидеть всё DIT):
root@client:~# ldapsearch -xZZLLLWD cn=nssproxy,ou=users,dc=kb,dc=edu
Enter LDAP Password:
dn: dc=kb,dc=edu
...
Поправим конфигурацию нашей локальной службы имён LDAP в файле /etc/nslcd.conf. Измените значение директивы bindpw на пароль записи cn=nssproxy,ou=users,dc=kb,dc=edu, который мы задавали ранее:
# /etc/nslcd.conf
# nslcd configuration file. See nslcd.conf(5)
# for details.
# The user and group nslcd should run as.
uid nslcd
gid nslcd
# The location at which the LDAP server(s) should be reachable.
uri ldap://server.kb.edu
# The search base that will be used for all queries.
base dc=kb,dc=edu
# The LDAP protocol version to use.
#ldap_version 3
# The DN to bind with for normal lookups.
#binddn cn=annonymous,dc=example,dc=net
#bindpw secret
binddn cn=nssproxy,ou=users,dc=kb,dc=edu
bindpw
# The DN used for password modifications by root.
#rootpwmoddn cn=admin,dc=example,dc=com
rootpwmoddn cn=admin,dc=kb,dc=edu
base group ou=groups,dc=kb,dc=edu
base passwd ou=users,dc=kb,dc=edu
base shadow ou=users,dc=kb,dc=edu
bind_timelimit 5
timelimit 10
idle_timelimit 60
# SSL options
#ssl off
ssl start_tls
#tls_reqcert demand
#tls_cacertfile /etc/ssl/certs/ca-certificates.crt
tls_reqcert allow
tls_cacertfile /etc/ssl/certs/rootca.crt
nss_initgroups_ignoreusers bin,daemon,games,lp,mail,nobody,nslcd,root,sshd,sync,uucp
nss_initgroups_ignoreusers sys,man,news,proxy,www-data,backup,list,irc,gnats,landscape
# The search scope.
#scope sub
Краткое описание использованных директив:
С помощью директивы base мы сообщаем демону nslcd, где в DIT искать ту или иную информацию;
bind_timelimit ограничивает время на установление соединения с сервером пятью секундами;
timelimit устанавливает максимальное время ожидания ответа от сервера в 10 секунд;
idle_timelimit заставит nslcd разорвать соединение с сервером, если в течении минуты в соединении не было никакой активности;
ssl заставляет клиента использовать TLS при подключении к серверу;
tls_reqcert и tls_cacertfile подобны директивам TLS_REQCERT и TLS_CACERT в конфигурации /etc/ldap/ldap.conf (необходимость проверки сертификата сервера и путь к корневому сертификату для выполнения проверки);
nss_initgroups_ignoreusers описывает пользователей системы, поиск которых не нужно производить в DIT (чтобы мы могли работать с машиной при проблемах с доступом к серверу каталогов). В значение этой директивы следует внести имена всех общесистемных пользователей.
Поменяем права доступа к nslcd.conf, потому что теперь в нём хранится информация для аутентификации:
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.
passwd: compat ldap
group: compat ldap
shadow: compat ldap
hosts: files dns
networks: files
protocols: db files
services: db files
ethers: db files
rpc: db files
netgroup: nis ldap
Убедимся в том, что демон nslcd запускается при старте системы и перезапустим его:
root@client:~# update-rc.d nslcd defaults
root@client:~# service nslcd restart
Убедимся, что в системе clientНЕТ учётной записи с именем nssproxy. Следующая команда должна выполняться без результата:
root@client:~# grep nssproxy /etc/passwd
Убедимся так же, что кэширующий демон службы имён загружается при старте системы и перезапустим его:
root@client:~# update-rc.d nscd defaults
root@client:~# service nscd restart
Сделаем пару запросов к LDAP-серверу, используя настроенную нами систему:
Отлично, всё работает! Вышеприведённые результаты команд означают, что система client может осуществлять поиск по данным пользователей и групп в нашем каталоге OpenLDAP.
Создадим домашний каталог нашего тестового пользователя и установим для него права доступа:
Запустим в отдельном терминале вывод журнала аутентификации:
root@client:~# tail -f /var/log/auth.log
В другом терминале выполним:
mpyrev@client:~$ su -
Мы должны получить приглашение командной строки пользователя test.user.
Теперь попробуем зайти на машину client по сети с использованием ssh под учётной записью test.user.
Демон ssh в конфигурации по умолчанию должен работать с поддержкой PAM (и, соответственно, поддерживать аутентификацию через LDAP). Но на всякий случай приведём /etc/ssh/sshd_config:
# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
#Port 22
#AddressFamily any
AddressFamily inet
AllowGroups sysadmin test.group
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
AllowTcpForwarding no
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
ClientAliveInterval 120
ClientAliveCountMax 2
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
Обратите внимание на строку с директивой AllowGroups. С помощью неё мы ограничиваем список групп пользователей, которые могут быть аутентифицированы через ssh. За информацией по остальным директивам обратитесь к документации.
Проверим работу с использованием какой-нибудь третьей машины. Например, выполним на нашей :
login as: test.user
test.user@localhost's password:
Linux client 5.10.0-21-amd64 #1 SMP Debian 5.10.162-1 (2023-01-21) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Apr 29 12:09:06 2023 from 192.168.3.2
test.user@client:~$
Где работаем: server
Давайте заглянем в /var/log/slapd.log на нашем сервере. Мы можем обнаружить там следующие строки:
ldap-srv slapd[1304]: <= mdb_equality_candidates: (objectClass) not indexed
ldap-srv slapd[1304]: <= mdb_equality_candidates: (uid) not indexed
С помощью следующей команды мы можем убедиться, что в нашем каталоге пока нет никаких индексов:
Это значит, что в нашей базе данных надо создать индексы для атрибутов из журнала /var/log/slapd.log. Поэтому создадим ещё один LDIF-файл posixAccount.indexes.ldif и запишем в него:
Отлично! Теперь в журнале /var/log/slapd.log не должно быть ошибок.
Kerberos KDC с использованием OpenLDAP в качестве бэкэнда и аутентификацией SASL GSSAPI
В этом разделе мы научимся использовать OpenLDAP 2.4 в качестве хранилища принципалов (principals) Kerberos и разберем, как настраивать клиентские рабочие станции. Kerberos — это сетевой протокол, который работает на основе билетов (tickets) и позволяет передавать данные через незащищённые сети для безопасной идентификации и аутентификации. Его дизайн преимущественно опирается на клиент-серверную модель и позволяет произвести взаимную аутентификацию субъекта и объекта доступа. Сообщения протокола устойчивы к прослушиванию и атакам повтора. Kerberos работает на основе криптографии с симметричным ключом и требует наличия доверенной третьей стороны, а так же может применяться с использованием криптографии с открытым ключом на некоторых этапах процесса аутентификации.
На текущем практическом занятии в роли сервера Kerberos будем использовать server. Но ничто не мешает Вам использовать для этого отдельную машину.
Настройка сервера Kerberos
Где работаем: server
Включите NTP и убедитесь, что сервер и клиенты синхронизированы! Мы не будем описывать, как настраивать NTP. Вы можете найти множество примеров в сети, если потребуется.
Теперь, когда наш сервер OpenLDAP настроен, мы можем приступить к конфигурированию сервера Kerberos. В этом разделе мы опишем, как развернуть центр распределения ключей Kerberos (KDC, Key Distribution Center) для области (realm) KB.EDU. Начнём с установки необходимых пакетов. В процессе будет так же установлено несколько пакетов-зависимостей. Пакет wamerican создаст файл /usr/share/dict/words, используемый kadmind. Вместо него можно использовать любой другой словарь или несколько словарей. Чтобы посмотреть их список, посмотрите содержимое метапакета wordlist.
Эта команда должна вернуть список объектов. Это важно, потому что если новых атрибутов Kerberos LDAP нет, то kdb5_ldap_util(8) выдаст следующую ошибку:
kdb5_ldap_util: Kerberos Container create FAILED: No such object while creating realm 'EXAMPLE.COM'
Итак, у нас есть набор схемы данных и объекты. Но есть ли у нас контейнер для принципалов Kerberos?
Нет, нету. Создадим его, а заодно — пользователя и группу, которые будут использоваться Kerberos для взаимодействия с сервером OpenLDAP. Используем для этой цели вот такой LDIF-файл kerberos.ldif:
[logging]
default = SYSLOG:INFO:LOCAL1
kdc = SYSLOG:NOTICE:LOCAL1
admin_server = SYSLOG:WARNING:LOCAL1
[libdefaults]
default_realm = KB.EDU
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
renew_lifetime = 7d
# The following krb5.conf variables are only for MIT Kerberos.
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
# The following encryption type specification will be used by MIT Kerberos
# if uncommented. In general, the defaults in the MIT Kerberos code are
# correct and overriding these specifications only serves to disable new
# encryption types as they are added, creating interoperability problems.
#
# The only time when you might need to uncomment these lines and change
# the enctypes is if you have local software that will break on ticket
# caches containing ticket encryption types it doesn't know about (such as
# old versions of Sun Java).
# default_tgs_enctypes = des3-hmac-sha1
# default_tkt_enctypes = des3-hmac-sha1
# permitted_enctypes = des3-hmac-sha1
# The following libdefaults parameters are only for Heimdal Kerberos.
fcc-mit-ticketflags = true
[realms]
KB.EDU = {
kdc = server.kb.edu
admin_server = server.kb.edu
default_domain = kb.edu
database_module = openldap_ldapconf
}
[domain_realm]
.kb.edu = KB.EDU
kb.edu = KB.EDU
[appdefaults]
pam = {
debug = false
ticket_lifetime = 36000
renew_lifetime = 36000
forwardable = true
krb4_convert = false
}
[dbmodules]
openldap_ldapconf = {
db_library = kldap
ldap_kerberos_container_dn = cn=kerberos,ou=services,dc=kb,dc=edu
ldap_kdc_dn = cn=krbadmin,ou=users,dc=kb,dc=edu
# этот объект должен иметь права на чтение контейнера области,
# контейнера принципала и поддеревьев области
ldap_kadmind_dn = cn=krbadmin,ou=users,dc=kb,dc=edu
# этот объект должен иметь права на чтение контейнера области,
# контейнера принципала и поддеревьев области
ldap_service_password_file = /etc/krb5.d/stash.keyfile
ldap_servers = ldapi:///
ldap_conns_per_server = 5
}
Теперь создадим список контроля доступа (ACL) администратора Kerberos. Не путайте этот ACL с ACL OpenLDAP. Это не одно и то же. Чуть ниже мы поработаем с ACL для OpenLDAP. Создадим файл /etc/krb5kdc/kadm5.acl с таким содержимым:
*/admin@KB.EDU *
Отредактируем /etc/krb5kdc/kdc.conf, конфигурационный файл службы аутентификации (AS, Authentication Service) и центра распределения ключей (KDC):
Но может ли кто-нибудь кроме пользователя cn=admin увидеть нашу информацию Kerberos? Это было-бы не очень мудро. Поэтому давайте взглянем на ACL нашего сервера OpenLDAP:
Что нам надо сделать, так это дать права доступа на чтение/запись администратору Kerberos (cn=krbadmin,ou=users,dc=kb,dc=edu) к поддереву cn=kerberos,ou=services,dc=kb,dc=edu. Никакой другой пользователь не должен иметь доступа к этой информации (за исключением администратора каталога).
Для этого сформируем LDIF-файл kerberos.acl.ldif:
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to *
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
by * break
olcAccess: {1}to attrs=userPassword,userPKCS12
by self write
by anonymous auth
olcAccess: {2}to attrs=shadowLastChange
by self write
olcAccess: {3}to dn.subtree="cn=kerberos,ou=services,dc=kb,dc=edu"
by dn.exact="cn=krbadmin,ou=users,dc=kb,dc=edu" manage
olcAccess: {4}to *
by dn.base="cn=nssproxy,ou=users,dc=kb,dc=edu" read
by self read
Убедитесь, что новые ACL работают. Суперпользователь и пользователь cn=admin,dc=kb,dc=edu должны иметь доступ к поддереву cn=kerberos,ou=services,dc=kb,dc=edu. Пользователь cn=nssproxy,ou=users,dc=kb,dc=edu не сможет обнаружить само существование контейнера Kerberos, а cn=krbadmin,ou=users,dc=kb,dc=edu должен не только видеть контейнер, но и иметь для него права на чтение/запись. Мы так же должны убедиться, что обычные пользователи всё ещё могут использовать сервер OpenLDAP для аутентификации и что они могут менять себе пароли.
Этот запрос возвращает поддерево cn=kerberos,ou=services,dc=kb,dc=edu:
Теперь с клиентской машины убедимся, что пользователь, учётная запись которого хранится на сервере каталогов, может менять свой пароль:
Где работаем: client
root@client:~# su - test.user
test.user@client:~$ passwd
(current) LDAP Password:
Новый пароль:
Повторите ввод нового пароля:
passwd: пароль успешно обновлён
Где работаем: server
Настало время настроить журналирование. Для начала добавим в конфигурацию rsyslog следующие строки (/etc/rsyslog.conf):
...
# Пишем журнал демона krb5-kdc в /var/log/krb5kdc.log:
if $programname == 'krb5kdc' then /var/log/krb5kdc.log
& ~
# Пишем журнал демона krb5-admin-server в /var/log/kadmind.log:
if $programname == 'kadmind' then /var/log/kadmind.log
& ~
Создадим файлы журналов и зададим для них права доступа:
Перезапустим демон rsyslog, чтобы конфигурация вступила в силу. Добавим демоны krb5-kdc и krb5-admin-server в автоматический запуск, затем запустим их:
root@server:~# service rsyslog restart
root@server:~# update-rc.d krb5-kdc defaults
root@server:~# update-rc.d krb5-admin-server defaults
root@server:~# service krb5-kdc start
root@server:~# service krb5-admin-server start
Загляните в журнал /var/log/krb5kdc.log. Вы должны увидеть там подобную строку:
...
Dec 1 15:49:54 ldap-srv krb5kdc[1992]: commencing operation
Проверим, что наши демоны слушают необходимые порты. Порт 88 (krb5kdc), порты 464 и 749 (kadmind):
Поздравляю, теперь у Вас есть рабочий сервер аутентификации (AS) и сервер распределения ключей (KDC) MIT Kerberos 5!
Что дальше? В первую очередь нам необходимо создать принципал для локального сервера. Затем — принципал для пользователя test.user. Сделаем это так (разобьем вывод на части, чтобы добавить комментарии):
root@server:~# kadmin.local
Authenticating as principal root/admin@KB.EDU with password.
Здесь мы создаём принципал машины для текущего сервера (на котором залогинены). Далее выделен вводимый нами текст:
kadmin.local: addprinc -randkey host/server.kb.edu@KB.EDU
WARNING: no policy specified for host/server.kb.edu@KB.EDU; defaulting to no policy
Principal "host/server.kb.edu@KB.EDU" created.
После создания принципала сервера мы можем добавить его в набор ключей Kerberos (/etc/krb5.keytab):
kadmin.local: ktadd host/server.kb.edu@KB.EDU
Entry for principal host/server.kb.edu@KB.EDU with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/server.kb.edu@KB.EDU with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/server.kb.edu@KB.EDU with kvno 2, encryption type des3-cbc-sha1 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/server.kb.edu@KB.EDU with kvno 2, encryption type arcfour-hmac added to keytab FILE:/etc/krb5.keytab.
Следующим шагом создадим принципал для персонального пользователя mpyrev и зададим для него пароль:
kadmin.local: addprinc mpyrev@KB.EDU
WARNING: no policy specified for mpyrev@KB.EDU; defaulting to no policy
Enter password for principal "mpyrev@KB.EDU":
Re-enter password for principal "mpyrev@KB.EDU":
Principal "mpyrev@KB.EDU" created.
Теперь создадим принципал пользователя с правами администратора. Помните файл /etc/krb5kdc/kadm5.acl? Вот где он вступает в игру. С помощью этого файла пользователи с префиксом /admin имеют права администратора на доступ к области Kerberos. Это значит, что они могут создавать и удалять записи пользователей и политики доступа. Поэтому убедитесь, что Вы знаете этих пользователей и доверяете им!
kadmin.local: addprinc mpyrev/admin@KB.EDU
WARNING: no policy specified for mpyrev/admin@KB.EDU; defaulting to no policy
Enter password for principal "mpyrev/admin@KB.EDU":
Re-enter password for principal "mpyrev/admin@KB.EDU":
Principal "mpyrev/admin@KB.EDU" created.
А эта команда выведет подробную информацию о принципале host/server.kb.edu@KB.EDU:
kadmin.local: getprinc host/server.kb.edu@KB.EDU
Principal: host/server.kb.edu@KB.EDU
Expiration date: [never]
Last password change: Сб апр 29 15:57:50 +05 2023
Password expiration date: [never]
Maximum ticket life: 1 day 00:00:00
Maximum renewable life: 0 days 00:00:00
Last modified: Сб апр 29 15:57:50 +05 2023 (root/admin@KB.EDU)
Last successful authentication: [never]
Last failed authentication: [never]
Failed password attempts: 0
Number of keys: 4
Key: vno 2, aes256-cts-hmac-sha1-96
Key: vno 2, aes128-cts-hmac-sha1-96
Key: vno 2, DEPRECATED:des3-cbc-sha1
Key: vno 2, DEPRECATED:arcfour-hmac
MKey: vno 1
Attributes:
Policy: [none]
kadmin.local: exit
Обратите внимание, что был создан новый файл /etc/krb5.keytab. Вот почему мы запустили бинарник kadmin.local от имени суперпользователя. Иначе мы получили бы следующую ошибку:
mpyrev@server:~$ kadmin.local
Authenticating as principal mpyrev/admin@KB.EDU with password.
kadmin.local: Error reading password from stash: Permission denied while initializing kadmin.local interface
Только суперпользователь имеет доступ на чтение к файлу-тайнику (/etc/krb5.d/stash.keyfile).
Давайте посмотрим, что записано в /etc/krb5.keytab:
С действующим KDC мы можем заставить клиентские машины и сервисы использовать его. Обозначим основные цели по настройке клиентов, чтобы интегрировать их в инфраструктуру Kerberos:
Аутентификация Kerberos для sshd.
Аутентификация OpenLDAP с помощью SASL GSSAPI.
Аутентификация Kerberos для sshd
Где работаем: client
Клиенты Kerberos должны иметь возможность подключения к TCP портам KDC с номерами 88 и 749
Во время установки в качестве области Kerberos можете задать KB.EDU, а в качестве серверов, обслуживающих область, server.kb.edu.
Отредактируйте конфигурацию клиента в файле /etc/krb5.conf следующим образом:
[logging]
default = SYSLOG:INFO:LOCAL1
kdc = SYSLOG:NOTICE:LOCAL1
admin_server = SYSLOG:WARNING:LOCAL1
[libdefaults]
default_realm = KB.EDU
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
renew_lifetime = 7d
# The following krb5.conf variables are only for MIT Kerberos.
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
# The following encryption type specification will be used by MIT Kerberos
# if uncommented. In general, the defaults in the MIT Kerberos code are
# correct and overriding these specifications only serves to disable new
# encryption types as they are added, creating interoperability problems.
#
# The only time when you might need to uncomment these lines and change
# the enctypes is if you have local software that will break on ticket
# caches containing ticket encryption types it doesn't know about (such as
# old versions of Sun Java).
# default_tgs_enctypes = des3-hmac-sha1
# default_tkt_enctypes = des3-hmac-sha1
# permitted_enctypes = des3-hmac-sha1
# The following libdefaults parameters are only for Heimdal Kerberos.
fcc-mit-ticketflags = true
[realms]
KB.EDU = {
kdc = server.kb.edu
admin_server = server.kb.edu
default_domain = kb.edu
}
[domain_realm]
.kb.edu = KB.EDU
kb.edu = KB.EDU
[appdefaults]
pam = {
debug = false
ticket_lifetime = 36000
renew_lifetime = 36000
forwardable = true
krb4_convert = false
}
Создайте новый принципал машины для этого хоста. Мы запускаем команду kadmin от имени суперпользователя, чтобы можно было записать результирующий файл /etc/krb5.keytab. Иначе мы получим не очень понятную ошибку No such file or directory while adding key to keytab.
Мы так же должны использовать модификатор -p, чтобы дать понять команде kadmin, от имени какого принципала мы хотим подключиться. Если мы его не зададим, то получим ошибку Client not found in Kerberos database while initializing kadmin interface, потому что не создавали принципал root/admin@KB.EDU.
Не создавайте этот принципал! Мы хотим знать, кто подключается с правами администратора (пользователи с префиксом /admin). Если создадим — не сможем различать администраторов между собой.
root@client:~# kadmin -p mpyrev/admin@KB.EDU
Authenticating as principal mpyrev/admin@KB.EDU with password.
Password for mpyrev/admin@KB.EDU:
kadmin: addprinc -randkey host/client.kb.edu@KB.EDU
No policy specified for host/client.kb.edu@KB.EDU; defaulting to no policy
Principal "host/client.kb.edu@KB.EDU" created.
kadmin: ktadd host/client.kb.edu@KB.EDU
Entry for principal host/client.kb.edu@KB.EDU with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/client.kb.edu@KB.EDU with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/client.kb.edu@KB.EDU with kvno 2, encryption type des3-cbc-sha1 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/client.kb.edu@KB.EDU with kvno 2, encryption type arcfour-hmac added to keytab FILE:/etc/krb5.keytab.
kadmin: exit
Эта команда создала файл /etc/krb5.keytab.
Теперь мы можем отредактировать /etc/ssh/sshd_config и включить аутентификацию Kerberos. Не забудьте добавить test.group в директиву AllowGroups. Иначе мы не сможем протестировать конфигурацию и увидим ошибку User test.user from server.kb.edu not allowed because none of user's groups are listed in AllowGroups в файле /var/log/auth.log.
# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
#Port 22
#AddressFamily any
AddressFamily inet
AllowGroups sysadmin test.group
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
#ChallengeResponseAuthentication no
ChallengeResponseAuthentication yes
# Kerberos options
#KerberosAuthentication no
KerberosAuthentication yes
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
GSSAPIAuthentication yes
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
AllowTcpForwarding no
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
ClientAliveInterval 120
ClientAliveCountMax 2
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
Banner /etc/issue
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
Перезапустим демон:
root@client:~# service ssh restart
Запустите на клиентской рабочей станции отображение файла журнала:
root@client:~# tail -F /var/log/auth.log
А пока вернёмся на сервер.
Где работаем: server
Создадим принципал пользователя test.user:
root@server:~# kadmin -p mpyrev/admin@KB.EDU
Authenticating as principal mpyrev/admin@KB.EDU with password.
Password for mpyrev/admin@KB.EDU:
kadmin: addprinc test.user@KB.EDU
WARNING: no policy specified for test.user@KB.EDU; defaulting to no policy
Enter password for principal "test.user@KB.EDU":
Re-enter password for principal "test.user@KB.EDU":
Principal "test.user@KB.EDU" created.
kadmin: exit
Возьмём билет Kerberos у test.user и прикинемся этим пользователем. Сначала мы уничтожим свои собственные билеты (если они есть), используя kdestroy, затем возьмём билет test.user с помощью kinit, а в итоге проверим, что он у нас есть с помощью klist:
root@server:~# kdestroy
kdestroy: No credentials cache found while destroying cache
root@server:~# kinit -p test.user@KB.EDU
Password for test.user@KB.EDU:
root@server:~# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: test.user@KB.EDU
Valid starting Expires Service principal
29.04.2023 16:28:10 30.04.2023 16:28:10 krbtgt/KB.EDU@KB.EDU
renew until 29.04.2023 16:28:10
Теперь попробуем авторизоваться на клиенте без пароля, используя этот билет:
root@server:~# ssh test.user@client.kb.edu
The authenticity of host 'client.kb.edu (192.168.3.140)' can't be established.
ECDSA key fingerprint is SHA256:mMV0STktM2g+B1pAdJjKacLjXj3c/qjW3uJR6jj/4No.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'client.kb.edu,192.168.3.140' (ECDSA) to the list of known hosts.
Debian GNU/Linux 11 \n \l
Linux client 5.10.0-21-amd64 #1 SMP Debian 5.10.162-1 (2023-01-21) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Apr 29 12:36:37 2023 from 192.168.3.2
test.user@client:~$
Где работаем: client
В открытом нами журнале на клиенте /var/log/auth.log мы должны увидеть что-то подобное:
Apr 29 15:00:55 client sshd[2170]: Authorized to test.user, krb5 principal test.user@KB.EDU (krb5_kuserok)
Apr 29 15:00:55 client sshd[2170]: Accepted gssapi-with-mic for test.user from 192.168.3.2 port 45995 ssh2
Apr 29 15:00:55 client sshd[2170]: pam_unix(sshd:session): session opened for user test.user by (uid=0)
Успех! Переходим к следующей цели.
Аутентификация OpenLDAP с помощью SASL GSSAPI
Где работаем: server
Для настройки аутентификации SASL GSSAPI мы должны изменить конфигурацию сервера OpenLDAP таким образом, чтобы он знал о существовании нашей области Kerberos. После этого мы можем настроить клиентов.
Подключимся к KDC и создадим новый принципал. Мы по-прежнему запускаем kadmin от имени суперпользователя, потому что хотим создать новый набор ключей в файле /etc/ldap/krb5.keytab, чтобы наш демон slapd имел свой набор.
root@server:~# kadmin -p mpyrev/admin@KB.EDU
Authenticating as principal mpyrev/admin@KB.EDU with password.
Password for mpyrev/admin@KB.EDU:
kadmin: addprinc -randkey ldap/server.kb.edu@KB.EDU
No policy specified for ldap/server.kb.edu@KB.EDU; defaulting to no policy
Principal "ldap/server.kb.edu@KB.EDU" created.
kadmin: ktadd -k /etc/ldap/krb5.keytab ldap/server.kb.edu@KB.EDU
Entry for principal ldap/server.kb.edu@KB.EDU with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/ldap/krb5.keytab.
Entry for principal ldap/server.kb.edu@KB.EDU with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/ldap/krb5.keytab.
Entry for principal ldap/server.kb.edu@KB.EDU with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/etc/ldap/krb5.keytab.
Entry for principal ldap/server.kb.edu@KB.EDU with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/etc/ldap/krb5.keytab.
Поменяем права доступа на этот файл, чтобы демон slapd смог его читать:
Все настройки для доступа на сервер у нас уже внесены в файл /etc/ldap/ldap.conf. Проверим, можем ли мы сделать запрос к LDAP-серверу:
mpyrev@client:~$ ldapwhoami
SASL/GSSAPI authentication started
SASL username: mpyrev/admin@KB.EDU
SASL SSF: 256
SASL data security layer installed.
dn:uid=mpyrev/admin,cn=kb.edu,cn=gssapi,cn=auth
Отлично. Теперь попробуем зайти с хостовой машины на client под пользователем test.user и поменять ему пароль.
login as: test.user
Pre-authentication banner message from server:
| Debian GNU/Linux 11 \n \l
|
End of banner message from server
Keyboard-interactive authentication prompts from server:
| Password:
End of keyboard-interactive prompts from server
Linux client 5.10.0-21-amd64 #1 SMP Debian 5.10.162-1 (2023-01-21) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Apr 29 16:29:21 2023 from 192.168.3.139
test.user@client:~$ passwd
Current Kerberos password:
Enter new Kerberos password:
Retype new Kerberos password:
passwd: пароль успешно обновлён
test.user@client:~$
Процесс обновления пароля изменился. Если мы попытаемся запустить команду passwd от имени пользователя, которого нет в локальном файле /etc/passwd, пароль будет изменен с использованием механизмов Kerberos.
Рекомендуется перед выполнением команды перейти в каталог, содержащий файл app.py
Значения флагов команд:
создается учетная запись без полноценного домашнего каталога (с помощью опции –d задается явный домашний каталог, в данном случае совпадающий с текущим каталогом, опция –M говорит, что каталог не нужно инициализировать);
создается системная учетная запись (т.е. uid менее 1000 – чистое украшательство), что задается опцией –r ;
у учетной записи отсутствует пароль и шелл (опция –s задает специальный «шелл» /usr/sbin/nologin) – это делает невозможным обычный вход от имени этой учетной записи (что локальный, что по SSH).
Показать, что просто так перейти в сеанс учетной записи невозможно:
mpyrev@server:~$ sudo su flask-run # выполнится с ошибкой
mpyrev@server:~$ sudo su –l flask-run –s /bin/bash # позволит перейти в сеанс flask-run
Запустить web-сервер из под учетной записи flask-run (в сеанс перешли в предыдущей демонстрации), команды предполагают, что текущий каталог это /home/mpyrev, а не web_server_for_OWASP:
start-stop-daemon – утилита, которая берет на себя рутину по «демонизации» любых процессов, поэтому удобно ее использовать для запуска различных серверов.
Пояснения по синтаксису:
-S – команда запуска
-K – команда останова
-b – запуск в режиме демона (освобождение консоли)
--make-pidfile – указывает что start-stop-daemon самостоятельно позаботиться о создании PID файла
--pidfile – указывает имя PID файла, которое надо использовать
-u flask-run – способ проверки, что демон еще не запущен (в данном случае по имени пользователя – если уже будет процесс python3 от имени flask-run, то start-stop-daemon ничего не запустит)
-d – указывает на домашний каталог демона (обязательно, иначе сервер не найдет свои файлы – БД, шаблоны и пр.)
-a – что, собственно, запускать (здесь сделано через подстановку результата работы утилиты which для универсальности, но можно просто задать полное имя)
-c – от чьего имени запускать
После -- идут опции, которые передаются запускаемому демону
Опционально можно убедиться, что через web сервер мы прекрасно можем прочитать файл start.sh (да и любой другой, к которому у flask-run есть доступ на чтение)
Помещение сервера в изолированный профиль AppArmor
Информацию про Linux Security Modules (механизм реализации альтернативной модели безопасности в Linux) можно прочитать в лекциях (презентации Лекция_13 и Лекция_16)
Создание нового профиля AppArmor
Останавливаем web сервер (stop.sh)
Устанавливаем утилиты для работы с профилями AppArmor:
Во второй консоли также запускаем web сервер и снова выполняем все легитимные действия. Можно сделать что-то запрещенное, убедиться, что все получилось, но запомнить, что сделали, чтобы не добавить потом это действие в разрешения профиля.
Если сервер перестал работать, возможно скорректировать профиль по пути /etc/apparmor.d в данной папке возможно найти профиль home.mpyrev.venv.bin.python3 и проверить что запрещено (строка начинается сdeny)
После сохранение профиля необходимо перезапустить сервис Apparmor командой
systemctl restart apparmor
Останавливаем web-сервер во второй консоли
Запускаем утилиту сканирования журнала:
mpyrev@server:~$ sudo aa-logprof
Анализируем вывод утилиты (аналогичен aa-genprof). Если видно, что запрашиваются какие-то нужные права – подтверждаем. Всякие сомнительные – либо Ignore, либо Deny (отличие в том, что Deny больше не попадет в логи вообще, а так оба варианта запрещают действие, так как политика AppArmor строится на принципе запрещено все, что не разрешено).
/home/mpyrev/venv Full
/home/mpyrev/web_server_for_OWASP Full
!/home/mpyrev/web_server_for_OWASP/database.db
!/home/mpyrev/web_server_for_OWASP/database.db-journal
Пояснение по содержимому: первые две сроки задают каталоги для контроля целостности и способ контроля. Full – это макрос, который говорит контролировать все, использовать все поддерживаемые контрольные суммы. Кому интересно, может найти определение макроса в /etc/aide/aide.conf (там сильная вложенность макросов).
Последние две строки задают исключения для контроля целостности.
В отличие от других мануалов, где следующим шагом идет «отключите SELinux», мы сейчас узнаем, почему так получилось и что можно сделать.
Для начала — установим консольные утилиты для управления политиками SELinux:
А потом — включим нужные нам модули ( командой semodule ):
[root@lamp ~]# semodule -e apache
[root@lamp ~]# semodule -e mysql
Давайте посмотрим, с какими именно проблемами столкнулся apache при открытии этой страницы?
audit2allow -lb -t httpd_t
#============= httpd_t ==============
#!!!! This avc can be allowed using one of the these booleans:
# httpd_enable_homedirs, httpd_unified
allow httpd_t httpd_user_content_t:file getattr;
Все верно: папка www (а так-же папки web и public_html) внутри домашней директории пользователя автоматически получает тип httpd_user_content_t, что и указано в правилах:
Лечение указано в выводе audit2allow, установка переменных выполняется командой setsebool(или semanage boolean).
[root@lamp ~]# cd /etc/httpd
[root@lamp httpd]# setsebool -P httpd_enable_homedirs=1
Обновляем страницу и получаем:
Смотрим логи:
/var/log/httpd/error_log
[Sun May 28 22:28:07.097784 2023] [proxy:error] [pid 37774:tid 37917] (13)Permission denied: AH00957: FCGI: attempt to connect to 127.0.0.1:9009 (*:80) failed
[Sun May 28 22:28:07.097863 2023] [proxy_fcgi:error] [pid 37774:tid 37917] [client 127.0.0.1:58310] AH01079: failed to make connection to backend: 127.0.0.1
Все ясно: httpd не может коннектиться куда попало, httpd может ходить только куда нужно. Это логично: если веб-сервер вдруг соединяется по ssh, то явно происходит что-то странное.
Давайте посмотрим, куда веб-серверу ходить можно?
sesearch -A -s httpd_t -c tcp_socket -p name_connect
MariaDB [(none)]> CREATE USER 'admin'@'localhost' IDENTIFIED BY 'P@ssw0rd';
MariaDB [(none)]> CREATE DATABASE phpbb;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON phpbb.* TO 'admin'@'localhost';
Пробуем зайти в инсталляшку phpbb:
Почему так? Потому что httpd не может изменять пользовательские данные. Давайте узнаем, какие же он изменять может?
Устанавливаем php-xml и php-mbstring включаем httpd_builtin_scripting и назначаем контекст httpd_user_rw_content_t на указанные файлы и папки (командой chcon):
Теперь мы ещё больше повысили значимость учётной записи администратора. С её помощью теперь можно получить полный доступ к службе каталогов. Имейте это ввиду.
Вот и всё! На этом танцы с бубном у Kerberos закончились.