Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
В связи с известными событиями российские компании всё чаще начали переходить на отечественное программное обеспечение. И так уж вышло, что я являюсь сотрудником одной из таких компаний.
Лично мне, как уже бывшему windows-администратору, при переходе на отечественную операционную систему остро не хватало такого инструмента, как групповые политики (GPO), позволяющего управлять настройками и безопасностью компьютеров в сети.
Для управления конфигурациями устройств в своей организации я выбрал Puppet.
Puppet сам по себе – отличный инструмент для управления небольшим количеством серверов. С помощью puppet DSL мы можем описать и сконфигурировать практически любую задачу. Вот здесь есть хорошая статья о puppet – Введение в Puppet.
Недостаток чистого Puppet – это способ выбора ноды (цели) для конфигурирования. Каждый манифест конфигурации начинается с селектора цели, к которой он будет применён. Цель можно описать точно по имени хоста, регулярным выражением или ключевым словом default – для всех остальных. Проблема в том, что для каждой ноды будет выбран только один, наиболее специфичный манифест. Мы не можем, например, описать некие общие правила для всех хостов в манифесте default, а затем добавить к этим правилам некоторые корректировки только нужным компьютерам. С таким поведением можно мирится, если нужно управлять небольшим количеством нод, но если их становится больше, то нужно что-то делать.
Для управления большим количеством нод тоже есть решения – например Hiera. С помощью Hiera можно гибко управлять большим парком серверов, назначая им функционал и роли. При использовании Hiera вся логика выносится в отдельные модули, а сама система занимается построением файла конфигурации, состоящим из применяемых классов и параметров. Подробнее об использовании Hiera можно почитать тут – Puppet+Hiera. Выжимаем максимум.
Но использование Hiera предполагает, что роли и назначение серверов заранее известно. В случае, когда речь идёт о клиентских машинах, как правило, невозможно определить их функционал заранее. Хочется получить способ динамически управлять конфигурацией компьютера, желательно основываясь на информации, полученной из Active Directory.
Для гибкой настройки конфигураций в Puppet применяется специальный механизм – внешний классификатор узлов (ENC). Если сильно упростить, то внешний классификатор – это программа или скрипт, принимающий в качестве параметра имя компьютера, и отдающая через стандартный вывод конфигурацию, описанную в формате yaml.
Combenc
Воспользовавшись этим механизмом мною на python в муках был рождён внешний классификатор, названный Combenc. Механизм работы связки Puppet + Combenc можно описать примерно так:
Компьютер, находящийся в домене, периодически запрашивает у puppet-сервера конфигурацию.
Сервер запускает Combenc, передавая в качестве параметра имя компьютера.
Combenc получает из Active Directory список групп безопасности, в которых состоит компьютер и пользователь. Обычно в группы включается пользователи, но так как Puppet управляет только хостами, мне был нужен способ привязать пользователя к компьютеру. Для связывания я заполняю атрибут Управляется у объекта компьютера в Active Directory.
Далее классификатор читает:
файл конфигурации, задающий правила для всех нод;
файлы конфигураций, соответствующие именам групп безопасности;
файл, соответствующий имени компьютера.
Затем Combenc комбинирует файлы конфигураций. Файлы конфигурации представляют собой yaml файлы, состоящие из структуры с именами классов и применяемых к классам параметров. Кроме своих параметров классы могут обладать булевыми параметрами merge и sealed. При использовании параметра merge Combenc будет пытаться объединить списки и словари конфигураций. При использовании параметра sealed класс будет «запечатан» и не будет переопределён, если встретится далее в файлах конфигураций.
В результате полученный конфиг применяется к компьютеру.
Как этим воспользоваться
Я предполагаю, что у Вас уже настроен puppet-сервер, к которому подключено некоторое количество нод.
Сперва разместим классификатор на сервере с Puppet. Создадим папку
/opt/combenc/
и расположим в ней скрипты Combenc:mkdir /opt/combenc cd /opt/combenc git clone https://github.com/nsuslov/combenc.git .
После скачивания не забываем дать права на запуск:
chmod +x /opt/combenc/combenc.py
Далее необходимо заполнить конфигурационный файл
config.yaml
:ldap: uri: 'ldap://ns01.example.com' user: 'CN=puppet,CN=Users,DC=example,DC=com' cred: 'Pa$$word' base_dn: 'OU=00-Unit,DC=example,DC=com' rules: folder: '/etc/puppetlabs/code/environments' environments: dev: - my-pc.example.com test: - 00-pc-01.example.com - 00-pc-02.example.com
ldap.uri – адрес одного из наших контроллеров домена;
ldap.user, user.cred – уникальное имя (dn) и пароль пользователя, которым мы будем забирать данные с ldap-сервера;
ldap.base_dn – начальная точка для поиска компьютеров. Позволяет ограничить поиск определённым организационным юнитом;
rules.folder – это каталог, в котором будут располагаться окружения. Я предпочитаю хранить в окружении вместе папку modules – описание логики применяемых конфигураций и combenc – описания конфигураций с параметрами;
environments – здесь могут быть словари с названием окружения и массивом нод, которые в него входят. Компьютеры, для которых не указано специфическое окружение, работают в окружении production. Я предпочитаю схему с тремя окружениями: development – моё окружение для разработки, testing – небольшая группа компьютеров для тестирования конфигураций перед внедрением в прод, production – все остальные.
Затем нужно настроить сервер puppet для использования Combenc. Для этого в конфиге
/etc/puppetlabs/puppet/puppet.conf
нужно добавить следующие строки и перезапустить сервисpuppetserver
:[master] node_terminus = exec external_nodes = /opt/combenc/combenc.py
В целом на этом настройка закончена. Теперь можно написать какой-нибудь модуль и применить его.
Пример модуля Puppet
Предположим, у нас есть следующая задача: мы хотим дать возможность пользователям группы domain-admins
подключаться по ssh ко всем компьютерам, а пользователям группы 01-unit-admins
подключаться к компьютерам, входящим в группу 01-computers
.
Создадим в
/etc/puppetlabs/code/environments/production/modules
каталогsshd
.mkdir -p /etc/puppetlabs/code/environments/production/modules/sshd
Перейдём в него и создадим нужную нам структуру папок:
cd /etc/puppetlabs/code/environments/production/modules/sshd mkdir {manifests,templates}
Теперь создадим файл
manifests/init.pp
со следующим содержимым:# Class: sshd # # Настройка sshd # # @param groups Группы, имеющие право подключаться по ssh # # @param merge Объединить правила. Combenc объединит список, # если правило встретится ниже # @param sealed Запечатать правило. Combenc не переопределит это правило, # если оно встретится ниже # class sshd ( Array[String] $groups, Boolean $merge = false, Boolean $sealed = false, ) { $groups_line = join($groups, ' ') file { 'sshd config': path => '/etc/ssh/sshd_config.d/10-puppet.conf', content => template('sshd/puppet.erb'), } service { 'sshd service': ensure => running, name => 'sshd', enable => true, subscribe => File['sshd config'], } }
Этот класс создаст файл
/etc/ssh/sshd_config.d/10-puppet.conf
по шаблону и перезапустит сервисsshd
, если файл10-puppet.conf
был изменен.Добавим шаблон
templates/puppet.erb
:# Puppet sshd # DONT EDIT THIS FILE <% if (@groups_line) -%> AllowGroups <%= @groups_line %> <% end -%>
Модуль готов. Теперь напишем правила, согласно которым этот класс будет применяться к компьютерам.
Пример правила Combenc
Создадим каталог с правилами –
/etc/puppetlabs/code/environments/production/combenc
mkdir -p /etc/puppetlabs/code/environments/production/combenc
Затем перейдём в него и создадим нужные папки: groups – для конфигураций групп безопасности и hosts – для конфигураций, применяемых к конкретным хостам.
cd /etc/puppetlabs/code/environments/production/combenc mkdir {groups,hosts}
Создадим общее правило для всех хостов
defautl.yaml
со следующим содержимым:sshd: merge: true groups: - domain-admins
Теперь создадим правило для группы компьютеров
groups/01-computers.yaml
:sshd: groups: - 01-unit-admins
Предположим, мы хотим дать возможность подключаться к компьютеру 01-pc-34 ещё и локальному пользователю user. Создадим файл
hosts/01-pc-34.example.com.yaml
со следующим содержимым:sshd: groups: - user
В результате Combenc должен сформировать конфиг для компьютеров объединив правила. Убедимся в этом вызвав скрипт и предав ему dns имя компьютера в качестве параметра:
/opt/combenc/combenc.py 01-pc-34.example.com
Команда вернёт следующий вывод:
classes:
sshd:
groups:
- domain-admins
- 01-unit-admins
- user
environment: production
При следующем обращении компьютеров к puppet-серверу эта конфигурация будет применена.
В результате мы должны добавить такую структуру файлов:
├── combenc
│ ├── default.yaml
│ ├── groups
│ │ └── 01-computers.yaml
│ └── hosts
│ ├── 01-pc-34.example.com.yaml
└── modules
└── sshd
├── manifests
│ └── init.pp
└── templates
└── puppet.erb
Вот такое решение мы используем в нашем предприятии. При желании дополнительно к группам безопасности из ldap можно тащить ещё и структуру организационных юнитов. Таким образом опыт использования будет ещё ближе к привычному GPO, однако мне показалось удобнее пользоваться группами безопасности.
Спасибо за внимание! Жду предложения, идеи, критику и прочую обратную связь в комментариях.
Репозиторий Сombenc