Всем привет. Монтируете ли вы шары, как их монтирую я? Вероятно, нет, т. к. очень крутой опции
multiuser
на просторах интернета уделено слишком мало внимания, а man mount.cifs
в её отношении весьма немногословен и скуп на наглядные примеры. Именно это и сподвигло меня поделиться с вами парой «рецептов», которые могут облегчить вам и вашим пользователям движение в сторону отечественных десктопов и ИТ-инфраструктур.
Как обычно у меня на стенде российская RedOS 7, просто как образец операционной системы с не самым древним набором пакетов и инициализацией посредством systemd. С другими дистрибутивами вы справитесь самостоятельно. Юзеры и компьютеры живут в виндовом домене, а из отягчающих обстоятельств — наличие многопользовательских рабочих мест (сменный персонал).
Отечественные операционные системы (а это в основном Linux) дают нам возможность монтировать сетевые файловые системы несколькими методами, которые создавались с целью обойти какие-либо ограничения безопасности, либо для снижения сложности ручной процедуры монтирования конечным пользователем. Это и классическое монтирование через fstab или просто ручной вызов mount, варианты automount/autofs, а также монтирование в пространстве пользователя посредством gvfs. Способов много, и все они имеют несомненные достоинства, основное из которых — они работают.
При этом и недостатков также хватает: тут и проблемы с безопасностью (установка бита суидности), неудобство с ручным монтированием, пугающее количество опций, низкая производительность и нечеловеческие пути в случае gvfs, уникальность путей для каждого юзера на многопользовательских машинах, а при глобальном монтировании получаем «анонимный» доступ к сетевому ресурсу (несколько пользователей системы работают с файлами на сетевом ресурсе с правами пользователя, под которым выполнено монтирование). Это далеко не полный список.
На мой взгляд, решением всех этих проблем является монтирование сетевых ресурсов с опцией multiuser. Данная опция позволяет иметь одновременный доступ к сетевому ресурсу по одному подключению нескольким пользователям под своими учётными данными и со своими правами. Пользователь root, либо система при загрузке, как обычно монтируют удалённую файловую систему в каталог, и каждый пользователь видит в нём только те файлы/каталоги, на которые у него назначены права на файловом сервере. Почти как NFS, только с учётом особенностей «однопользовательского» протокола CIFS.
В чём основные плюсы данного решения:
- Настраивается глобально, конфигурация рабочих мест унифицирована.
- Чёткое разграничение прав. Каждый пользователь видит только то, что ему разрешено, а root монтирует файловые ресурсы под весьма ограниченным в правах «техническим» пользователем.
- У всех пользователей одинаковые пути — можно обмениваться абсолютными ссылками и пропадают проблемы с программами, не умеющими работать с gvfs.
- Высокая производительность.
- Отсутствует необходимость выдачи избыточных прав пользователям.
Далее прорабатываем два варианта в зависимости от методов аутентификации.
▍ Рецепт 1. Монтирование с логином/паролем
Стандартная ситуация, когда для доступа к ресурсу необходимо ввести логин и пароль. Варианты такие не редкость, например, у меня эксплуатируется старенький NAS, который решили не интегрировать в домен, а пользоваться его внутренней базой пользователей.
На клиентской машине добавляем строчку монтирования в fstab:
//NAS/FOTO /mnt/foto cifs cred=/root/.config/cifscred,multiuser,file_mode=0600,dir_mode=0700 0 0
Как видим, опций немного. Обязательно указываем multiuser, а опцией cred задаём файл, содержащий данные для аутентификации на сервере. Можно вместо опции cred использовать совокупность опций username/password/domain (man mount.cifs
), но это несколько несекьюрно с моей точки зрения :) Соответственно, у рута создаём файлик ~/.config/cifscred вот такого вида:
username=needly
password=P@ssw0rd
domain=CORP
Перезагружаемся и видим следующую картину:
- Ресурс смонтировался.
- Пользователь root кое-что видит. На самом деле иногда удобно не держать его бесправным, а дать доступ к каким-нибудь полезным папкам.
- Обычный пользователь ничего не увидел. Почему?
Всё дело в том, что пользователи должны повесить на ядрёный брелок (kernel keyring) свои логин/пароль. Тогда ядро сможет получать с сервера необходимые ресурсы, используя эти данные.
С командной строки это можно сделать утилиткой cifscreds из пакета cifs-utils
:
$ cifscreds add -u alef13 -d CORP
Password: P@ssw0rd
В примере выше заданы пароль/логин на домен. Они будут применяться при доступе к любому серверу, входящему в этот домен/рабочую группу.
Можно сделать иначе и указать учётные данные на конкретный сервер:
$ cifscreds add -u alef13 nas.corp.ru
Password: P@ssw0rd
Посмотреть наличие аутентификационных данных (но не их содержимое!) можно командой keyctl из пакета keyutils
:
$ keyctl show
Session Keyring
30364231 --alswrv 0 0 keyring: _ses
500025711 --alswrv 0 65534 _ keyring: _uid.0
497176618 ----sw-v 0 0 _ logon: cifs:d:CORP
343241234 ----sw-v 0 0 _ logon: cifs:a:192.168.0.2
Впрочем, свои учётные данные можно загонять в брелок с помощью команды keyctl (и так даже проще скриптовать):
$ keyctl add logon cifs:d:CORP alef13:P@ssw0rd @s
Или
$ keyctl add logon cifs:a:192.168.0.2 alef13:P@ssw0rd @s
После таких манипуляций картина совершенно другая:
- Проверяем, что видит root.
- Проверяем, что видит обычный пользователь
- Вешаем на брелок наш логин/пароль. Проверили, как висит.
- Пользователь имеет доступ! И обратите внимание, что видит он больше, чем рут.
Напрягать пользователя на дополнительный ручной ввод своих учётных данных не хочется, поэтому сделаем, чтобы они вводились автоматом. Если логин/пароль для доступа к ресурсу совпадают с учётными данными, под которыми пользователь авторизуется в системе, то всё решается подключением pam_cifscreds. Для настройки достаточно прочитать соответствующий man. Только не забывайте синхронизировать пароль рабочей учётной записи и пароль на общем ресурсе, иначе можно заблокироваться при безуспешных попытках входа.
Если учётки/пароли не совпадают, то надо создать скрипт, который будет вызываться из папки автостарта вашего Desktop Environment и загонять необходимые парольные пары в ядро при входе пользователя в систему. Это либо простейший bash-скрипт с вызовом keyctl, как я показал выше, либо скрипт на Python.
Для начала подсмотрим, как работает с keyring утилита cifscreds.
alef13 ~ $ strace cifscreds add -u alef13 192.168.0.2 2>&1| grep key
openat(AT_FDCWD, "/lib64/libkeyutils.so.1", O_RDONLY|O_CLOEXEC) = 3
keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 0) = 67942699
keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_USER_SESSION_KEYRING, 0) = 956021303
keyctl(KEYCTL_SEARCH, KEY_SPEC_SESSION_KEYRING, "logon", "cifs:a:192.168.0.2", 0) = -1 ENOKEY (Required key not available)
Password: P@ssw0rd
add_key("logon", "cifs:a:192.168.0.2", "alef13:P@ssw0rd", 15, KEY_SPEC_SESSION_KEYRING) = 697036719
keyctl(KEYCTL_SETPERM, 697036719, KEY_POS_VIEW|KEY_POS_WRITE|KEY_POS_SEARCH|KEY_USR_VIEW|KEY_USR_WRITE|KEY_USR_SEARCH) = 0
Видна полезная нагрузка — это подтягивание libkeyutils.so.1 и вызов add_key. Соответствующий сниппет Python-кода:
keyutils = ctypes.CDLL('libkeyutils.so.1')
key_id = b'cifs:a:192.168.0.2'
key_value = b'alef13:P@ssw0rd'
n = keyutils.add_key(b'logon', key_id, key_value, len(key_value), -3)
print(n)
Осталось разработать красивую обвязку: проверка/удаление старых ключей, работа с конфигурационными файлами и т. д.
▍ Рецепт 2. Монтирование с аутентификацией kerberos
Штатная опция mount.cifs
, отвечающая за метод аутентификации, называется sec, и для kerberos имеет значения krb5
и krb5i
. Выбираете подходящий и будете аутентифицироваться при монтировании ресурса с помощью билетика kerberos, лежащего в вашем кэше.
Опять клиенту в /etc/fstab
добавляем запись типа:
//srv1/shara1 /mnt/shara1 cifs domain=CORP,sec=krb5,multiuser,file_mode=0600,dir_mode=0700 0 0
Здесь, по сравнению с «Рецептом 1», ситуация противоположная — входя в систему, пользователь аутентифицируется в домене, и билетик автоматически складывается в кэш kerberos-а, а вот руту этот кэш необходимо пополнить принудительно при старте системы. Для этого мы сделаем простейший сервис, который посредством kinit будет получать билетик при загрузке системы, а чтобы избежать интерактивности (ввод пароля) будем использовать keytab.
Работа с утилитами kerberos это практически отдельная статья, при желании вы найдёте их в интернете в достаточном количестве. Здесь я приведу минимальный набор только лишь для того, чтобы стартануть и потестировать предлагаемый метод монтирования.
Прежде всего необходимо сформировать keytab-файл. Для этого запускаем команду ktutil, и в приглашении вводим следующие заклинания:
# ktutil
ktutil: addent -password -p needly -k 1 -e rc4-hmac
Password for needly@CORP: P@ssw0rd
ktutil: wkt /etc/krb5.keytab
ktutil: q
Кратко по параметрам: -password — аутентификация по паролю, -p needly — «технический» пользователь (principal), который будет логиниться к разделяемому ресурсу, -k 1 — версия записи KVNO (из нескольких идентичных записей будет использоваться с большим номером), -e rc4-hmac — метод шифрования.
Далее авторизуемся, чтобы сгенерировать кэш (заодно протестируем наш keytab).
# kinit -k -V needly
Using default cache: /tmp/krb5cc_0
Using principal: needly@CORP
Authenticated to Kerberos v5
Прошу обратить внимание, что кейтаб наш работает, пока не истёк пароль учётной записи, а также в домене должен существовать пользователь needle с паролем P@ssw0rd.
Итак, кейтаб подготовлен, теперь необходим сервис для обновления кэша kerberos при загрузке системы.
Формируем текстовый файл /etc/systemd/system/root_krb_init.service
:
[Unit]
Description=Updating k-ticket root
After=network-online.target
[Service]
ExecStart=/usr/bin/kinit -k -t /etc/krb5.keytab needly
[Install]
WantedBy=remote-fs-pre.target
Далее стандартно:
# systemctl daemon-reload && systemctl enable root_krb_init.service
Перезагружаемся и пробуем:
- Пользователь root ничего не видит (просто на этом сервере ему ничего не выдали), но и ошибок никаких нет.
- Обычный пользователь ничего не видит (тут я забыл заскриншотить пустой вывод klist), есть ошибки.
- Получаем билетик.
- Профит!!!
▍ Специи и приправы
Унифицированной точки монтирования и правильного разграничения доступа мы добились, однако внедрять по рабочим местам ещё рановато — надо дать необходимые пояснения и красиво это подать пользователю.
- Многие обратили внимание, что изменения вносятся в fstab, а не в модули systemd. Я знаю и умею их писать, однако работа с fstab мне нравится больше — всё в одном месте, редактировать легко, все опции удобны и понятны. Более того, Леннарт Пёттеринг (автор systemd) также рекомендует вносить изменения в /etc/fstab — смотрите
man systemd.mount
в разделеFSTAB
. Там же находятся и опции, позволяющие определить порядок монтирования и другие полезные директивы, используемые в unit-файлах для файловых систем (кстати, в рецепт с собакой необходимо в строчку монтирования ресурса добавить опциюx-systemd.after=root_krb_init.service
). - В примерах строчек для монтирования я указал права на ресурсы — файлы 600, каталоги 700. Система прав Linux (точнее POSIX) довольно примитивна, но и она вызывает затруднения у некоторых товарищей, из которых они выходят простейшим образом — дают на файлы и каталоги права 777. Это ужасно, хоть и работает в большинстве случаев. При таком подходе существует ненулевая вероятность поймать троянского коня, вот примерно такого — «Файлы полиглоты или как картинка с котиком станет угрозой для безопасности вашей информации». Самое опасное — это права выполнения на все файлы. Поэтому рекомендую ставить как я написал выше, про группу и прочих не волнуйтесь — права хоть и будут отображаться, но опция multiuser работает только с пользователями, предоставившими свои учётки для доступа к серверу.
- Чтобы смонтированный сетевой ресурс появился на рабочем столе и в файловом менеджере, нам необходимо монтировать их в каталоги
/media
,$HOME
или/run/media/$USER
. Если стандартные точки монтирования не нравятся, монтируем куда хочется, только добавляем опцию x-gvfs-show в соответствующую строкуfstab
, и тогда ресурс также отобразится на десктопе. Дополнительные визуальные параметры описаны здесь what-is-shown.txt.
Если решите опцией x-gvfs-name дать своему ресурсу красивое имя на рабочем столе, то учтите — пробелы в чистом виде использовать не получится, и их не заэкранировать слэшами со всякими кавычками. Просто вместо пробелов и спецсимволов используйте их шестнадцатеричное (x-gvfs-name=my%20cool%20share
) представление. - Формирование кэша с помощью kinit — рабочий вариант, но есть и получше. Я имею в виду kstart, который позволяет автоматически продлевать билет и восстанавливать его при обрыве связи. К сожалению, в коробку с РедОС его не положили, поэтому разбирайтесь с ним самостоятельно. Если остаётесь на kinit, то постарайтесь сделать так, чтобы пользователи ежедневно выключали систему.
- Когда возникают проблемы — отключайте антивирус :) В данном случае это хоть и выглядит шуткой, однако при проработке решений он попортил у меня немало крови. Как оказалось, один отечественный антивирус игнорирует исключения путей, внесённые в настройки задач, а ведёт себя адекватно только когда точки монтирования прописаны в глобальные исключения.
▍ Финал
Обозначенные ранее цели достигнуты — это безопасно, унифицировано, прозрачно для любого пользователя, и вдобавок у них одинаковые фиксированные пути к любому сетевому ресурсу. Настройки сделаны удалённо на всех рабочих местах, можно идти к пользователю и показывать красивую иконку диска «R» на рабочем столе. Изначально писал как некую шпаргалку для себя и своих коллег, но надеюсь, и вам этот небольшой туториал поможет немного упростить задачу импортозамещения.
Автор:
alef13