Как подружить Ovirt и Let's Encrypt

  • Tutorial
Шагая по пути улучшения инфраструктуры, я решил добить древний и мучительный вопрос — без лишних телодвижений предоставлять возможность коллегам (разработчикам, тестировщикам, админам, etc ) самостоятельно управлять своими виртуалками в ovirt'е. В ovirt есть несколько компонентов, которые надо настроить для решения моего вопроса: сам веб интерфейс, noVNC консоль и заливка образов дисков.

Кнопки «Сделать Зашибись» я не нашёл, поэтому показываю какие ручки я крутил, чтобы решить данную задачу. Полная инструкция под катом:





DISCLAIMER:


Перед началом хотел бы обратить внимание, что по какой-то неизвестной мне причине домены инфраструктуры создаются в частных зонах lan, local, и так далее.

Что мешает использовать домен организации в публичной зоне мне неизвестно. К примеру, вместо домена Alex-GLuck-Awesome-Company.local, можно смело использовать домен для сайта компании Alex-GLuck-Awesome-Company.com.

Если вы боитесь, что не сможете уследить за доменами в своей организации, и это что-нибудь сломает, то за скромные 100 рублей в год можете взять отдельный домен для инфраструктуры aglac.com.

Почему выгодней использовать домены в публичных зонах:

1. У вас внутри организации появляются сервисы выходящие в публичное пространство: впн, обмен файлами(seafile, nextcloud) и другие. Настраивать шифрование трафика на таких сервисах обычно выглядит как тяп-ляп, и от MitM защищаться мы не будем, потому что сложно(на самом деле нет).

Или внутри офиса у вас один адрес сервиса, а из интернета другой, и связи эти надо поддерживать, на что тратятся наши ограниченные ресурсы специалистов. Ну и сотрудникам приходится запоминать разные адреса, что неудобно.

2. Вы можете использовать бесплатные центры сертификации для шифрования ваших внутренних сервисов.

Собственный PKI — это сервис, который надо поддерживать, 100 рублей в год за возможность использование PKI от бесплатных центров сертификации с лихвой окупают время сотрудников, которые могли бы тратить его на другие задачи.

3. При использовании собственного центра сертификации вы будете вставлять палки в колёса вашим удалённым сотрудникам и коллегам, которые хотят работать с BYOD (приносят свои ноуты, телефон, планшеты) и вы не можете управлять их устройствами. Они приносят маки, линуксы, андройды, IOS, винду — поддерживать такой зоопарк нет никакого смысла.

Во всём, конечно, есть исключения, и банки с другими суровыми энтрпрайзами, которые имеют устоявшиеся политики безопасности, уже никогда не смогут улучшить сервис для своих сотрудников.

Для них есть платные центры сертификации, которые за определённую сумму могут подписать их CA сертификат(гуглить «root signing service»).

Есть и другие причины, почему публичный домен использовать выгодней(самое главное, чтобы он принадлежал вам), но статья не об этом.

Суть, да дело...


ВНИМАНИЕ! Если вы добавите сертификат CA от Let's Encrypt в список доверенных для ovirt'а, это может повлиять на безопасность ваших систем!

Первое на что надо обратить внимание — интерфейсы овирта выставлять в интернет это плохая практика, т.к. в этом нет никакого практического смысла, а дополнительные угрозы безопасности создаёт.

Следовательно получать сертификат необходимо на каком-нибудь нашем бастион-хосте, после чего переносить сертификат и ключ на наш хост с ovirt-engine.

Добавляем внешний адрес нашего бастион-хоста в днс с нашим именем овирта ovirtengine.example.com, установку certbot и nginx я оставлю за кадром(как это сделать на хабре уже описано).

Настраиваем нджинкс версии >=1.15.7

/etc/nginx/conf.d/default.conf
server {
    server_name _;
    listen 80 default_server;
    location /robots.txt { alias /usr/share/nginx/html/robots.txt; }
    location /.well-known {
        root /usr/share/nginx/html;
    }
    location / {
        return 444;
    }
}

server {
    server_name _;
    listen 443 ssl http2 default_server;
    location /robots.txt { alias /usr/share/nginx/html/robots.txt; }
    location /.well-known {
        root /usr/share/nginx/html;
    }

    ssl_certificate /etc/nginx/ssl/$ssl_server_name/fullchain.pem; 
    ssl_certificate_key /etc/nginx/ssl/$ssl_server_name/privkey.pem;

    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;

    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;

    # позволяем серверу прикреплять OCSP-ответы, тем самым уменьшая время загрузки страниц у пользователей
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

    location / {
        return 444;
    }
}


Потом получаем наш сертификат и ключ:

certbot certonly --nginx -d ovirtengine.example.com

Архивируем наш сертификат и ключ:

tar Phczf /tmp/ovirtengine.example.com.tgz /etc/letsencrypt/live/ovirtengine.example.com

Скачиваем с бастион-хоста архив, заливаем на наш овирт-енжин:

scp bastion-host:/tmp/ovirtengine.example.com.tgz /tmp/
scp /tmp/ovirtengine.example.com.tgz ovirtengine.example.com:/

Переходим к цели


Далее мы распаковываем наш архив и создаём симлинки для упрощения понимания системы расположения файлов:

tar Pxzf /ovirtengine.example.com.tgz && rm -f ovirtengine.example.com.tgz
mkdir -p /etc/letsencrypt/live
ln -f -s /etc/letsencrypt/live /etc/pki/letsencrypt

Настраиваем встроенный pki в овирт, чтобы для проверки сертификатов использовалось хранилище сертификатов java(openjdk):

cat << EOF > /etc/ovirt-engine/engine.conf.d/99-setup-pki.conf 
ENGINE_HTTPS_PKI_TRUST_STORE="/etc/pki/java/cacerts"
ENGINE_HTTPS_PKI_TRUST_STORE_PASSWORD=""
EOF

Конвертируем CA от let's encrypt'а в der формат и добавляем в хранилище сертификатов java trust store овирта (это такой контейнер, в котором находится перечень сертификатов, такая система используется в java):

openssl x509 -outform der -in /etc/pki/letsencrypt/ovirtengine.example.com/chain.pem -out /tmp/ovirtengine.example.com.chain.der
keytool -import -alias "Let's Encrypt Authority X3" -file /tmp/ovirtengine.example.com.chain.der -keystore /etc/pki/ovirt-engine/.truststore -storepass $(grep '^ENGINE_PKI_TRUST_STORE_PASSWORD' /etc/ovirt-engine/engine.conf.d/10-setup-pki.conf | cut -f 2 -d '"')
rm -f /tmp/ovirtengine.example.com.chain.der

Редактируем настройки SSL для apache, добавляем параметр для поддержки симлинков и убираем параметр для CA, которым проверять сертификаты (по умолчанию будет пользоваться системный набор доверенных CA для проверки):

sed -r -i 's|^(SSLCACertificateFile.*)|#\1|g' /etc/httpd/conf.d/ssl.conf
sed -r -i '0,/(^#?SSLCACertificateFile.*)/ s//\1\nOptions FollowSymlinks/' /etc/httpd/conf.d/ssl.conf

После чего бекапируем на всякий случай оригинальные файлы, сгенерированные через PKI ovirt'а автоматический и подменяем симлинками на файлы от Let's Encrypt:

ln -f -s /etc/pki/letsencrypt/ovirtengine.example.com/fullchain.pem /etc/pki/ovirt-engine/apache-chain.pem
services=( 'apache' 'imageio-proxy' 'websocket-proxy' )
for i in "${services[@]}"; do
cp /etc/pki/ovirt-engine/certs/$i.cer{,."$( date +%F )".bak}
cp /etc/pki/ovirt-engine/keys/$i.key.nopass{,."$( date +%F )".bak}
ln -f -s /etc/pki/letsencrypt/ovirtengine.example.com/privkey.pem /etc/pki/ovirt-engine/keys/$i.key.nopass
ln -f -s /etc/pki/letsencrypt/ovirtengine.example.com/cert.pem /etc/pki/ovirt-engine/certs/{apache,imageio-proxy,websocket-proxy}.cer
done

Восстанавливаем SElinux контексты на файлах и перезапускаем наши сервисы (httpd, ovirt-engine, ovirt-imageio-proxy, ovirt-websocket-proxy):

restorecon -Rv /etc/pki
systemctl restart httpd ovirt-engine ovirt-imageio-proxy ovirt-websocket-proxy

httpd — веб сервер apache
ovirt-engine — веб интерфейс ovirt
ovirt-imageio-proxy — демон для загрузки образов дисков
ovirt-websocket-proxy — сервис для работы noVNC консоли

Всё выше перечисленное было проверено на версии овирта 4.2.

Автообновление сертификатов на ovirt


Согласно хорошим практикам по безопасности, связи между бастион-хостом и овиртом быть не должно, а сертификат выдаётся только на 3 месяца. Вот тут появляется спорный момент о том, как реализовано обновление сертификатов у меня.

У меня есть ансибл плейбук, который запускается на foreman ежедневно в 5 утра по расписанию. Этот плейбук заходит на овирт, проверяет срок действия сертификата и если до истечения осталось меньше 5 дней, идёт на бастион-хост и запускает обновление сертификата.

После обновления сертификата он архивирует папку с файлами, скачивает на хост формана и разархивирует на хост овирта. После чего восстанавливает SElinux контексты на файлах и перезапускаем наши сервисы.
Поделиться публикацией

Комментарии 14

    0
    К примеру, вместо домена Alex-GLuck-Awesome-Company.local, можно смело использовать домен для сайта компании Alex-GLuck-Awesome-Company.com.

    Как этом случае, из внутренней сети, попасть на внешний сайт компании Alex-GLuck-Awesome-Company.com?
      0
      Когда вы используете домен внутри организации(freeipa, ldap, ad) машины в этом домены создаются с адресами 3его уровня: host1.Alex-GLuck-Awesome-Company.com, host2.Alex-GLuck-Awesome-Company.com, ovirtengine.Alex-GLuck-Awesome-Company.com. И они не пересекаются с именем сайта, следовательно когда вы пытаетесь открыть ресурс по домену у вас днс резолвит интернет адрес сайта, куда вы преспокойненько попадаете. Понятненько?
        0
        Мне-то это понятно, но у вас в статье написано про один и тот же домен. Что я и процитировал.

        И причем тут имена машин в домене, вот это мне непонятно, я вроде про официальное имя внешнего сайта, а никак не машин.
        0
        Я возможно что то путаю, но проблемы с внешними и внутренними именами доменов и хостов в разных зонах и в одной вполне можно решить за счет Split DNS, данная технология реализована, например, в BIND. Делается это достаточно легко, достаточно погуглить: «Split DNS: заставим BIND работать на два фронта» и прочитать.
          0
          Как правило в организациях используется АД и там split zone(название технологии в BIND) или zone view(название технологии в powerDNS) сделать и поддерживать нецелесообразно. Лучше жёстко разделить ДНС записи на публичные и внутруненние по разным ДНС серверам. ДНС для внутренних записей будут переназначать параметры для внешних. А во внешних будет вполне примитивная логика работы, и ограниченный объём по количеству записей.
            0
            Абсолютно солидарен с Вами. Так в «продакшене» обычно и происходит. Однако замечу, что данное положение дел может резко измениться если у вас много раздельных внутренних и внешних доменов, принадлежащих разным организациям, но по тем или иным причинам, внезапно, решившим объединить свою инфраструктуру ИТ. Сценарии могут быть разными и каждый сам выбирает, что и как ему будет удобно в его инфраструктуре.
            0
            Не очень понимаю, чем нам поможет Split-DNS в случае одинаковых имен внешнего сайта и домена AD.
            Допустим, есть домен AD company.ru и внешний сайт company.ru. Изнутри company.ru будет резолвиться в имена контроллеров домена. И собственно должен в них резолвиться, иначе AD не будет нормально работать.
            Попадать на внешний сайт придется всякими извратными путями, не совсем удобными для конечных пользователей. Если знаете какой-то приличный путь, я был бы не против его узнать тоже.
              0
              Создайте домен ad.company.ru или office.company.ru. Ну или купите другой публичный домен, если не знаете как совместить одновременную работу публичной и внутренней части.
                0
                Как же я с Вами солидарен. Жаль не имею прав, надеюсь пока, «лайкать» комментарии.
                0
                Резонный вопрос. Если внутри организации действительно развернут AD DC и его доменная зона совпадает с публичной, то простой и «бескостыльный» метод всё это подружить, приучить сотрудников писать имя хоста сервера где размещен сайт, обычно это «www», например: «www.company.ru» и вопрос уйдет сам собой. В прочих случаях DNS конечно не поможет никак в такой ситуации, так как корень домена в AD DC предопределен и менять данное положение дел очень чревато последствиями, кроме того корень домена это ещё и корень DFS. А что касается «костылей», то если вопрос ограничивается лишь сайтом компании, то веб-прокси сервер внутри компании может закрыть данную проблему, правда это потребует дистрибуции самого этого прокси сервера, что породит отдельную проблему, но в конечном счете каждый сам решает на что он может пойти ради искусства.
                  0
                  Ну, метод к чему-то приучать пользователей, мне бескостыльным никак не кажется. Это первый из двух известных мне костылей. Второй, это использовать прокси (уже не очень приятно, в век, когда космические корабли бороздят просторы) и на нем перенаправлять HTTP-запросы куда надо.

                  А бескостыльные, на мой взгляд, это именно что использование для внутреннего домена домена третьего уровня типа office .company.ru, как выше было сказано, или (сюрприз!) использование домена типа .local.

                  А вообще, учитывая, что у компаний иногда бывают переименования, объединения, разделения и т.п., использование какого-нибудь безликого corp.local мне видится наиболее оптимальным.
                  Проблемы с сертификатами для доменов .local, мне кажутся надуманными, так как публиковать сертификаты умеет любой мало-мальски приличный реверс-прокси.
                    0
                    Абсолютно согласен и в своих практиках предпочитаю именно такой способ, разве что мне не очень нравится домен «local», как-то длинно и не благозвучно, я лично использую «lan». Мне кажется, все мы говорим об одном и том же, просто автор не достаточно точно описал данный момент в своей статье. И я вообще не до конца понимаю зачем он это сделал, так как данный вопрос лежит за рамками статьи.
                      0
                      Вашему самоподписанному сертификату на зоны local или lan никто не будет доверять. Никакой реверс-прокси не поможет, вы будете использовать 2 зоны тогда. Статья не об этом. Про домены я так понял тема холиварная, я добавлю в план статью с мыслями на этот счёт.
                        0
                        Никто и не предлагает использовать самоподписанные сертификаты на зоны local или lan. Обычно на реверс-прокси публикуют нормальные публичные сертификаты на внешние зоны.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое