Система централизованного управления авторизацией пользователей на FreeIPA в Docker
На волне популярности Docker на Хабре, после участия в некоторых дискуссиях в комментариях относительно Docker, и в связи с недавней необходимостью настроить централизованную авторизацию для кластера Linux машин, я решил написать небольшую заметку. Здесь будет показан яркий, на мой взгляд, пример применения Docker’a для небольшой частной задачи.Вот так, кстати, выглядит FreeIPA WebUI (официальное демо, временное демо у меня на сервере (подробности в комментариях)) (кликабельно):
Какие задачи я хотел решить при помощи FreeIPA:
Иметь возможность создавать/изменять/удалять акаунты пользователей централизовано, а не на каждом отдельном сервере Централизованные плавила для sudo В последствии мы подключим к этой системе ещё и VPN авторизацию, а потом может и другие внутриофисные сервисы Да, скорее всего FreeIPA в нашем случае это выстрел пушкой по воробьям, но с другой стороны — альтернатив что-то не видно. Я рассматривал такие варианты: NIS (по-моему он уже давно должен отправиться на отдых), OpenLDAP +… +… (не очень дружелюбно, да и FreeIPA в итоге под собой имеет LDAP, только нам не приходится с ним иметь дело напрямую), тут перечень заканчивается, я не нашёл ничего больше.Итак, приступим!
Перечень используемых технологий: FreeIPA — открытый проект компании RedHat, который объединяет в себе множество других открытых проектов: 389 Directory Server, MIT Kerberos, NTP, DNS (bind), Dogtag certificate system, SSSD и другие. При этом у данного решения есть Web UI, CLI, XMLRPC, JSONRPC API и Python SDK. Dnsmasq — легковесный DNS сервер (позже я объясню зачем мне он нужен был в дополнение к bind, который используется в FreeIPA). Docker — open-source платформа, автоматизирующая развертывание приложений в легковесные, переносимые, самодостаточные контейнеры, которые могут без изменений переноситься между серверами. © Используем Docker и не волнуемся о vendor-lock FreeIPA, в следствие того, что это продукт RedHat, естественно умеет хорошо разворачиваться на CentOS и Fedora и практически никак не разворачивается на других дистрибутивах. (прим. Я не особо задавался целью, поэтому может и есть где-то инструкции, но пакетов в Debian/Ubuntu для FreeIPA сервера нет, зато есть клиентский пакет freeipa-client, но об этом потом.)
Меня этот факт ни разу не расстроил, а, наоборот, воодушевил! Это же идеальная задача для Docker, когда на серверах Debian/Ubuntu/Gentoo/etc. То есть я мог взять базовый образ Fedora, поставить там нужные пакеты, собрать всё в кучу и запустить, НО ещё более приятной новостью для меня стал официальный Docker образ freeipa-server (есть у них и клиент, но меня интересовал вариант с клиентом на Ubuntu, поэтому я запускал ubuntu образ в Docker и таким образом моделировал и быстро начинал с начала для отладки процесса «с нуля»).
Вообще, запуск freeipa-server не вызвал никаких проблем, всё в соответствии с документацией к образу Docker’a:
Создаём директорию, которая будет монтироваться в образ для конфигов FreeIPA, которые нужно оставлять после перезапуска (в документации предлагается использовать /var/lib/ipa-data/, но я не люблю засорять систему, поэтому /opt/): $ sudo mkdir -p /opt/dockers/freeipa-data Добавим файл с опциями, которые будут использоваться при инсталяции freeipa-server: $ sudo tee /opt/dockers/freeipa-data/ipa-server-install-options --ds-password=The-directory-server-password --admin-password=The-admin-password Всё, запускаем (в доке не хватает проброса портов, хотя это и очевидно, что нужно сделать; стоит также отметить, что в доке написано, что нужно подключать раздел с постфиксом : Z: rw, но если у вас нет SELinux, вам эта опция не нужна (спасибо grossws)): $ docker run \ --name freeipa-server-test \ -it \ --rm \ --hostname freeipa.example.test \ --volume /opt/dockers/freeipa-data:/data \ --publish »443:443» \ --publish »389:389» \ --publish »636:636» \ --publish »88:88» \ --publish »88:88/udp» \ --publish »464:464» \ --publish »464:464/udp» \ adelton/freeipa-server После недолгой установки вам любезно предоставят bash — на этом установка и настройка FreeIPA Server по большому счёту завершена. Можете добавить freeipa.example.test себе в /etc/hosts, пройти на https://freeipa.example.test/, залогиниться под admin и создать пользователя. FreeIPA у себя в образе поднял целый зоопарк служб, в том числе и bind (DNS), который настроил по своему усмотрению (магия, которую практически невозможно повторить на других DNS). Для клиентов FreeIPA ожидается, что они будут иметь доступ к этому DNS, который ещё умеет как-то хитро failover обрабатывать, только вот в случае как здесь — всё в одном образе Docker я не очень вижу пользу с такого failover. Однако, я не стал идти на перекор и учёл пожелания разработчиков FreeIPA (кстати, это особенность Kerberos, всё-таки FreeIPA — просто объединяет множество пакетов).Так вот, к чему я про DNS? Мне нужен был DNS внутри кластера, но мне категорически не хотелось влезать в bind внутри FreeIPA контейнера. Поэтому я решил воспользоваться проверенным решением — Dnsmasq. На Docker Hub есть минималистичный образ Dnsmasq, основанный на Alpine Linux — 6МБ.
Вот как я его подготовил:
Создал директорию для конфигов: $ sudo mkdir -p /opt/dockers/dnsmasq.d Добавил туда конфиг dnsmasq: $ sudo tee /opt/dockers/dnsmasq.d/dnsmasq.conf address=/freeipa.example.test/10.12.0.172 address=/server00.example.test/10.12.0.172 address=/server01.example.test/10.12.0.173 address=/server02.example.test/10.12.0.174 Запускаем (DNS работает на 53/tcp и 53/udp портах, так что пробрасываем их, папку с конфигами): $ docker run \ --name dnsmasq-test \ --rm \ --publish 53:53 \ --publish 53:53/udp \ --cap-add NET_ADMIN \ --volume /opt/dockers/dnsmasq.d:/etc/dnsmasq.d \ --entrypoint /bin/sh \ andyshinn/dnsmasq \ -c '/usr/sbin/dnsmasq -k -h --conf-dir /etc/dnsmasq.d/' Проверяем, что работает: $ nslookup server00.example.test 127.0.0.1 Итого, у нас есть FreeIPA Server в одном контейнере и Dnsmasq в другом. Кстати, Dnsmasq, как можно было заметить, никак с bind DNS сервером FreeIPA ещё не взаимодействует.Дальше я связал эти два сервиса в один docker-compose.yml:
docker-compose.yml dnsmasq: image: andyshinn/dnsmasq ports: — »53:53» — »53:53/udp» cap_add: — NET_ADMIN links: — freeipa volumes: — »/opt/dockers/dnsmasq.d:/etc/dnsmasq.d» entrypoint: [»/bin/sh»,»-c»,»/usr/sbin/dnsmasq -k -h --conf-dir /etc/dnsmasq.d/ -S /example.test/`getent hosts freeipa | cut -f1 -d' '`»]
freeipa: image: adelton/freeipa-server hostname: freeipa.example.test ports: — »443:443» — »389:389» — »636:636» — »88:88» — »88:88/udp» — »464:464» — »464:464/udp» cap_add: — NET_ADMIN volumes: — »/opt/dockers/freeipa-data:/data» Можно заметить небольшую магию с дополнительной опцией к команде dnsmasq, эта опция будет перенаправлять запросы к *.example.test на bind DNS, уставновленный в freeipa контейнере.Удобство Docker Compose в данном конкретном случае в том, что его конфиг всё-таки удобнее читать, чем bash-скрипт с docker run. Да и лучше сразу делать хорошо. Сохраняем docker-compose.yml и запускаем:
$ docker-compose up -d
C сервером, наконец, закончили.
Тут у меня есть решение в 2 команды :)Нужно исправить /etc/hosts таким образом, чтобы первым в списке было полностью определённое имя домена (FQDN):
127.0.1.1 server00.example.test server00
И теперь немного подредактировав вот эту команду (адрес Dnsmasq, имя домена, пароль admin’a в FreeIPA), можете её запустить:
$ sudo bash -c 'echo -e «nameserver 10.12.0.172\nsearch example.test\n# HEAD END\n#» >> /etc/resolvconf/resolv.conf.d/head && service resolvconf restart && bash -c «cat > /usr/share/pam-configs/mkhomedir <