Добрый день всем.
Не думаю, что описанная мной ситуация типична для большинства, но тем не менее думаю, что будет полезно знать.
Моя история о методе надежной защиты на случай, если у вас есть САН сети имеется несколько СХД (систем хранения данных), не поддерживающих технологию ограничения доступа к определенным LUN (номеру логического устройства) и серверам на базе Linux (в нашем случае все действия будут осуществляться с использованием ОС SLES 10SP1) .
Фон
В 2008 году мне пришлось сдавать в эксплуатацию вычислительную инфраструктуру одного заказчика.Была построена небольшая сеть SAN с определенным количеством запоминающих устройств (около 10 единиц разных классов).
Большинство этих стеков предназначались для построения файловой системы вычислительного кластера, поэтому изначально проблема не была очевидной и о ней даже не думали.
Но проблема в том, что для некоторых подсистем инфраструктуры было выделено хранилище, которое не умеет ограничивать доступ к определённым LUN-ам с определённых хостов (у каждого производителя это называется по-разному Port Masking, LUN MAPPING и т.п.
), а точнее может сделать это, но вам нужно приобрести доп.
лицензию, но этого сделано не было.
И тут возникла проблема — все сервера, подключающиеся к данному хранилищу, видят все его разделы.
Вроде бы ничего страшного в этом нет, но необходимо оградить заказчика от возможности форматирования чужого раздела, т.к.
данные каждой подсистемы очень важны.
Итого имеем:
- Система хранения данных БИС (точнее один из его партнёров)
- Серверы на базе SLES10 SP1 с двухголовым адаптером FC
- Огромное желание застраховать себя и заказчика от ошибок.
Шаг первый, вводный
Сразу оговорюсь для тех, кто не обладает глубокими знаниями темы: Каждое устройство в сети SAN имеет уникальный адрес WWN (World Wide Name), это своего рода аналог MAC-адреса сетевого адаптера, но, как и в случае с Ethernet, свитч не знает, что находится внутри пакет приходит на свитч, поэтому сделать ограничение на свитче (зонирование) невозможно, можно только ограничить область видимости СХД для определенных узлов, что и было сделано.Поиск решения ограничился следующими вариантами:
- Наличие в драйвере возможности использовать только определенные LUN
- Используйте инструменты ОС для блокировки ненужных LUN
Первый вариант
Он исчез после того, как мы посмотрели информацию по этому модулю.
Он содержит только возможность сканирования устройства и определяет максимальное количество LUN. Так что этот вариант исключен
Второй вариант
Эта опция сразу направляет нас на «проведение земляных работ» в сторону подсистемы udev. Именно она отвечает в Linux за инициализацию устройств, присвоение им специализированных имен и другие действия.Проще говоря, нам нужно правильно описать правило для udev, которое будет создавать только нужные нам устройства.
Забегая немного вперед, скажу, что данное решение лишь ограничит создание специальных.
устройства (например, /dev/sdb, /dev/sdc и т. д.), но физически хост будет видеть все доступные ему LUN.
Шаг второй, исследование
Перейдем к детальному изучению темы.После беглого изучения документации, а также правил, существующих в системе, мы можем выделить следующие интересующие нас блоки:
- Блок «SUBSYSTEM», определяющий подсистему.
Существует три типа подсистем: «block» (блочные устройства), «char» (символьные устройства) и «pipe» (устройства FIFO).
man mknod
Нас интересует «блочная» подсистема, поскольку диски относятся именно к этому классу. - udev может просматривать атрибуты устройства.
Обычно они хранят различные данные, такие как:
- тип производителя,
- название модели,
- различные аппаратные данные.
устройство, назначенное этому устройству SCSI Утилита udevinfo — показывает все необходимые данные о запрашиваемом устройстве.
Давайте начнем: Во-первых, нам нужно отобразить список всех устройств, доступных на этом сервере:
# lssci SCSI ID TYPE VENDOR MODEL REV. device [5:0:0:10] disk XXX YYYYY 0619 /dev/sdr [5:0:0:20] disk XXX YYYYY 0619 /dev/sds [5:0:0:21] disk XXX YYYYY 0619 /dev/sdu .
[5:0:1:10] disk XXX YYYYY 0619 /dev/sdan [5:0:1:20] disk XXX YYYYY 0619 /dev/sdao [5:0:1:21] disk XXX YYYYY 0619 /dev/sdar
Вывод этой команды будет большим, поэтому я приведу только часть.Итак, теперь мы знаем: SCSI ID — идентификатор в формате H:B:T:L (Host:Bus:Target:Lun).
Host — серийный номер адаптера, который отвечает за это устройство.
Bus(Channel) — номер канала SCSI. на адаптере Target — номер FC-порта на хранилище, LUN — идентификатор раздела, выделенного на хранилище.
VENDOR - название производителя хранилища МОДЕЛЬ - название модели РЕД.
— Версия прошивки на памяти устройство - специальное устройство, доступное пользователю В этой операции нас интересовали поля «устройство» и «SCSI ID».
Остальные поля игнорируем.
- Следующим шагом будет получение списка атрибутов хранилища, которые нам нужны:
- имя водителя
- название производителя
- название модели
именно там хранится вся необходимая нам информация.
# udevinfo -a -p /sys/block/sds looking at device '/block/sds': KERNEL=="sds" SUBSYSTEM=="block" SYSFS{stat}==" 151707 2355 3422965 430068 436954 12273 18585533 1098588 0 651944 1528756" SYSFS{size}=="2129838080" SYSFS{removable}=="0" SYSFS{range}=="16" SYSFS{dev}=="65:32" looking at device '/devices/pci0000:00/0000:00:04.0/0000:08:00.0/host5/rport-5:0-0/target5:0:0/5:0:0:20': ID=="5:0:0:20" BUS=="scsi" DRIVER=="sd" SYSFS{ioerr_cnt}=="0x7" SYSFS{iodone_cnt}=="0xec62d" SYSFS{iorequest_cnt}=="0xec62d" SYSFS{iocounterbits}=="32" SYSFS{retries}=="5" SYSFS{timeout}=="60" SYSFS{state}=="running" SYSFS{rev}=="0619" SYSFS{model}=="YYYYY " SYSFS{vendor}=="XXX " SYSFS{scsi_level}=="6" SYSFS{type}=="0" SYSFS{queue_type}=="simple" SYSFS{queue_depth}=="64" SYSFS{device_blocked}=="0" .
looking at device '/devices/pci0000:00/0000:00:04.0/0000:08:00.0': ID=="0000:08:00.0" BUS=="pci" DRIVER=="mptfc" SYSFS{modalias}=="pci:v00001000d00000646sv00001000sd00001020bc0Csc04i00" SYSFS{local_cpus}=="00000000,00000000,00000000,0000000f" SYSFS{irq}=="169" SYSFS{class}=="0x0c0400" SYSFS{subsystem_device}=="0x1020" SYSFS{subsystem_vendor}=="0x1000" SYSFS{device}=="0x0646" SYSFS{vendor}=="0x1000"
Нет необходимости запрашивать информацию для каждого устройства, потому что.Вывод «lsscsi» содержит повторяющиеся записи.
Это пути к определенному LUN через разные устройства (например, 1 FC порт на хосте и 3 Port на хранилище), а так как это одно и то же хранилище, то и требуемые нами параметры будут одинаковыми для всех.
- DRIVER==“sd” — это имя драйвера, который идентифицирует это устройство.
Почему «sd», а не драйвер FC «mptfc» — потому что именно драйвер «sd» отвечает за идентификацию дискового устройства, полученного от адаптеров SCSI/FC.
- SYSFS{vendor}==“XXX” — производитель хранилища.
Если вы обратите внимание, его имя — это не просто «ХХХ», но и ряд пробелов.
Именно по этой причине вывод lsscsi не столь информативен и если используется только «XXX», то правило просто не будет работать.
- SYSFS{model}==“YYYYY” — название модели.
Причина та же, что и в пункте выше.
- ID==“5:0:0:20” — идентификатор в формате H:B:T:L. Его тоже нужно запомнить, потому что… Он нам понадобится позже.
- BUS==“scsi” — тип шины.
Нам нужно будет более точно идентифицировать устройство
Шаг третий, пишет контора!
Теперь перейдем к написанию правил.
Нам понадобится документация udev.
Вот окончательное правило и описание опций: # If not a block device (ex. tape) ignore this rule
SUBSYSTEM!="block", GOTO="go_ignore_end"
# Phisical device section
BUS=="scsi", DRIVER=="sd", SYSFS{vendor}=="XXX ", SYSFS{model}=="YYYYY ", ID=="*:*:*:20", GOTO="go_ignore_end"
BUS=="scsi", DRIVER=="sd", SYSFS{vendor}=="XXX ", SYSFS{model}=="YYYYY ", ID=="*:*:*:21", GOTO="go_ignore_end"
BUS=="scsi", DRIVER=="sd", SYSFS{vendor}=="XXX ", SYSFS{model}=="YYYYY ", OPTIONS+="ignore_device,last_rule"
LABEL="go_ignore_end"
А теперь объяснение что к чему: SUBSYSTEM!="block", GOTO="go_ignore_end"
Эта опция сообщает udev, что если подсистема работает с каким-либо неблоковым устройством, то данное правило применять не следует. BUS=="scsi", DRIVER=="sd", SYSFS{vendor}=="XXX ", SYSFS{model}=="YYYYY ", ID=="*:*:*:20", GOTO="go_ignore_end"
BUS=="scsi", DRIVER=="sd", SYSFS{vendor}=="XXX ", SYSFS{model}=="YYYYY ", ID=="*:*:*:21", GOTO="go_ignore_end"
Это самая важная часть, собственно ради этой части и была написана данная статья.
Правило определяет поведение: если устройство проходит через шину BUS==“scsi” и использует драйвер DRIVER==“sd”, у нас также есть производитель SYSFS{vendor}==“XXX” и название модели SYSFS. {model}==“YYYYY” и LUN этого устройства соответствует ID=="*:*:*:20", то это устройство должно следовать всем остальным правилам и создать специальное устройство в каталоге /dev. Запись ID=="*:*:*:20" — это запись в формате H:B:T:L, которая описывает только идентификатор LUN; остальные поля могут быть любыми.
Это позволяет нам пропускать из хранилища все устройства, имеющие данный LUN. Если нам нужно расширить список LUN, то мы просто добавляем записи и в последнее поле пишем нужный нам идентификатор.
Главное, чтобы они располагались перед следующим правилом.
BUS=="scsi", DRIVER=="sd", SYSFS{vendor}=="XXX ", SYSFS{model}=="YYYYY ", OPTIONS+="ignore_device,last_rule"
Это правило применяет те же условия, что и предыдущее, только OPTIONS+="ignore_device,last_rule" сообщает udev игнорировать все дальнейшие действия с этим устройством.
Те.
все устройства, кроме указанных, будут игнорироваться.
LABEL="go_ignore_end"
Это правило представляет собой простую метку конца файла.
Оно должно быть последним в списке.
Шаг четвертый, финальная битва
Теперь все, что нам нужно сделать, это сохранить это правило и использовать его.Сохраняем это правило в папке /etc/udev/rules.d в правильном формате.
Я использовал имя «52-ignore-unused-devices.rules».
После этого нужно сделать еще одну вещь.
Если драйвер адаптера находится на рамдиске, то его необходимо удалить оттуда и загружать только после запуска подсистемы udev, иначе это правило не сработает, поскольку устройства будут созданы до запуска udev. Для этого вам необходимо внести изменения в файл /etc/sysconfig/kernel:
- Удалите драйвер устройства FC из переменной INITRD_MODULES=".
"
- Добавьте его в переменную MODULES_LOADED_ON_BOOT=".
"
- Восстановите виртуальный диск с помощью команды mkinitrd.
Остальные хоть и видны в системе, но не указаны.
файлы, и поэтому пользователь не сможет ничего с ними сделать.
Это будет выглядеть так: # lssci
SCSI ID TYPE VENDOR MODEL REV. device
[5:0:0:10] disk XXX YYYYY 0619 -
[5:0:0:20] disk XXX YYYYY 0619 /dev/sds
[5:0:0:21] disk XXX YYYYY 0619 /dev/sdu
.
[5:0:1:10] disk XXX YYYYY 0619 -
[5:0:1:20] disk XXX YYYYY 0619 /dev/sdao
[5:0:1:21] disk XXX YYYYY 0619 /dev/sdar
В результате наша задача была решена элегантно и красиво.
Это также ускорит загрузку, особенно если вы используете встроенный механизм multipath. Надеюсь, это будет полезно хотя бы одному человеку.
Материалы, которые очень помогли
- http://reactivated.net/writing_udev_rules.html
- Существующие правила udev
-
Литтре, Максимилиан Поль Эмиль
19 Oct, 24 -
Заткнись И Возьми Мои Деньги
19 Oct, 24 -
Виртуализация И Безопасность
19 Oct, 24 -
Комета Хейла-Боппа
19 Oct, 24 -
На Лифте В Космос - 2009: День №2
19 Oct, 24 -
Покорение Карелии Валдайцами.
19 Oct, 24