четверг, 17 декабря 2015 г.

Разворачивание Asterisk на Debain 8 с поддержкой ODBC и защитой Fail2Ban

В данной статье я хотел бы описать процесс установки и настройки asterisk на Debian (Jessie). Asterisk будет работать с базой данных postgresql через ODBC.

Установка asterisk:

  • Обновим систему до актуального состояния
    apt-get update && apt-get dist-upgrade 
    
  • Установим все необходимые зависимости для сборки asterisk
    apt-get install gcc g++ uuid-dev libsqlite3-dev libxslt1-dev libjansson-dev libxml2-dev \ 
    libncurses5-dev unixodbc-dev libnewt-dev libssl-dev libsqlite3-dev build-essential
    
  • Скачиваем последнюю версию asterisk. На момент написания статьи это 13 версия
    wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13-current.tar.gz
    
  • Распаковываем архив и переходим в папку с исходным кодом
    tar -xvf asterisk-13-current.tar.gz
    cd asterisk-13.6.0/
    
  • Запускаем процедуру проверки, собираем библиотеки и устанавливаем их в систему
    ./configure
    make
    make install
    
  • Установим скрипты запуска/останова
    make config
    
  • Установим примеры конфигурационных файлов
    make samples
    
  • Проверим что asterisk запускается через скрипты инициализации и подключимся к нему
    service asterisk start
    asterisk -R
    
  • P.S. Если после запуска asterisk в логах /var/log/asterisk/messages проскакивают ошибки вида
    ERROR[27158] ari/config.c: No configured users for ARI
    ERROR[27158] netsock2.c: getaddrinfo("debian-asterisk", "(null)", ...): Name or service not known
    
    то необходимо отключить поддержку ARI в файле /etc/asterisk/ari.conf
    enabled = no        ; When set to no, ARI support is disabled.
    
    и перезапустить модуль res_ari
    asterisk -rx 'module reload res_ari'
    

Итак, мы установили asterisk, однако необходимо сделать ряд первичных действий.
Во-первых, asterisk работает из-под пользователя root - настроим работу от непривилегированного пользователя:
  • Добавим системного пользователя и группу asterisk:
    adduser --system --group --home /nonexistent --no-create-home asterisk
    
  • Изменим владельца и группу всех рабочих директорий asterisk
    chown -R asterisk:asterisk /var/spool/asterisk/
    chown -R asterisk:asterisk /var/run/asterisk/
    chown -R asterisk:asterisk /var/log/asterisk/
    chown -R asterisk:asterisk /var/lib/asterisk/
    chown -R asterisk:asterisk /usr/lib/asterisk/
    
  • Укажем asterisk от имени какого пользователя пользователя и группы запускаться - эти параметры прописываются в файле /etc/asterisk/asterisk.conf
    runuser = asterisk  ; The user to run as.
    rungroup = asterisk  ; The group to run as.
    
  • Перезапустим asterisk
    service asterisk restart
    
Во-вторых, конфигурация по умолчанию не предполагает никакой защиты от подключения нежелательных абонентов. В связи с этим, сделаем ряд настроек для улучшения безопасности:
  • По умолчанию, asterisk разрешает гостевые звонки сквозь себя без предварительной аутентификации вызываемой стороны. Гостевые вызовы запрещаются в /etc/asterisk/sip.conf одной строчкой
    allowguest=no
    
  • Дополнительно изменим в /etc/asterisk/sip.conf контекст по умолчанию на default вместо public
    context=default
    
  • и пропишем контекст default в /etc/asterisk/extensions.conf, добавив в него единственное правило запрета набора любых номеров. Вся работа по маршрутизации звонков будет происходить в других контекстах
    [default]
    exten => _X.,1,Hangup
    
  • Далее, отключим оповещения о неверном пароле - это необходимо чтобы asterisk "не засветил" валидных пользователей при попытках перебора паролей. При отключении данного оповещения ответ asterisk будет всегда однотипным независимо от того, валидный ли у нас пользователь или нет. В /etc/asterisk/sip.conf прописываем
    alwaysauthreject=yes
    
  • После вышеприведенных изменений перезапустим перечитаем конфиги /etc/asterisk/sip.conf и /etc/asterisk/extensions.conf
    asterisk -rx 'sip reload'
    asterisk -rx 'dialplan reload'
    
Список вышеприведенных действий по обеспечению безопасности можно продолжить исходя из своих реалий/предпочтений, например, предоставлению каждому пиру уникального сложному паролю, использование директив permit/deny для явного указания сетей, из которых разрешено регистрироваться, использование нестандартного порта для SIP/IAX2 и прочее. От себя я лишь опишу процесс настройки fail2ban для блокирования "переборщиков":
  • Сначала перенастроим логирование asterisk в соответствие с форматом ISO 8601. Для этого нам нужен файл /etc/asterisk/logger.conf
    dateformat=%F %T
    
  • Включим логирование security events в отдельный файл security
    security => security
    
  • Перезапустим модуль логирования
    asterisk -rx "logger reload"
    
  • Установим fail2ban
    apt-get install fail2ban
    
  • Создадим "кастомный" файл /etc/fail2ban/jail.local и активируем в нем правила для asterisk
    [asterisk]
    enabled         = true
    filter          = asterisk
    logpath         = /var/log/asterisk/messages
                      /var/log/asterisk/security
    port            = 5060,5061
    protocol        = udp
    maxretry        = 3
    bantime         = 86400 ; 1 day
    findtime        = 3600  ; 1 hour
    ignoreip        = 127.0.0.1/8
    
  • Прикажем fail2ban перечитать конфигурацию
    service fail2ban reload
    
  • В случае успеха в iptables должны появиться соответствующие правила, наподобие следующих
    root@debian-asterisk:~# iptables -L -vn
    Chain INPUT (policy ACCEPT 27 packets, 1844 bytes)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 fail2ban-asterisk-security  udp  --  *      *       0.0.0.0/0            
     0.0.0.0/0            multiport dports 5060,5061
        0     0 fail2ban-asterisk  udp  --  *      *       0.0.0.0/0            
     0.0.0.0/0            multiport dports 5060,5061
       29  1948 fail2ban-ssh  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            
     multiport dports 22
    
    Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination         
    
    Chain OUTPUT (policy ACCEPT 18 packets, 2024 bytes)
     pkts bytes target     prot opt in     out     source               destination         
    
    Chain fail2ban-asterisk (1 references)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    
    Chain fail2ban-ssh (1 references)
     pkts bytes target     prot opt in     out     source               destination         
       29  1948 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0  
    
  • Дополнительно настроим ротацию логов /var/log/asterisk/messages и /var/log/asterisk/security, так как они могут очень быстро наполняться. Для этого создадим в каталоге /etc/logrotate.d/ файл asterisk со следующим содержимом
    /var/log/asterisk/messages /var/log/asterisk/security {
     weekly
     missingok
     rotate 4
     compress
     nocreate
     postrotate
      /usr/sbin/asterisk -rx 'logger reload'
     endscript
    }
    

Настройка взаимодействия asterisk с postgresql через ODBC:

  • Установим postgresql-server
    apt-get install postgresql
    
  • Создадим пользователя asterisk посредством которого мы будем подключаться и управлять базой данных. Для этого, сначала переключимся на пользователя postgres
    su - postgres 
    
    Затем запустим следующую команду для создания роли asterisk в базе данных и установки для привелегий:
    postgres@debian-asterisk:~$ createuser --interactive -P asterisk
    Введите пароль для новой роли: 
    Повторите его: 
    Должна ли новая роль иметь полномочия суперпользователя? (y - да/n - нет) n
    Новая роль должна иметь право создавать базы данных? (y - да/n - нет) y
    Новая роль должна иметь право создавать другие роли? (y - да/n - нет) n
    
  • Создадим базу astersik и назначим ей в качестве владельца роль asterisk
    createdb --owner=asterisk asterisk
    
  • Проверим подключение под ролью asterisk к базе данных
    psql -h 127.0.0.1 -U asterisk
    Пароль пользователя asterisk: 
    psql (9.4.5)
    SSL-соединение (протокол: TLSv1.2, шифр: ECDHE-RSA-AES256-GCM-SHA384, бит: 256, сжатие: выкл.)
    Введите "help", чтобы получить справку.
    
    asterisk=> 
    
  • Если unixODBC не подтянулся по зависимостям, то установим его явно
    apt-get install postgresql
    
  • Установим PostgreSQL ODBC connector
    apt-get install odbc-postgresql
    
  • Настроим PostgreSQL ODBC driver, прописав в файл /etc/odbcinst.ini следующие данные
    [PostgreSQL]
    Description=ODBC for PostgreSQL
    Driver=psqlodbca.so
    Setup=libodbcpsqlS.so
    FileUsage=1
    
  • Убедимся что система видит наш драйвер с помощью следующей команды. В случае успеха нам должна вернуться метка PostgreSQL
    odbcinst -q -d
    [PostgreSQL]
    
  • Затем настроим файл /etc/odbc.ini, который используется для создания идентификатора, на который asterisk будет ссылаться в своей конфигурации
    [asterisk-connector]
    Description         = PostgreSQL connection to 'asterisk' database
    Driver              = PostgreSQL
    Database            = asterisk
    Servername          = localhost
    Port                = 5432
    ReadOnly            = No
    RowVersioning       = No
    ShowSystemTables    = No
    ShowOidColumn       = No
    FakeOidIndex        = No
    ConnSettings        =
    
  • Проверим наше соединение к базе, использую программу isql. Вывод echo через канал направляется в isql, которое будет подключаться используя секцию asterisk-connector, ранее настроенную в /etc/odbc.ini. Подключение будет происходить под ранее созданной ролью asterisk с указанием пароля. В случае успеха, мы получим примерно следующий вывод
    echo "select 1" | isql -v asterisk-connector asterisk some_secret_password
    +---------------------------------------+
    | Connected!                            |
    |                                       |
    | sql-statement                         |
    | help [tablename]                      |
    | quit                                  |
    |                                       |
    +---------------------------------------+
    SQL> select 1
    +------------+
    | ?column?   |
    +------------+
    | 1          |
    +------------+
    SQLRowCount returns 1
    1 rows fetched
    [PostgreSQL]
    
  • Теперь, когда мы настроили взаимодействие ODBC и postgresql, настроим asterisk к ODBC - для этого нам понадобится сконфигурировать файл /ect/asterisk/res_odbc.conf. Этот файл содержит набор параметров, которые различные модули asterisk'а используют для соединения с базой данных. Добавим в этот файл следующую секцию
    [asterisk-conn]
    enabled => yes
    dsn => asterisk-connector
    username => asterisk
    password => asterisk
    pooling => no
    limit => 1
    pre-connect => yes
    
  • Параметр dsn ссылается на соединение к базе данных, настроенное в /etc/odbc.ini. Параметр pre-connect говорит asterik'у подключиться к базе сразу же после загрузки модуля res_odbc.so.
  • Перезапустим модуль res_odbc
    asterisk -rx 'module reload res_odbc.so'
    
  • Проверим подключение к базе дынных
    asterisk -rx 'odbc show'
    
    ODBC DSN Settings
    -----------------
    
      Name:   asterisk-conn
      DSN:    asterisk-connector
        Last connection attempt: 1970-01-01 05:00:00
      Pooled: No
      Connected: Yes
    
    
Теперь мы можем в полный рост работать с базой данных, например, использовать Realtime.

четверг, 5 марта 2015 г.

Боевая миграция CentOS с KVM (DigitalOcean) в OpenVZ-контейнер

Возникла задача мигрировать несколько виртуалок (дроплетов) с DigitalOcean на один сервер под управлением Proxmox и изменить тип виртуализации на OpenVZ. Так будут экономятся часть ресурсов, поскольку у нас будет одно ядро на все контейнеры, да и переносить так проще. На дроплетах установлены CentOS 6 либо 7 версий. Описанные мною шаги целиком опираются на официальную вику OpenVZ с некоторыми дополнениями.

  • Создаем в Proxmox новый контейнер. В качестве шаблона берем minimal версии CentOS - отдельно для 6 и 7 версий. Взять их можно отсюда.

  • Создаем файл с исключениями того, что там не надо копировать с дроплета. В моем случае он получился таким:
    cat /root/exclude.txt
    /tmp
    /boot
    /lib/modules
    /etc/blkid
    /etc/mtab
    /etc/lvm
    /etc/fstab
    /etc/udev
    /etc/inittab
    /etc/rc.digitalocean
    /etc/sysconfig/network
    /etc/sysconfig/network-scripts
    /etc/sysctl.conf
    /etc/sysctl.d
    /etc/rc.sysinit
    /usr/lib/sysctl.d
    
  • Останавливаем все лишние сервисы на дроплете. По хорошему оставить запущенным только sshd.

  • На сервере Proxmox запускаем rsync:
    rsync -avz -H -X --one-file-system --numeric-ids --exclude-from=/root/exclude.txt \ 
    -e ssh root@a.b.c.d:/ /var/lib/vz/private/$CID
    
    Примечание: a.b.c.d - IP-адрес дроплета, $CID - номер OpenVZ-контейнера, опция -H нужна чтобы копировать хардлинки как хардлинки, -X сохраняет расширенные атрибуты.
    Примечание: если на дроплете, помимо корневой файловой системы есть дополнительные файловые системы, для них надо запускать отдельно rsync, например, в случае /home:
    rsync -avz -H -X --one-file-system --numeric-ids --exclude-from=/root/exclude.txt \ 
    -e ssh root@a.b.c.d:/home/ /var/lib/vz/private/$CID/home/
    
  • Запускаем контейнер и заходим в него:
    vzctl enter $CID
    
  • Отключаем лишние сервисы:
    • Для CentOS 7 у меня получился следующий список:
      systemctl mask irqbalance
      systemctl mask auditd
      systemctl mask digitalocean-rc-local
      systemctl mask NetworkManager
      systemctl mask cloud-config
      systemctl mask cloud-final
      systemctl mask cloud-init-local
      systemctl mask cloud-init
      systemctl mask kdump
      systemctl mask iprdump
      systemctl mask iprinit
      systemctl mask iprupdate
      systemctl mask tuned
      systemctl mask avahi-daemon
      systemctl mask microcode
      systemctl mask plymouth-start
      systemctl mask firewalld
      
    • Для CentOS 6:
      chkconfig auditd off
      chkconfig lvm2-monitor off
      chkconfig ntpdate off
      chkconfig blk-availability off
      chkconfig iscsi off
      chkconfig iscsid off
      chkconfig mdmonitor off
      chkconfig netfs off
      chkconfig iptables off
      chkconfig ip6tables off
      chkconfig modules_dep off
      chkconfig udev-post off
      
  • Перегружаемся.

В зависимости от конфигурации, предложенных выше действий может оказаться недостаточно для полной работоспособности контейнера. Вот на что следует обратить внимание:
  • У некоторых сервисов может быть жесткая привязка ко старому IP-адресу. Если таковая привязка имеется - то убрать ее либо заменить на новый IP-адрес. В большинстве случаев достаточно просмотреть директорию /etc:
    egrep -R a.b.c.d /etc/
    
  • В CentOS-7 контейнере после переноса на заработал ping даже из под root. Все это оказалось из-за механизма linux capabilities. Чтобы найти все файлы, на которые "навешаны" capabilities, необходимо выполнить:
    getcap -r / 2>/dev/null
    
    и потом для каждого из них командой setcap удалить capabilities.

  • Если у нас был настроен демон firewalld, то в контейнере он работать не будет из-за привязке к ebtables - в таком случае все его правила надо перенести в хост-систему.

  • Если у нас в дроплете настраиваются дополнительные сетевые интерфейсы, например, PPP, то их надо будет дополнительно настроить.

пятница, 6 февраля 2015 г.

Настройка Software RAID в Proxmox 3.3


К сожалению, в процессе установки Proxmox нет возможности установить его на программный рейд. Об этом даже упоминается в официальной вики. Оно и понятно, учитывая что основной упор в плане высокой доступности и избыточности Proxmox возлагает на кластеризацию. Однако, когда в нашем распоряжении есть только один сервер с Proxmox, хотелось бы иметь возможность обеспечить избыточность хотя бы на уровне дисков в виде программного рейд-массива.

Итак, мы имеем следующую конфигурацию: 2 идентичных диска - /dev/sda и /dev/sdb, Proxmox 3.3 установлен на sda, второй диск чистый. Мы создадим raid 1 взяв за основу диск sda.

Установим mdadm:
root@proxmox:~# apt-get update
root@proxmox:~# apt-get install mdadm
Посмотрим содержимое диска sda. Начиная с версии 3.2, Proxmox использует таблицу разделов GPT, независимо от того BIOS у нас или UEFI. Для работы с GPT нужны утилиты gdisk/sgdisk:
root@proxmox:~# gdisk -l /dev/sda
GPT fdisk (gdisk) version 0.8.5

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.
Disk /dev/sda: 16777216 sectors, 8.0 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 7FC0CE80-7258-4231-8F88-F336FF77C998
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 16777182
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048            4095   1024.0 KiB  EF02  primary
   2            4096         1048575   510.0 MiB   EF00  primary
   3         1048576        16777182   7.5 GiB     8E00  primary
Мы видим, что у нас есть 3 раздела: первый раздел (EF02) - это bios_grub, на котором у нас находится grub, второй раздел (EF00)- /boot раздел с файловой системой ext3, третий раздел (8E00) отдан под lvm. Для нашей задачи нам достаточно сделать два отдельных зеркальных рейда для второго и третьего раздела.

Перенесем таблицу разделов с sda на sdb:
sgdisk -R=/dev/sdb /dev/sda
sgdisk -G /dev/sdb
Первая команда копирует таблицу разделов, а вторая заново генерирует рандомные GUID для диска sdb, чтобы они отличались от диска sda.

Примечание: некоторые авторы советуют помечать разделы  специальным флагом FD, чтобы mdadm смог их автоматически распознать. Однако это действие излишне, поскольку mdadm способен автоматически распознать raid-разделы путем сканирования заголовка разделов на предмет размещения в них суперблоков особого вида.
Теперь создадим 2 зеркала - для разделов /boot и корневого соответственно. Один из дисков для рейда будет sdb, а второй пропущенный ("missing"), который мы позже заменим на sda:
root@[server]:/# mdadm --create boot --level=1 --raid-disks=2 missing /dev/sdb2
root@[server]:/# mdadm --create root --level=1 --raid-disks=2 missing /dev/sdb3
Скопируем раздел /boot с /dev/sda2 на свеже созданный /dev/md/boot:
root@proxmox:~# mkdir /mnt/boot
root@proxmox:~# mkfs.ext3 /dev/md/boot
root@proxmox:~# mount /dev/md/boot /mnt/boot/
root@proxmox:~# cp -ax /boot/* /mnt/boot/
root@proxmox:~# umount /mnt/boot
root@proxmox:~# rmdir /mnt/boot/
 Изменим в /etc/fstab путь монтирования раздела /boot на новый:
# <file system> <mount point> <type> <options> <dump> <pass>
/dev/pve/root / ext3 errors=remount-ro 0 1
/dev/pve/data /var/lib/vz ext3 defaults 0 1
#UUID=b4c01a34-b56b-4d52-8678-02f1b79b16a4 /boot ext3 defaults 0 1
/dev/md/boot /boot ext3 defaults 0 1
/dev/pve/swap none swap sw 0 0
proc /proc proc defaults 0 0
Убедимся, что mdadm у нас автоматически запускается при старте и активирует все найденные массивы. В файле /etc/default/mdadm должно быть следующее:
INITRDSTART='all'
AUTOSTART=true
Перезагружаемся:.
root@proxmox:~# reboot
И проверяем:
root@proxmox:~# mount | egrep boot
/dev/md126 on /boot type ext3 (rw,relatime,errors=continue,user_xattr,acl,barrier=0,data=ordered)
Добавим нужные модули для grub и initrd:
root@proxmox:~# echo 'GRUB_DISABLE_LINUX_UUID=true' >> /etc/default/grub
root@proxmox:~# echo 'GRUB_PRELOAD_MODULES="raid dmraid"' >> /etc/default/grub
root@proxmox:~# echo raid1 >> /etc/modules
root@proxmox:~# echo raid1 >> /etc/initramfs-tools/modules
Установим загрузчик на оба диска:
root@proxmox:~# grub-install --recheck /dev/sda
root@proxmox:~# grub-install --recheck /dev/sdb
root@proxmox:~# update-grub
root@proxmox:~# update-initramfs -u -k all
Добавим /dev/sda2 в raid:
root@proxmox:~# mdadm --manage /dev/md/boot --add /dev/sda2
Поскольку поверх /dev/sda3 поднят lvm, нам необходимо сделать то же самое на /dev/md/root и клонировать его:
root@proxmox:~# pvcreate /dev/md/root
root@proxmox:~# vgextend pve /dev/md/root
root@proxmox:~# pvmove /dev/sda3 /dev/md/root
В зависимости от объема раздела /dev/sda3 данная процедура может занять определенное время.

После этого мы можем удалить /dev/sda3 из lvm:
root@proxmox:~# vgreduce pve /dev/sda3
root@proxmox:~# pvremove /dev/sda3
Добавляем /dev/sda3 в raid:
root@proxmox:~# mdadm --manage /dev/md/root --add /dev/sda3
Статус синхронизации дисков в raid можно посмотреть следующей командой:
root@proxmox:~# cat /proc/mdstat
По ее завершению мы получим работающий Proxmox в софт-рейде!

За основу взята следующая статья:
http://blog.synyx.de/2015/01/running-proxmox-ve-3-3-on-a-software-raid/