1. Предпосылки
Настраивая сервер zimbra столкнулся с проблемой синхронизации пользователей по группе в Active Directory (AD). Если мы создаем нового пользователя в AD, то он нормально добавлялся, но если мы делаем доступ к почтовому серверу по группе, то первый раз все пользователи синхронизируются. А вот потом, изменения в группе никак не влияют на изменения пользователей почтового сервера zimbra.
Что не понравилось в статьях этих статьях, это использование скрипта на powershell (зачем, если есть ldapsearch) и постоянный вызов утилиты zmprov, и когда идет синхронизация большого количества пользователей, то скрипт выполняется продолжительное время
2. Исходные данные
ОС сервера: CentOS 7
Язык скрипта: bash
Домен Zimbra: test.ru
Сервер Zimbra: zimbra.test.local
Домен Active Directory: test.local
Группа AD для доступа к почте: mail
У пользователя может быть почта отличающаяся от его логина, такую почту вносим в AD в поле mail и по нему создаем алиас в zimbra (например вася пупкин входит в систему под логином vasia, но почту должен отправлять и получать еще как пользователь v.pupkin@test.ru)
3. Схема работы скрипта
- Сохраняем в файл пользователей AD входящих в группу mail
- Сохраняем в файл всех пользователей zimbra со всеми атрибутами
- Разделяем файл со списком всех пользователей zimbra на файлы формата: имя файла — логин пользователя, содержание — атрибуты пользователя
- Убираем из списка пользователей zimbra системные учетные записи (admin, gal,antivirus)
- Сравниваем список пользователей AD и zimbra
- Создаем файл с командами добавления, удаления (в моем случае блокировки пользователя), синхронизации и создания алиасов
- Применяем данные действия в zimbra (один вызов zmprov)
- Отправляем отчет на почту администратору (если есть что отправлять)
- Удаляем временные файлы и каталоги
4. Скрипт синхронизации
У скрипта есть два режима работы — это запуск без параметров, тогда отработают только блокировка и добавление пользователей. И запуск с параметром «all», тогда будут синхронизированны все пользователи группы mail в AD.
Так же необходимо обратить внимание на использование утилиты декодирования base64 в функции синхронизации, ее необходимо использовать для полей AD в которых используются русские символы.
#!/bin/bash # #1. Определение переменных # #1.1 Общие переменные #Путь к рабочему каталогу path="/mnt/zimbra/user-sync" #Временная метка timestamp=`date +%F-%H-%M` #путь к временным файлам tmp_dir=$path/tmp #Путь к файлам с атрибутами пользователей zimbra zim_us=$tmp_dir/zim-us #путь к файлам логов log_dir=$path/log #имя лог-файла log=$log_dir/grouplog_$timestamp.txt #путь ко временному файлу со списком пользователей usname=$tmp_dir/usname #Путь к файлу со списком команд на пакетное выполнение утилитой zmprov zmcmdfile=$tmp_dir/zmcmdfile #путь ко временным файлам со списком атрибутов пользователей AD userfil=$tmp_dir/userfil #отправка почты mutt="/usr/bin/mutt" # #1.2 переменные сервера zimbra #имя домена Zimbra domain="test.ru" #путь к командлету zmprov zmprov="/opt/zimbra/bin/zmprov" # #1.3 переменные доступа к AD по LDAP #LDAP search ldapsearch=/opt/zimbra/common/bin/ldapsearch # Подключение к серверу (либо сервер, либо домен (если больше одного сервера)) ldap_server="ldap://test.local:389" #Базовая OU поиска basedn="DC=test,DC=local" #Пользователь и пароль для доступа к AD по LDAP binddn="CN=zimbra,CN=Users,DC=test,DC=local" bindpw="qwe123" #user password #Фильтр поиска - кто входит в группу mail filter="(memberof=cn=mail,cn=users,dc=test,dc=local)" #какие поля данных ищем (логин, почту и поле с не совпадающей с логином почтой для алиаса и подписи) fields="sAMAccountName mail description displayName givenName cn sn department title" #конец блока переменных #Начинаем обработку #Функции обработки #Запись ошибки в лог function err_log() { if [ $1 -eq 0 ]; then #echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]" #echo echo $2" [Ok]" >> $log else #echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" #echo echo $2" [Fail]" >> $log fi } #Проверка существования каталога function if_path () { #Если каталог не существует то создаем его if [ ! -d $1 ]; then #Создание каталога для обработки echo "Создание каталога $1..." >> $log mkdir -p $1 err_log $? "Проверка каталога $1" else echo "Каталог обработки $1 существует" >> $log fi } #Запись в файл списка пользователей из AD function searchusersAD() { echo "Запись списка пользователей рассылки из AD..." >> $log $ldapsearch -x -o ldif-wrap=no -H $ldap_server -D $binddn -w $bindpw -b $basedn $filter $fields | grep sAMAccountName | egrep -v '^#|^$' | awk '{print $2}' | sort > $usname.ad echo "Found (Найдено) "`cat $usname.ad | wc -l`" Group in AD (групп в AD)" >> $log } function alluserattrzimbra() { #Создаем файл со списком всех пользователей и их атрибутов $zmprov -l gaa -v $domain > $usname.gaa #Переходим в папку где будут созданы файлы с атрибутами пользователей cd $zim_us #разбиваем файл со всеми пользователями на файлы, с атрибутами только одного пользователя csplit $usname.gaa --prefix='user.' --suffix-format='%03d.zim' --elide-empty-files -s /"# name"/ '{*}' #Переименовываем файлы по пользователям. имя берем из имени пользователя zimbra в файле for i in $( ls $zim_us ) do nam=`grep "# name" $zim_us/$i | awk '{ print $3}' | sed 's/@.*//g'` mv -f $zim_us/$i $zim_us/$nam done cd $path } #Запись в файл списка пользователей из zimbra function searchuserzimbra() { echo "Запись списка пользователей из zimbra..." >> $log ls $zim_us | sort > $usname.tem #Удаляем системные аккаунты из проверки. файл $path/system.acc содержит список системных пользователей diff -u -i $usname.tem $path/system.acc | sed 1,3d | grep ^- | cut -c 2- | sort > $usname.zim #rm -f $usname.tem echo "Found (Найдено) "`cat $usname.zim | wc -l`" Group in Zimbra (групп в Zimbra)" >> $log } #Разница между списками пользователей (для добавления или блокировки function diffuserlist() { diff -u -i $usname.zim $usname.ad | sed 1,3d | sed '/@.*/d' > $usname.diff } #добавление пользователей function adduser() { #Проверяем существование пользователя на добавление adddif=`grep ^+ $usname.diff | sed '1!d'` if [ -n $adddif ]; then for addus in $( grep ^+ $usname.diff | cut -c 2- ) do # проверяем есть ли такой пользователь в zimbra (если есть - разблокируем, нет - создаем) ifclos=`grep "zimbraAccountStatus:" $zim_us/$addus | awk '{print $2}' | cut -c -1` echo "c="$ifclos"!" if [ $ifclos = "c" ]; then echo "ma $addus@$domain zimbraAccountStatus active" >> $zmcmdfile echo "Пользователь $addus разблокирован" >> $tmp_dir/send.txt if [ $addus != "" ]; then sync_one_user $addus fi else #echo $addus"-2" echo "ca $addus@$domain" >> $zmcmdfile echo "Пользователь $addus создан" >> $tmp_dir/send.txt if [ $addus != "" ]; then sync_one_user $addus fi fi done fi } #блокировка пользователей перед отключением function blockuser() { deldif==`grep ^- $usname.diff | sed '1!d'` if [ -n $deldif ]; then for delus in $( grep ^- $usname.diff | cut -c 2- ) do #zimbraAccountStatus closed if [ $delus != "" ]; then ifclos=`grep "zimbraAccountStatus:" $zim_us/$delus | awk '{print $2}'` if [ "$ifclos" != "closed" ]; then echo "user closed - $delus" echo "ma $delus@$domain zimbraAccountStatus closed" >> $zmcmdfile echo "Пользователь $delus заблокирован! Удалите его с сервера самостоятельно!" >> $tmp_dir/send.txt echo $delus >> $path/close.1 cat $path/close.1 | sort > $path/close.diff echo "$delus" fi fi done fi } #Функция проверки существования атрибута function ifattr() { if1char=`echo $2 | cut -c -1` if [[ -n $2 && $if1char != "" ]]; #if [ $2 != "" ]; then #echo $2 echo -n " $1 \"$2\"" >> $zmcmdfile fi } #функция синхронизации пользователя function sync_one_user() { echo "Синхронизация пользователя $1..." >> $log $ldapsearch -x -o ldif-wrap=no -H $ldap_server -D $binddn -w $bindpw -b $basedn "(sAMAccountName=$1)" $fields > $userfil/$1.ad #Создаемначало строки атрибутов синхронизации echo -n "ma "$1 >> $zmcmdfile #samacc=`grep "sAMAccountName:" $userfil/$1 | awk '{print $2}'` description=`grep "description:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}'` #echo $description ifattr "description" "$description" displayName=`grep "displayName:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d` ifattr "displayName" "$displayName" givenName=`grep "givenName:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d` ifattr "givenName" "$givenName" cn=`grep "cn:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}'` ifattr "cn" "$cn" sn=`grep "sn:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d` ifattr "sn" "$sn" department=`grep "department:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d` ifattr "company" "$department" title=`grep "title:" $userfil/$1.ad | awk '{split ($0, a, ": "); print a[2]}' | base64 -d` ifattr "title" "$title" #Вставляем перевод строки в файле echo >> $zmcmdfile #Добавляем алиас mailnew=`grep "mail:" $userfil/$1.ad | awk '{print $2}'` if [ "$mailnew" != "" ]; then # [ -n $mailnew ] # echo $2 #Проверяем наличие алиаса у пользователя #${1,,} - приводим все символы к нижнему регистру useralias=`grep "zimbraMailAlias:" $zim_us/${1,,} | awk '{print $2}'` if [ $useralias != $mailnew ]; then echo "aaa \"$1@$domain\" \"$mailnew\"" >> $zmcmdfile fi fi #ifattr "mail" $mailnew # echo $mailnew echo "Синхронизация пользователя $1 " >> $tmp_dir/send.txt # echo "Пользователь $1 - $atrruser" #echo "Found (Найдено) "`cat $usname.ad | wc -l`" Group in AD (групп в AD)" >> $log } #Выполнение скрипта date +%F-%H-%M #2.Проверка существования каталогов #Корневой каталог обработки if_path $path #Каталог временных файлов if_path $tmp_dir #Каталог лог-файла if_path $log_dir #Каталог со списком групп if_path $userfil #каталог со файлами пользователей зимбра if_path $zim_us #Очищаем файл со списком команд на пакетное выполнение утилитой zmprov :> $zmcmdfile # Очищаем тело письма администратору :> $tmp_dir/send.txt #3.Создаем список групп рассылки из AD searchusersAD #4.Создаем список существующих в zimbra пользователей alluserattrzimbra #удаляем лишних (системных) searchuserzimbra #5.Сравниваем оба списка групп рассылки diffuserlist #Блокируем пользователей blockuser #Создаем или разблокируем новых пользователей adduser #tckb скрипту передан параметр "all" при запуске, то синхронизируем всех пользователей находящихся в группе mail AD if [[ -n $1 && $1 = "all" ]]; then for us in $(cat $usname.ad ); do # echo $us sync_one_user $us done fi # запускаем выполнение всех команд утилитой zmprov из файла $zmprov -f $zmcmdfile # дописываем в лог файл с командами cat $zmcmdfile >> $log #Отправляем письмо с изменениями админу (если они есть) if [ -s $tmp_dir/send.txt ]; then $mutt -s "Синхронизация списка пользователей $timestamp" admins@test.ru -a $log < $tmp_dir/send.txt fi #Удаляем временные файлы и каталоги rm -R -f $tmp_dir
5. Заключение
В целом скрипт получился довольно шустрый, утилита zmprov используется всего два раза, остальные утилиты и функции отрабатывают намного быстрее.
6. Ссылки
При создании данной статьи использовались идеи и статьи:
1. Сысоева Андрея
2. DruGoeDeLo
ссылка на оригинал статьи https://habr.com/ru/post/495688/
Добавить комментарий