Большинство системных администраторов так или иначе мониторящих оборудование компании, знакомы с пакетом smstools, зачастую используемого лишь для отправки SMS сообщений о состоянии инфраструктуры. Оборотной стороной медали является необходимость удалённого управления инфраструктурой предприятия при недоступности VPN подключения или нахождении вне зоны доступа в интернет. Ранее описанные способы управления безусловно имеют право на жизнь, но рассчитаны на управление одним сервером и не предоставляют возможности безопасного выполнения команд. Ниже по тексту я предлагаю вашему вниманию рабочий механизм безопасного подтверждения выполнения sms команд внутри локальной сети.
Согласно правилу «Правильно настроенная система в обслуживании не нуждается», правильные сисадмины не перенастраивают стабильно работающее оборудование ограничиваясь только установкой обновлений.
Но в работе серверов бывают моменты когда вешается какой-нить процесс обеспечивающий работу сетевых шар и RPC, скажем LanManServer(в простонародии server), причём вешается не сам процесс, а какая-то его ветка. В итоге мы имеем сервер, который нельзя перезапустить через удалённое управление или корректно погасить.
Почти все современные сервера имеют на борту IPMI и возможность управления питанием. Отсюда и будем строить наш функционал. Если ваши сервера дополнительно мониторятся через nagios или аналогичные пакеты, то в большинстве случаев у вас используется nrpe -Nagios Remote Plugin Executor, а это значит у вас есть независимый от системных служб механизм по управлению сервером. Достаточно в конфиге NSClient++ прописать часто используемые команды типа reboot, shutdown, stop_server, start_server и удалённо делать с сервером необходимые действия.
В старом конфиге клиента вызов внешних скриптов расположен в разделе "[External Scripts]", в новом "[/settings/external scripts/scripts]". Текстовка в обоих случаях одинаковая.
текстовка скриптов
s_reboot.cmd
s_shutdown.cmd
start_server.cmd
stop_server.cmd
Это базовый список команд которые можно использовать удалённо. Можно вызывать остановку или поднятие сервиса передавая в аналогичный скрипт аргументы. Например передёрнуть IIS.
Вызов команды обычно прост и выглядит как
С nrpe вроде бы разобрались, теперь нужно обслужить IPMI.
Для диалога с IPMI системой сервера можно воспользоваться пакетом ipmitool, который представляет собой интерфейс доступа к управлению ipmi из командной строки.
Основной набор команд который нам необходим, относится к разделу «power», а именно
Можно еще почитать температурные сенсоры, скорость вращения вентиляторов, но это нам не особо нужно.
С основным набором команд разобрались.
В связи с тем, что последнее время появилось некоторое количество сервисов позволяющих подделать номер отправителя смс — обычная проверка номера отправителя стала недостаточно надёжной.
Пересылка прямого пароля в сообщении тоже вещь ненадёжная, т.к. перехват сообщения позволит получить полный доступ к вашей системе управления. Что же делать?
Выход на удивление прост. OTP (One Time Passwords). С точки зрения простоты использования и отсутствии зависимости генерируемых паролей от времени оптимальным решением будет использование OPIE.
Если у вас есть несколько системных администраторов или инженеров обслуживающих сервера, то выдавать каждому пароль и начальный вектор инициализации будет не совсем корректным. Для обслуживания серверов уместно выдать каждому список паролей из различных блоков.
А в случае использования блоков паролей можно точно утверждать чьей рукой был выключен или перезагружен сервер. С точки зрения использования системы «в одно лицо», для Android телефонов, целесообразнее будет установить пакет OTPDroid для онлайн генерации паролей. Прекрасен он тем, что в буфер обмена сразу копируется значение сгенерированного пароля и трёх нажатий хватает для копипаста пароля в sms.
Вы спросите «А как же двойное использование одного и того же пароля ?»
Ответ прост: «Нужно просто контролировать и вести список использованных последовательностей прилетевших в смс»
Первым делом в конфигурационном файле smsd необходимо добавить вызов обработчика событий.
Программа обработки представляет собой обычный shell скрипт.
Немного комментариев о файле обработчика smsevent
В начале файла задаются основные переменные о нахождении файла конфигурации, программ проверки и управления, а также OPIE параметры для проверки паролей.
В конфигурационном файле вы задаёте телефоны и список доступных им команд, список адресов серверов, логины и пароли IPMI для различных хостов, темплейты выполняемых команд.
В блоке темплейтов команд второй аргумент имеет значение 0 или 1 и либо пропускает проверку OPIE для команды, либо проверяет OPIE.
Самый простой смс запрос пришлёт обратно поочередно 2 sms с результатами проверки доступности хостов:
Запрос вида отправит хост 192.168.55.2 в перезагрузку путём эмуляции кнопки RESET, а хост 192.168.54.5 выключит штатным образом:
Все выполняемые посредством sms действия пишутся в расширенный лог smsd.
В общем-то, всё. Редактируете под себя конфиг, настраиваете сервера на приём команд и можно ехать с телефоном на отдых. Если вдруг что повиснет, выстрел прямой наводкой посредством sms сделает своё дело.
PS: Скрипт немного сыроват, но как говорится «совершенству нет предела!».
Начнём с того «Зачем это нужно?»
Согласно правилу «Правильно настроенная система в обслуживании не нуждается», правильные сисадмины не перенастраивают стабильно работающее оборудование ограничиваясь только установкой обновлений.
Но в работе серверов бывают моменты когда вешается какой-нить процесс обеспечивающий работу сетевых шар и RPC, скажем LanManServer(в простонародии server), причём вешается не сам процесс, а какая-то его ветка. В итоге мы имеем сервер, который нельзя перезапустить через удалённое управление или корректно погасить.
Что можно с этой проблемой сделать ?
Почти все современные сервера имеют на борту IPMI и возможность управления питанием. Отсюда и будем строить наш функционал. Если ваши сервера дополнительно мониторятся через nagios или аналогичные пакеты, то в большинстве случаев у вас используется nrpe -Nagios Remote Plugin Executor, а это значит у вас есть независимый от системных служб механизм по управлению сервером. Достаточно в конфиге NSClient++ прописать часто используемые команды типа reboot, shutdown, stop_server, start_server и удалённо делать с сервером необходимые действия.
В старом конфиге клиента вызов внешних скриптов расположен в разделе "[External Scripts]", в новом "[/settings/external scripts/scripts]". Текстовка в обоих случаях одинаковая.
reboot=scripts\s_reboot.cmd
shutdown=scripts\s_shutdown.cmd
stop_server=scripts\stop_server.cmd
start_server=scripts\start_server.cmd
текстовка скриптов
s_reboot.cmd
@echo "Reboot initiated"
@start cmd /c shutdown -r -f -t 00
@exit 0
s_shutdown.cmd
@echo "Shutdown initiated"
@start cmd /c shutdown -s -f -t 00
@exit 0
start_server.cmd
@start cmd /c net start server
@if %ERRORLEVEL% EQU 0 goto ok
@echo Some problem with service start
@exit 1
:ok
@echo Service started
@exit 0
stop_server.cmd
@start cmd /c net stop server /y
@if %ERRORLEVEL% EQU 0 goto ok
@echo Some problem with service stop
@exit 1
:ok
@echo Service stopped
@exit 0
Это базовый список команд которые можно использовать удалённо. Можно вызывать остановку или поднятие сервиса передавая в аналогичный скрипт аргументы. Например передёрнуть IIS.
Вызов команды обычно прост и выглядит как
/usr/local/libexec/nagios/check_nrpe2 -H <HOST> -c <command> -a <arguments>
С nrpe вроде бы разобрались, теперь нужно обслужить IPMI.
Для диалога с IPMI системой сервера можно воспользоваться пакетом ipmitool, который представляет собой интерфейс доступа к управлению ipmi из командной строки.
Основной набор команд который нам необходим, относится к разделу «power», а именно
ipmitool -H <host> -U <username> -P <password> power status - узнать состояние питания на сервере
ipmitool -H <host> -U <username> -P <password> power up - включить сервер
ipmitool -H <host> -U <username> -P <password> power off - выключить питание
ipmitool -H <host> -U <username> -P <password> power reset - эмулировать нажатие клавиши reset
Можно еще почитать температурные сенсоры, скорость вращения вентиляторов, но это нам не особо нужно.
С основным набором команд разобрались.
Как обеспечить безопасность управления ?
В связи с тем, что последнее время появилось некоторое количество сервисов позволяющих подделать номер отправителя смс — обычная проверка номера отправителя стала недостаточно надёжной.
Пересылка прямого пароля в сообщении тоже вещь ненадёжная, т.к. перехват сообщения позволит получить полный доступ к вашей системе управления. Что же делать?
Выход на удивление прост. OTP (One Time Passwords). С точки зрения простоты использования и отсутствии зависимости генерируемых паролей от времени оптимальным решением будет использование OPIE.
Почему OPIE ?
Если у вас есть несколько системных администраторов или инженеров обслуживающих сервера, то выдавать каждому пароль и начальный вектор инициализации будет не совсем корректным. Для обслуживания серверов уместно выдать каждому список паролей из различных блоков.
# opiekey -5 -n 5 5 habrahabr
Using the MD5 algorithm to compute response.
Reminder: Dont use opiekey from telnet or dial-in sessions.
Enter secret pass phrase:
1: JIG RIFT BODE OLGA RICK JAG
2: RIM HIVE BANG LIMA HELL OMEN
3: BULB MOD CARR BANK MOS SET
4: GARB BAWL MANY HAL GLOW FEED
5: FAWN EDGY MEET SHUT LIKE TIME
# opiekey -5 -n 5 25 habrahabr
Using the MD5 algorithm to compute response.
Reminder: Dont use opiekey from telnet or dial-in sessions.
Enter secret pass phrase:
21: MAIN HOFF JAM OATH SMOG LIED
22: FUND DENY BYTE BOLT NIBS EASY
23: SLY COAT FLEA CAGE MAE COAL
24: SURE LEFT HULK CLAN SHUN DAR
25: GRAB LIE CLAN FLAK MEL ROSE
А в случае использования блоков паролей можно точно утверждать чьей рукой был выключен или перезагружен сервер. С точки зрения использования системы «в одно лицо», для Android телефонов, целесообразнее будет установить пакет OTPDroid для онлайн генерации паролей. Прекрасен он тем, что в буфер обмена сразу копируется значение сгенерированного пароля и трёх нажатий хватает для копипаста пароля в sms.
Вы спросите «А как же двойное использование одного и того же пароля ?»
Ответ прост: «Нужно просто контролировать и вести список использованных последовательностей прилетевших в смс»
Как всё это заставить работать вместе ?
Первым делом в конфигурационном файле smsd необходимо добавить вызов обработчика событий.
eventhandler = /usr/local/etc/smshandlers/smsevent
Программа обработки представляет собой обычный shell скрипт.
Далее пойдёт много shell кода smsevent
#!/bin/sh
NRPETOOL="/usr/local/libexec/nagios/check_nrpe2"
IPMITOOL="/usr/local/bin/ipmitool"
FPINGTOOL="/usr/local/sbin/fping"
PARAMFILE="/usr/local/etc/smshandlers/param.list"
OPIEKEYBIN="/usr/bin/opiekey"
OPIESEED="HABROPIEProc"
OPIEPASS="StrongOPIEPassword"
OPIEUSEDSEED="/var/tmp/used.opie"
SMSDOUTSPOOL="/var/spool/sms/outgoing"
if [ ! -f ${OPIEUSEDSEED} ]; then
echo "#USED SEEDS FILE. Do not EDIT" > ${OPIEUSEDSEED}
fi
if [ ! -w ${OPIEUSEDSEED} ]; then
echo "file ${OPIEUSEDSEED} is not writable"
exit
fi
if [ ! -r ${PARAMFILE} ]; then
echo "file ${PARAMFILE} is not readable"
exit
fi
IFS="
"
FOUNDNUM=""
NUMBER=""
# search any properties
search (){
# $1 - section [name] from param.list
# $2 - search string in section
SECTION=$1
SEARCHSTR=$2
shift
shift
OLDIFS=${IFS}
IFS="
"
[ "X"${SEARCHSTR} == "X" ] && exit
for i in ${PARAMS}; do
# search section definition
if [ `echo ${i} | grep -e "^\["` ]; then
CURSECTION=${i}
continue
fi
if [ "${CURSECTION}" == "["${SECTION}"]" ]; then
if [ `echo ${i} | grep -e "^\b${SEARCHSTR}\b:"` ]; then
echo ${i}
break
fi
fi
done
IFS=${OLDIFS}
}
cut_message_body (){
# split sms file to parts
# BSD buggy "grep -m 1 -A 10 -e '^$'" replacement
#
FILE=$1
NULLSTR=0
for i in `cat -e $1`; do
if [ "X"${i} == "X\$" ]; then
NULLSTR=1
continue
fi
if [ ${NULLSTR} -eq 1 ]; then
echo ${i}
fi
done
}
process_command () {
CMD=$1
shift
CMDPARAM=$*
oIFS=$IFS
IFS=" "
for host in ${CMDPARAM}; do
HOSTACCOUNT=$( search hosts "${host}" )
if [ "X"${HOSTACCOUNT} != "X" ]; then
ACCOUNT=`echo ${HOSTACCOUNT} | cut -d ":" -f 2-`
LOGINPW=$( search logins "${ACCOUNT}" )
if [ "X"${ACCOUNT} != "X" ]; then
if [ "${ACCOUNT}" != "null" ]; then
USER=`echo ${LOGINPW} | cut -d ":" -f 2`
PASSWORD=`echo ${LOGINPW} | cut -d ":" -f 3`
else
USER="USER"
PASSWORD="PASSWORD"
fi
else
echo "ACCOUNT ${ACCOUNT} NOT FOUND!"
break
fi
else
echo "HOST ${host} NOT FOUND!"
continue
fi
opierequired=$( search commands_template "${CMD}" | cut -d ":" -f 2 )
commandtemplate=$( search commands_template "${CMD}" | \
cut -d ":" -f 3- | sed \
-e "s@\%HOST\%@${host}@g" \
-e "s@\%FPING\%@${FPINGTOOL}@g" \
-e "s@%IPMITOOL%@${IPMITOOL}@g" \
-e "s@%CHECK_NRPE%@${NRPETOOL}@g" \
-e "s@%USER%@${USER}@g" \
-e "s@%PASSWORD%@${PASSWORD}@g" )
if [ "${opierequired}" -eq "1" ]; then
if [ "${OPIERES}" == "True" ]; then
echo "OPIE Success"
res=$( eval ${commandtemplate} )
sendsms ${NUMBER} ${host} ${res}
else
echo "OPIE Failed"
sendsms ${NUMBER} ${host} "OPIE Challenge failed"
fi
else
res=$( eval ${commandtemplate} )
sendsms ${NUMBER} ${host} ${res}
fi
done
IFS=$oIFS
}
sendsms () {
NM=$1
shift
TMPFILE=`mktemp ${SMSDOUTSPOOL}/smscmd.XXXXXX` || exit 1
echo "To: ${NM}" >> ${TMPFILE}
echo >> ${TMPFILE}
echo "$*" >> ${TMPFILE}
}
opiecheck () {
OPIESEQ=`echo $* | cut -d " " -f 1 | sed -e 's/[^0-9]//g'`
OPIESTR=`echo $* | cut -d " " -f 2-`
if [ "X"${OPIESEQ} == "X" ]; then
echo "OPIE SEQUENCE FOR NUMBER ${NUMBER} IS NOT SET!"
OPIERES="False"
break
fi
if [ `grep "^${OPIESEQ}$" ${OPIEUSEDSEED}` ]; then
echo "USED OPIE SEQUENCE ${OPIESEQ} DETECTED"
OPIERES="False"
sendsms ${NUMBER} "OPIE SEQUENCE ${OPIESEQ} ALREADY USED"
exit 1
else
echo ${OPIESEQ} >> ${OPIEUSEDSEED}
fi
OPIEGEN=`echo ${OPIEPASS} | ${OPIEKEYBIN} -5 -a ${OPIESEQ} ${OPIESEED} 2>/dev/null`
if [ "X"${OPIESTR} != "X"${OPIEGEN} ]; then
OPIERES="False"
else
OPIERES="True"
fi
}
parse_commands () {
for command in $*; do
command=`echo ${command} | sed -e 's/\$$//g' -e 's/^\#//g'`
CURCOMMAND=`echo ${command} | cut -d " " -f 1`
CMDPARAM=`echo ${command} | cut -d " " -f 2-`
case "${CURCOMMAND}" in
"OPIE")
opiecheck ${CMDPARAM}
continue
;;
*)
if [ `echo ${FOUNDNUM} | cut -d : -f 2 | grep "\b${CURCOMMAND}\b"` ]; then
TMPMSG="ALLOWED COMMAND FOR NUMBER "${NUMBER}" - COMMAND: "${CURCOMMAND}" ARGS "${CMDPARAM}
echo ${TMPMSG}
process_command ${CURCOMMAND} ${CMDPARAM}
else
TMPMSG="DISALLOWED COMMAND FOR NUMBER "${NUMBER}" - COMMAND: "${CURCOMMAND}" ARGS "${CMDPARAM}
echo ${TMPMSG}
fi
;;
esac
done
}
PARAMS=`cat ${PARAMFILE} | grep -E -v '^#'`
if [ $1 == "RECEIVED" ]; then
FILENAME=$2
NUMBER=`grep 'From:' ${FILENAME} | sed -e 's/^From\:\ //g' -e 's/[^0-9]//g;'`
FOUNDNUM=$( search phones ${NUMBER} )
if [ "X"${FOUNDNUM} != "X" ]; then
commands=$( cut_message_body ${FILENAME} )
parse_commands ${commands}
fi
elif [ $1 == "SENT" ]; then
echo $@
else
echo "UNKNOWN STATUS $@"
fi
Немного комментариев о файле обработчика smsevent
В начале файла задаются основные переменные о нахождении файла конфигурации, программ проверки и управления, а также OPIE параметры для проверки паролей.
Немного конфигурационного файла param.list
# ---------------------------------------
#
# ALLOWED PHONES
# PHONENUMBER:COMMAND,COMMAND,COMMAND
# ---------------------------------------
[phones]
79030000000:RESET,PWROFF,PWRON,REBOOT,SHUTDOWN,STOPSERVER,STARTSERVER,ALIVE,PWRSTAT
79160000000:ALIVE,PWRSTAT
79020000000:PWRON,STARTSERVER,ALIVE
# ---------------------------------------
#
# HOST LIST
# REAL_IP:IPMI_USER
# ---------------------------------------
[hosts]
192.168.55.2:ADMSM
192.168.54.2:null
192.168.55.5:ADMDEF
192.168.54.5:null
# ---------------------------------------
#
# IPMI LOGINS
# IPMI_ACCOUNT:IPMI_NAME:IPMI_PASSWORD
# ---------------------------------------
[logins]
ADMSM:ADMIN:PW1234
ADMDEF:ADMIN:ADMIN
ADMIBM:USERID:USERID
# ---------------------------------------
#
# COMMANDS TEMPLATE
# COMMAND:OPIE_CHECK:COMMAND_TEXT
# ---------------------------------------
[commands_template]
RESET:1:%IPMITOOL% -H %HOST% -U %USER% -P %PASSWORD% power reset
PWROFF:1:%IPMITOOL% -H %HOST% -U %USER% -P %PASSWORD% power off
PWRON:0:%IPMITOOL% -H %HOST% -U %USER% -P %PASSWORD% power on
PWRSTAT:0:%IPMITOOL% -H %HOST% -U %USER% -P %PASSWORD% power status
REBOOT:1:%CHECK_NRPE% -H %HOST% -p 5666 -c reboot
SHUTDOWN:1:%CHECK_NRPE% -H %HOST% -p 5666 -c shutdown
STOPSERVER:1:%CHECK_NRPE% -H %HOST% -p 5666 -c stop_server
STARTSERVER:0:%CHECK_NRPE% -H %HOST% -p 5666 -c start_server
ALIVE:0:%FPING% %HOST%
В конфигурационном файле вы задаёте телефоны и список доступных им команд, список адресов серверов, логины и пароли IPMI для различных хостов, темплейты выполняемых команд.
В блоке темплейтов команд второй аргумент имеет значение 0 или 1 и либо пропускает проверку OPIE для команды, либо проверяет OPIE.
Самый простой смс запрос пришлёт обратно поочередно 2 sms с результатами проверки доступности хостов:
ALIVE 192.168.54.2 192.168.54.5
Запрос вида отправит хост 192.168.55.2 в перезагрузку путём эмуляции кнопки RESET, а хост 192.168.54.5 выключит штатным образом:
OPIE 1 COT NORM TILL JILL MOST MESH
RESET 192.168.55.2
SHUTDOWN 192.168.54.5
Все выполняемые посредством sms действия пишутся в расширенный лог smsd.
В общем-то, всё. Редактируете под себя конфиг, настраиваете сервера на приём команд и можно ехать с телефоном на отдых. Если вдруг что повиснет, выстрел прямой наводкой посредством sms сделает своё дело.
PS: Скрипт немного сыроват, но как говорится «совершенству нет предела!».