Сервис на языке Dart: доменное имя, SSL

  • Tutorial
Оглавление
  1. 1. Введение
  2. 2. Backend
  3. 2.1. Инфраструктура.
  4. 2.2. Доменное имя. SSL (мы находимся здесь)
  5. 2.3. Серверное приложение на Дарт.
  6. ...
  7. 3. Web
  8. 3.1. Заглушка “Under construction”
  9. ...
  10. 4. Mobile
  11. ...


disclaimer (по комментариям к предыдущей статье)
  • Эта статья не является в полной мере самостоятельной и является продолжением серии Сервис на языке Дарт. Начало здесь.
  • Предмет данной статьи только то, что вынесено в заголовок: доменное имя и шифрование соединения.
  • Облаков, оркестрации, масштабирования, K8s, AWS, GKE здесь нет. Автору известно, что данный подход не является современным и модным. Более того, автор признаёт, что общается в окружении «ретроградов», многие из которых вообще считают неприемлемым передачу критических данных и сервисов за пределы контролируемого периметра.
  • Автор не может отказаться от использования Дарт на сервере в пользу других языков и технологий, поскольку сама концепция данной серии статей заключается в реализации работоспособного сервиса на языке Дарт для всех уровней приложения: сервера, веб и мобильных клиентов.
  • Список подлежащих рассмотрению в ходе реализации приложений вопросов выбран автором по собственному усмотрению. Список может быть расширен читателем соответствующим комментарием к этой или последующим статьям. Предлагайте, попробуем сделать.
  • Список вопросов
    • Декомпозиция приложения на компоненты и слои
    • Dependency injection (кодогенерация boilerplate)
    • Генерация нативного серверного приложения
    • ORM. Генерация схемы и миграций для БД.
    • oAuth2 + JWT авторизация. Изолированный сервер авторизации.
    • Deeplinks (Universal links/ App links). Бесшовная интеграция web/app
    • Маршрутизация в приложениях
    • Взаимодействие реального времени (websockets)
    • Адаптивная верстка flutter



Доменное имя


В прошлый раз мы закончили на том, что в докер контейнере запустили веб-сервер NGINX, раздающий статический файл index.html. В этот раз мы расширим функциональность веб-сервера, добавив шифрование данных и принудительную переадресацию с http на https.



Для этого понадобится решить организационную задачу: дело в том, что сертификат шифрования можно получить только на доменное имя или группу имён. По этой причине отправляемся к любому из регистраторов доменных имён и выбираем название, соответствующее бренду (назначению, слогану и т.д.) не забывая о назначении доменных имён верхнего уровня. В моём случае отлично подойдёт dartservice.ru. В процессе регистрации необходимо заполнить форму сведений о владельце включая ФИО, почтовый адрес и электронную почту. Затем необходимо в панели управления регистратора перейти к управлению записями DNS и сделать три записи:

  • Не менее двух NS записей (NS records). Это имена серверов доменных имён регистратора и их наименование регистратор сообщает при покупке доменного имени.
  • A запись (A record). Это непосредственно запись связи между доменным именем и IP-адресом сервера.

В моём случае DNS записи выглядят так:



Сделав это не стоит ожидать немедленного результата. Обмен сведениями между DNS серверами занимает обычно от 1 до 12 часов для зоны RU. После чего… добавим в проект ещё один тест /test/http/client.http



SSL


Вообще, конечно, протокол SSL — устаревшее наименование. Новые версии протокола называются TLS 1.0...1.3, но механизм остался прежним — шифрование данных при переходе между протоколом прикладного уровня (в нашем случае HTTP) и протоколом транспортного уровня (TCP/IP). Фактически необходимо:

  • Получить сертификат шифрования от специального удостоверяющего центра, подтвердив владение соответствующим доменом.
  • Передать сертификат серверу NGINX.
  • Настроить конфигурацию веб сервера для шифрования соединения.
  • Принудительно переключать соединения, устанавливаемые по http на https.

Общепринятым на данный момент является использование бесплатных сертификатов, автоматически выдаваемых сервисом Let’s encrypt. Одним из ограничений таких сертификатов является срок действия. Всего 90 дней. После чего сертификат необходимо получить вновь. Для автоматического (без участия человека) получения сертификатов был разработан протокол ACME и приложения, периодически выполняющие действия по подтверждению владения доменом. Let’s encrypt рекомендует использовать приложение certbot. Оно написанно на python и требует установки собственного репозитория и python3. Поэтому воспользуемся docker контейнером с установленным certbot из регистра DockerHub. Выберем последнюю стабильную версию certbot/certbot:v1.5.0.

Теперь разберёмся с механизмом получения сертификата по протоколу ACME:

  • Certbot при первом запуске генерирует закрытый и открытый ключ, затем создаёт аккаунт администратора домена в сервисе Let’s encrypt, передавая открытый ключ и сведения о домене.
  • После этого Let’s encrypt передаёт сообщение, которое certbot должен подписать закрытым ключом и вернуть обратно.
  • Сertbot должен разместить на сервере специальный файл, доступный для чтения в dartservice.ru/.well-known/acme-challenge для подтверждения владения этим доменом.
  • Certbot составляет запрос сертификата, отправляет его в Let’s encrypt и получает взамен сертификат для домена.

Добавим контейнер приложения в наш сценарий docker-compose.yaml:



Новый параметр здесь comand: тут находится команда, которая будет выполнена после запуска контейнера. В данном случае certonly (получить сертификат). Получение сертификата происходит в интерактивном режиме, то есть необходимо последовательно ответить на несколько вопросов. Передача флагов после команды позволяет сделать это без участия человека: --webroot (способ подтверждения) --webroot-path=/usr/share/nginx/html/letsencrypt (путь, по которому будут размещены файлы подтверждения владения доменом) --email admin@email.com (почта администратора домена) --agree-tos (принимаем условия лицензионного соглашения) --no-eff-email (не сообщать электронную почту разработчикам certbot) -d dartservice.ru (список доменов).

Настроим контейнер NGINX:



Изменения здесь заключаются в открытии порта https (443) и монтировании папок с SSL сертификатом и файлами подтверждения владения доменом.

Важным параметром является папка с ключом Диффи-Хеллмана. Если быть кратким: этот ключ нужен для того, чтобы безопасно обмениваться ключами шифрования между сервером и клиентом при установлении соединения. Более подробно здесь.

Давайте сгенерируем такой ключ, однако мы столкнёмся со следующей проблемой: создание ключа выполняется программой openssl, это Linux консольная утилита, которая вряд ли обнаружится на нашей Windows машине. Самое простое решение — запустить наш сценарий, зайти в консоль контейнера web и там создать ключ, передав в выходном пути для файла папку хоста смонтированную в контейнер:

Запускаем сценарий:

docker-compose up -d

Запрашиваем список работающих контейнеров:

docker-compose ps



Открываем консоль контейнера:

docker exec -it srv_web_1 bash

Запускаем генерацию ключа в папку конфигурации NGINX (которая, как мы помним, смонтирована из хоста):

openssl dhparam -out /etc/nginx/conf.d/dhparams.pem 2048



Переместим ключ в ./dhparams/dhparam-2048.pem

Выходим из консоли контейнера Ctrl-D, останавливаем сценарий:

docker-compose down

Теперь изменим конфигурацию NGINX ./conf.d/defaulf.conf:



Добавим новый location ^~ /.well-known/acme-challenge для раздачи статических файлов из папки /usr/share/nginx/html/letsencrypt. Здесь будут размещаться файлы подтверждения certbot. Настроим переадресацию для всех остальных запросов на https.

Всё готово для первого получения SSL сертификата.

Скопируем наш проект на VPS в новую папку /opt/srv_1/ командой:

scp -r ./* root@91.230.60.120:/opt/srv_1/

Подключимся из VScode по SSH к VPS.

Перейдём в папку работающего сервера:

cd /opt/srv_0/

и остановим сценарий:

docker-compose down

Теперь переходим в папку нового сервера cd /opt/srv_1/ и запускаем сценарий:

docker-compose up



В консоли мы видим, что certbot создал файл подтверждения zeS4O87S6AfRQ3Kj4MaBlBFZx3AIiWdPn61DwogDMK4 и сообщил об этом сервису Let’s encrypt, который, в свою очередь, из четырёх разных IP адресов запросил данный файл после чего выдал сертификат. Сертификат в виде полной цепочки и приватного ключа были сохранены в соответствующей папке. Срок действия сертификата 90 дней (до 05.10.2020).

Самое время создать второй location для защищенного соединения в конфигурации NGINX на сервере ./conf.d/defaulf.conf:



Перезапустим сценарий
docker-compose restart

Посмотрим, как отреагирует браузер на наш сертификат:



Google Chrome нашим сертификатом доволен. Теперь задачка посложнее — протестируем безопасность и доступность для разных браузеров наше SSL соединение https://www.ssllabs.com/ssltest/. Вводим адрес, и получаем результат:



С сертификатом и обменом ключами (спасибо Диффи-Хеллману) всё отлично, однако тестовый робот снизил оценку («В» — это «4» по-нашему) за поддержку устаревших протоколов TLS1.0 и TLS1.1. Отключить их в конфигурации NGINX несложно, однако, просматривая тестовый отчет дальше, мы видим что, например, браузеры некоторых мобильных устройств в этом случае не смогут подключиться:





Осталось выполнить несколько служебных задач.

Число попыток получения сертификата для домена не должно превышать 5 в течение 7 дней. После этого сервис Let’s encrypt может нас заблокировать. Однако запуская сценарий при разработке каждый раз certbot будет делать такую попытку, поэтому в сценарии docker-compose.dev.yaml изменим параметр command контейнера certbot:



Флаг --dry-run — это тестовый прогон без получения сертификата.

Напишем тест:



Исходный код github.

Заключение


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

В следующей статье напишем flutter web страницу с обратным отсчетом времени до запуска нашего сервиса, соберём его и разместим на нашем сервере.
Surf
Компания

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

    +2
    Опять таки, вместо 2го поста по Dart с примерами, мы видим how-to №2.
    Не боитесь, что вам в карму минусов упадет прилично количество?

    PS: я бы сделал полный цикл постов и опубликовал сразу, или объеденить несколько в 1 под названием — настраиваем серверную среду для работы нашего приложения
      +1
      Да, когда видишь в названии цикла статей сервис на Dart, а уже вышла вторая статья и до сих пор Dart-ом не пахнет, как то расстраивает. А, видимо, SSL настроить можно и без Dart.
        +1
        Всё нормально, нагоняет интригу чтобы заинтересовать читателя. С нетерпением ждём кульминации.
          +1
          Удален
            –1
            публикации идут строго по порядку разработки. Часто бывает, что траблы возникают именно на стыке стейджей. Очень хочу надеяться, что мое описание работы того же certbot станет одним из самых простых для первого знакомства

            Traefik это все решает к.м.к., но вам виднее :D
            +1
            Можно и все сразу. Но:
            • потом не интересно будет тратить время на оформление статьи. Работает и хорошо
            • публикации идут строго по порядку разработки. Часто бывает, что траблы возникают именно на стыке стейджей. Очень хочу надеяться, что мое описание работы того же certbot станет одним из самых простых для первого знакомства
            • карма? Для буста кармы в Хабр лучше писать что-нибудь лирическое или теплое ламповое. Скриншоты из CLI — это неправильный путь в Топ авторов
              +1

              Да. Только описание работы certbot под заголовком "Чото там на Dart Чото там" никто никогда не найдет. Предлагаю упомянуть сиськи, например.

            0
            Меня не оставляет ощущение, что я читаю что-то типа этого письма в техподдержку . Может вам таки наконец начать писать про Dart? А то может чего-нибудь интересное расскажете вместо того, чтобы учить как серваки админить не надо?
            Могу кстати посоветовать обратить внимание на caddy — можно половину статьи с ним выбросить
              0
              За что мне нравится Хабр, это комментарии под статьями. Под этой конкретно уже два полезных: Traefik и caddy.
              0
              в этом проекте не хватает gRPC
                –1
                Может хватить гнать на автора? Мне например очень интересно узнать о всем процессе от и до. Мне как мобильному разработчику например не хватает знаний по настраиванию сервера.

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

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