
Когда-нибудь ловили себя на мысли, что половину рабочего дня тратите на одно и то же? Открываешь консоль, подключаешься по SSH, вводишь команду за командой, ждешь, проверяешь, переходишь к следующему серверу. Особенно «весело», когда таких серверов не три, а тридцать.
Заказчик попросил развернуть Kaspersky Security Center на десяти серверах. Час на установку — если все идет гладко. Умножаем на десять серверов, добавляем неизбежные косяки и перекуры — получается несколько рабочих дней. А все это время в бэклоге лежат куда более интересные задачи, то самое, ради чего мы вообще шли в профессию.
Меня зовут Максим Гусев, системный инженер направления защиты ИТ-инфраструктуры в К2 Кибербезопасность. Мы вместе с коллегой Артемом Емельяненко написали три Ansible-плейбука, которые превратили 60 минут ручной работы в 16 минут автоматической установки. Минус 73% времени, плюс куча освободившихся часов на настоящую инженерию. Сейчас расскажу, как они работают, и почему этот проект изменил не только наши процессы, но и культуру команды.
С чего все началось
История простая. В нашей компании шла внутренняя трансформация, было три трека работ. Наш трек назывался «Долго и дорого» — намек на то, что проекты затягиваются и стоят недешево. Мы решили это исправить через автоматизацию.
Для первого MVP выбрали установку Kaspersky Security Center 15.1 на Debian. Это базовое средство защиты, которое мы ставим постоянно — и на стендах, и у заказчиков. У некоторых клиентов по несколько инсталляций KSC. Если тут сэкономить время, это принесет ощутимую пользу.
На Windows автоматизировать смысла нет, там просто кликаешь «Далее» несколько раз. А вот на Linux установка сложнее: много команд, параметров, которые нужно рассчитывать и прописывать вручную. В общем, этот процесс — хороший кандидат на автоматизацию.
Почему Ansible?
Инструментов для автоматизации хватает, но мы остановились на Ansible. Причина в архитектуре: push-модель против pull-модели.
Инструменты вроде Puppet или SaltStack работают по pull-модели. Это значит, что на каждый сервер нужно поставить агента, который регулярно опрашивает центральный сервер: «Есть новые инструкции? Мне что-то менять?». Подход мощный для поддержания конфигурации, но требует предварительной настройки. И да, на каждой машине крутится дополнительный процесс.
Ansible работает иначе — по push-модели: подключился по SSH, выполнил задачу, отключился. Для нас это было решающим преимуществом. Безагентность — никаких программ, которые нужно предварительно разворачивать и поддерживать. Минимализм — никаких лишних процессов на целевой машине. Просто старый добрый SSH.
Три плейбука, чтобы править всем
Можно было бы упаковать все настройки в один огромный скрипт, но это неправильно с архитектурной точки зрения. Мы разбили задачу на три независимых плейбука. Каждый отвечает за свою часть: база данных, бэкенд, веб-консоль. Плюс отдельный файл переменных, где в одном месте задаются все параметры, которые прокидываются во все три плейбука.
С его помощью мы реализовали выбор между онлайн и офлайн установкой. Для онлайн-режима плейбук сам скачает нужные пакеты из интернета. Если у заказчика машина изолирована от сети — не проблема, можно указать локальные пути к дистрибутивам.
Разделение на три плейбука дает гибкость. У заказчика уже может быть развернута база — запускаем только два набора инструкций. Или он захочет вынести консоль на отдельную машину — пожалуйста, это работает из коробки. Модули независимы, но связаны между собой.
Еще один козырь Ansible — идемпотентность. Это значит, что плейбук можно запускать сколько угодно раз, и результат будет одинаковым. Мы специально написали логику так, чтобы перейти от команд «создать» к декларациям «убедиться, что существует и настроено правильно».
Запустили дважды? Ansible проверит текущее состояние и поменяет только те настройки, которые отличаются от целевых. Никаких дублирующих записей в конфигах, никаких повторных установок. Система просто придет к нужному состоянию.
Задаем переменные в vars.yml
Файл с параметрами был вынесен отдельно, переменные отсюда пробрасываются в остальные плейбуки. Тут можно быстро поменять версию БД, выбрать тип установки: офлайн или онлайн, указать имя пользователя веб-консоли и многое другое.
# Версия PostgreSQL
postgresql_version: 15
# Путь к конфигурационному файлу postgresql
postgresql_conf_path: "/etc/postgresql/{{postgresql_version}}/main/postgresql.conf"
# Пер��менные для настройки репозитория postgres
repos:
debian:
repo: "deb http://apt.postgresql.org/pub/repos/apt {{ ansible_distribution_release }}-pgdg main"
key_url: "https://www.postgresql.org/media/keys/ACCC4CF8.asc"
# Имя пакета postgres
pkg_name: "{{ 'postgresql-' + postgresql_version | string }}"
# install_type offline при установке из предварительно загруженных пакетов
# install_type online для загрузки пакетов из сети
install_type: "offline"
# Если установка из скачанного пакета, то в deb_pkg_name указывается полный путь, если онлайн установка - то url
# https://products.s.kaspersky-labs.com/administrationkit/ksc10/15.1.0.11795/russian-18886828-ru/3834323230397c44454c7c31/ksc64_15.1.0-11795_amd64.deb
ksc_deb_pkg_path: /home/user/ksc64_15.1.0-11795_amd64.deb
# https://products.s.kaspersky-labs.com/administrationkit/ksc10/15.1.0.11795/russian-18886828-ru/3834323231337c44454c7c31/ksc-web-console-15.1.523.x86_64.deb
kscweb_deb_pkg_path: /home/user/ksc-web-console-15.1.523.x86_64.deb
# Имя файла установочного пакета
ksc_deb_pkg_name: "{{ ksc_deb_pkg_path | regex_search ('(?:^|.*[\\/\\\\])(ksc[^\\/\\\\]*\\.deb)$', '\\1') }}"
kscweb_deb_pkg_name: "{{ kscweb_deb_pkg_path | regex_search ('(?:^|.*[\\/\\\\])(ksc[^\\/\\\\]*\\.deb)$', '\\1') }}"
# Временная директория
temp_path: /tmp
# IP-адрес KSC. Используем IP-адрес хоста, по которому подключаемся "{{ ansible_default_ipv4.address }}"
# или указываем другой
ip_address: "{{ ansible_default_ipv4.address }}"
# Порт Web консоли
kscweb_port: 8080
# Пользоваетль Web консоли
kscweb_user: ksc
# Пароль пользователя Web консоли
kscweb_pass: P@ssw0rd
Установка базы данных: postgresql.yml
Этот плейбук берет на себя всю черновую работу и превращает чистый Debian-сервер в готовую к работе базу данных PostgreSQL.
---
- name: Установка и настройка PostgreSQL. Создание пользователя и базы данных, а также назначение всех нужных привилегии для пользователя.
hosts: all
become: yes
# Все переменные хранятся в файле ./vars.yml
vars_files:
./vars.yml
tasks:
- name: Добавление GPG ключа
apt_key:
url: "{{ repos['debian'].key_url }}"
state: present
- name: Настройка репозитория PostgreSQL
apt_repository:
repo: "{{ repos['debian'].repo }}"
state: present
- name: Установка PostgreSQL
package:
update_cache: yes
name: "{{ pkg_name }}"
state: present
- name: Включение и запуск службы PostgreSQL
systemd:
name: postgresql
state: started
enabled: yes
- name: Создание переменной для вывода версии PostgreSQL
shell: |
psql --version | tee /dev/tty
register: psql_version_output
- name: Вывод версии PostgreSQL
ansible.builtin.debug:
msg: "PostgreSQL version: {{ psql_version_output.stdout }}"
- name: Получение значения максимального размера стека (ulimit -s)
command: bash -c 'ulimit -s'
register: ulimit_output
changed_when: false
- name: Настройка PostgreSQL - max_stack_depth
community.general.ini_file:
path: "{{ postgresql_conf_path }}"
option: "max_stack_depth"
value: "{{ (ulimit_output.stdout | int) - 1024 }}kB # max stack depth minus 1 MB"
create: yes
backup: yes
- name: Настройка PostgreSQL - shared_buffers
community.general.ini_file:
path: "{{ postgresql_conf_path }}"
option: "shared_buffers"
value: "{{ (ansible_memtotal_mb * 0.25) | int }}MB # shared memory buffers"
create: yes
when: ansible_memtotal_mb > 1024 # Меняется если значение ОЗУ больше 1 Гб, в противном случае не меняется
- name: Настройка PostgreSQL - temp_buffers
community.general.ini_file:
path: "{{ postgresql_conf_path }}"
option: "temp_buffers"
value: "24MB # temporary buffers"
create: yes
- name: Настройка PostgreSQL - work_mem
community.general.ini_file:
path: "{{ postgresql_conf_path }}"
option: "work_mem"
value: "16MB # work memory"
create: yes
- name: Настройка PostgreSQL - max_connections
community.general.ini_file:
path: "{{ postgresql_conf_path }}"
option: "max_connections"
value: "151 # maximum number of connections"
create: yes
- name: Настройка PostgreSQL - max_parallel_workers_per_gather
community.general.ini_file:
path: "{{ postgresql_conf_path }}"
option: "max_parallel_workers_per_gather"
value: "0 # maximum number of parallel workers per gather"
create: yes
- name: Настройка PostgreSQL - maintenance_work_mem
community.general.ini_file:
path: "{{ postgresql_conf_path }}"
option: "maintenance_work_mem"
value: "128MB # maintenance work memory"
create: yes
- name: Добавление записи для административного входа в базу данных с помощью доменного сокета Unix
lineinfile:
path: "/etc/postgresql/15/main/pg_hba.conf"
insertafter: '^# Database administrative login by Unix domain socket'
line: "local all KSCAdmin md5"
create: yes
- name: Перезагрузка PostgreSQL
systemd:
name: postgresql
state: reloaded
- name: Создание пользователя KSCAdmin и базы данных kav, а также назначение всех нужных привилегии для пользователя
command: sudo -u postgres psql
args:
executable: /bin/bash
stdin: |
CREATE USER "KSCAdmin" WITH PASSWORD 'P@ssw0rd';
CREATE DATABASE "kav" ENCODING 'UTF8' OWNER "KSCAdmin";
GRANT ALL PRIVILEGES ON DATABASE "kav" TO "KSCAdmin";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA "public" TO "KSCAdmin";
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA "public" TO "KSCAdmin";
\q
Первым делом — установка и фиксация версии. Плейбук добавляет официальные репозитории и устанавливает строго определенную версию PostgreSQL, которая протестирована и рекомендована вендором для работы с KSC 15.1. Это защищает от сюрпризов при обновлениях.
Дальше идет тюнинг производительности. Плейбук меняет ключевые параметры:
shared_buffers выделяет оперативную память под буферы PostgreSQL. Это кеш для самых нужных данных: база берет их из памяти, а не лезет каждый раз на диск. Параметр вычисляется автоматически как 25% от доступной памяти.
synchronous_commit=off говорит базе не ждать физической записи данных на диск после каждой транзакции. Это снижает нагрузку на диск ценой небольшого риска потери данных за последние несколько транзакций, если сервер вдруг вырубится. Для KSC это приемлемый компромисс ради скорости.
Потом создаем пользователя KSCAdmin и базу kav. Следуем принципу минимальных привилегий: даем пользователю ровно те права, которые нужны для работы. CONNECT на базу, CREATE на схему, ALL PRIVILEGES на базу kav — каждую привилегию назначаем отдельным запросом, чтобы контролировать процесс.
Все таски написаны так, что их можно запускать повторно. Модуль ini_file проверит существующие значения и поменяет только то, что отличается.
Ядро системы: install-ksc.yml
Если первый плейбук готовит базу данных, то этот разворачивает сам сервер KSC 15.1.
---
- name: Установка и настройка KSC
hosts: all
become: yes
vars_files:
./vars.yml
tasks:
- name: Добавить пользователя 'ksc'
user:
name: ksc
- name: Добавить группу 'kladmins'
group:
name: kladmins
- name: Добавить пользователя 'ksc' в группу 'kladmins'
command: gpasswd -a ksc kladmins
- name: Изменить основную группу пользователя 'ksc' на 'kladmins'
command: usermod -g kladmins ksc
- name: Скачать пакет установки KSC (online-установка) в {{ temp_path }}
get_url:
url: '{{ ksc_deb_pkg_url }}'
dest: '{{ temp_path }}/{{ ksc_deb_pkg_name[0] }}'
when: install_type == "online"
- name: Скопировать пакет установки KSC (offline-установка) в {{ temp_path }}
copy:
src: '{{ ksc_deb_pkg_path }}'
dest: '{{ temp_path }}/{{ ksc_deb_pkg_name[0] }}'
when: install_type == "offline"
- name: Установить пакет Kaspersky
apt:
deb: '{{ temp_path }}/{{ ksc_deb_pkg_name[0] }}'
- name: Скопировать answers.txt на хост
copy:
src: answers.txt
dest: '{{ temp_path }}/answers.txt'
mode: '0755'
- name: Редактирование файла автоответов answers.txt
community.general.ini_file:
path: '{{ temp_path }}/answers.txt'
value: KLSRV_UNATT_SERVERADDRESS
option: '{{ ip_address }}'
state: present
- name: Установка KSC с файлом автоответов answers.txt
command: "sudo KLAUTOANSWERS={{ temp_path }}/answers.txt /opt/kaspersky/ksc64/lib/bin/setup/postinstall.pl"
args:
chdir: '{{ temp_path }}'
- name: Удалить все deb файлы, начинающиеся на ksc из {{ temp_path }}
command: find {{ temp_path }} -name 'ksc*.deb' -exec rm -f {} +
- name: Удалить файл ответов answers.txt из {{ temp_path }}
file:
path: '{{ temp_path }}/answers.txt'
state: absent
Весь фокус здесь в грамотном использовании штатных возможностей Kaspersky.
Работаем с файлом ответов answers.txt. У Kaspersky есть скрипт postinstall.pl, который умеет принимать параметры для тихой установки из файла ответов. Плейбук берет шаблон этого файла и на лету заполняет его актуальными данными: IP-адресами, номерами портов, именами пользователей, паролями.
Как безопасно передать пароль от базы данных в answers.txt? Решение — Ansible Vault. Все пароли и чувствительные переменные хранятся в зашифрованном файле. Плейбук расшифровывает их в памяти в момент выполнения, генерирует answers.txt на целевой машине.
Потом идет бесшовная установка. Подготовленный answers.txt передается установочному скрипту, и KSC устанавливается полностью автоматически.
Финал — зачистка. Сразу после установки временные файлы удаляются, включая answers.txt с учетными данными.
Интерфейс и удобства: install-ksc-web.yml
Последний плейбук разворачивает веб-консоль — интерфейс для управления KSC.
---
- name: Настройка и установка KSC Web console
hosts: all
become: yes
vars_files:
./vars.yml
tasks:
- name: Создание конфигурационного файла /etc/ksc-web-console-setup.json
copy:
dest: /etc/ksc-web-console-setup.json
content: |
{
"address": "{{ ip_address }}",
"port": {{ kscweb_port }},
"trusted": "{{ ip_address }}|13299|/var/opt/kaspersky/klnagent_srv/1093/cert/klserver.cer|KSC Server",
"acceptEula": true
}
- name: Скачать пакет установки KSC Web Console (online-установка) в {{ temp_path }}
get_url:
url: '{{ kscweb_deb_pkg_path }}'
dest: '{{ temp_path }}/{{ kscweb_deb_pkg_name[0] }}'
when: install_type == "online"
- name: Скопировать пакет установки KSC Web Console (offline-установка) в {{ temp_path }}
copy:
src: '{{ kscweb_deb_pkg_path }}'
dest: '{{ temp_path }}/{{ kscweb_deb_pkg_name[0] }}'
when: install_type == "offline"
- name: Установка пакета ksc-web-console
apt:
deb: '{{ temp_path }}/{{ kscweb_deb_pkg_name[0] }}'
- name: Создание учетной записи {{ kscweb_user }} для работы с Kaspersky Security Center Web Console
command: "sudo /opt/kaspersky/ksc64/sbin/kladduser -n {{ kscweb_user }} -p {{ kscweb_pass }}"
- name: Перезагрузка сервисов KSC
command: systemctl restart KSC*
- name: Удалить все deb файлы, начинающиеся на ksc
command: find {{ temp_path }} -name 'ksc*.deb' -exec rm -f {} +
Плейбук создает конфигурационный JSON с параметрами подключения: IP-адресом сервера и портом 8080. Если у вас конфликт портов, просто измените значение kscweb_port в vars.yml. Плейбук подхватит новое значение и настроит все автоматически. Затем он устанавливает DEB-пакет веб-консоли и перезапускает службы KSC, чтобы применить изменения. После этого интерфейс становится доступен по указанному адресу.
Метрики и результаты
В нашем случае итоговые цифры превзошли ожидания.
Время установки Kaspersky Security Center сократилось на 73%
Артем Емельяненко писал дипломную работу по оптимизации ИT-процессов, провел эксперимент на нашем стенде и все зафиксировал. Ручная установка KSC опытным инженером занимает примерно 60 минут. Автоматизированная установка через Ansible — 16 минут. Но дело не только в скорости. Вот ч��о мы получили на самом деле:
Воспроизводимость результата
Если правильно задали параметры в файле переменных (или оставили их по умолчанию), каждая установка будет идентична предыдущей. Мы исключили человеческий фактор — никаких опечаток в командах, пропущенных шагов или неправильных параметров. Плейбук не устает, не отвлекается и не ошибается.
Экономия времени инженеров
Освободившиеся часы пошли на R&D и пилотирование более сложных систем. Когда не нужно сидеть час у консоли и следить, чтобы все прошло гладко, появляется время на творческие задачи.
Передача знаний
Мы делились этими скриптами с заказчиками. Они сами ставили KSC с помощью наших плейбуков — причем успешно. Это говорит о том, что автоматизация работает не только в наших руках, но и у людей с меньшим опытом.
Неожиданный эффект
Успех проекта подействовал на команду как катализатор. Коллеги увидели, что автоматизация работает и дает результат. Сейчас в нашем внутреннем GitLab-репозитории уже больше дюжины плейбуков для разных средств защиты информации. Люди начали автоматизировать свои задачи просто потому, что увидели, что это работает.
Что дальше
Если вы хотите начать автоматизировать свои процессы, вот с чего можно начать.
Найдите самую надоевшую рутину: выберите одну повторяющуюся задачу, которая съедает больше всего времени.
Освойте один инструмент автоматизации на примере этой задачи. Ansible — хорошая точка входа, потому что дает широкие возможности при низком пороге входа.
Покажите результат команде. Первый работающий пример вдохновит коллег эффективнее любых презентаций.
Мы выложили наши плейбуки на GitHub. Используйте их, дорабатывайте под свои задачи и делитесь опытом. В README есть краткий чеклист, который поможет все настроить и запустить.
Давайте вернем инженерам время на интересную работу. Автоматизация — не замена сотрудников машинами, а освобождение людей от механической работы. Так что рекомендуем использовать наши скрипты и писать свои.
navion
Могли бы сделать нормальную роль с пайплайном для публикации (или попросить коллег), а башсиблом вряд ли привлечёте новых клиентов.