Службы каталогов играют важную роль в ИТ-инфраструктуре любой организации. Каждая компания использует службу каталогов по-своему, отсюда возникает необходимость в ее адаптации под уникальные условия эксплуатации. В этой статье рассмотрим программный комплекс ALD Pro от «Группы Астра» — как встроенные возможности, так и примеры его кастомизации под требования заказчиков.
Привет, Хабр! Меня зовут Александр Усов, я работаю системным инженером в K2Tex. Когда я рассказываю заказчикам про ALD Pro, обычно сразу уточняю: это не жёсткая конструкция, а скорее продвинутая система, которую можно и нужно подстраивать под свои задачи. Сам по себе продукт уже мощный и гибкий, а вендор специально оставил место для кастомизации. Вот как раз этим мы в K2Тех активно и пользуемся. У нас накопилась технологическая экспертиза, и мы знаем, где продукт стоит дополнить, а где — адаптировать под конкретные запросы бизнеса. Моя задача — не просто внедрить решение и оставить заказчика наедине со сложной системой, а сделать так, чтобы он получил инструмент, идеально подходящий именно ему.
Что такое ALD Pro
ALD Pro — это российская служба каталога, которая позволяет централизованно управлять рабочими станциями, группами пользователей, применять политики безопасности и автоматизировать большую часть рутинных задач администраторов. В основу ALD Pro положены каталог FreeIPA, система управления конфигурациями Salt и другие инфраструктурные компоненты.
У «Группы Астра» есть блог на Хабре, так что можете почитать ещё и вот эти посты:
Мы в K2Tex используем ALD Pro при создании импортонезависимых ИТ-инфраструктур заказчиков. Когда аппаратная часть инфраструктуры развернута и поверх нее созданы виртуальные машины, первое, что необходимо сделать — это развернуть ALD Pro и тем самым создать базовую программную инфраструктуру.
Автоматизация развертывания ALD Pro с помощью API
Ручное развертывание всех компонентов ALD Pro в больших, распределенных инсталляциях — задача нетривиальная и затратная по времени. Именно здесь на помощь приходит автоматизация. Наличие документированного API позволяет автоматизировано разворачивать систему ALD Pro.
Начиная с версии 2.2.0, в ALD Pro появился полноценный API, что стало поворотным моментом — особенно для нас, интеграторов. Описание API доступно в личном кабинете в виде YAML-файла в формате OpenAPI. Это сильно упростило автоматизацию, и теперь мы можем разворачивать ALD Pro не руками, а по нажатию кнопки. В K2Tex мы разработали и активно используем собственные сценарии для автоматизации развертывания подсистем ALD Pro.
В качестве примера автоматизации процесса развертывания хочу с вами поделиться моими наработками на языке Bash. Развертывание первого контроллера представлено ниже (актуально для версии ALD Pro 2.5.0):
Скрытый текст
#!/bin/bash
#**************************************************************************************************************************
#Репозиторий Astra Linux - BASE
ASTRA_BASE=" http://dl.astralinux.ru/astra/frozen/1.7_x86-64/1.7.6/uu/2/repository-base/"
#Репозиторий ALDPro
ALD_MAIN="https://dl.astralinux.ru/aldpro/frozen/01/2.5.0/ "
#Короткое имя контроллера домена
DC_NAME="dc1"
#IP-адрес контроллера домена
IPADDR="192.168.8.10"
#Маска сети
MASK="255.255.255.0"
#IP-адрес шлюза по-умолчанию
GATEWAY="192.168.8.1"
#Название домена
DOMAIN_NAME="ald.pro.ru"
#IP-адрес DNS серевера для КД на момент установки пакетов из внешнего сервера репозиториев, после заменится на 127.0.0.1
NAMESERVER="77.88.8.8"
#Ввод пароля учетной записи администратора домена
echo "Укажите пароль для администратора домена:"
read -sr PASSWORD_ADMIN
#**************************************************************************************************************************
function install_pdc() {
#Добавление репозиториев Astra Linux
cat <<EOL > /etc/apt/sources.list
deb $ASTRA_BASE 1.7_x86-64 main non-free contrib
EOL
#Обновление ОС до актуальной версии
apt update -y
apt install astra-update -y && sudo astra-update -A -r -T
#Добавление репозиториев ALD Pro
cat <<EOL > /etc/apt/sources.list.d/aldpro.list
deb $ALD_MAIN 1.7_x86-64 base main
EOL
apt update -y
#Изменение имени контроллера домена
hostnamectl set-hostname $DC_NAME.$DOMAIN_NAME
#Настройка сети
cat <<EOL > /etc/network/interfaces
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address $IPADDR
netmask $MASK
gateway $GATEWAY
dns-search $DOMAIN_NAME
EOL
#Настройка файла /etc/hosts
cat <<EOL > /etc/hosts
127.0.0.1 localhost.localdomain localhost
$IPADDR $DC_NAME.$DOMAIN_NAME $DC_NAME
EOL
#Настройка файла /etc/resolv.conf
cat <<EOL > /etc/resolv.conf
search $DOMAIN_NAME
nameserver $NAMESERVER
EOL
#Отключение службы NetworkManager
systemctl stop NetworkManager
systemctl disable NetworkManager
systemctl enable networking
systemctl restart networking
#Настройка уровня безопасности
LEVEL=`astra-modeswitch get`
case $LEVEL in
0|1)
astra-modeswitch set 2
astra-mic-control enable
astra-mac-control enable
echo "Уровень безопасности: Смоленск"
;;
2)
echo "Уровень безопасности: Смоленск"
;;
esac
#Установка пакетов
DEBIAN_FRONTEND=noninteractive apt-get install -q -y aldpro-mp aldpro-syncer aldpro-gc
#Проверка установки пакета aldpro-mp
ALDPRO_CHECK=`dpkg -l | grep aldpro-mp`
if [[ -z $ALDPRO_CHECK ]];
then
echo "Ошибка ввода в домен! Пакет aldpro-mp - не установлен в системе."
exit 1
else
#Настройка /etc/resolv.conf
cat <<EOL > /etc/resolv.conf
search $DOMAIN_NAME
nameserver 127.0.0.1
EOL
systemctl restart networking
#Запуск развертывания первого контроллера домена
aldpro-server-install -d $DOMAIN_NAME -p $PASSWORD_ADMIN -n $DC_NAME --ip $IPADDR --setup_syncer --setup_gc --no-reboot
fi
reboot
}
if [[ -z $DC_NAME || -z $IPADDR || -z $MASK || -z $GATEWAY || -z $NAMESERVER || -z $DOMAIN_NAME || -z $PASSWORD_ADMIN ]];
then
echo "Ошибка запуска скрипта! Проверьте заполняемые параметры и повторите попытку запуска."
else
install_pdc
fi
Скрипт для ввода сервера в домен и развертывания подсистем представлен ниже (актуально для версии ALD Pro 2.5.0):
Скрытый текст
#!/bin/bash
#**************************************************************************************************************************
#Репозиторий Astra Linux - BASE
ASTRA_BASE="http://dl.astralinux.ru/astra/frozen/1.7_x86-64/1.7.6/uu/2/repository-base/"
#Репозиторий ALDPro
ALD_MAIN="https://dl.astralinux.ru/aldpro/frozen/01/2.5.0/ "
#Короткое имя сервера
SERVER_NAME="dc2"
#IP-адрес сервера
IPADDR="192.168.8.11"
#Маска сети
MASK="255.255.255.0"
#IP-адрес шлюза по-умолчанию
GATEWAY="192.168.8.1"
#Название домена
DOMAIN_NAME="ald.pro.ru"
#IP-адрес первого контроллера домена
NAMESERVER="192.168.8.10"
FIRST_DC_NAME="dc1"
SITENAME="Головной офис"
#Ввод имя учетной записи с правами ввода в домен
echo "Укажите учетную запись с правами ввода в домен:"
read ADMIN_NAME
#Ввод пароля учетной записи с правами ввода в домен
echo "Укажите пароль учетной записи для ввода в домен:"
read -sr PASSWORD_ADMIN
#**************************************************************************************************************************
function join_domain() {
#Изменение имени сервера
hostnamectl set-hostname $SERVER_NAME.$DOMAIN_NAME
#Настройка сети
systemctl stop NetworkManager
systemctl disable NetworkManager
systemctl enable networking
cat <<EOL > /etc/network/interfaces
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address $IPADDR
netmask $MASK
gateway $GATEWAY
dns-nameservers $NAMESERVER
dns-search $DOMAIN_NAME
EOL
#Настройка /etc/hosts
cat <<EOL > /etc/hosts
127.0.0.1 localhost.localdomain localhost
$IPADDR $SERVER_NAME.$DOMAIN_NAME $SERVER_NAME
EOL
#Настройка /etc/resolv.conf
cat <<EOL > /etc/resolv.conf
search $DOMAIN_NAME
nameserver $NAMESERVER
EOL
#Добавление репозиториев Astra Linux
cat <<EOL > /etc/apt/sources.list
deb $ASTRA_BASE 1.7_x86-64 main non-free contrib
EOL
#Обновление ОС
apt update -y
apt install astra-update -y && sudo astra-update -A -r -T
#Добавление репозиториев ALD Pro
cat <<EOL > /etc/apt/sources.list.d/aldpro.list
deb $ALD_MAIN 1.7_x86-64 base main
EOL
systemctl restart networking
#Настройка уровня безопасности
LEVEL=`astra-modeswitch get`
case $LEVEL in
0|1)
astra-modeswitch set 2
astra-mic-control enable
astra-mac-control enable
echo "Уровень безопасности: Смоленск"
;;
2)
echo "Уровень безопасности: Смоленск"
;;
esac
#Установка пакетов ALD Pro
apt update -y
DEBIAN_FRONTEND=noninteractive apt-get install -q -y aldpro-client
ALDPRO_CHECK=`dpkg -l | grep aldpro-client`
if [[ -z $ALDPRO_CHECK ]];
then
echo "Ошибка ввода в домен! Пакет aldpro-client - не установлен в системе."
exit 1
else
#Ввод в домен
/opt/rbta/aldpro/client/bin/aldpro-client-installer -c $DOMAIN_NAME -u $ADMIN_NAME -p $PASSWORD_ADMIN -d $SERVER_NAME -i -f
sleep 10
systemctl stop sssd
sed -i '/id_provider = ipa/a dyndns_update = true\ndyndns_refresh_interval = 60' /etc/sssd/sssd.conf
systemctl restart sssd
fi
}
function install_roles() {
echo "Укажите какую роль для сервера необходимо устанавливать? (DC, DHCP, REPO, CUPS, FS, MON, LOG, PXE):"
read ROLE_NAME
echo "Укажите учетную запись с правами на установку подсистемы $ROLE_NAME:"
read ROLE_USERNAME
echo "Укажите пароль учетной записи с правами на установку подсистемы $ROLE_NAME:"
read -sr ROLE_PASSWORD
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME/ad/api/ds/login" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{ \"data\": { \"login\": \"$ROLE_USERNAME\", \"password\": \"$ROLE_PASSWORD\" } }" \
-c curl.cookie
case $ROLE_NAME in
DC)
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME./ad/api/ds/domain-controllers" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{\"data\": { \"domaincontroller_ipa_login\": \"admin\",
\"domaincontroller_ipa_password\": \"QAZxsw123\",
\"domaincontroller_name\": \"$SERVER_NAME.$DOMAIN_NAME\",
\"domaincontroller_roles\": [],
\"domaincontroller_site_name\": \"$SITENAME\" } }" \
-b curl.cookie
;;
DHCP)
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME/ad/api/ds/dhcp/servers" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{\"data\": { \"dhcpserver_name\": \"$SERVER_NAME.$DOMAIN_NAME\", \"dhcpserver_site_name\": \"$SITENAME\" } }" \
-b curl.cookie
;;
REPO)
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME/ad/api/ds/repo/servers" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{\"data\": { \"repositoryserver_name\": \"$SERVER_NAME.$DOMAIN_NAME\", \"repositoryserver_site\": \"$SITENAME\" } }" \
-b curl.cookie
;;
CUPS)
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME/ad/api/ds/automation-tasks/print_install/run" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"data\": {
\"automationtask_computer_groups\": [
{
\"automationtask_computer_group_name\": \"\"
}
],
\"automationtask_computers\": [
{
\"automationtask_computer_name\": \"$SERVER_NAME.$DOMAIN_NAME\"
}
],
\"automationtask_organizational_units\": [
{
\"automationtask_organizational_unit_name\": \"\"
}
],
\"automationtask_parameters\": [
{
\"automationtask_attribute_cn\": \"sitename\",
\"automationtask_attribute_value\": \"$SITENAME\"
}
]
}
}" \
-b curl.cookie
;;
FS)
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME/ad/api/ds/automation-tasks/samba_install/run" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"data\": {
\"automationtask_computer_groups\": [
{
\"automationtask_computer_group_name\": \"\"
}
],
\"automationtask_computers\": [
{
\"automationtask_computer_name\": \"$SERVER_NAME.$DOMAIN_NAME\"
}
],
\"automationtask_organizational_units\": [
{
\"automationtask_organizational_unit_name\": \"\"
}
],
\"automationtask_parameters\": [
{
\"automationtask_attribute_cn\": \"sitename\",
\"automationtask_attribute_value\": \"$SITENAME\"
}
]
}
}" \
-b curl.cookie
;;
MON)
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME/ad/api/ds/automation-tasks/grafana_zabbix_install/run" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"data\": {
\"automationtask_computer_groups\": [
{
\"automationtask_computer_group_name\": \"\"
}
],
\"automationtask_computers\": [
{
\"automationtask_computer_name\": \"$SERVER_NAME.$DOMAIN_NAME\"
}
],
\"automationtask_organizational_units\": [
{
\"automationtask_organizational_unit_name\": \"\"
}
],
\"automationtask_parameters\": [
{
\"automationtask_attribute_cn\": \"sitename\",
\"automationtask_attribute_value\": \"$SITENAME\"
},
{
\"automationtask_attribute_cn\": \"servicerole\",
\"automationtask_attribute_value\": \"master\"
}
]
}
}" \
-b curl.cookie
;;
LOG)
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME/ad/api/ds/automation-tasks/audit_install/run" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"data\": {
\"automationtask_computer_groups\": [
{
\"automationtask_computer_group_name\": \"\"
}
],
\"automationtask_computers\": [
{
\"automationtask_computer_name\": \"$SERVER_NAME.$DOMAIN_NAME\"
}
],
\"automationtask_organizational_units\": [
{
\"automationtask_organizational_unit_name\": \"\"
}
],
\"automationtask_parameters\": [
{
\"automationtask_attribute_cn\": \"sitename\",
\"automationtask_attribute_value\": \"$SITENAME\"
},
{
\"automationtask_attribute_cn\": \"servicerole\",
\"automationtask_attribute_value\": \"master\"
}
]
}
}" \
-b curl.cookie
;;
PXE)
echo "Укажите полное имя сервера DHCP для использование в связке с PXE. Для использования внешнего DHCP-сервера оставьте строку пустой"
read DHCP_NAME
if [ -z "$DHCP_NAME" ]; then
DHCP_VALUE="true"
else
DHCP_VALUE="false"
fi
curl -X 'POST' "https://$FIRST_DC_NAME.$DOMAIN_NAME/ad/api/ds/installer-servers" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"data\": {
\"installerserver_dhcpserver\": \"$DHCP_VALUE\",
\"installerserver_dhcpserver_name\": \"$DHCP_NAME\",
\"installerserver_ip_address\": \"\",
\"installerserver_name\": \"$SERVER_NAME.$DOMAIN_NAME\",
\"installerserver_site_name\": \"$SITENAME\"
}
}" \
-b curl.cookie
;;
esac
}
if [[ -z $SERVER_NAME || -z $IPADDR || -z $MASK || -z $GATEWAY || -z $NAMESERVER || -z $DOMAIN_NAME || -z $PASSWORD_ADMIN || -z $ADMIN_NAME ]];
then
echo "Ошибка запуска скрипта! Проверьте заполняемые параметры и повторите попытку запуска."
else
join_domain
install_roles
fi
Язык Bash удобен для написания простых автоматизаций и позволяет создавать конвейеры для последовательной обработки информации. Но в тех случаях, когда необходимо исполнить параллельно несколько задач, и перед нами стоят вопросы консистентности, идемпотентности, предпочтительнее использовать декларативный подход систем управления конфигурациями. Например, сейчас я переношу все свои наработки на Ansible и поделюсь с вами наиболее полезными наработками, а именно обращениями к API ALD Pro для автоматизированного развертывания подсистем.
Пример обращения для авторизации в API:
- name: ALD api login
ansible.builtin.uri:
validate_certs: true
url: "https://{{ dc01_fqdn }}/ad/api/ds/login"
method: POST
headers:
accept: application/json
Content-Type: application/json
body_format: json
body:
data:
login: "{{ domain_admin }}"
password: "{{ domain_password }}"
return_content: true
delegate_to: "{{ dc01_fqdn }}"
Примеры обращений к API для автоматизированного развертывания подсистем:
Скрытый текст
ald_api:
dc:
get_url: https://{{ dc01_fqdn }}/ad/api/ds/domain-controllers
post_url: https://{{ dc01_fqdn }}/ad/api/ds/domain-controllers
body:
data:
domaincontroller_ipa_login: "{{ domain_admin }}"
domaincontroller_ipa_password: "{{ domain_password }}"
domaincontroller_name: "{{ ansible_nodename }}"
domaincontroller_roles: []
domaincontroller_site_name: "{{ ald_site_name }}"
fs:
get_url: https://{{ dc01_fqdn }}/ad/api/ds/shared-folders/servers
post_url: https://{{ dc01_fqdn }}/ad/api/ds/automation-tasks/samba_install/run
body:
data:
automationtask_computer_groups:
- automationtask_computer_group_name: ''
automationtask_computers:
- automationtask_computer_name: "{{ ansible_nodename }}"
automationtask_organizational_units:
- automationtask_organizational_unit_name: ''
automationtask_parameters:
- automationtask_attribute_cn: sitename
automationtask_attribute_value: "{{ ald_site_name }}"
audit:
get_url: https://{{ dc01_fqdn }}/ad/api/ds/logging/servers
post_url: https://{{ dc01_fqdn }}/ad/api/ds/automation-tasks/audit_install/run
body:
data:
automationtask_computer_groups:
- automationtask_computer_group_name: ''
automationtask_computers:
- automationtask_computer_name: "{{ ansible_nodename }}"
automationtask_organizational_units:
- automationtask_organizational_unit_name: ''
automationtask_parameters:
- automationtask_attribute_cn: sitename
automationtask_attribute_value: "{{ ald_site_name }}"
- automationtask_attribute_cn: servicerole
automationtask_attribute_value: master
dhcp:
get_url: https://{{ dc01_fqdn }}/ad/api/ds/dhcp/servers
post_url: https://{{ dc01_fqdn }}/ad/api/ds/dhcp/servers
body:
data:
dhcpserver_name: "{{ ansible_nodename }}"
dhcpserver_site_name: "{{ ald_site_name }}"
ps:
get_url: https://{{ dc01_fqdn }}/ad/api/ds/print-service/servers
post_url: https://{{ dc01_fqdn }}/ad/api/ds/automation-tasks/print_install/run
body:
data:
automationtask_computer_groups:
- automationtask_computer_group_name: ''
automationtask_computers:
- automationtask_computer_name: "{{ ansible_nodename }}"
automationtask_organizational_units:
- automationtask_organizational_unit_name: ''
automationtask_parameters:
- automationtask_attribute_cn: sitename
automationtask_attribute_value: "{{ ald_site_name }}"
repo:
get_url: https://{{ dc01_fqdn }}/ad/api/ds/repo/servers
post_url: https://{{ dc01_fqdn }}/ad/api/ds/repo/servers
body:
data:
repositoryserver_name: "{{ ansible_nodename }}"
repositoryserver_site: "{{ ald_site_name }}"
mon:
get_url: https://{{ dc01_fqdn }}/ad/api/ds/monitoring/servers
post_url: https://{{ dc01_fqdn }}/ad/api/ds/automation-tasks/grafana_zabbix_install/run
body:
data:
automationtask_computer_groups:
- automationtask_computer_group_name: ''
automationtask_computers:
- automationtask_computer_name: "{{ ansible_nodename }}"
automationtask_organizational_units:
- automationtask_organizational_unit_name: ''
automationtask_parameters:
- automationtask_attribute_cn: sitename
automationtask_attribute_value: "{{ ald_site_name }}"
- automationtask_attribute_cn: servicerole
automationtask_attribute_value: "master"
pxe:
get_url: https://{{ dc01_fqdn }}/ad/api/ds/installer-servers
post_url: https://{{ dc01_fqdn }}/ad/api/ds/installer-servers
body:
data:
installerserver_dhcpserver: 'false'
installerserver_dhcpserver_name: '{{ dhcp_server_fqdn }}'
installerserver_ip_address: ''
installerserver_name: "{{ ansible_nodename }}"
installerserver_site_name: "{{ ald_site_name }}"
Инструменты миграции с Active Directory на ALD Pro
Успешное развертывание ALD Pro — это только полдела. Для многих компаний, особенно в рамках стратегии импортозамещения, следующим шагом является миграция с существующей инфраструктуры, чаще всего построенной на базе Microsoft Active Directory.
Для этого можно использовать следующие инструменты миграции:
встроенный в ALD Pro инструмент миграции из MS AD (не рекомендуется для больших инфраструктур);
встроенный в ALD Pro модуль синхронизации с MS AD;
Pragmatic Tools Migrator;
собственные наработки K2Tex.
Разберем каждый инструмент из списка подробнее.
Встроенный в ALD Pro инструмент миграции из MS AD
Начиная с самой первой версии ALD Pro, в нем присутствует встроенный инструмент миграции с MS AD. В интерфейсе его можно найти по пути: «Управление доменом» -> «Интеграция с доменами» -> «Миграциия с MS AD».
Запуск миграции выглядит следующим образом:

Он позволяет сопоставить подразделения доменов MS AD и ALD Pro, выбрать необходимые объекты для миграции (пользователей, группы, организационные подразделения) и сопоставить для объектов необходимые атрибуты для миграции. Инструмент предназначен для разового переноса объектов из домена MS AD в ALD Pro. Но в нём есть ограничения:
В ходе миграции объекты из MS AD переносятся в ALD Pro только один раз. Если после выполнения миграции какие-то атрибуты объекта в MS AD будут изменены, то при повторной миграции эти изменения не отразятся в ALD Pro. Для того, чтобы перенести измененный объект еще раз, вам потребуется его полностью удалить из ALD Pro.
Чтобы сохранить членство пользователей в группах, необходимо мигрировать сначала все группы из MS AD, и только затем мигрировать пользователей.
Нигде не отображаются статусы исполнения задач во время миграции (количество мигрированных объектов успешно/с ошибкой или в очереди). Только по факту завершения задачи можно ознакомиться с результатами ее выполнения.
Этот инструмент очень прост в использовании, но подходит только для разовой миграции объектов с MS AD в небольших инфраструктурах до 2-3 тысяч объектов. Нам, конечно, известно об успешном применении этого модуля и на 20-30 тысяч, но в этом случае серверу нужно обязательно накидывать дополнительные ресурсы и очень терпеливо ждать полного завершения процесса.
Встроенный в ALD Pro модуль синхронизации с MS AD
Начиная с релиза 2.0.0, в ALD Pro добавлен специализированный инструмент, который закрыл указанные в предыдущем разделе недостатки. Модуль синхронизации устанавливается на первый контроллер домена при инсталляции или обновлении системы. В веб-интерфейсе первого контроллера домена он находится на главной странице:

Подход к сопоставлению атрибутов одинаковый с предыдущим инструментом, но новый модуль позволил именно синхронизировать изменения со стороны MS AD, что необходимо в гибридной инфраструктуре на все время сосуществования двух доменов.
Дополнительно к этому модуль позволил синхронизировать пароли в обе стороны, но если вы не хотите ослаблять политику безопасности для MS AD, то эту функцию можно не использовать и задавать первоначальный пароль пользователя в веб-интерфейсе ALD Pro.
Это большое преимущество, когда в службе каталогов есть встроенный модуль для миграции с MS AD, да еще и включающий синхронизацию паролей. Данный инструмент подойдет для более длительных процессов миграции благодаря возможности синхронизировать изменения, при этом администраторы смогут самостоятельно отслеживать перенос данных из MS AD в ALD Pro, хотя и не в графическом интерфейсе, а в подробном журнале событий (можно применить уровень логирования debug).
Pragmatic Tools Migrator
Решение Pragmatic Tools Migrator от компании Pragmatic Tools, специализирующейся на разработке инструментов миграции из MS AD в отечественные службы каталогов (не только ALD Pro), покрывает функциональность штатного модуля синхронизации, а также предоставляет ряд дополнительных возможностей, которые могут носить решающий характер в отдельных сценариях миграции:
миграция паролей с MS AD в ALD Pro (не требует ослаблять политику безопасности в MS AD);
возможность настройки правил миграции (например, по подразделениям);
возможность настройки правил трансформации (изменения) объектов при их синхронизации;
возможность ручного запуска и многое другое.
Но самое главное, что я вынес отдельно — этот продукт имеет возможность детального контроля процесса миграции, предоставляя подробную отчетность, что существенно упрощает отладку и решение инцидентов в период гибридного развертывания, который может продлиться неопределенно длительное время (до года и более).
Собственные наработки K2Tex
Следующий инструмент — это наши собственные наработки в К2Тех, которые мы создаем в тех случаях, когда заказчик предъявляет нестандартные требования, не реализованные в описанных ранее инструментах. Например, у одного из заказчиков использовалась служба каталога на базе Novell eDirectory, для которой на рынке нет готовых инструментов миграции, поэтому для реализации миграции (синхронизации) объектов домена мы разработали собственные сценарии.
Также мы очень часто сталкивались со специфичными атрибутами каталога, которые заполнялись с пробелами или содержали символы, недопустимые для атрибутов ALD Pro. Как раз под такие задачи мы разрабатывали сценарии с правилами транслитерации.
В наших скриптах нет графического интерфейса, нет синхронизации паролей, но присутствует подробное логирование, есть возможности по кастомизации процессов миграции под особенности каталога заказчика.
Наши скрипты и методики позволяют оптимизировать процесс, сэкономить ресурсы заказчика и ускорить переход на отечественную службу каталога.
Инструмент миграции |
Когда использовать |
Инструмент миграции из MS AD |
Подходит для разовой миграции объектов с MS AD |
Модуль синхронизации ALD Pro |
Подходит для относительно небольших и простых инфраструктур |
Pragmatic Tools Migrator |
Решение, которое мы рекомендуем и используем для крупных и сложных миграций с сотнями тысяч объектов |
Собственные наработки K2Tex |
Для нестандартных инфраструктур заказчиков, сценариев средней сложности, но со специфическими требованиями заказчиков. |
Развертывание рабочих мест пользователей с ОС Astra Linux
Следующим этапом после миграции объектов службы каталога является развертывание рабочих мест пользователей с ОС Astra Linux. В рамках ALD Pro имеется подсистема для установки ОС по сети. В актуальной версии (на момент написания статьи — 2.5.0) возможна установка по сети ОС Astra Linux 1.7, но многие уже эксплуатируют версию 1.8. Как раз здесь хочется рассказать о возможности настройки развертывания версии 1.8 с установщиком Debian:
Разархивировать ISO-образ версии 1.8.
Скопировать файлы initrd и linux из ISO-образ версии 1.8 на сервер установки ОС по сети в директорию /var/www/tftp/. Обязательно переименовать данные файлы, так как на сервере с этими названиями уже присутствуют файлы для установки ОС Astra Linux 1.7 (Например: linux_18, 18_initrd.gz).
Создать новый профиль загрузки в веб-интерфейсе ALD Pro (Например: Astra18).

В новом созданном профиле загрузки привести скрипт Grub к виду:
if loadfont $prefix/font.pf2 ; then
set gfxmode=800x600
set gfxpayload=keep
insmod efi_gop
insmod efi_uga
insmod video_bochs
insmod video_cirrus
insmod gfxterm
insmod png
terminal_output gfxterm
fi
if background_image /isolinux/aldpro.png; then
set color_normal=light-gray/black
set color_highlight=white/black
else
set menu_color_normal=cyan/blue
set menu_color_highlight=white/blue
fi
# Установка Astra Linux Special Edition
menuentry 'Install AstraLinux Operating System' {1
set background_color=black
linux (http,<IP-адрес вашего сервера установки ОС по сети>)/tftp/18_linux modprobe.blacklist=evbug debian-installer/allow_unauthenticated=true auto=true priority=critical debian-installer/locale=en_US console-keymaps-at/keymap=ru hostname={HOSTNAME} domain={DOMAIN_REALM} astra-license/license=true url=http://<IP-адрес вашего сервера установки ОС по сети>/tftp/{PROFILE_UNIQ_NAME}/{PRESEED_FILE_NAME} interface=auto netcfg/dhcp_timeout=60
initrd (http,<IP-адрес вашего сервера установки ОС по сети>)/tftp/18_initrd.gz
}
В новом созданном профиле загрузки привести скрипт Boot-меню к виду:
UI vesamenu.c32
# 0 - отключение приглашения командной строки. Загрузка начнется сразу
PROMPT 0
# Автоматический выбор меню по таймеру. Секунды вычисляются делением на 10 введенного значения
TIMEOUT 100
# Выбор по-умолчанию загрузки по сети
DEFAULT pxeinstall
menu background back.jpg
menu title User Management Portal Boot Menu
# Локальная загрузка с диска
LABEL bootlocal
menu label Boot from first HDD
kernel chain.c32
append hd0 0
TEXT HELP
Normal boot from HDD
ENDTEXT
# Загрузка из сети
LABEL pxeinstall
menu label PXE operation system install
kernel linux
append initrd=18_initrd.gz vga=788 auto=true priority=critical debian-installer/locale=ru_RU console-keymaps-at/keymap=ru hostname={HOSTNAME} domain={DOMAIN_REALM} astra-license/license=true url=http://<IP-адрес вашего сервера установки ОС по сети>/tftp/{PROFILE_UNIQ_NAME}/{PRESEED_FILE_NAME} interface=auto netcfg/dhcp_timeout=60
TEXT HELP
Install AstraLinux Operating System
ENDTEXT
В новом созданном профиле загрузки в preseed файле, привести настройку сетевого интерфейса к виду:
# Автоматический выбор сетевого интерфейса
d-i netcfg/choose_interface select enp4s0
ALD Pro не предполагает настроек для установки разных версий операционных систем из веб-интерфейса и для отображения необходимой операционной системы нужно в базу данных PostgreSQL добавить строки с версией ОС на сервере PXE, для этого выполнить следующие действия:
Запустить оболочку из-под пользователя postgres:
sudo –i –u postgres
Версии операционных систем хранятся в таблице installs_os. Для просмотра текущих ОС необходимо выполнить команду:
psql -d osinstall -c" select* from installs_os;”
Изначально там будет присутствовать только запись с версией Astra_1_7. Чтобы добавить запись, например, с 1_8, необходимо выполнить команду:
psql -d osinstall -c "INSERT INTO installs_os VALUES ('Astra_1_8', '/astra18/bin/1', '64', '/opt/rbta/aldpro/os/storage/astra17/bin/1/', '1', 'Головной офис');"
Но на этом еще не все. Теперь нужно обновить запись с используемой ОС в нужном нам профиле. Для просмотра используемых профилей необходимо выполнить команду:
psql -d osinstall -c "select* from installs_osprofile;”
Для обновления записи в профиле необходимо выполнить команду:
psql -d osinstall -c " UPDATE installs_osprofile SET os_id = 'Astra_1_8' WHERE os_id = 'Astra_1_7';”
Теперь можно устанавливать Astra Linux 1.8 посредством ALD Pro, в веб-интерфейсе будет отображаться указанная версия операционной системы:

Групповые политики и кастомизация
Групповые политики (GPO) — один из самых важных инструментов управления инфраструктурой. В ALD Pro этот механизм реализован на базе Salt, но со временем эволюционировал. Изначально использовалась классическая модель «мастер-миньон». Позже появилась автономная служба aldpro-salt-minion, которая позволяет рабочим станциям самостоятельно получать конфигурации и скрипты через LDAP, что повышает производительность и отказоустойчивость.
Гибкость системы GPO в ALD Pro позволяет реализовывать кастомные дополнительные параметры под специфические требования заказчиков, например, для настройки корпоративного ПО. С помощью дополнительных параметров можно реализовать также и более сложную логику, которая выходит за рамки функциональных возможностей продукта. Например, можно сделать так, чтобы параметр применялся только для определенных групп пользователей или компьютеров.
Шаблон групповой политики для применения на уровне групп пользователей:

{% set id = '<Уникальный идентификатор ГП>' %}
{% set my_user = salt['pillar.get']("user") %}
{% set homedir = salt['user.info'](my_user).home %}
{% set apply_to_user_group_ids = (salt['pillar.get']('aldpro-users:'+ my_user + id)).split(' ') %}
{% if apply_to_user_group_ids %}
{% set groups_user = (salt['cmd.run']('id -G ' + my_user)).split(' ') %}
{% for group_user in groups_user %}
{% if group_user in apply_to_user_group_ids %}
< Тело групповой политики>
{% break %}
{% endif %}
{% endfor %}
{% endif %}
Шаблон групповой политики для применения на уровне групп компьютеров:

{% set id = '<Уникальный идентификатор ГП>' %}
{% set my_host = salt['grains.get']("nodename") %}
{% set domain = salt['grains.get']("domain") %}
{% if salt['pillar.get']('aldpro-hosts:'+ my_host) is defined %}
{% set apply_to_pc_group_names = (salt['pillar.get']('aldpro-hosts:'+ my_host +':' + id)).split(' ') %}
{% if apply_to_pc_group_names %}
{% for group_pc in apply_to_pc_group_names %}
{% if (salt['cmd.run']("getent netgroup " + group_pc + " " + node + " " + "-" + " " + ))[-1] == '1' %}
< Тело групповой политики>
{% break %}
{% endif %}
{% endfor %}
{% endif %}
Одним из примеров кастомного сценария может быть автоматическое монтирование сетевых ресурсов с помощью механизма pam_mount при входе пользователя в систему. Несмотря на то, что правила автоматического монтирования autofs, которые можно централизованно настроить в домене FreeIPA, имеют целый ряд преимуществ, способ через pam_mount может быть все же востребован — например, если вам потребуется реализовать подключение пользовательского профиля с файлового сервера.
Используя Salt, который лежит в основе групповых политик ALD Pro, можно управлять конфигурационными файлами, такими как pam_mount.conf.xml, для динамического подключения CIFS/SMB-ресурсов на основе данных пользователя из LDAP. Ниже приведен пример фрагмента SLS-файла для добавления правил монтирования.
Директория монтирования на клиенте |
mountpoint |
Целевая директория, куда будет смонтирована сетевая папка на клиентском АРМ, например: /home/%(USER)/Desktops/Desktop1/ |
Название сетевой папки на файловом сервере |
path |
Название сетевой папки на файловом сервере |
Название файлового сервера |
server |
В формате FQDN файлового сервера |
Локальные права на директорию |
share_local_permissions |
Права на примонтируемую директорию на клиенте, например: 0777 |
Скрытый текст
# Пример управления pam_mount.conf.xml через Salt (управляется через ALD Pro GPO)
# Задаем переменные (путь к конфигу, данные о шарах - могут приходить из Pillar/LDAP)
{% set config_f = '/etc/security/pam_mount.conf.xml' %}
{% set get_vars = [
{'server': 'fileserver.domain.local', 'path': 'share1', 'mountpoint': '/mnt/share1', 'share_local_permissions': '0770'},
{'server': 'otherserver.domain.local', 'path': 'docs', 'mountpoint': '~/docs', 'share_local_permissions': '0700'}
]
%}
# Убеждаемся, что базовый файл существует и имеет корректный заголовок
pam_mount_conf_xml_header:
file.managed:
- name: {{ config_f }}
- contents: |
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE pam_mount SYSTEM "pam_mount.conf.xml.dtd">
<pam_mount>
<debug enable="0" />
<cifsmount>mount.cifs //%(SERVER)/%(VOLUME) %(MNTPT) -o %(OPTIONS) </cifsmount>
# Добавляем блоки <volume> для каждой шары
{% for item in get_vars %}
{% set server_s = item.get('server') %}\
{% set path_s = item.get('path') %}\
{% set mountpoint_s = item.get('mountpoint') %}\
{% set share_local_permissions_s = item.get('share_local_permissions') %}
pam_mount_conf_xml_addvol_{{ path_s }}:
file.append:
- name: {{ config_f }}
- text: |
<volume
fstype="cifs"
server="{{ server_s }}"
path="{{ path_s }}"
mountpoint="{{ mountpoint_s }}"
options="user=%(USER),cruid=%(USER),sec=krb5i,file_mode={{ share_local_permissions_s }},dir_mode={{ share_local_permissions_s }}"
/>
{% endfor %}
# Добавляем завершающие теги
pam_mount_conf_xml_footer:
file.append:
- name: {{ config_f }}
- text: |
<luserconf name=".pam_mount.conf.xml" />
<mntoptions allow="nosuid,nodev,loop,encryption,sec=krb5i" />
<logout wait="0" hup="0" term="0" kill="0" />
<mkmountpoint enable="1" remove="true" />
</pam_mount>
Приведенные примеры демонстрируют способы управления конфигурацией средствами Salt. В рамках ALD Pro такие задачи могут быть реализованы через кастомные сценарии групповых политик, что позволяет централизованно настраивать окружение пользователей и конфигурацию компьютеров.
Безопасность: PKI Proxy и защита ключей
PKI Proxy — это новый модуль ALD Pro, который обеспечивает выпуск и управление сертификатами безопасности в рамках инфраструктуры ALD Pro. В некоторых сценариях возможно разворачивать более одного инстанса для отказоустойчивости. Доменные компьютеры могут отправить запрос на получение сертификата через LDAP, а контроллер домена с ролью PKI Proxy может получить этот запрос, обработать его и также через LDAP передать компьютеру готовый сертификат. Такой подход исключает необходимость хранения закрытых ключей на всех репликах домена, что существенно повышает безопасность инфраструктуры.
При развертывании реплик контроллеров домена можно выбрать данную роль:

Вендор активно развивает этот модуль. Планируется расширение интеграции с внешними Удостоверяющими Центрами, в том числе российскими, такими как CryptoPro УЦ и SafeTech CA. Это позволит использовать сертификаты, соответствующие российским криптографическим стандартам (ГОСТ), что важно для выполнения требований регуляторов и работы с защищенными ресурсами.
Вот простой пример того, как работает PKI Proxy: есть контроллер домена с ролью PKI Proxy КД-1, его реплика КД-2 без роли PKI Proxy, а также есть вновь добавляемый в домен контроллер КД-3. На сетевом уровне КД-3 не имеет доступа к КД-1, но имеет к КД-2.

При добавлении в домен КД-3 происходит следующее:
Процесс развертывания КД-3 добавляет запрос на получение сертификата в учетную запись КД-3 в каталоге на КД-2.
КД-2 реплицирует изменения на КД-1.
КД-3 ожидает в течение 5 минут появления сертификата в соответствующем атрибуте своей УЗ.
PKI Proxy на КД-1 видит запрос на получение сертификата, выпускает его, записывает сертификат и удаляет запрос в УЗ КД-3 в своем каталоге.
КД-1 реплицирует изменения на КД-2.
КД-3 видит свой сертификат на КД-2, напрямую не связываясь с КД-1.
Если КД-3 через 5 минут не увидит свой сертификат, он сделает еще 6 попыток с интервалами в 5 минут. Такое поведение обусловлено тем, что репликация может занимать продолжительное время, особенно если в LDAP активно вносятся изменения или PKI Proxy в топологии домена сильно удален от клиента, который запрашивает сертификат.
После получения сертификата процесс добавления контроллера домена КД-3 продолжается и на нем создается реплика каталога.
Эволюция процесса обновлений ALD Pro
Продукт ALD Pro активно развивается. Периодически необходимо устанавливать новые версии, при этом процесс обновления может быть не всегда простым (в зависимости от количества новых функций и изменений в очередном релизе).
С 2.4.0 обновления ALD Pro стали выполняться по кнопке в веб-интерфейсе. Администратор назначает политику обновления ALD Pro, клиенты сами скачивают нужные скрипты из LDAP и применяют обновления. Процесс обновления ALD Pro постоянно совершенствуется вендором для повышения удобства и надежности, особенно в крупных инфраструктурах:
До версии 2.2.0: Обновление запускалось одной командой, которая централизованно обновляла все компоненты (серверы и клиенты), что могло создавать высокую нагрузку.
С версии 2.2.0: Процесс разделили. Ключевые компоненты (первый КД, подсистемы) обновлялись централизованной командой, а клиенты получали обновления через специальную встроенную групповую политику.
С версии 2.4.0: Обновление первого КД выполняется набором команд на нем самом, подсистемы можно обновить через веб-интерфейс (нажатием кнопки), а клиенты теперь переходят на новую версию самостоятельно через политику обновления ALD Pro, считывая необходимые скрипты и инструкции напрямую из LDAP-каталога. Это снимает зависимость от механизма Salt для доставки обновлений клиентам и повышает скорость и надёжность процесса в больших и географически распределенных сетях.
Также мы реализовали два сценария обновления ОС:
Bash-скрипт с уведомлениями пользователей;
-
Python-скрипт с дополнительными функциями:
валидацией репозиториев ОС;
резервным копированием (/opt/backup -> файловый сервер);
логированием и отправкой отчёта на почту;
Перед использованием скрипта обновления ОС посредством Bash необходимо включить оповещения в ОС для всех пользователей. Затем необходимо сделать перезагрузку ПК, поэтому можно заготовить заранее ГП или даже добавить в заливку ОС по сети сценарий:
#!/bin/bash
####Включение оповещений для всех пользователей системы
sudo apt install libdbus-glib-1* fly-notifications -y
cat <<EOL > /etc/xdg/fly-notificationsrc
[Notifications]
ListenForBroadcasts=true
EOL
Сценарий на BASH протестирован при переходе с Astra 1.8.1 UU1 на 1.8.1 UU2 :
Скрытый текст
#!/bin/bash
#**************************************************************************************************************************
ASTRA_BASE="https://dl.astralinux.ru/astra/frozen/1.8_x86-64/1.8.1/uu/2/main-repository/"
ASTRA_EXT="https://dl.astralinux.ru/astra/frozen/1.8_x86-64/1.8.1/uu/2/extended-repository/"
ASTRA_VERSION_DST="1.8.1"
ASTRA_BUILD_VERSION_DST="1.8.1.16"
ASTRA_VERSION_SRC=`cat /etc/astra_version | head -n 1| awk -F" " '{print $1}'`
ASTRA_BUILD_VERSION_SRC=`cat /etc/astra/build_version | head -n 1 | awk -F" " '{print $1}'`
NOTIFICATION_USER="Добрый день! Ваш компьютер будет обновлен до новой версии ОС Astra Linux через 10 минут.\nПросим вас пожалуйста закрыть критическое ПО для предотвращения проблем с его данными."
NOTIFICATION_USER_POST="Добрый день! На вашем компьютере обновляется операционная система! Просьба не выключать ваш компьютер и не редактировать критические файлы!"
NOTIFICATION_USER_POST_UPGRADE="Добрый день! Ваша ОС успешно обновлена, вы можете продолжить работу. Хорошего вам дня!"
#**************************************************************************************************************************
if [[ ("$ASTRA_VERSION_DST" != "$ASTRA_VERSION_SRC") || ("$ASTRA_BUILD_VERSION_DST" != "$ASTRA_BUILD_VERSION_SRC") ]]; then
#Добавление репозиториев Astra Linux
cat << EOL > /etc/apt/sources.list
deb $ASTRA_BASE 1.8_x86-64 contrib main non-free non-free-firmware
EOL
#Обновление репозиториев ОС
apt update -y
apt install astra-update -y
#Оповещение пользователей об обновлении ОС.
gdbus emit --system --object-path / --signal org.kde.BroadcastNotifications.Notify "{'appIcon': <'network-disconnect'>, 'body': <'$NOTIFICATION_USER'>, 'summary': <'Обновление ОС.'>, 'timeout': <'600000'>}"
sleep 600
gdbus emit --system --object-path / --signal org.kde.BroadcastNotifications.Notify "{'appIcon': <'network-disconnect'>, 'body': <'$NOTIFICATION_USER_POST'>, 'summary': <'Обновление ОС.'>, 'timeout': <'60000'>}"
#Обновление ОС
astra-update -A -r -T
ASTRA_BUILD_VERSION_SRC_POST=`cat /etc/astra/build_version | head -n 1 | awk -F" " '{print $1}'`
echo $ASTRA_BUILD_VERSION_SRC_POST
#Добавление репозиториев Astra Linux, включая расширенный
cat << EOL > /etc/apt/sources.list
deb $ASTRA_BASE 1.8_x86-64 contrib main non-free non-free-firmware
deb $ASTRA_EXT 1.8_x86-64 contrib main non-free non-free-firmware
EOL
#Обновление репозиториев ПО
apt update -y
gdbus emit --system --object-path / --signal org.kde.BroadcastNotifications.Notify "{'appIcon': <'network-disconnect'>, 'body': <'$NOTIFICATION_USER_POST_UPGRADE'>, 'summary': <'Обновление ОС.'>, 'timeout': <'60000'>}"
if [[ "$ASTRA_BUILD_VERSION_DST" != "$ASTRA_BUILD_VERSION_SRC_POST" ]]; then
echo "Ошибка обновления! Проверьте логи обновления на наличие ошибок: /var/log/astra_update*.log"
gdbus emit --system --object-path / --signal org.kde.BroadcastNotifications.Notify "{'appIcon': <'network-disconnect'>, 'body': <'Ошибка обновления ОС - обратитесь к администратору!'>, 'summary': <'Обновление ОС.'>, 'timeout': <'60000'>}"
exit 1
fi
else
echo -e "ОС уже была обновлена.\nАктуальная версия: $ASTRA_VERSION_SRC\nАктуальный build: $ASTRA_BUILD_VERSION_SRC"
exit 0
fi
Сценарий на языке Python протестирован при переходе с Astra 1.7.5 на 1.7.6.
В рамках скрипта используются пароли от почтового ящика, с которого идет отправка уведомлений, и от файлового сервера, на который производится резервное копирование. Чтобы в явном виде не оставлять пароли в скрипте, необходимо вшить их в переменные окружения у пользователя root (от которого работает Salt), согласно таблице ниже:
Переменная окружения |
Назначение |
Формат |
MAIL_USER |
Почтовый адрес отправителя |
|
MAIL_PASS |
Пароль почтового адреса отправителя |
— |
FS_USER |
Пользователь с доступом на запись на файловом сервере |
user |
FS_PASSWORD |
Пароль пользователя на файловом сервере |
— |
Начнем с блока со всеми библиотеками, статическими переменными и маленькими функциями:
Скрытый текст
import os
import subprocess
import smtplib
import ssl
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import logging
DEFINE_COMMAND_GET_VERSION_ALDPRO_CLIENT = "dpkg -l | grep -i aldpro-client | head -n 1 | awk -F' ' '{print $3}' | grep 2.4.0"
DEFINE_LOG_FILE_176 = "/var/log/upgrade_to_176.log"
DEFINE_REPO_ASTRA_EXT = "deb https://vm-repo-01.domain.ald.pro/repos/astra17/astra-176-ext/ 1.7_x86-64 main non-free contrib"
DEFINE_REPO_ASTRA_BASE = "deb https://vm-repo-01.domain.ald.pro/repos/astra17/astra-176-base/ 1.7_x86-64 main non-free contrib"
DEFINE_REPO_SERVER_VALIDATE = "vm-repo-01.domain.ald.pro"
DEFINE_CRED_EMAIL = {
"user": os.environ.get('MAIL_USER'),
"password": os.environ.get('MAIL_PASS'),
"smtp_server": "mail.domain.ald.pro",
"smtp_port": 465,
"smtp_ssl": "True"
}
DEFINE_CRED_FS = {
"user": os.environ.get('FS_USER'),
"password": os.environ.get('FS_PASS'),
"server_fqdn": vm-fs-01.domain.ald.pro
}
def get_os_version():
"""
:return: Возвращает версию ОС Astra Linux
"""
with open("/etc/astra_version") as file:
astra_version = file.readline().rstrip('\n')
return str(astra_version)
def get_kernel_version():
"""
:return: Возвращает версию ядра ОС
"""
return str(os.uname()[2])
def get_fqdn():
"""
:return: Возвращает FQDN АРМ
"""
return str(os.uname()[1])
def get_version_aldpro_client():
"""
:return: Возвращает версию ALD PRO клиента
"""
result = subprocess.run(DEFINE_COMMAND_GET_VERSION_ALDPRO_CLIENT, capture_output=True, shell=True).stdout.decode()
return result.rstrip('\n')
Все библиотеки уже установлены на АРМ, введенный в домен ALD PRO 2.4.0, поэтому нет необходимости в их доустановке. Далее рассмотрим блок с функциями валидации и резервного копирования данных:
Скрытый текст
def validate_repos_and_backup(logger: logging):
"""
:logger: Объект класса для логирования операций
:return: Возвращает bool-значение в случае успеха/неудачи
"""
directory = "/etc/apt/sources.list.d/"
command_update = "apt update -y"
command_mount = f"mount -t cifs //{DEFINE_CRED_FS["server_fqdn"]}/backup/ /mnt -o username={ DEFINE_CRED_FS["user"]},password=''{DEFINE_CRED_FS["password"]}"
command_umount = "umount /mnt -f -l"
command_backup_folder = f"cp -r -v /opt/backup/ /mnt/root_backup/{get_fqdn()}"
list_repos = []
list_repos += os.listdir(directory)
for repolist in list_repos:
with open(directory + str(repolist), 'r') as file:
lines = file.readlines()
with open(directory + str(repolist), 'w') as file:
for line in lines:
if line.strip() and line.find("#") and line.rfind(DEFINE_REPO_SERVER_VALIDATE) != -1:
file.write(line)
try:
result_update = subprocess.run(command_update, capture_output=True, shell=True)
logger.info(":\n" + result_update.stdout.decode())
logger.info(":\n" + "Валидация репозиториев закончена.\nВыполняется резервное копирование папки /opt/backup.")
except subprocess.CalledProcessError as error_process:
logger.info(f":\n" + f"Ошибка выполнения обновления репозиториев и команды apt update.\nПодробнее: "
f"{error_process}")
return False
try:
subprocess.run(command_mount, capture_output=True, shell=True)
except subprocess.CalledProcessError as error_process:
logger.error(":\n", error_process)
if os.path.exists("/mnt/root_backup"):
os.mkdir(f"/mnt/root_backup/{get_fqdn()}")
else:
logger.error(":\n" + "Ошибка монтирования сетевой директории для бэкпаирования!")
return False
try:
result_cp = subprocess.run(command_backup_folder, capture_output=True, shell=True)
logger.info(":\n" + result_cp.stdout.decode())
except subprocess.CalledProcessError as error_process:
logger.error(":\n", error_process)
return False
subprocess.run(command_umount, capture_output=True, shell=True)
return True
И, наконец, блок функции с подключением к почтовому серверу и отправкой сообщения:
Скрытый текст
def send_email(email_to: str, subject: str, message_text: str, attachment: bool):
"""
Отправляет письмо на почту
:email_to: Адрес почты пользователя/группы рассылки
:subject: Тема письма
:message_text: Готовое сообщение TXT
"""
message = MIMEMultipart("alternative")
message["Subject"] = subject
message["From"] = DEFINE_CRED_EMAIL["user"]
message["To"] = email_to
part1 = MIMEText(message_text, "plain")
message.attach(part1)
if attachment == True:
with open(DEFINE_LOG_FILE_176, "rb") as file:
part = MIMEBase('application', 'octet-stream')
part.set_payload(file.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', f"attachment; filename=upgrade_to_176.log")
message.attach(part)
err_code = 0
try:
if DEFINE_CRED_EMAIL["smtp_ssl"].lower() == 'true' or DEFINE_CRED_EMAIL["smtp_ssl"].lower() == '1':
context = ssl.create_default_context()
with smtplib.SMTP_SSL(DEFINE_CRED_EMAIL["smtp_server"],
DEFINE_CRED_EMAIL["smtp_port"],
context=context) as server:
server.login(DEFINE_CRED_EMAIL["user"], DEFINE_CRED_EMAIL["password"])
server.sendmail(DEFINE_CRED_EMAIL["user"], email_to, message.as_string())
server.quit()
email_sended_print_msg = f"Email {subject} to {email_to} sended!"
except Exception as err:
print(f"Ошибка отправки оповещения на рассылку: {email_to},"
f"\nПодробности ошибки: {err}.")
Перейдем к самой функции обновления ОС:
Скрытый текст
def upgrade_to_176(email_group_send: str, logger: logging):
"""
Обновление ОС до версии 1.7.6
:email_group_send: Группа рассылки для оповещения об статусе обнолвения АРМ
:logger: Объект класса для логирования операций
"""
command_update = "apt update -y"
command_upgrade = "astra-update -A -r -T"
if (get_fqdn() != "" and (get_os_version() != "" and get_os_version() != "1.7.6") and get_version_aldpro_client() != ""):
if validate_repos_and_backup(logger):
try:
with open("/etc/apt/sources.list", 'w') as file:
file.write(DEFINE_REPO_ASTRA_BASE + "\n")
logger.info("Файл /etc/apt/sources.list - успешно изменен.")
except IOError as error:
text_email_false_edit_file = f"Добрый день! Произошла ошибка обновления ОС Astra Linux до версии 1.7.6," \
f"\nАРМ: {get_fqdn()}," \
f"\nАктуальная версия ОС: {get_os_version()}, " \
f"\nАктуальная версия ядра: {get_kernel_version()}," \
f"\nОшибка: {error}."
send_email(email_group_send,
subject="Ошибка обновления АРМ",
message_text=text_email_false_edit_file,
attachment=True)
logger.error("Произошла ошибка открытия файла /etc/apt/sources.list")
try:
result_update = subprocess.run(command_update, capture_output=True, shell=True)
logger.info(":\n" + result_update.stdout.decode())
result_upgrade = subprocess.run(command_upgrade, capture_output=True, shell=True)
logger.info(":\n" + result_upgrade.stdout.decode())
if (result_update.returncode != 0 or result_upgrade.returncode != 0):
result_add_ssh_user = subprocess.run(command_add_ssh_user, capture_output=True, shell=True)
logger.info(":\n" + result_add_ssh_user.stdout.decode())
text_email_false = f"Добрый день! Произошла ошибка обновления ОС Astra Linux до версии 1.7.6," \
f"\nАРМ: {get_fqdn()}," \
f"\nАктуальная версия ОС: {get_os_version()} ," \
f"\nАктуальная ядра ОС: {get_kernel_version()} ," \
f"\nПодробнее об ошибке можно узнать в лог файле: {DEFINE_LOG_FILE_176}."
send_email(email_group_send,
subject="Ошибка обновления АРМ",
message_text=text_email_false,
attachment=True)
else:
text_email_true = f"Добрый день! " \
f"\nАРМ: {get_fqdn()}, c ОС Astra Linux успешно обновлен." \
f"\nАктуальная версия ОС: {get_os_version()}," \
f"\nАктуальная ядра ОС: {get_kernel_version()} ," \
f"\nПодробнее об процессе обновления можно узнать в лог файле: {DEFINE_LOG_FILE_176}"
send_email(email_group_send,
subject="Успешное обновление АРМ",
message_text=text_email_true,
attachment=True)
postinstall(logger)
except subprocess.CalledProcessError as eror_process:
text_email = f"Добрый день! Произошла ошибка обновления ОС Astra Linux 1.7.6, " \
f"\nАРМ: {get_fqdn()}." \
f"\nАктуальная версия ОС: {get_os_version()}," \
f"\nАктуальная ядра ОС: {get_kernel_version()} ," \
f"\nОшибка вызвана: {eror_process}."
send_email(email_group_send,
subject="Ошибка обновления АРМ",
message_text=text_email,
attachment=True)
elif get_version_aldpro_client() == "":
logger.info("ALD Pro версия клиента не соответствует обновлению ОС до версии 1.7.6")
else:
text_email = f"Добрый день! Произошла ошибка обновления ОС Astra Linux 1.7.6, " \
f"\nАРМ: {get_fqdn()}." \
f"\nАктуальная версия ОС: {get_os_version()}," \
f"\nАктуальная ядра ОС: {get_kernel_version()} ," \
f"\nОшибка связана с валидацией репозиториев и созданием бэкапа."
send_email(email_group_send,
subject="Ошибка обновления АРМ",
message_text=text_email,
attachment=True)
else:
logger.info("ОС уже обновлена до версии 1.7.6 | Агент не соответствует версии 2.4.0 | Не выполнен бэкап и валидация репозиториев")
Для обновлений ОС есть рекомендации, какие репозитории необходимо указывать до момента обновления. В нашем случае при переходе с 1.7.5 на 1.7.6 необходим либо репозиторий «base», либо «main и update». Но помимо этих репозиториев есть еще и расширенный (extended), в котором иногда находятся пакеты с нужным программным обеспечением. В следующем блоке рассмотрим подключение этого репозитория:
def postinstall(logger: logging):
"""
Добавляет расширенный репозиторий в ОС.
:logger: Объект класса для логирования операций
"""
command_update = "apt update -y"
try:
with open("/etc/apt/sources.list", 'w') as file:
file.write(DEFINE_REPO_ASTRA_BASE + "\n" + DEFINE_REPO_ASTRA_EXT)
logger.info("Файл /etc/apt/sources.list - успешно изменен, добавлен расширенный репозиторий.")
except IOError as error:
logger.error("Произошла ошибка открытия файла /etc/apt/sources.list - не добавлен расширенный репозиторий")
result_update = subprocess.run(command_update, capture_output=True, shell=True)
logger.info(":\n" + result_update.stdout.decode())
Ну и в заключение функция main:
if __name__ == '__main__':
logger = logging.getLogger()
logging.basicConfig(filename=DEFINE_LOG_FILE_176, level=logging.DEBUG, format=f'%(asctime)s --- %(levelname)s --- %(message)s')
upgrade_to_176("upgrade@k2.tech", logger)
Планы развития ALD Pro на 2025 год и перспективы
«Группа Астра» активно развивает ALD Pro. Согласно опубликованной дорожной карте (декабрь 2024), на 2025 год и далее запланированы важные улучшения:
Улучшение управления и интерфейса:
Новая консоль управления: появится динамическая форма для редактирования расширенных атрибутов объектов (пользователей, компьютеров, групп), которая существенно упростит работу администраторов по управлению сторонним программным обеспечением, которое при интеграции со службой каталога создает собственные атрибуты.
Механизм синхронизации 2.6: будет доработан алгоритм для повышения его надежности и производительности, автоматического решения сложных конфликтов, управляемой привязки существующих объектов каталога.
Графическая утилита для ввода в домен: загрузка утилиты стала доступна из личного кабинета уже в рамках 2.5, а в версии 2.6 она должна будет войти уже в состав коробки и устанавливаться автоматически вместе с клиентской частью.
Резервное копирование и восстановление: реализация встроенных функций бэкапа и восстановления (план на Q2-Q4 2025).
Расширение экосистемы и мультивендорность:
Поддержка ОС: клиентская часть для альтернативных вендоров Альт и РедОС в формате MVP доступна уже сейчас, а со второго квартала будет поставляться уже в коробке. Сейчас идет активная работа по проверке и адаптации параметров групповых политик, чтобы их можно было использовать в том числе и для управления этими системами.
Безопасность:
Интеграция PKI Proxy: расширение интеграции с внешними УЦ (CryptoPro, SafeTech).
Усиление ГПО: доработка механизмов с учетом делегирования прав, внедрение LMI-фильтров (аналог WMI-фильтров в AD) для гибкой настройки условий применения политик.
Защита контроллеров: планируется решение задачи по шифрованию системного диска контроллеров домена для возможности их размещения в физически незащищенных локациях без риска компрометации всего домена (план на 2027).
Шифрование диска (аналог BitLocker): хранение ключей в TPM и LDAP (план на 2027).
Оптимизация и новые возможности:
Оптимизация репликации: для поддержки каталогов с десятками миллионов записей.
Улучшение файловой службы: использование AutoFS для динамического монтирования общих папок (альтернатива DFS Namespaces).
Репликация репозиториев: замена rsync на apt-mirror для создания зеркал внешних Debian-репозиториев и управляемой топологии репликации.
Вместо заключения
ALD Pro — это мощная и гибкая платформа, которая постоянно развивается. Как показывает наш опыт, для раскрытия полного потенциала продукта, особенно в сложных и масштабных внедрениях, часто требуются кастомные доработки — от написания salt-скриптов и Ansible-плейбуков до тонкой настройки процессов миграции и политик. В статье я поделился практическим опытом и показал, как российское ПО может адаптироваться под реальные задачи крупного бизнеса.
Мы продолжим следить за развитием ALD Pro, внедрять и делиться своими наработками. Если у вас есть вопросы по внедрению, миграции или кастомизации продукта или собственный опыт работы с ним — расскажите в комментариях!
RumataEstora
Несколько замечаний
1.
В первом листинге: коммент не соответствует действию
2.
Во втором листинге используется необъявленная переменная PC_NAME
3.
это можно упростить до
4.
Чтобы не мучиться с экранированием кавычек в кавычках, лучше вызвать
cat
в субшелле, например:5.
обновление ОС - первый скрипт
обновление ОС - второй скрипт
Получается на второй машине почему-то игнорируется обновление системы. И вообще в целом, обновление репозиториев выстроено нелогично. Лучше прописать все источники в sources.list и//или sources.list.d/, а потом выполнить обновления репо, системы и установку нужных пакетов.
Дальше уже читал по диагонали.
UsovA Автор
Большое спасибо за ваш комментарий!
1) Исправил - согласен с вами!
2) Исправил - согласен с вами!
3) Эта конструкция возможно будет удобнее, протестирую.
4) Эта конструкция возможно будет удобнее, протестирую.
5) Не согласен - по требованиям вендора необходимо использовать последовательность и конфигурационные файлы согласно скриптам.
RumataEstora
По п5. Все верно. Редактируете
/etc/apt/sources.list
и/etc/apt/sources.list.d/*
- пишете туда все, что вам требуется, а потомapt update ; apt dist-upgrade -y ; apt install все что надо для счастья
. Или вендор рекомендует другой путь?AnatolijL
В большинстве случаев dist-upgrade справится с задачей, но лучше все-таки использовать штатную утилиту astra-update, как указано в статье, т.к. она реализует предусмотренную разработчиками ОС стратегию обновления пакетов и может отключать/включать собственные функции безопасности, что может быть необходимо для корректного обновления системы.