Pull to refresh

Система централизованного управления авторизацией пользователей на FreeIPA в Docker

Reading time 6 min
Views 86K
На волне популярности Docker на Хабре, после участия в некоторых дискуссиях в комментариях относительно Docker, и в связи с недавней необходимостью настроить централизованную авторизацию для кластера Linux машин, я решил написать небольшую заметку. Здесь будет показан яркий, на мой взгляд, пример применения Docker'a для небольшой частной задачи.

Вот так, кстати, выглядит FreeIPA WebUI (официальное демо) (кликабельно):



Какие задачи я хотел решить при помощи FreeIPA:
  1. Иметь возможность создавать/изменять/удалять акаунты пользователей централизовано, а не на каждом отдельном сервере
  2. Централизованные плавила для sudo
  3. В последствии мы подключим к этой системе ещё и 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:

  1. Создаём директорию, которая будет монтироваться в образ для конфигов FreeIPA, которые нужно оставлять после перезапуска (в документации предлагается использовать /var/lib/ipa-data/, но я не люблю засорять систему, поэтому /opt/):
    $ sudo mkdir -p /opt/dockers/freeipa-data
    

  2. Добавим файл с опциями, которые будут использоваться при инсталяции freeipa-server:
    $ sudo tee /opt/dockers/freeipa-data/ipa-server-install-options
    --ds-password=The-directory-server-password
    --admin-password=The-admin-password
    

  3. Всё, запускаем (в доке не хватает проброса портов, хотя это и очевидно, что нужно сделать; стоит также отметить, что в доке написано, что нужно подключать раздел с постфиксом :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
    

  4. После недолгой установки вам любезно предоставят 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МБ.

Вот как я его подготовил:
  1. Создал директорию для конфигов:
    $ sudo mkdir -p /opt/dockers/dnsmasq.d
    

  2. Добавил туда конфиг 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
    

  3. Запускаем (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/'
    

  4. Проверяем, что работает:
    $ 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 сервером, наконец, закончили.

Настройка клиентов


Тут у меня есть решение в 3 команды :)

  1. Нужно исправить /etc/hosts таким образом, чтобы первым в списке было полностью определённое имя домена (FQDN):
    127.0.1.1    server00.example.test server00
    

  2. Настроить DNS (через /etc/network/interfaces или /etc/resolvconf/resolv.conf.d/head) так, чтобы в /etc/resolv.conf появились следующие строки:
    nameserver 10.12.0.172
    search example.test
    

  3. И теперь изменив пароль admin'a к FreeIPA в следующей команде, можете её запустить:
    $ sudo bash -c 'bash -c "cat > /usr/share/pam-configs/mkhomedir <<EOF
    Name: activate mkhomedir
    Default: yes
    Priority: 900
    Session-Type: Additional
    Session:
            required                        pam_mkhomedir.so umask=0022 skel=/etc/skel
    EOF" && DEBIAN_FRONTEND=noninteractive apt-get install -y freeipa-client && ipa-client-install -U -N -p admin -w The-admin-password && sed -i "s/services = .*/services = nss, pam, ssh, sudo/" /etc/sssd/sssd.conf && restart sssd && restart ssh'
    

    Здесь добавится PAM-модуль для автоматического создания домашних директорий, установится freeipa-client, запустится установка ipa-client, добавится сервис sudo в sssd.conf и перегрузятся sssd и ssh.

Вот и всё, теперь на этом хосте можно делать su/sudo/ssh, где пользователя при самом первом входе заставят сменить пароль, а при первом входе на новом хосте для пользователя будет автоматически создана домашняя директория из /etc/skel.

Выводы


Docker может упростить разворачивание сложных проектов в любой инфраструктуре. У Docker есть масса применений и это только одно из них.

В дальнейшем я, возможно, сподвигнусь написать о другом проекте, который интенсивно использует ограничения ресурсов, интегрированные в Docker (CPU, RAM).
Tags:
Hubs:
+12
Comments 21
Comments Comments 21

Articles