Azure: Application Gateway, CDN и SSL

Автор: | 04/04/2017

Задача – поднять Azure Application Gateway с поддержкой HTTPS. Пост достаточно кратенький, без обзора, просто HowTo.

Имеется CDN, за которым находится Traffic Manager.

CDN работает по HTTPS, с сертификатом от DigiCert, который выдаётся при добавлении CustomDomain для CDN-endpoint-а.

Для того, что бы CDN по HTTPS мог получить данные с бекенда (VMSS с Docker Swarm-нодами в нашем случае) – на бекенде нужен настроенный SSL.

Для этого – между VMSS и Traffic Manager – добавим Application Gateway с SSL-сертификатом.

Схема получится следующая:

  1. www.domain.com – через CNAME привязан к CDN. На CDN-ендпоинте для CustomDomain HTTPS Enabled. Конец SSL-сессии с сертификатом от DigiCert/Azure для посетителя.
  2. CDN-ендпоинт обращается к Traffic Manager, что бы получить данные для загрузки на Edge-locations. Начало SSL-сессии с самоподписанным сертификатом на AWG.
  3. TM переадресовывает запрос к своему ендпоинту, в роли которого будет AGW (ранее был VMSS).
  4. AGW проксирует запрос к данным на VMSS со Swarm-нодами. Конец SSL-сессии от CDN-ендпоинта. AGW работает с нодами по HTTP.

Создание Azure Application Gateway

Дана ресурс-группа:

  • сеть
  • две подсети – для Swarm-мастеров и Swarm-нод
  • две VMSS, два Load Balancer и прочая мелочь

(вообще-то AGW вполне может заменить Load balancer для Swarm-нод, но решили оставить как есть – время)

Для добавления Application Gateway – требуется добавить новую подсеть для интансов AGW и публичный IP.

Кроме того для IP не должно быть задано DNS имя – ARM сгенерирует рандомное имя вида a63bc0b9-67576–472c-9f81-c3831765f54f.cloudapp.net.

При этом IP должен быть типа DynamicStatic использовать с AGW нельзя.

SSL сертификат, подключаемый к AGW, судя по всему вообще ни на что не влияет – мы используем самоподписанный, ещё и сгенерированный для другого имени (в Common Name) – тем не менее всё работает.

Добавляем подсеть.

Проверяем имещиеся:

[simterm]

# azure network vnet subnet list -g jm-website-sw-production-blue -e jm-website-sw-production-blue-net
info:    Executing command network vnet subnet list
+ Looking up the virtual network "jm-website-sw-production-blue-net"           
+ Getting virtual network subnets                                              
data:    Name                                         Provisioning state  Address prefix
data:    -------------------------------------------  ------------------  --------------
data:    jm-website-sw-production-blue-master-subnet  Succeeded           10.0.0.0/24   
data:    jm-website-sw-production-blue-nodes-subnet   Succeeded           192.168.0.0/24
info:    network vnet subnet list command OK

[/simterm]

Добавляем ещё одну подсеть:

[simterm]

$ azure network vnet subnet create -g jm-website-sw-production-blue -e jm-website-sw-production-blue-net -n jm-website-sw-production-agw -a 10.0.1.0/28 -w /subscriptions/0a4f2b9c-***-40b17ef8c3ab/resourceGroups/jm-website-sw-production-blue/providers/Microsoft.Network/networkSecurityGroups/jm-website-sw-production-blue-nodes-nsg

[/simterm]

Тут:

  • -g: имя группы ресурсов
  • -e: имя виртуальной сети
  • -n: имя новой создавайемой подсети
  • -a: блок адресов новой подсети
  • -w: ID группы безопасности

Далее – получаем Public IP для этого гейтвея:

[simterm]

$ azure network public-ip create -g jm-website-sw-production-blue -n jm-website-sw-production-blue-agw-ip -l westeurope -a Dynamic

[/simterm]

Ключик уже сгенерирован:

[simterm]

$ file /home/setevoy/Work/SSL/cert.pfx 
/home/setevoy/Work/SSL/cert.pfx: data

[/simterm]

ID ресурсов ищем на https://resources.azure.com.

Хотел и AGW создавать через Azure CLI – но он глючит, пишем очередной стотысячный уже тикет в саппорт, и идём делать руками через Portal.

Деплой занял 10-15 минут:

Пока деплоится AGW – проверим настройки Traffic Manager.

Настройка Traffic Manager

У TM есть два ендпоинта:

Для Blue – указан Target publish-blue.domain.com:

Обновляем запись для publish-blue.domain.com, и направляем его на IP созданного для AGW (IP – типа Dynamic, так что придётся ждать пока задеплоится AGW):

Возвращаемся к AGW, переходим в Backend pools, редактируем созданный AGW бекенд, задаём Target в виде IP или URL к нашему VMSS со Swarm-нодами:

Сейчас можно проверить – как ТМ работает с VMSS через созданный AGW:

[simterm]

$ curl -k https://jm-website-publish-tm.trafficmanager.net/version
0.0.103

[/simterm]

Файл version получен с бекенда/VMSS, всё работает. Т.к. на AGW самоподписанный сертификат – добавляем -k (--insecure) для curl.

Теперь остаётся ждать, пока CDN Verizon не подтянет данные.

Настройка Network Security

Доступ к подсети, в которой находится VMSS со Swarm-нодами закрыт фаерволом.

Правим Network Security правила, добавляем в Allow IP созданный для AGW (что бы AGW смог получить доступ к нодам и вытянуть с них информацию для передачи в CDN):

В CDN – включаем HTTPS для Custom домена:

Проверяем.

Сначала – пробуем напрямую с ноды, по HTTP:

[simterm]

$ curl jm-website-s-blue-nodes-ip.westeurope.cloudapp.azure.com
Found. Redirecting to /en

[/simterm]

Теперь – шаг “назад”, в сторону посетителя – проверяем AGW, уже по HTTPS, сертификат тот же, самоподписанный – используем -k:

[simterm]

$ curl -k https://52.***.***.182
Found. Redirecting to /en

[/simterm]

Пробуем по домену, который указан у TM в ендпоинте:

[simterm]

$ curl -k https://publish-blue.domain.com
Found. Redirecting to /en

[/simterm]

Проверяем через URL самого ТМ:

[simterm]

$ curl -k https://jm-website-production-tm.trafficmanager.net
Found. Redirecting to /en

[/simterm]

И проверяем CDN:

[simterm]

$ curl -k https://jm-website-production-cdn.azureedge.net
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
                <title>404 - Not Found</title>
        </head>
        <body>
                <h1>404 - Not Found</h1>
        </body>
</html>

[/simterm]

Ждём обновления CDN, и к утру всё заработало.

P.S. Пост писался в спешке, мог что-то упустить. Но в целом – схема рабочая.