Монтируем шары для юзеров

в 9:00, , рубрики: CIFS, mount, ruvds_статьи, импортозамещение по

Монтируем шары для юзеров - 1


Всем привет. Монтируете ли вы шары, как их монтирую я? Вероятно, нет, т. к. очень крутой опции 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

Перезагружаемся и видим следующую картину:

Монтируем шары для юзеров - 2

  1. Ресурс смонтировался.
  2. Пользователь root кое-что видит. На самом деле иногда удобно не держать его бесправным, а дать доступ к каким-нибудь полезным папкам.
  3. Обычный пользователь ничего не увидел. Почему?

Всё дело в том, что пользователи должны повесить на ядрёный брелок (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

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

Монтируем шары для юзеров - 3

  1. Проверяем, что видит root.
  2. Проверяем, что видит обычный пользователь
  3. Вешаем на брелок наш логин/пароль. Проверили, как висит.
  4. Пользователь имеет доступ! И обратите внимание, что видит он больше, чем рут.

Напрягать пользователя на дополнительный ручной ввод своих учётных данных не хочется, поэтому сделаем, чтобы они вводились автоматом. Если логин/пароль для доступа к ресурсу совпадают с учётными данными, под которыми пользователь авторизуется в системе, то всё решается подключением pam_cifscreds. Для настройки достаточно прочитать соответствующий man. Только не забывайте синхронизировать пароль рабочей учётной записи и пароль на общем ресурсе, иначе можно заблокироваться при безуспешных попытках входа.

Если учётки/пароли не совпадают, то надо создать скрипт, который будет вызываться из папки автостарта вашего Desktop Environment и загонять необходимые парольные пары в ядро при входе пользователя в систему. Это либо простейший bash-скрипт с вызовом keyctl, как я показал выше, либо скрипт на Python.

Для любителей Питона

Чтобы написать скрипт на Python, надо научиться работать с keyring ядра. Штатных библиотек я не нашёл, вроде есть какие-то древние исходники на GitHub, но и они нам не понадобятся.

Для начала подсмотрим, как работает с 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

Перезагружаемся и пробуем:

Монтируем шары для юзеров - 4

  1. Пользователь root ничего не видит (просто на этом сервере ему ничего не выдали), но и ошибок никаких нет.
  2. Обычный пользователь ничего не видит (тут я забыл заскриншотить пустой вывод klist), есть ошибки.
  3. Получаем билетик.
  4. Профит!!!

▍ Специи и приправы

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

  • Многие обратили внимание, что изменения вносятся в 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

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js