commit 7321db5c7e2e02731ba097784a123d4da9871fb8 Author: yaprodunov Date: Fri May 15 13:33:47 2026 +0300 Первая автонастройка и автозахват образа для доменного использования Astra Linux 1.8 new file: domain_builder_1.8.sh new file: prepare_files/admin-helper.bin new file: prepare_files/grub_default.conf new file: prepare_files/krb5.conf new file: prepare_files/skel_profile.conf new file: prepare_files/sssd.conf diff --git a/domain_builder_1.8.sh b/domain_builder_1.8.sh new file mode 100755 index 0000000..ab310cc --- /dev/null +++ b/domain_builder_1.8.sh @@ -0,0 +1,162 @@ +#!/bin/bash + +VIRT_IP="192.168.122.116" +SSH_CMD="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null linadmin@$VIRT_IP" +BASE_DIR="/home/linadmin/domain_build" +LOG_FILE="${BASE_DIR}/build.log" +VM_NAME="debian11" +DEVICE_PATH="/dev/nvme0n1p6" +VG_NAME="astra95067" + +mkdir -p "$BASE_DIR" + +echo "Начало сборки образа: $(date)" | tee "$LOG_FILE" + +STEPS=( + "step_01_prepare_system_for_image" + "step_02_shutdown_vm" + "step_03_create_archive" +) + +step_01_prepare_system_for_image() { + echo "=== Шаг 1: Подготовка системы для образа ===" | tee -a "$LOG_FILE" + $SSH_CMD "sudo apt install -y cifs-utils keyutils sssd sssd-tools realmd adcli krb5-user puppet autofs python3-apt dialog whiptail \ + fly-notifications astra-kvm ovmf dialog python3-tk python3-termcolour" \ + && echo "$(date +%T) Базовый софт установлен" | tee -a "$LOG_FILE" + $SSH_CMD "sudo apt install -y evolution evolution-ews evolution-plugins evolution-plugin-pstimport yandex-browser-stable" \ + && echo "$(date +%T) Кастомный софт установлен" | tee -a "$LOG_FILE" + $SSH_CMD "sudo apt install -y libreoffice-math libreoffice-calc libreoffice-impress libreoffice-draw libreoffice-writer" \ + && echo "$(date +%T) libre офис установлен" | tee -a "$LOG_FILE" + $SSH_CMD "sudo mkdir -p /home/image_prepare/ | sudo chmod -R 777 /home/image_prepare/" + scp "prepare_files/sssd.conf" linadmin@$VIRT_IP:/home/image_prepare/ \ + && $SSH_CMD "cat /home/image_prepare/sssd.conf | sudo tee /etc/sssd/sssd.conf" | tee -a "$LOG_FILE" + scp "prepare_files/krb5.conf" linadmin@$VIRT_IP:/home/image_prepare/ \ + && $SSH_CMD "cat /home/image_prepare/krb5.conf | sudo tee /etc/krb5.conf" | tee -a "$LOG_FILE" + scp "prepare_files/skel_profile.conf" linadmin@$VIRT_IP:/home/image_prepare/ \ + && $SSH_CMD "cat /home/image_prepare/skel_profile.conf | sudo tee /etc/skel/.profile" | tee -a "$LOG_FILE" + scp "prepare_files/admin-helper.bin" linadmin@$VIRT_IP:/home/image_prepare/ \ + && $SSH_CMD "sudo mv /home/image_prepare/admin-helper.bin /root/" | tee -a "$LOG_FILE" + $SSH_CMD "sudo chmod +x /root/admin-helper.bin" | tee -a "$LOG_FILE" + scp "prepare_files/grub_default.conf" linadmin@$VIRT_IP:/home/image_prepare/ \ + && $SSH_CMD "cat /home/image_prepare/grub_default.conf | sudo tee /etc/default/grub" | tee -a "$LOG_FILE" + $SSH_CMD "echo | sudo tee /etc/initramfs-tools/conf.d/resume" | tee -a "$LOG_FILE" + $SSH_CMD "sudo update-initramfs -u -k all" | tee -a "$LOG_FILE" + $SSH_CMD "sudo update-grub" | tee -a "$LOG_FILE" + $SSH_CMD "sudo virsh net-autostart default"| tee -a "$LOG_FILE" + echo "=== Шаг 1: Завершен ===" | tee -a "$LOG_FILE" +} + +step_02_shutdown_vm() { + echo "=== Шаг 2: Выключение виртуальной машины ===" | tee -a "$LOG_FILE" + echo "$(date +%T) Выполняется выключение ВМ через SSH..." | tee -a "$LOG_FILE" + $SSH_CMD "sudo poweroff" | tee -a "$LOG_FILE" + EXIT_CODE=${PIPESTATUS[0]} + if [[ $EXIT_CODE -ne 0 ]]; then + echo "$(date +%T) Предупреждение: SSH команда завершилась с кодом $EXIT_CODE (возможно, соединение разорвано при выключении)" | tee -a "$LOG_FILE" + fi + echo "Ожидание полного выключения ВМ..." | tee -a "$LOG_FILE" + local max_attempts=30 + local attempt=1 + while [[ $attempt -le $max_attempts ]]; do + echo "Проверка состояния ВМ (попытка $attempt/$max_attempts)..." | tee -a "$LOG_FILE" + if ! sudo LANG=C virsh list --all | grep -q "$VM_NAME"; then + echo "ОШИБКА: ВМ '$VM_NAME' не найдена в virsh list" | tee -a "$LOG_FILE" + exit 1 + fi + if sudo LANG=C virsh list --state-shutoff | grep -q "$VM_NAME"; then + echo "$(date +%T) ВМ успешно выключена" | tee -a "$LOG_FILE" + break + fi + if [[ $attempt -eq $max_attempts ]]; then + echo "ОШИБКА: ВМ не выключилась за $max_attempts попыток" | tee -a "$LOG_FILE" + exit 1 + fi + sleep 5 + ((attempt++)) + done + echo "=== Шаг 2 завершен успешно ===" | tee -a "$LOG_FILE" +} + +step_03_create_archive() { + echo "=== Шаг 3: Создание архива образа ===" | tee -a "$LOG_FILE" + cd "$BASE_DIR" + MOUNT_DIR="${BASE_DIR}/part_mount" + ARCHIVE_PATH="${BASE_DIR}/obraz.tar.bz2" + + mkdir -p "$MOUNT_DIR" + + echo "$(date +%T) Монтируем устройство..." | tee -a "$LOG_FILE" + sudo kpartx -a "$DEVICE_PATH" 2>&1 | tee -a "$LOG_FILE" + if [[ ${PIPESTATUS[0]} -ne 0 ]]; then + echo "$(date +%T) OШИБКА: Ошибка монтирования kpartx" | tee -a "$LOG_FILE" + exit 1 + fi + sudo vgscan --config "devices { use_devicesfile = 0 }" 2>&1 | tee -a "$LOG_FILE" + sudo vgchange -ay "$VG_NAME" --devicesfile "" 2>&1 | tee -a "$LOG_FILE" + if [[ ${PIPESTATUS[0]} -ne 0 ]]; then + echo "$(date +%T) ОШИБКА: Ошибка активации LVM" | tee -a "$LOG_FILE" + sudo kpartx -d "$DEVICE_PATH" + exit 1 + fi + if [[ ! -d "$MOUNT_DIR" ]]; then + echo "$(date +%T) Создаем точку монтирования..." | tee -a "$LOG_FILE" + mkdir -p "$MOUNT_DIR" 2>&1 | tee -a "$LOG_FILE" + fi + echo "$(date +%T) Монтируем раздел..." | tee -a "$LOG_FILE" + sudo mount "/dev/${VG_NAME}/lv_root" "$MOUNT_DIR/" 2>&1 | tee -a "$LOG_FILE" + if [[ ${PIPESTATUS[0]} -ne 0 ]]; then + echo "$(date +%T) ОШИБКА: Ошибка монтирования раздела" | tee -a "$LOG_FILE" + sudo vgchange -an "$VG_NAME" --devicesfile "" + sudo kpartx -d "$DEVICE_PATH" + exit 1 + fi + echo "$(date +%T) Создаем архив..." | tee -a "$LOG_FILE" + SIZE_BYTES=$(sudo du -sb "$MOUNT_DIR" | cut -f1) + + if sudo tar cf - --preserve-permissions --same-owner --acls --xattrs -C "$MOUNT_DIR" . | pv -s "$SIZE_BYTES" | bzip2 > "$ARCHIVE_PATH" 2>/dev/null; then + echo "$(date +%T) Архив успешно создан" | tee -a "$LOG_FILE" + if [[ -f "$ARCHIVE_PATH" ]]; then + ARCHIVE_SIZE=$(du -h "$ARCHIVE_PATH" | cut -f1) + echo "Размер архива: $ARCHIVE_SIZE" | tee -a "$LOG_FILE" + fi + else + echo "$(date +%T) ОШИБКА: Создание архива" | tee -a "$LOG_FILE" + sudo umount "$MOUNT_DIR/" + sudo vgchange -an "$VG_NAME" --devicesfile "" + sudo kpartx -d "$DEVICE_PATH" + exit 1 + fi + echo "Размонтируем..." | tee -a "$LOG_FILE" + sudo umount "$MOUNT_DIR/" 2>&1 | tee -a "$LOG_FILE" + sudo vgchange -an "$VG_NAME" --devicesfile "" 2>&1 | tee -a "$LOG_FILE" + echo "Очищаем mapping..." | tee -a "$LOG_FILE" + sudo kpartx -d "$DEVICE_PATH" 2>&1 | tee -a "$LOG_FILE" + echo "$(date +%T)" + rm -rf "$MOUNT_DIR" + echo "🔄 Конвертация образа из tar.bz2 в tar.zst" + TEMP_DIR=$(mktemp -d) + echo "📁 Временная папка: $TEMP_DIR" + echo "📦 Распаковка tar.bz2..." + pv "$ARCHIVE_PATH" | tar -xj -C "$TEMP_DIR" + echo "🔨 Упаковка в zstd (используем все ядра)..." + if tar --help | grep -q zstd; then + tar -C "$TEMP_DIR" -cf "$BASE_DIR/obraz.tar.zst" --zstd . + else + # Вариант 2: Классический способ через pipe + tar -C "$TEMP_DIR" -cf - . | zstd -T0 -19 -o "$BASE_DIR/obraz.tar.zst" + fi + rm "$ARCHIVE_PATH" + rm -rf "$TEMP_DIR" + echo "=== Шаг 3 завершен успешно ===" | tee -a "$LOG_FILE" +} + +for step in "${STEPS[@]}"; do + if declare -f "$step" > /dev/null; then + "$step" + else + echo "ОШИБКА: Функция $step не определена" | tee -a "$LOG_FILE" + exit 1 + fi +done + +echo "Сборка образа завершена: $(date)" | tee -a "$LOG_FILE" \ No newline at end of file diff --git a/prepare_files/admin-helper.bin b/prepare_files/admin-helper.bin new file mode 100755 index 0000000..0d48a3e Binary files /dev/null and b/prepare_files/admin-helper.bin differ diff --git a/prepare_files/grub_default.conf b/prepare_files/grub_default.conf new file mode 100644 index 0000000..095833b --- /dev/null +++ b/prepare_files/grub_default.conf @@ -0,0 +1,10 @@ +GRUB_TIMEOUT=1 +GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` +GRUB_CMDLINE_LINUX_DEFAULT="quiet splash parsec.mac=0 parsec.max_ilev=63" +GRUB_CMDLINE_LINUX="" +GRUB_CMDLINE_LINUX_HARDENED="slub_debug=P page_poison=1 slab_nomerge pti=on user.max_user_namespaces=0 kernel.kptr_restrict=1 vsyscall=none" +GRUB_GFXMODE=1024x768 +GRUB_DISABLE_RECOVERY="true" +GRUB_DISABLE_SUBMENU=y +GRUB_DEFAULT=gnulinux-6.1.158-1-generic-advanced-ccd7a7eb-1ae9-4832-88be-6d02deda01bc +GRUB_DISABLE_OS_PROBER=True \ No newline at end of file diff --git a/prepare_files/krb5.conf b/prepare_files/krb5.conf new file mode 100644 index 0000000..cece705 --- /dev/null +++ b/prepare_files/krb5.conf @@ -0,0 +1,33 @@ +[libdefaults] + default_realm = GK.ROSATOM.LOCAL + default_ccache_name = FILE:/tmp/krb5cc_%{uid} + kdc_timesync = 1 + ccache_type = 4 + forwardable = true + proxiable = true + fcc-mit-ticketflags = true + dns_lookup_realm = false + dns_lookup_kdc = true + v4_instance_resolve = false + v4_name_convert = { + host = { + rcmd = host + ftp = ftp + } + plain = { + something = something-else + } + } + rdns = false + +[realms] + GK.ROSATOM.LOCAL = { + default_domain = GK.ROSATOM.LOCAL + } + +[domain_realm] + .gk.rosatom.local = GK.ROSATOM.LOCAL + gk.rosatom.local = GK.ROSATOM.LOCAL +[login] + krb4_convert = true + krb4_get_tickets = false \ No newline at end of file diff --git a/prepare_files/skel_profile.conf b/prepare_files/skel_profile.conf new file mode 100644 index 0000000..a5adc69 --- /dev/null +++ b/prepare_files/skel_profile.conf @@ -0,0 +1,46 @@ +if [ -n "$BASH_VERSION" ]; then + # include .bashrc if it exists + if [ -f "$HOME/.bashrc" ]; then + . "$HOME/.bashrc" + fi +fi + +# set PATH so it includes user's private bin if it exists +if [ -d "$HOME/bin" ] ; then + PATH="$HOME/bin:$PATH" +fi + +# set PATH so it includes user's private bin if it exists +if [ -d "$HOME/.local/bin" ] ; then + PATH="$HOME/.local/bin:$PATH" +fi + +if [ -n "$DISPLAY" ] && [ -z "$GNOME_KEYRING_CONTROL" ]; then + KEYRING_DIR="$HOME/.local/share/keyrings" + LOGIN_KEYRING="$KEYRING_DIR/login.keyring" + + if [ ! -f "$LOGIN_KEYRING" ]; then + # Создаем директорию + mkdir -p "$KEYRING_DIR" + + # Создаем минимальный ключ-ринг + cat > "$LOGIN_KEYRING" << 'EOF' +[keyring] +display-name=Вход +ctime=$TIMESTAMP +mtime=$TIMESTAMP +lock-on-idle=false +lock-after=false +EOF + + # Заменяем timestamp + sed -i "s/TIMESTAMP/$(date +%s)/g" "$LOGIN_KEYRING" + fi + + # Экспортируем переменные + export GNOME_KEYRING_CONTROL="$XDG_RUNTIME_DIR/keyring" + export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/keyring/ssh" + + # Запускаем daemon + gnome-keyring-daemon --start --components=secrets >/dev/null 2>&1 & +fi \ No newline at end of file diff --git a/prepare_files/sssd.conf b/prepare_files/sssd.conf new file mode 100644 index 0000000..89cced9 --- /dev/null +++ b/prepare_files/sssd.conf @@ -0,0 +1,29 @@ +[sssd] +domains = gk.rosatom.local +config_file_version = 2 +services = nss, pam, ifp +default_domain_suffix = gk.rosatom.local + +[domain/] +ad_domain = gk.rosatom.local +krb5_realm = GK.ROSATOM.LOCAL +realmd_tags = manages-system joined-with-adcli +cache_credentials = True +id_provider = ad +krb5_store_password_if_offline = True +default_shell = /bin/bash +ldap_id_mapping = True +use_fully_qualified_names = True +fallback_homedir = /home/%d/%u +access_provider = ad +ad_gpo_access_control = disabled +ignore_group_members = True +krb5_auth_timeout = 20 +case_sensitive = false +dyndns_update = true +dyndns_refresh_interval = 43200 +dyndns_update_ptr = true +dyndns_ttl = 3600 + +[pam] +pam_id_timeout = 20 \ No newline at end of file