Эта статья довольно долго не могла увидеть свет, по ряду причин, от проблем со здоровьем после COVID (я отупел), до отсутствия времени. Время шло, импортозамещение набирало обороты, пилоты становились продакш-средами, и все катилось под откос шло к светлому будущему.
Какое-то время назад мы с командой тоже приступили к пилотированию миграции на «отечественное» ПО. И вот, что из этого вышло.
Началось все с разговоров. А куда без них?
С чего начинается миграция? С выбора ПО? Нет, с планирования и анализа.
- Чего мы хотим достичь?
- Заместить импортные программные продукты отечественными аналогами.
- Полностью?
- Да.
- А если аналогов нет?
- Тогда в максимально возможном объеме.
И тут у нас встала дилемма. Потому что сотрудники Компании в работе помимо прочего используют CAD и PLM софт, который просто не умеет работать на Linux. Вернее, умеет, но через костыли wine’а, что вызывает недовольство пользователей в плане быстродействия. Так же мы используем VDI Horizon, который умеет работать только с AD. А аналогов у Horizon нет. И не говорите про всякие там надстройки для ProxMox и вот это вот все. Ни одна из других существующих VDI-систем не умеет работать с Instant Clones. Максимум, что предлагает OpenSource (и импортозамещение, которое построено на OpenSource) - это Linked Clones. А у нас на IC построены как Windows пулы, так и Linux. И администрировать VDI-рабочие столы как полноценные машины — это смерти подобно, и стоимость владения вырастает за счет необходимости держать огромный штат техподдержки. Поэтому мы не сможем полностью уйти от Windows, как бы нам этого ни хотелось. И из этого вытекает следующее:
Мы не сможем уйти от домена на базе Windows.
Для обеспечения работоспособности инфраструктуры нужны также сервисы DNS, DHCP, WSUS, CA and etc, которые нет смысла (или невозможно) переносить на Linux.
А раз мы не сможем полностью импортозаместиться, то и проект не имеет особого смысла. На этом можно было бы и закончить, но мы решили, что раз уж инфраструктуру импортозаместить не выйдет — займемся хотя бы пользовательской средой. А со стороны инфры сделаем все, что сможем. Zabbix перевезем на отечественную ОСь.. еще чего-нибудь.. Потому что проблема, например, почтового сервера заключается в том, что Exchange у нас есть, и он работает.. А чтобы его заменить на условный Communigate Pro нам нужно потратить кучу денег. А кто же любит тратить деньги, если и так все работает?.. И так с большинством развернутых в проде систем.
На том и порешали.
0. Ansible
Как поднять Ansible я писать не буду, информации об этом в интернетах более, чем достаточно, не вижу смысла загромождать статью лишней информацией. Главное, что там нужно сделать — это сформировать ssh-ключ, с которым Ansible будет ходить к клиентам, и продумать доставку этого ключа на клиентов.
И еще один нюанс – динамическое inventory. Клиентские ПК – дело непостоянное: кто-то уволился, кто-то пришел, какие-то ПК выключены, какие-то больше не существуют. И как это поддерживать в актуальном состоянии – целая задача. Особенно, когда речь идет не о десятках, и даже не о сотнях, а о тысячах машин. Мы пошли по более-менее простому пути – использование плагина nmap в связке с плагином constructed для Ansible. При запуске он опрашивает указанные подсети и формирует список хостов для применения плейбуков или ролей, а потом делает свои грязные делишки на отобранные по правилам хосты.
0.1. Муки выбора дистрибутива
Из представленных на рынке «отечественных» ОС по факту выбор-то и не велик, благо, 99% наших рабочих мест не нужно закрывать сертифицированными ОСями. DEB или RPM, Gentoo-подобные поделки для централизованного администрирования даже не рассматривались, спасибо. Астра\Альт\РедОС\ROSA. Проблема в том, что все они платные. Но. У Альта есть форк - Simply Linux, который бесплатен для коммерческого использования. Думаю, дальше не стоит объяснять, почему мы выбрали Simply Linux.
Ниже есть глава про преобразование ISO-образа.
1. Локальный репозиторий
В нашем случае все даже проще, чем обычно. БазАльт сделал веб-интерфейс, который в пару кликов позволяет настроить репликацию их репозитория (выбранных веток).
Выглядит вот так:
Чтобы попасть на эту страничку, нужно доустановить пакеты ahttpd, alterator-fbi и alterator-mirror, и запустить-активировать ahttpd:
systemctl start ahttpd
systemctl enable ahttpd
В целом в этой админке довольно много функций помимо зеркалирования репозитория, доступ к которым открывается с доустановкой нужных пакетов альтератора.
Дальше мы столкнулись с тем, что нельзя выбрать, куда будут зеркалироваться пакеты. В Вике Альта пишут про то, что надо лезть в fstab
, и там монтировать желаемое расположение к /srv/public/mirror
*. Но нам это показалось странным. В итоге нашли файлик /usr/lib/alterator/backend3/mirror
, в котором указаны пути для alterato-mirror. Поменяли dest_dir=/repos/alt_main-repo
и все поехало.
*(Статью в Вике Альта правил я по результатам наших изысканий)
Дальше мы подумали о том, что нам нужен будет кастомный репозиторий, в который мы будем сваливать пакеты того же Каспера и 1С.. да и прочие, которых нет в репозах Альта (Simply). Список доп.софта у нас получился примерно такой:
1С толстый и тонкий клиент
Google Chrome
Касперский агент и клиент
OnlyOffice (ну не Libre же офисным работникам отдавать..)
VNC-Viewer
VMWare Horizon Client (про него отдельная история, как Windows-админ (я) пытался RPM собрать)
Чтобы создать кастомный репозиторий, нужно прочитать это и это, создать нужную структуру каталогов, наполнить нужное место RPM-пакетами, создать gpg-ключ, создать и подписать индексы, подключить репозиторий клиентам, и можно радоваться.
В целом – ничего сложного, если не накосячить с деревом каталогов, как я по началу.
После заполнения каталога с RPM-пакетами, в моем случае это /repos/alt_custom-repo/x86_64/RPMS.alt_custom_repo/
, нужно создать и подписать индексы:
genbasedir --create --progress --sign --default-key=[gpg-key без скобок] --topdir=/repos/alt_custom-repo x86_64 alt_custom_repo
*genbasedir
является командой из пакета apt-utils
.
Основные сложности у меня вызвали 2 пакета – OnlyOffice и VMWare Horizon Client. Первый не может удовлетворить зависимости, второй просто не существует.
1.3. Пакеты
Тут я вынужден сделать лирическое отступление - я и моя команда - чистый SRE, парни, которые про эти ваши CI\CD и DevOps практики знают только из интернетов и разговоров с коллегами. Это я к тому, что пересобрать RPM-пакет для сисадмина - это тёмный лес. Но мы не отступаем перед сложностями. Самое сложное было разобраться в скриплетах и найти инфу о том, в какой последовательности они применяются при обновлении пакета. И тут мне помогла вот эта дока.
1.3.1. OnlyOffice
Тут все просто – пересобрать RPM без отсутствующих зависимостей. Но стоит сразу уточнить, что Альт (Simply) по дефолту не даст руту собрать RPM-пакет, для этого предлагается использовать непривилегированного пользователя. Делаем:
cd /tmp
wget https://download.onlyoffice.com/install/desktop/editors/linux/onlyoffice-desktopeditors.x86_64.rpm?_ga=2.238710784.1633530263.1666265796-724860256.1666265796
sudo apt-get install wget
wget https://download.onlyoffice.com/install/desktop/editors/linux/onlyoffice-desktopeditors.x86_64.rpm?_ga=2.238710784.1633530263.1666265796-724860256.1666265796
rpmrebuild -enp onlyoffice-desktopeditors.x86_64.rpm\?_ga\=2.238710784.1633530263.1666265796-724860256.1666265796
sudo apt-get install rpmrebuild
rpmrebuild -enp onlyoffice-desktopeditors.x86_64.rpm\?_ga\=2.238710784.1633530263.1666265796-724860256.1666265796
=Ъ
И в открывшейся спеке комментируем пакеты, которых нет в репозиториях Р10. Приводим к виду:
Requires: /bin/sh
Requires: /bin/sh
Requires: /bin/sh
Requires: /bin/sh
Requires: /bin/sh
Requires: atk
Requires: boost-filesystem
Requires: curl
Requires: fonts-ttf-dejavu
Requires: gtk3
Requires: libX11
Requires: libXScrnSaver
Requires: fonts-ttf-liberation
Requires: fonts-ttf-liberation-narrow
Requires: libstdc++ >= 4.8.0
Requires: libxcb
#Requires: rpmlib(CompressedFileNames) <= 3.0.4-1
#Requires: rpmlib(FileDigests) <= 4.6.0-1
#Requires: rpmlib(PayloadFilesHavePrefix) <= 4.0-1
#Requires: rpmlib(PayloadIsXz) <= 5.2-1
Requires: libxcbutil-image
Requires: libxcbutil-keysyms
Requires: libxcb-render-util
Requires: xdg-utils
И сохраняем. На выходе получается RPM-пакет без неудовлетворенных зависимостей. Да, так делать неправильно. Но, на Вике Альта так и написано – игнорируй зависимости, и "спина болеть не будет".
Можно сделать то же самое, но в одну команду. Так менее наглядно, но более автоматизированно:
rpmrebuild -np --change-spec-requires='sed -e "s/dejavu-sans-fonts/fonts-ttf-dejavu/" \
-e "/dejavu-sans-mono-fonts/d" -e "/dejavu-serif-fonts/d" \
-e "s/xcb-util-image/libxcbutil-image/" -e "s/xcb-util-keysyms/libxcbutil-keysyms/" \
-e "s/xcb-util-renderutil/libxcb-render-util/" -e "/xcb-util-wm/d" \
-e "s/liberation-mono-fonts/fonts-ttf-liberation/" -e "/liberation-sans-fonts/d" \
-e "/liberation-serif-fonts/d" -e "s/liberation-narrow-fonts/fonts-ttf-liberation-narrow/"' \
onlyoffice-desktopeditors.x86_64.rpm
Более правильным решением, конечно же, было бы собрать пакет из исходников. Но мы же SRE.. И поэтому это мы записали в планы. На потом.
1.3.2. VMWare Horizon Client
Собрать из исходников проприетарное ПО не получится, даже если вы - не я. Horizon можно скачать в виде tarball-архива с бинарниками, и писать спеку под них. Но я пошел по более простому пути. Я скачал bundle, написал spec-файл для его установки, и запаковал это все в RPM-пакет.
А потом я решил автоматизировать это дело. И написал скриптик, который, получая на вход ссылку на скачивание bundle'а Horizon Client'а, создает структуру каталогов для сборки, меняет в спеке "хххххх" на "версию", и запускает сборку.
Spec-файл Horizon Agent for Linux выглядит так:
Name: vmware-horizon-client
Version: xxxxxx
Release: 1
Summary: custom rpm package vmware-horizon-client
License: GPL
Source0: %{name}-%{version}.tar.gz
Requires: bash
Requires: python3-modules-sqlite3
Requires: python3-modules-curses
Requires: python3-module-pexpect
Requires: python-modules-json
Requires: python-module-pygtk
Requires: python-module-jinja2
Requires: python-module-yaml
Requires: python-module-distutils-extra
%description
VMware Horizon Client for LAB.RU team custom repo
%prep
%setup -q
%install
install -d -m 0755 $RPM_BUILD_ROOT/opt/vdi/
install -m 0755 %{name}-%{version} $RPM_BUILD_ROOT/opt/vdi/%{name}-%{version}
%pretrans
if !([ -z "$(pgrep vmware-view)" ]); then
pkill -f vmware-view
fi
%preun
if !([ -z "$(pgrep vmware-view)" ]); then
pkill -f vmware-view
fi
file=(`ls /opt/vdi/`)
if !([ -z $file ]); then
env VMWARE_KEEP_CONFIG=no /opt/vdi/$file -u vmware-horizon-client --console
rm -f /opt/vdi/$file
fi
if test -f "/etc/skel/Рабочий стол/vmware-view.desktop"; then
rm -f "/etc/skel/Рабочий стол/vmware-view.desktop"
fi
%posttrans
env TERM=dumb VMWARE_EULAS_AGREED=yes /opt/vdi/%{name}-%{version} --console --set-setting vmware-horizon-integrated-printing vmipEnable yes --set-setting vmware-horizon-html5mmr html5mmrEnable yes --set-setting vmware-horizon-usb usbEnable yes --set-setting vmware-horizon-smartcard smartcardEnable yes --set-setting vmware-horizon-rtav rtavEnable yes --set-setting vmware-horizon-tsdr tsdrEnable yes --set-setting vmware-horizon-scannerclient scannerEnable yes --set-setting vmware-horizon-serialportclient serialportEnable yes --set-setting vmware-horizon-mmr mmrEnable yes --set-setting vmware-horizon-media-provider mediaproviderEnable yes --set-setting vmware-horizon-teams-optimization teamsOptimizationEnable no
echo "view.defaultBroker = 'uag.lab.ru'" > /etc/vmware/view-mandatory-config
echo "view.defaultDomain = 'lab'" >> /etc/vmware/view-mandatory-config
echo "view.defaultProtocol = 'BLAST'" >> /etc/vmware/view-mandatory-config
echo "view.autoHideToolbar = 'TRUE'" >> /etc/vmware/view-mandatory-config
echo "view.autoConnectBroker = 'uag.lab.ru'" >> /etc/vmware/view-mandatory-config
echo "view.enableMMR = 'TRUE'" >> /etc/vmware/view-mandatory-config
chmod +x /usr/share/applications/vmware-view.desktop
if !([[ -f "/etc/skel/Рабочий\ стол/vmware-view.desktop" ]]); then
ln -sf /usr/share/applications/vmware-view.desktop /etc/skel/Рабочий\ стол/vmware-view.desktop
chmod 755 /etc/skel/Рабочий\ стол/vmware-view.desktop
fi
if [[ -d /home/LAB.RU/ ]]; then
for dir in $(ls /home/LAB.RU/ | grep -v _); do
if !([[ -f "/home/LAB.RU/$dir/Рабочий\ стол/vmware-view.desktop" ]]); then
ln -sf /usr/share/applications/vmware-view.desktop /home/LAB.RU/$dir/Рабочий\ стол/vmware-view.desktop
chmod 755 /home/LAB.RU/$dir/Рабочий\ стол/vmware-view.desktop
fi
done
fi
%files
/opt/vdi/%{name}-%{version}
%changelog
* August 2022 ANSysoev
-
Скрипт для выглядит так:
#!/bin/bash
if [ -z "$@" ]; then
echo "run script with link to download Horizon Client as argument at run"
else
cd /home/user/rpmbuild/
rm -rf /home/user/rpmbuild/*
mkdir BUILD BUILDROOT SOURCES SPECS SRPMS
cd /home/user/rpmbuild/SOURCES
wget "$@"
version=$(ls | sed -e "s/VMware-Horizon-Client-//" -e "s/.bundle//" -e "s/-/./g")
name="vmware-horizon-client"
fullname=$(echo $name-$version)
mkdir $fullname
mv $(find /home/user/rpmbuild/SOURCES/ -maxdepth 1 -type f) /home/user/rpmbuild/SOURCES/$fullname/$fullname
tar -czvf $fullname.tar.gz $fullname
cp /home/user/vmware-horizon-client.spec /home/user/rpmbuild/SPECS/vmware-horizon-client.spec
sed -i "s/xxxxxx/$version/" /home/user/rpmbuild/SPECS/vmware-horizon-client.spec
cd /home/user/rpmbuild/
rpmbuild -bb SPECS/vmware-horizon-client.spec
fi
Для запуска надо сделать вот такую магию:
horizon-client-RPM-1.sh https://download3.vmware.com/software/CART23FQ3_LIN64_2209/VMware-Horizon-Client-2209-8.7.0-20616018.x64.bundle
И На выходе получится собранный пакетик:
tree
rpmbuild
├── BUILD
│ └── vmware-horizon-client-2209.8.7.0.20616018.x64
│ └── vmware-horizon-client-2209.8.7.0.20616018.x64
├── BUILDROOT
├── RPMS
│ └── x86_64
│ └── vmware-horizon-client-2209.8.7.0.20616018.x64-1.x86_64.rpm
├── SOURCES
│ ├── vmware-horizon-client-2209.8.7.0.20616018.x64
│ │ └── vmware-horizon-client-2209.8.7.0.20616018.x64
│ └── vmware-horizon-client-2209.8.7.0.20616018.x64.tar.gz
├── SPECS
│ └── vmware-horizon-client.spec
└── SRPMS
1.3.3. Google Chrome and etc.
Тут вообще проблем нет, просто скачивается RPM-пакет с официального сайта, копируется в каталог, и все. Все пакеты с удовлетворенными зависимостями ставятся так. И это хорошо.
2. Преобразование ISO-образа
Мы выбрали Simply, потому что он бесплатный.
Но. Отдавать офисным работникам Linux с xfce на борту — это парализовать работу офиса на неопределенный срок. Если более-менее привычные к ПК ребята освоятся достаточно быстро, но тоже не сразу, то тётушки-бухгалтеры — скорее никогда, чем быстро. Поэтому что? Правильно, надо поставить KDE! Это тоже не решит все проблемы, но порог вхождения существенно снизится.
Но. Если выпилить xfce и поставить сверху KDE — получится не кошерно. Останутся лишние пакеты от DM и DE, поэтому надо лезть в ISO и понять, как же происходит установка Linux, чтобы вмешаться в этот процесс и вместо одной DE поставить другую.
На самом деле ничего сложного в этом нет (если разобраться), но все по порядку.
Прочитав Вику Альта Модификация установочного ISO образа, Создание образов устройств, Autoinstall, и ничего в ней не поняв, я решил отвязаться от дистрибутива, и полез в теорию. Хотя последняя ссылка мне помогла во многом.
Что есть дистрибутив Linux? Дистрибутив – это, сильно упрощая, ядро Linux + набор пакетов. Всё. Набор пакетов ПО – суть «встроенный в ISO репозиторий». У Simply пакеты лежат в \ISOroot\ALTLinux\RPMS.main\
. Чтобы собрать дистрибутив, нужно набрать выбранные пакеты, удовлетворить их зависимости, и положить в ISO, описать «группы ПО», пересчитать и подписать индексы. . В директории Metadata\pkg-groups.tar\lists\
лежит файл .base
, содержащий в себе список пакетов, которые накатываются в любом случае, а так же директория slinux
, содержащая в себе описание этих самых групп ПО (имя и состав пакетов каждой группы).
Для того, чтобы избавиться от xfce и добавить вместо него KDE есть 2 пути: сложный и очень сложный.
Очень сложный предполагает скачивание из репозитория нужных пакетов (KDE и его зависимости). Но мне было лень. Наверное, есть какой-то специальный софт, который умеет считывать зависимости из метадаты указанного пакета, и выкачивать эти зависимости.. Но я такого не нашел, поэтому пошел по сложному пути, а именно — скачал Альт Workstation 10 K (у которого та же пакетная база, что и у Simply, только с KDE искаропке), и подменил пакеты в ISO-репозитории и файл .base
, собрал, установил… … … … ..ииииии.. получил свежеустановленный Альт 10 K. Удивился. Много думал. В основном о том, что моих теоретических познаний явно недостаточно для реализации поставленной мной же задачи. (Как же сложно и неприятно быть тупым! Проклятый COVID!)
После пролитых слез, покрасневших глаз, вырванных волос и обгрызенных ногтей поиска причин, я понял, что в списке пакетов есть RPM’ки со словом branding в имени, и понял, что именно их установка в целевую систему отвечает за то, какой дистрибутив получится на выходе. Например, один из пакетов правит файлик/etc/system-release
, другой накидывает нескучные обои и т.д.
Словом, после нехитрых, но скучных и утомительных правок файлика .base
и закидывания в репозиторий недостающих пакетов (у меня на это ушло примерно 10 попыток установки системы), я получил на выходе Simply Linux 10 K. Потом я решил, что этого недостаточно, и отсобрал еще один ISO уже без DE.. Simply Linux Server. А то на чем мне Ansible и локальный репозиторий разворачивать?
Список команд чуть ниже.
Далее — доставка на свежеустановленную систему ключей Ansible и установка hostname. Если в ОСи будут установлены ключи от Ansible, то дальше можно все сделать через сам Ansible. Тут нам поможет пакет alterator-postinstall и простейший скрипт, который доставит в /root/.ssh/authorized_keys
нужные ключи. У меня 2 Ansible, 1 в головном офисе, и 1 в филиале, канал с которым, мягко говоря, оставляет желать лучшего. Поэтому 2 ключа. Так же нужно позаботиться об инженерах техподдержки, и закинуть в свежую систему скрипт, который на основе существующих в AD записей для компьютеров, будет подбирать подходящий hostname для нового ПК перед вводом в домен. Эти скрипты тоже нужно будет доставить в целевую систему. Скрипт назовем 87-set-ansbls-keys.sh, и напишем в нем следующее (ну почти так, ключи я вам не покажу =Ъ):
#!/bin/sh
. install2-init-functions
echo "ssh-rsa бла-бла-бла-набор-символов root@ansible-filial-hostname" > $destdir/root/.ssh/authorized_keys
echo "ssh-rsa бла-бла-бла-набор-символов root@ansible-hostname" >> $destdir/root/.ssh/authorized_keys
cp /var/ChangeHostName.py $destdir/var/
Тут одна тонкость — таргет указывается с преффиксом $destdir
, иначе установщик, выполняя директиву postinstall, запишет ключи в свой /root, а не в устанавливаемую ОС.
Скрипт поиска подходящего hostname прост, как 5 копеек (которых никто не видел уже черт знает сколько лет). Я создал в AD бесправную учетку, чтобы Python мог сходить в AD и считать уже существующие в определенной OU учетки компьютеров, и выбрать следующий по списку.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import sys
from getpass import getpass
from ldap3 import Server, Connection, SUBTREE, LEVEL
import time
username="lab.ru\linux_to_domain"
password="Passw0rd!"
server = Server("dc-1.lab.ru", port=389, use_ssl=False, get_info='ALL')
connection = Connection(server, user=username, password=password,
fast_decoder=True, auto_bind=True, auto_referrals=True, check_names=False, read_only=True,
lazy=False, raise_exceptions=False)
hostnamedigit=1
hostname = "ARM-"+'{:0>4}'.format(hostnamedigit)
def get_all_ad_hosts(connection):
results = list()
elements = connection.extend.standard.paged_search(
search_base='OU=LINUX,OU=Computers,dc=lab,dc=ru',
search_filter='(&(objectCategory=computer)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))',
search_scope=SUBTREE,
attributes=['name'],
paged_size=100)
for element in elements:
host = dict()
if 'dn' in element:
host['dn'] = element['dn']
host['name'] = element['attributes'][u'name'][0]
results.append(host)
return(results)
connection.unbind()
def search_for_duplicatename(hostname,list_of_computers):
for computer in list_of_computers:
if computer['name'].casefold() == hostname.casefold():
print(hostname+" already exists")
return 1
return 0
computers = get_all_ad_hosts(connection)
while search_for_duplicatename(hostname, computers) != 0:
hostnamedigit += 1
hostname = "ARM-"+'{:0>4}'.format(hostnamedigit)
print(hostname)
os.system("hostnamectl set-hostname "+hostname)
print("Your system is gonna reboot in 10 seconds....")
time.sleep(10)
os.system("reboot now")
Теперь о том, куда же эти скрипты поместить. Целевая директория — архив altinst, находящийся в корне ISO. В архиве скрипт нужно расположить в директории /usr/share/install2/postinstall.d/
и не забыть сделать его исполняемым, иначе чуда не произойдет. Скрипт подбора hostname я положил в /var, хотя это не играет особой роли.
Но. Прежде, чем все это сделать, нужно смонтировать скачанный ISO, скопировать куда-то его содержимое, распаковать архив с помощью squashfs-tools (пакет нужно поставить), скопировать скрипты, поменять файлик .base
.. Словом, сделать все свои грязные делишки, и потом запаковать архив и собрать ISO. Итого (перед выполнением genbasedir
нужно скопировать необходимые пакеты, удалить лишние, и привести в порядок файлы, отвечающие за установку групп ПО, как было описано выше):
apt-get install apt-utils squashfs-tools
mkdir /home/user/slinux_iso /home/user/altinst
cd /home/user/altinst
sudo mount /home/user/slinux.iso /mnt
cp -r /mnt/* /home/user/slinux_iso/
unsquashfs /home/user/slinux_iso/altinst
cp /path_to_script_ansible_keys.sh /home/user/altinst/squashfs-root/usr/share/install2/postinstall.d/87-set-ansbls-keys.sh
chmod +x /home/user/altinst/squashfs-root/usr/share/install2/postinstall.d/87-set-ansbls-keys.sh
cp /path_to_script_hostname /home/user/altinst/squashfs-root/var/ChangeHostName.py
chmod +x /home/user/altinst/squashfs-root/var/ChangeHostName.py
rm /home/user/slinux_iso/altinst
mksquashfs /home/user/altinst/squashfs-root/ /home/user/slinux_iso/altinst
genbasedir --create --topdir=/home/user/slinux_iso/ ALTLinux main
cd /home/user/slinux_iso
sudo xorriso \
-as mkisofs "/home/user/slinux_iso"\
-joliet \
-partition_cyl_align "off" \
-partition_offset 16 \
-iso-level 3 \
-full-iso9660-filenames \
-sysid "LINUX" \
-volid "Simply Linux 10.1 x86_64" \
-volset "ALT" \
-publisher "BASEALT LTD" \
-appid "SIMPLY LINUX 10.1 X86_64 2022-06-28" \
-copyright "LICENSE_ALL_HTML" \
-eltorito-boot syslinux/isolinux.cfg \
-eltorito-catalog syslinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-isohybrid-mbr syslinux/isohdpfx.bin \
-eltorito-alt-boot \
-e EFI/.efiboot.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
-output ../SimplyLinux10_KDE.iso
И ждем.
В целом, можно было заскриптовать и еще какие-то штуки, которые делаются при первом запуске системы, как то – установка доменных сертификатов, прописывание локального репозитория и т.д. Но мы предпочли делать это через Ansible. Так это проще контролировать, и проще что-то изменить, если это потребуется.
3. Ansible playbooks
Дальше мы приступили к написанию плейбуков для доставки на клиенты нужных настроек:
ssh
sssd
samba
kerberos
pam
cups
ввод в домен
… etc.
Я довольно долго думал о том, нужно ли приводить листинг плейбуков. И, посоветовавшись с командой, мы решили, что не все стоит выкладывать. По ряду причин.
Спойлер
Да, мы знаем, что в нижеследующем можно сделать все иначе. Использовать роли, переменные и т.д. Хранить все в гите, отслеживать там изменения и прочее, прочее, прочее. Мы знаем, спасибо. Но читать это в рамках статьи будет невозможно. Поэтому плейбуки. Поэтому разбито так, как разбито.
Итак, требования следующие:
Доставить внутренние сертификаты, импортировать их
Добавить локальные репозитории
Установить в систему весь требуемый софт, закинуть конфиги для установленного софта, настроить skel, чтобы при первом входе в систему, пользователь получил нужные линки и каталоги, предусмотреть подключение для пользователей сетевых шар, живущих на Windows-сервере, предусмотреть подключение пользователям списка баз 1С, как это описано здесь (ну это просто удобно)
Сформировать конфиги для подключения ПК к домену, предусмотреть запуск логон-скриптов, обойти проблему авторизации на proxy-сервере (в нашем случае это скрипт, который стучится в proxy-сервер с Kerberos-тикетом, посредством curl’а, и получает на проксе тикет на 8 часов). Да, WSA – она такая..
Настроить ssh согласно требованиям от ИБ, в том числе ограничить доступ для определенных групп AD
Настроить доступ к sudo для определенной группы AD
Соблюсти прочие требования ИБ (мне запретили это показывать. ИБ – те еще параноики)
Ввести ПК в домен
Предусмотреть механизм «брендирования» - обои рабочего стола, загрузчика и прочее (это мне тоже запретили вам показывать)
Предусмотреть возможность массового обновления
В плейбуках все понятно по названиям тасков. Поэтому в проде мы вообще не делали комментариев. Для статьи я добавил немного комментов там, где посчитал необходимым.
«Кто в теме и так поймет, кто не в теме – тот все равно листинг читать не будет».
Оговорюсь лишь о том, что для доставки файлов, открытых ключей и прочего, мы опубликовали их рядом с репозиториями. Там все равно web-сервер поднят, почему бы его не использовать?
3.1. Доставить внутренние сертификаты, импортировать их
- name: Install local CA certs
gather_facts: false
hosts: simply
tasks:
- name: Execute script
shell: |
mkdir /tmp/certs
cd /tmp/certs
wget --no-check-certificate https://local-repo-srv.lab.ru/alt_custom-repo/certs/root.crt
wget --no-check-certificate https://local-repo-srv.lab.ru/alt_custom-repo/certs/subca.crt
cp ./rootca.crt /etc/pki/ca-trust/source/anchors/
cp ./subca.crt /etc/pki/ca-trust/source/anchors/
chmod a-x /etc/pki/ca-trust/source/anchors/*
update-ca-trust extract
3.2. Добавить локальные репозитории
- name: add repositories
gather_facts: false
hosts: simply
tasks:
- name: delete all /etc/apt/sources.list.d/
shell: rm -f /etc/apt/sources.list.d/*
- name: create lab.list
copy:
dest: /etc/apt/sources.list.d/lab.list
content: |
rpm [p10] http:// local-repo-srv.lab.ru /alt_main-repo p10/branch/x86_64 classic
rpm [p10] http:// local-repo-srv.lab.ru /alt_main-repo p10/branch/noarch classic
rpm [alt_custom_repo] http:// local-repo-srv.lab.ru /alt_custom-repo x86_64 alt_custom_repo
- name: add custom gpg key
shell: curl http:// local-repo-srv.lab.ru /alt_custom-repo/x86_64/base/custom_repo.pgp >> /etc/apt/custom_repo.pgp && gpg --no-default-keyring --keyring /usr/lib/alt-gpgkeys/pubring.gpg --import /etc/apt/custom_repo.pgp
- name: add /etc/apt/vendors.list.d/lab.list
copy:
dest: /etc/apt/vendors.list.d/lab.list
content: |
simple-key "alt_custom_repo" {
Fingerprint "бла-бла-бла-буквы-и-цЫфры";
Name "Vasily <Vasya@lab.ru>";
}
- name: apt-get update
shell: |
apt-get update
apt-get dist-upgrade -y
3.3. Установить в систему весь требуемый софт, …
- name: soft installation
gather_facts: false
hosts: simply
tasks:
- name: update
shell: apt-get update -y
- name: install packages
apt_rpm:
name:
- sudo
- apt-scripts
- openssh
- task-auth-ad-sssd
- sssd-ad
- samba-client
- 1c-preinstall-full
- vmware-view-preinstall
- onlyoffice-desktopeditors
- nano
- firefox
- libinput
- libinput-devel
- xorg-drv-libinput
- xorg-drv-libinput-devel
- x11vnc
- x11vnc-service
- 1c-enterprise-8.3.18.1483-thin-client
- vlc
- google-chrome-stable
- autofs
- vmware-horizon-client
- system-config-printer
- kde5-spectacle
- evolution
- evolution-ews
- conky
- remmina
- remmina-plugins
- cups
state: present
- name: remove Libre, stop cups
shell: |
apt-get remove libreoffice5 -y && apt-get clean -y && apt-get autoremove -y
systemctl stop cups
#для VNC есть еще таска для установки пароля, но я вам ее не покажу.
#Там тривиально
- name: x11vnc config
copy:
dest: /usr/sbin/x11vnc-start-daemon
content: |
#!/bin/bash
AUTH=`ps aux | grep "\-auth " | head -n 1`
AUTH=${AUTH/*\-auth /}
AUTH=${AUTH/ */}
/usr/bin/x11vnc -auth $AUTH -dontdisconnect -usepw -shared -forever -rfbport 5900 -rfbauth /etc/vncpasswd -display :0 -repeat
- name: catalogs and files
file:
path: "{{ item.path }}"
state: "{{ item.state }}"
with_items:
- { path: /etc/skel/Рабочий стол/, state: directory } #каталог для создания ярлыков
- { path: /mnt/share/, state: directory } #каталог для монтирования «сетевых дисков»
- { path: /var/ChangeHostName.py, state: absent } #удаление скрипта подбора hostname
- { path: /opt/1cv8/x86_64/8.3.18.1483/libstdc++.so.6, state: absent } #для работы 1С этот файл надо удалить. Не спрашивайте, это не баг, это фича.
- { path: /etc/skel/.1C/1cestart/, state: directory } #каталог для монтирования шары со списком баз для 1С
- name: create links
file:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
state: "{{ item.state }}"
mode: "{{ item.mode }}"
force: yes
with_items:
- { src: /mnt/share/, dest: /etc/skel/Рабочий стол/Сетевые_Папки, state: link, mode: '755' }
- { src: /usr/share/applications/firefox.desktop, dest: /etc/skel/Рабочий стол/firefox.desktop, state: link, mode: '755' }
- { src: /usr/share/applications/google-chrome.desktop, dest: /etc/skel/Рабочий стол/google-chrome.desktop, state: link, mode: '755' }
- { src: /usr/share/applications/1cestart-8.3.18-1483.desktop, dest: /etc/skel/Рабочий стол/1C.desktop, state: link, mode: '755' }
- { src: /usr/share/kf5/applications/kf5/org.kde.dolphin.desktop, dest: /etc/skel/Рабочий стол/Dolphin.desktop, state: link, mode: '755' }
- { src: /usr/share/applications/onlyoffice-desktopeditors.desktop, dest: /etc/skel/Рабочий стол/onlyoffice-desktopeditors.desktop, state: link, mode: '755' }
- { src: /usr/share/applications/vmware-view.desktop, dest: /etc/skel/Рабочий стол/vmware-view.desktop, state: link, mode: '755' }
- { src: /mnt/.services/1CBases/1cestart_alt.cfg, dest: /etc/skel/.1C/1cestart/1cestart.cfg, state: link, mode: '755' }
- name: copy files
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
mode: "{{ item.mode }}"
with_items:
#блок копирования настроек cups. Они для всех одинаковы, подключается очередь
#печати на принтер MyQ
- { src: /etc/ansible/playbooks/files/cups/cupsd.conf, dest: /etc/cups/cupsd.conf, owner: root, group: lp, mode: '640' }
- { src: /etc/ansible/playbooks/files/cups/cups-files.conf, dest: /etc/cups/cups-files.conf, owner: root, group: root, mode: '644' }
- { src: /etc/ansible/playbooks/files/cups/printers.conf, dest: /etc/cups/printers.conf, owner: root, group: lp, mode: '600' }
- name: enable services
service:
name: "{{ item }}"
enabled: yes
state: restarted
with_items:
- x11vnc
- cups
- name: firefox set krb enable
copy:
dest: /usr/lib64/firefox/browser/defaults/preferences/myprefs.js
content: |
pref("network.negotiate-auth.trusted-uris",".lab.ru");
pref("network.automatic-ntlm-auth.trusted-uris",".lab.ru");
pref("network.automatic-ntlm-auth.allow-non-fqdn","true");
pref("network.negotiate-auth.allow-non-fqdn","true");
pref("network.negotiate-auth.delegation-uris",".lab.ru");
- name: chrome set krb enable
copy:
dest: /etc/opt/chrome/policies/managed/krb.json
content: |
{
"AuthServerAllowlist": "*.lab.ru",
"AuthNegotiateDelegateAllowlist": "*.lab.ru"
}
- name: apt dedup, enable cups
shell: |
apt-get dedup -y
systemctl start cups
3.4. Сформировать конфиги для подключения ПК к домену, ..
- name: pre-domain config
gather_facts: false
hosts: simply
tasks:
- name: krb config
copy:
dest: /etc/krb5.conf
content: |
[logging]
# default = FILE:/var/log/krb5libs.log
[libdefaults]
default_realm = LAB.RU
dns_lookup_realm = true
dns_lookup_kdc = true
ticket_lifetime = 24h
renew_lifetime = 7d
rdns = false
forwardable = yes
default_ccache_name = FILE:/tmp/krb5cc_%{uid}
- name: samba config
copy:
dest: /etc/samba/smb.conf
content: |
[global]
security = ads
realm = LAB.RU
workgroup = LAB
netbios name = {{inventory_hostname}}
template shell = /bin/bash
kerberos method = system keytab
wins support = no
idmap config * : range = 10000-20000000
idmap config * : backend = tdb
- name: sssd config
copy:
dest: /etc/sssd/sssd.conf
content: |
[sssd]
config_file_version = 2
user = root
domains = LAB.RU
services = pam,nss,autofs
[nss]
[pam]
[domain/LAB.RU]
id_provider = ad
auth_provider = ad
chpass_provider = ad
default_shell = /bin/bash
fallback_homedir = /home/%d/%u
ad_server = dc-1.lab.ru,dc-2.lab.ru
ad_backup_server = _srv_
cache_credentials = true
debug_level = 2
#монтирование сетевых дисков. Через pam mount ничего не вышло. Он либо багованый,
#либо фича у него такая, но мы перешли на смб, который монтирует шары при
#обращении к ним пользователя
- name: autofs config
copy:
dest: /etc/auto.master
content: |
/mnt/share /etc/auto.samba --ghost
/mnt/.services /etc/auto2.samba --ghost --timeout 60
- name: autofs config 1
copy:
dest: /etc/auto.samba
content: |
disk_1 -fstype=cifs,multiuser,cruid=$UID,sec=krb5,domain=LAB.RU ://dfs-server.lab.ru/Share
disk_2 -fstype=cifs,multiuser,cruid=$UID,sec=krb5,domain=LAB.RU ://file-server.lab.ru/Share2
disk_3 -fstype=cifs,multiuser,cruid=$UID,sec=krb5,domain=LAB.RU ://file-server.lab.ru/Share3
- name: autofs config 2
copy:
dest: /etc/auto2.samba
content: |
1CBases -fstype=cifs,multiuser,cruid=$UID,sec=krb5,domain=LAB.RU ://file-server.lab.ru /1CBases
background -fstype=cifs,multiuser,cruid=$UID,sec=krb5,domain=LAB.RU ://file-server.lab.ru/background
- name: enable autofs
service:
name: autofs
enabled: yes
state: restarted
- name: configure nsswitch and cronyd
lineinfile:
path: "{{ item.path }}"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { path: /etc/nsswitch.conf, regexp: '^passwd', line: 'passwd: files sss' }
- { path: /etc/nsswitch.conf, regexp: '^shadow', line: 'shadow: tcb files sss' }
- { path: /etc/nsswitch.conf, regexp: '^group', line: 'group: files sss' }
- { path: /etc/chrony.conf, regexp: '^pool', line: 'pool dc-1.lab.ru iburst' }
- name: set control policy and system-auth
shell: |
control sudo public
control system-auth sss
#Cisco WSA – довольно «интересный» proxy-сервер..
#И так как далеко не все Linux’овые приложения умеют использовать krb-тикеты
#для авторизации на прокси, приходится использовать костыль. Нет, можно было
#заставить пользователя сначала запустить браузер, авторизоваться на проксе,
#и только после этого получить доступ в интернет, скажем, с мессенджера..
#но мы посчитали это издевательством.
- name: proxy auth script
copy:
dest: /var/proxy_auth.sh
content: |
#!/bin/bash
ip=$(echo `ifconfig eth0 2>/dev/null|awk '/inet addr:/ {print $2}'|sed 's/addr://'`)
echo "curl -isL --negotiate -u : https://proxy-server.lab.ru/same_text/$ip/http://lab.ru/ > /dev/null" > /tmp/proxy_auth.sh
/bin/bash /tmp/proxy_auth.sh
rm -f /tmp/proxy_auth.sh
mode: "755"
- name: create logon script fpr proxy auth
copy:
dest: /etc/profile.d/proxy_auth.sh
content: |
#!/bin/bash
/var/proxy_auth.sh
mode: "755"
3.5. Настроить ssh согласно требованиям от ИБ, в том числе ограничить доступ для определенных групп AD
- name: ssh
gather_facts: false
hosts: simply
tasks:
- name: edit sshd config
lineinfile:
path: /etc/openssh/sshd_config
regex: "^(#)?{{item.key}}"
line: "{{item.key}} {{item.value}}"
state: present
loop:
- { key: "LogLevel", value: "VERBOSE" }
- { key: "PermitRootLogin", value: "prohibit-password" }
- { key: "MaxAuthTries", value: "3" }
- { key: "MaxSessions", value: "2" }
- { key: "PermitEmptyPasswords", value: "no" }
- { key: "UsePAM", value: "yes" }
- { key: "AllowGroups", value: "domain?users root wheel linux-sudoers" }
#да, да, именно в таком формате тут нужно указывать доменные группы с пробелами
#в названиях
notify:
- restart sshd
- enable sshd
handlers:
- name: restart sshd
service:
name: sshd
state: restarted
- name: enable sshd
service:
name: sshd
enabled: yes
3.6. Настроить доступ к sudo для определенной группы AD
- name: sudoers
gather_facts: false
hosts: simply
tasks:
- name: edit sudoers file
blockinfile:
path: /etc/sudoers
backup: yes
block: |
%Linux-Sudoers ALL=(ALL) ALL
%Linux-Users ALL=/usr/bin/apt-cache
%Linux-Users ALL=/usr/sbin/poweroff
%Linux-Users ALL=/usr/sbin/NetworkManager
validate: /usr/sbin/visudo -cf %s
- name: replace line
lineinfile:
path: /etc/sudoers
regexp: '^@includedir /etc/sudoers.d'
line: '#@includedir /etc/sudoers.d'
validate: /usr/sbin/visudo -cf %s
3.8. Ввести ПК в домен
#При запуске спрашивает логин и пароль (в «приватном» виде).
#После чего получает керберос-тикет и подключает ОС к домену
- name: domain join
gather_facts: false
hosts: simply
vars_prompt:
- name: "adlogin"
prompt: "Enter AD Login"
private: no
- name: "password"
prompt: "Enter password"
private: yes
tasks:
- name: domain check
shell: timeout 6s net ads testjoin
register: domain_state
failed_when: domain_state.rc == 0
- name: Clear the sssd cache
shell: rm -f /var/lib/sss/db/* /var/lib/sss/mc/*
- name: get krb ticket
shell: echo '{{ password }}'| kinit "{{ adlogin }}"
- name: join domain
command: net ads join -U "{{ adlogin }}"%"{{ password }}" createcomputer="/Computers/Linux"
- name: sssd enable
service:
name: sssd
enabled: yes
state: restarted
- name: reboot
reboot:
reboot_timeout: 120
3.10. Предусмотреть возможность массового обновления
Тут пришлось сделать отдельный playbook для обновления, и отдельный playbook для брендирования, так как мы пошли по простому пути – не стали пилить тему для кедов, а просто поменяли интересующие нас картинки. И поэтому при обновлении пакетов картинки затираются. Поэтому сразу после обновления происходит брендирование.
Playbook апдейта:
- name: update and upgrade
hosts: simply
gather_facts: false
tasks:
- name: update & upgrade
shell: |
apt-get update -y && apt-get dist-upgrade -y
apt-get dedup -y
Брендинг у нас уже был (но я вам его не покажу, мне запретили). И поэтому playbook обновления выглядят так:
- import_playbook: update.yml
- import_playbook: branding.yml
4. Server-side
Следующий этап импортозамещения – перенос инфраструктурных сервисов на «отечественные» программные продукты. Об этом мы долго думали, рассматривали варианты, поднимали стенды (но стенд и боевые тесты – это совсем не одно и то же). Словом, перекинуть на Альт или Астру, или какую-то еще ОС, например, Zabbix, dhcp, dns, proxy-сервер – не проблема. Это все есть и работает. Но заменить VMWare Hypervisor просто нечем. OpenNebula? Ну да, ну да. KVM? ProxMox? VDI – отсутствует. Проблема «отечественного» софта осталась той же – это пересобранное OpenSource ПО, которое стоит денег. И как весь OpenSource, его стоимость заключается не в «коробка + 2 инженера», а в «десяток инженеров с зарплатами сильно выше, чем у «коробочного» (в зависимости от размера инфраструктуры).
По итогу мы перекинули на Simply Linux продуктовый Zabbix, и подняли Ansible, jitsi и локальный репозиторий. Дальше по плану перенос Nextcloud, Kaspersky Security Center, Certification Authority. Но все это.. такое.. Фикция и профанация.
5. Выводы
В целом, со слов тестовой группы, работать на Linux «можно». Да, недостает привычных виндовых удобств, типа SSO для Outlook, предпросмотра документов в 1С (над этим работает наш центр компетенций 1С), «адок с банк-клиентами и криптопрой» (с) техподдержка.
«Работать можно». Базовый функционал есть. Да, не искаропке, его приходится допиливать, ибо парадигма Linux такова, что каждый каждый делает «это» так, как хочет. Если вы понимаете, о чем я. А допиливать функционал приходится в основном силами админов и ТП.
В итоге: используя данный инструментарий, сотрудник сможет выполнять свои обязанности.
Но. Шаг влево\шаг вправо вызывает жуткий butthurt как у пользователя, так у техпода, привыкшего к Windows. У нас же как заведено? Логи начинают читать только тогда, когда google ничего не подсказал. И перестроить мышление довольно трудно, потому что «ну там же так работает! И это удобно! Так зачем уходить от удобного и привычного к сложному и непонятному?». Но это уже политика, это на другом ресурсе обсуждается.
«Мыши плакали и кололись..» А, стоп, где-то я это уже писал..