Автоматизируем настройку серверов с помощью CFEngine 2
Евгений Зобнин (j1m@synack.ru)
Администрируя сеть из множества машин, выполняющих однотипные функции, ты рано или поздно начнешь задумываться об автоматизации процесса их конфигурирования и управления. Программы вроде dssh и rsync в этом случае помогут только отчасти, вынуждая выполнять львиную долю работы вручную. Однако существует инструмент, способный автоматизировать большую часть функций администрирования и превратить сеть серверов в интеллектуальную самонастраиваемую инфраструктуру.
Содержание:
- Установка
- Правила
- Использование
- Настройка сервера
- Настройка клиентов
- Что дальше
- Мини-статья: Настройка аутентификации
- Боковые выносы
CFEngine (ConFiguration Engine) — один из старейших и наиболее мощных инструментов администратора, который позволяет управлять сетью машин в автоматическом режиме с минимумом ручной работы. С помощью правил CFEngine администратор может описать состояние, в котором должна находиться та или иная машина или сеть машин в определенное время или при определенных обстоятельствах. Отклонение от этого состояния повлечет за собой принятие корректирующих мер.
CFEngine позволяет контролировать многие аспекты состояния системы, включая редактирование файлов, запуск/остановку сервисов, установку/удаление приложений, настройки сети и многое, многое другое. При должном уровне терпения и знаний особенностей работы контролируемых машин, ты вполне сможешь создать интеллектуальную сеть, где сбой какой-либо машины или появление аномалий будут автоматически исправлены без необходимости вмешательства со стороны человека.
Не так давно разработчики CFEngine объявили о выходе третьей версии своего ПО, которое включает множество дополнений, расширяющих функциональность и повышающих гибкость системы. Однако официальное англоязычное руководство и огромное множество другой документации, которую ты сможешь найти в Сети, до сих пор ссылается на версию номер два. Более того, во многих дистрибутивах третья версия вообще недоступна в репозиториях, поэтому мы не будем рассматривать ее в рамках статьи, а остановимся на стабильном и проверенном временем CFEngine 2.
Итак, вторая версия CFEngine доступна почти во всех UNIX-подобных ОС и Linux-дистрибутивах, поэтому получить и установить его не составит труда. Например, для установки в Debian/Ubuntu достаточно выполнить всего одну команду:
$ sudo apt-get install cfengine2
Пакет CFEngine состоит из трех ключевых компонентов:
- Сервер (cfservd)
- Клиент (cfagent)
- Планировщик (cfexecd)
Сервер cfservd — центральная часть комплекса, принимает запросы клиентов и отдает им файлы, содержащие инструкции по изменению конфигурации машин.
Клиент cfagent, называемый в словаре CFEngine агентом, устанавливается на все управляемые машины. Его задача — подключение к серверу, получение конфигурационных файлов и исполнение содержащихся в них инструкций (модификация системных файлов, установка ПО, запуск серверов и т.д.)
Планировщик cfexecd ответственен за запуск агента на машине-клиенте. Его задача — запуск агента через определенные интервалы времени с возможным перенаправлением стандартных ввода/вывода и отсылка диагностических сообщений администратору.
Кроме описанных выше компонентов, CFEngine устанавливает в систему набор подсобных утилит, необходимых для выполнения специфических задач. Одна из них — cfrun, которая может быть использована для запроса экстренного подключения удаленных агентов к серверу (можно использовать для отладки). Утилита cfkey предназначена для создания пар «публичный/приватный ключ», используемых для взаимной аутентификации сервера и агентов. Демон cfenvd осуществляет мониторинг работоспособности системы, отслеживая информацию о процессах, сетевых соединениях, общей загруженности, свободной памяти и т.д. В дальнейшем эту информацию может использовать cfagent для обнаружения аномалий и принятия мер по устранению проблем, а утилита cfenvgraph способна визуализировать эту информацию в виде графа. Cfshow позволяет исследовать текущее состояние CFEngine с помощью интерфейса командной строки.
После установки пакет создает собственный подкаталог в каталоге var (/var/lib/cfengine2), который содержит все компоненты системы:
Каталоговая структура CFEngine 2:
- bin — бинарные файлы, ссылка на /usr/sbin
- inputs — конфигурационные файлы, ссылка на /etc/cfengine2
- modules — сторонние расширения
- ppkeys — публичные и приватные ключи
- state — текущее состояние CFEngine
Управление поведением агента CFEngine производится с помощью правил, описанных в конфигурационных файлах. Модифицируя их, администратор может изменять многие аспекты состояния системы, включая:
- Проверка и изменение прав доступа и владельцев файлов.
- Редактирование файлов.
- Компрессия, удаление и другие манипуляции с файлами.
- Удаленный запуск команд.
- Перезапуск упавших демонов.
- Установка ПО, включая обновления безопасности.
- Конфигурирование сетевых интерфейсов и таблиц маршрутизации.
Конфигурационные файлы представляют собой своего рода скрипт на языке высокого уровня, читая который, агент получает информацию о том, какие действия ему необходимо выполнить для конфигурации целевой машины. Ключевая особенность этого скрипта заключается в том, что он ориентирован на получение одинаковых результатов на всех конфигурируемых машинах без необходимости составления отдельного скрипта для каждой из них.
Чтобы добиться этого, язык конфигурационного файла требует задать набор действий, которые приведут целевую систему к желаемому состоянию. Все это похоже на управление группой администраторов-эникейщиков, за каждым из которых закреплена определенная машина. Вместо того, чтобы давать задание по установке и настройке apache каждому из них по отдельности, ты собираешь их всех и говоришь, что на подчиненных машинах необходимо выполнить команду «apt-get install apache2», а затем изменить определенные строки файла httpd.conf. Таким образом можно получить идентичные настройки индейца на всех машинах без лишней головной боли.
Конфигурационные файлы CFEngine разделены на блоки, каждый из которых включает действие, условие и объявление. Описание этих блоков имеют следующую форму:
действие:
class1:: # 'class1' - условие
объявление
объявление
class2|class3:: # 'class2|class3' - условие
объявление
Первая строка задает тип действия, который необходимо выполнить. CFEngine второй версии поддерживает более 20 различных типов действий, среди которых есть тип files, который позволяет проверять и исправлять права и владельцев файлов, editfiles для редактирования файлов, packages для установки пакетов и другие. Условие, как можно догадаться из названия, задает условие, при котором действие будет выполнено. Это может быть время на системных часах, тип операционной системы или что-то другое. Чтобы действие было выполнено в любом случае, условие можно опустить. Объявление представляет собой описание того, что необходимо проделать в рамках заданного действия. Для различных типов действий форма их описания будет отличаться, поэтому при задании неиспользуемых ранее действий тебе придется обращаться к документации.
Кроме «обычных» действий, CFEngine позволяет задавать также мета-действия, которые предназначены не для модификации состояния системы, а для выполнения различных вспомогательных функций. Наиболее важным мета-действием является control, которое позволяет конфигурировать агента, скажем, задать список действий и их очередность в переменной actionsequence. Приведу пример:
$ sudo vi /tmp/sample.conf
control:
actionsequence = ( files )
files:
/etc/shadow owner=root group=shadow mode=0640 action=fixall
С помощью этих правил мы указали агенту, что:
- Он должен выполнить действие files (первый блок).
-
В рамках действия files он должен проверить права доступа и владельца файла /etc/shadow и исправить их, если они не совпадают с указанными (0640, root, shadow).
Для проверки работоспособности правил сохрани их в файл (например, /tmp/sample.conf) и выполни следующую команду:
$ sudo cfagent -f /tmp/sample.conf
Кроме прав доступа и владельца, в рамках правила files агент может выполнить проверку MD5-суммы файла, что можно использовать в качестве альтернативы системам контроля целостности системы (вроде tripwire).
Список действий в порядке приоритета
- mountall — монтирование файловых систем, перечисленных в fstab
- mountinfo — получение информации о смонтированных файловых системах
- checktimezone — проверка и установка временной зоны
- netconfig — сетевые настройки
- resolve — настройка файла /etc/resolv.conf
- unmount — размонтирование файловых систем
- packages — установка/обновление/удаление пакетов
- shellcommands — запуск команд
- editfiles — редактирование файлов
- addmounts — монтирование ранее неиспользуемых файловых систем
- directories — создание каталогов
- links — проверка и управление ссылками
- mailcheck — проверка на существование каталога спулинга
- required — проверка файловых систем на доступность
- tidy — поиск и удаление устаревших файлов
- disable — переименование файлов
- files — проверка прав доступа и владельцев файлов
- copy — копирование файлов
- processes — управление процессами
- module:name — запуск определенного пользователем модуля
Администрируя сеть из машин с различными операционными системами, ты столкнешься с проблемой отличий имен/прав/владельцев системных файлов. Ведь если в Linux файл теневых паролей носит имя /etc/shadow, а его владельцем является root:shadow, то, например, во FreeBSD ты получишь совсем иную картину: файл /etc/master.passwd и владелец root:wheel. Как быть в этом случае?
Именно для этого и нужны условия (классы). Следующий набор правил одинаково хорошо отработает как на Linux-машинах, так и на машинах с FreeBSD:
$ sudo vi /tmp/sample.conf
control:
actionsequence = ( files )
files:
linux::
/etc/shadow owner=root group=shadow mode=0440 action=fixall
freebsd::
/etc/master.passwd owner=root group=wheel mode=0440 action=fixall
В зависимости от используемой операционной системы, времени суток, нагрузки на систему, клиент CFEngine определяет множество классов, которые можно использовать для управления тем, какое действие будет выполнено в определенной ситуации. Ты можешь легко проверить, какие классы определены на машине, с помощью запуска следующей команды:
$ sudo cfagent -pv
Наиболее используемыми являются классы, определяющие операционную систему. CFEngine позволяет определить тип операционки вплоть до версии ядра и библиотеки libc, что может оказаться важным для обхода возможных проблем, связанных с этими компонентами. Также популярны классы, определяющие текущее время (например, Hr00 — полночь, Hr12 — полдень и т.д.), они могут быть использованы для выполнения действий по расписанию.
CFEngine позволяет делать выбор между классами на основе логического «ИЛИ» или «И». Так, например, действие с условием freebsd|openbsd будет выполнено как на машине с ОС FreeBSD, так и на OpenBSD. Однако условие Hr00.OpenBSD будет выполнено только на опенке в полночь. Классы можно отрицать, указав перед ними знак восклицания. Это значит, что действие будет выполняться, пока класс не будет определен.
Особую роль условия играют внутри действия control, позволяя устанавливать переменные в зависимости от параметров машины:
$ sudo vi /tmp/sample.conf
control
openbsd::
crondir = ( /var/cron/tabs )
linux::
crondir = ( /var/spool/cron )
solaris::
crondir = ( /var/spool/cron/crontabs )
CFEngine позволяет создавать пользовательские классы, которые определяются в момент выполнения определенного условия. Например:
$ sudo vi /tmp/sample.conf
control:
actionsequence = ( editfiles )
classes:
linux_sys = ( IsDir(/sys) )
shellcommand:
linux_sys::
"/bin/echo Каталог /sys существует"
Мета-действие classes создает класс linux_sys, который будет определен только в том случае, если каталог /sys существует. В данном случае IsDir — это условие, при выполнении которого будет определен класс. В арсенале CFEngine имеется солидный багаж самых разнообразных условных выражений, среди которых:
Некоторые популярные условные выражения действия classes
- IsNewerThan(f1,f2) — истина, если файл f1 был модифицирован позже файла f2.
- FileExists(f) — истина, файл f существует.
- IPRange(диапазон) — IP-адрес машины соответствует диапазону IP-адресов.
- IsDefined(переменная) — переменная определена
- IsDir(f) — файл f является каталогом
- IsLink(f) — файл f — ссылка
- IsPlain(f) — файл f — обычный файл
- Regcmp(re, строка) — строка соответствует регулярному выражению re
- Strcmp(s1,s2) — строки совпадают
Чтобы начать использовать CFEngine, тебе понадобятся:
- Сервер с установленным CFEngine.
- Клиенты, на каждом из которых установлен агент CFEngine.
- Набор грамотно составленных правил.
Первые два пункта легко выполнить, следуя инструкциям, приведенным в разделе «Установка». Для составления правил ты можешь использовать приведенные ниже примеры, дополненные в соответствии с твоими требованиями.
Важным шагом является настройка доверительной системы, которая включает в себя взаимный обмен публичными ключами между сервером и клиентами. Однако в большинстве случаев этот шаг излишен, потому как применение CFEngine для управления серверами глобальной сети — явление редкое, а во внутренней локальной сети можно обойтись и без аутентификации узлов. Мы сделаем так, чтобы все машины локальной сети изначально доверяли друг-другу и не требовали аутентификации с использованием ключей.
Для правильного функционирования сервера важно наличие трех конфигурационных файлов:
-
cfagent.conf — файл правил агента (агент будет получать от сервера правила и выполнять их на клиентской машине).
-
cfservd.conf — конфигурационный файл сервера, определяющий его поведение.
- cfrun.hosts — список управляемых машин (клиентов).
Начнем с файла правил агента. Его начальное содержимое может выглядеть следующим образом:
$ sudo vi /etc/cfengine2/cfagent.conf
# Настройки
control:
# Список действий
actionsequence = ( resolve files tidy processes )
# Домен
domain = ( xakep.ru )
# Временная зона (Москва)
timezone = ( MSK )
# SMTP-сервер и e-mail админа (для отправки отчетов об ошибках)
smtpserver = ( smtp.xakep.ru )
sysadm = ( admin@xakep.ru )
# Модификация resolv.conf
resolve:
192.168.1.1
192.168.1.2
# Проверка и установка прав доступа на системные файлы
files:
/etc/sudoers mode=440 owner=root group=root action=fixall
/etc/passwd mode=644 owner=root group=root action=fixall
/etc/shadow mode=640 owner=root group=shadow action=fixall
# Очистка каталогов от устаревших файлов
tidy:
/tmp pattern=* age=7 recurse=inf
/home pattern=*~ age=7 recurse=inf
# Управление процессами
processes:
# Перезапускаем inetd
"inetd" signal=hup
Обратившись к документации CFEngine, ты сможешь дополнить его любыми правилами, которые актуальны для твоих клиентских машин. Следующий файл cfservd.conf очень прост и прозрачен:
$ sudo vi /etc/cfengine2/cfservd.conf
control:
domain = ( xakep.ru )
# Полностью доверять всем хостам указанной подсети
TrustKeysFrom = ( 192.168.1.0/24 )
any::
# Максимальное количество одновременных соединений
MaxConnections = ( 50 )
grant:
# Дать доступ всем клиентам, входящим в домен xakep.ru
/var/lib/cfengine2/inputs *.xakep.ru
Единственное, что следует поменять в нем: имя домена и подсети. Наконец, cfrun.hosts содержит список обслуживаемых сервером хостов:
$ sudo vi /etc/cfengine2/cfrun.hosts domain = xakep.ru # Управляемые машины srv1.xakep.ru srv2.xakep.ru
Закончив настройку, перезапусти CFEngine:
$ sudo /etc/init.d/cfengine2 restart
Ключевой конфигурационный файл агента носит имя update.conf. Он нужен для начальной настройки агента до того, как он сможет подключиться к серверу и забрать основной конфигурационный файл: cfagent.conf. Следующего варианта будет вполне достаточно в большинстве ситуаций:
$ sudo vi /etc/cfengine2/update.conf
control:
actionsequence = ( copy )
domain = ( xakep.ru )
# Имя сервера cfengine
policyhost = ( cfserver.xakep.ru )
# Каталог сервера, хранящий конфигурационные файлы
master_cfinput = ( /var/lib/cfengine2/inputs )
# Хранилище бэкапов и мусора
repository = ( /var/lib/cfengine2/outputs )
# Копирование конфигурационного файла cfagent.conf с сервера
# в каталог /etc/cfengine2 клиента
copy:
$(master_cfinput)/cfagent.conf dest=/etc/cfengine2/cfagent.conf
mode=600
server=$(policyhost)
force=true
trustkey=true
Чтобы сетевая инфраструктура, построенная на CFEngine, заработала, каждый клиент должен быть оснащен не только агентом, но и сервером. Вот конфигурационный файл сервера для клиентов:
$ sudo vi /etc/cfengine2/cfservd.conf
control:
domain = ( xakep.ru )
# Разрешить соединения с узлами указанной подсети
AllowConnectionsFrom = ( 192.168.1.0/24 )
TrustKeysFrom = ( 192.168.1.0/24 )
# Сервер должен запустить cfagent
cfrunCommand = ( "/usr/sbin/cfagent" )
MaxConnections = ( 50 )
grant:
/usr/sbin/cfagent *.xakep.ru
Заставляем CFEngine перечитать свои конфиги:
$ sudo /etc/init.d/cfengine2 restart
Теперь необходимо настроить клиентские машины так, чтобы агент CFEngine запускался в определенные промежутки времени.
$ sudo crontab -e 0,30 * * * * /var/cfengine/bin/cfexecd -F
Каждые полчаса cron будет запускать cfexecd, который вызовет агента CFEngine, который в свою очередь получит последнюю версию cfagent.conf с сервера и выполнит описанные в ней правила. Таким образом ты сможешь динамически обновлять cfagent.conf на сервере, и в течение получаса внесенные тобой изменения отразятся на клиентах.
CFEngine — сложный инструмент, и в этой статье ты открыл для себя лишь несколько процентов его возможностей. Файлы правил CFEngine серьезных контор насчитывают сотни и даже тысячи строк, благодаря чему контролируемые им машины могут находиться без присмотра в течение месяцев. В боковом выносе WWW перечислены ссылки на ресурсы, обратившись к которым, ты сможешь узнать о настоящей мощи CFEngine.
Мини-статья: Настройка аутентификации
Если ты решишь использовать CFEngine для конфигурирования географически распределенных узлов, то тебе не обойтись без настройки аутентификации. Для этого запусти команду cfkey на сервере и клиентах. Это приведет к созданию двух ключей в каталоге /var/lib/cfengine2/ppkeys: localhost.pub (публичный ключ) и localhost.priv (приватный ключ).
После этого публичный ключ сервера необходимо скопировать на каждую машину-клиента под именем /var/lib/cfengine2/ppkeys/IP-сервера.pub. Публичные ключи клиентов также придется скопировать на сервер под именем /var/lib/cfengine2/ppkeys/root-IP-клиента.pub.
INFO
Что можно почитать по данной теме:
-
Вызов агента по расписанию можно настроить и без использования cron. Для этого в правило control файла cfagent.conf достаточно добавить строку:
Schedule = ( Min30_35 )
-
WWW
- — Перевод документации к CFEngine2
- — Справочник по CFengine2
Статья опубликована в апрельском номере журнала «Xakep» за 2010 год.




