Синхронизация пользователей Zimbra Collaboration OSE на основе Active Directory

от автора

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. Схема работы скрипта

  1. Сохраняем в файл пользователей AD входящих в группу mail
  2. Сохраняем в файл всех пользователей zimbra со всеми атрибутами
  3. Разделяем файл со списком всех пользователей zimbra на файлы формата: имя файла — логин пользователя, содержание — атрибуты пользователя
  4. Убираем из списка пользователей zimbra системные учетные записи (admin, gal,antivirus)
  5. Сравниваем список пользователей AD и zimbra
  6. Создаем файл с командами добавления, удаления (в моем случае блокировки пользователя), синхронизации и создания алиасов
  7. Применяем данные действия в zimbra (один вызов zmprov)
  8. Отправляем отчет на почту администратору (если есть что отправлять)
  9. Удаляем временные файлы и каталоги

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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *