Azure Self-Study 3.2 - Application GatewayのDNSの指定とHTTPS化
はじめに
以前の記事「Azure Self-Study 3 - Application Gatewayを使ったVMの簡易Blue-Greenデプロイ」で構築したApplication GatewayにDNS名の指定を行い、HTTPS化してみましょう。SSL(TLS)の証明書にはLets's Encrpytを利用します。
Aplication Gatewayを再構築する場合
もしApplication Gatewayを削除していたら、いずれかの方法で再度構築してください。
DNS名の指定
以前の記事「DNSの設定」の中で書いたように、パブリックIPアドレスに対してazコマンドを利用してDNS名を指定できます。この例では次の環境、名前を使っています(自分の環境に合わせた名前に置き換えてください)
- リソースグループ名 ... myAGgroup
- パブリックIPアドレス名 ... myAGPublicIPAddress
- DNS名 ... 好きな名前(例: my-dns-name-2022 )
- ※DNS名はその地域(リージョン)でユニークな名前の必要あり。他のユーザがすでに利用している場合は指定できない
azコマンドでのDNS指定
Cloud Shell上から次のようにazコマンドを実行します。
RGNAME="myAGgroup"
IPNAME="myAGPublicIPAddress"
DNSNAME="my-dns-name-2022"
az network public-ip update --resource-group $RGNAME -n $IPNAME --dns-name $DNSNAME
結果の確認
結果は次のコマンドで確認できます。
az network public-ip list -g $RGNAME --query "[].{ fqdn: dnsSettings.fqdn }"
[
{
"fqdn": "my-dns-name-2022.japaneast.cloudapp.azure.com"
}
]
ブラウザでのアクセス
サーバーがデプロイ済みであれば、ブラウザから次のようにDSN名を使ってアクセスできるはずです。例えば地域(リージョン)が Japan Eastの場合、次のようなURLになります。
- http://指定したDNS名.japaneast.cloudapp.azure.com/
Application Gatewayのバックエンドプールにサーバーが何もない場合は、サーバーをデプロイしてからブラウザでアクセスしてください。
Let's Encryptを使ったHTTPS化
Application GatewayによるTLSの終端
Application Gatewayはレイヤー7で動作するので、次の図のようにTLSの証明書を使ってHTTPS→HTTPの変換(SSLの終端)を行うことができます。バックエンドのサーバーが複数ある場合に個別に証明書を設定する必要がなくなり、便利です。
Let's Encryptとは
Webの安全性を向上させるため、常時SSL(Always On SSL)という取り組みが進んでいます。その一環として無料でSSL証明書を提供するサービスが出てきており、Internet Security Research Groupが運営するLet's Encryptもその一つです。
SSL証明書はIPアドレスではなくドメインを使ったサーバー名に対して発行されます。そのため、あらかじめDNS名を指定してドメインを含む名前(FQDN)でアクセスできるようにしました。
Certbotの利用
Let's EncrpytでSSL証明書を発行するために、Linux VM上でcertbot というツールを利用します。VMはこれまでとは別の、第3のサブネットに配置します。
サブネットの作成
certbot用に新たなサブネットを作成します。PotalのCloud Shell上でazコマンドを用いて作成します。
RGNAME="myAGgroup"
VNET="myVNet"
SUBNET="myCertbotSubnet"
SUBNETRANGE="10.1.2.0/24"
az network vnet subnet create \
--name $SUBNET \
--resource-group $RGNAME \
--vnet-name $VNET \
--address-prefix $SUBNETRANGE
この例では、次を想定しています。
- 仮想ネットワーク(VNet) ... myVnet
- サブネット名 ... myCertbotSubnet
- サブネットのアドレス範囲 ... 10.1.2.0/24"
VMの作成
次に用意したサブネットにVMを作ります。Cloud Shell上で次のコマンドを実行します。
RGNAME="myAGgroup"
VNET="myVNet"
SUBNET="myCertbotSubnet"
SERVERNAME="myVMcertbot"
az vm create \
--resource-group $RGNAME \
--name $SERVERNAME \
--image Canonical:0001-com-ubuntu-server-focal:20_04-lts-gen2:latest \
--size Standard_B1ls \
--public-ip-sku Standard \
--subnet $SUBNET \
--vnet-name $VNET \
--storage-sku StandardSSD_LRS \
--nic-delete-option Delete \
--os-disk-delete-option Delete \
--admin-username azureuser \
--generate-ssh-keys
作成に成功したら、次のようなメッセージが返ってきます。
{
"fqdns": "",
"id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx/resourceGroups/myAGgroup/providers/Microsoft.Compute/virtualMachines/myVMcertbot",
"location": "japaneast",
"macAddress": "xx-xx-xx-xx-xx-xx",
"powerState": "VM running",
"privateIpAddress": "10.1.2.x",
"publicIpAddress": "xxx.xxx.xxx.xxx",
"resourceGroup": "myAGgroup",
"zones": ""
}
作成したVMには新たにパブリックIPアドレス(publicIpAddress)が割り振られているので、それを記録しておいてください。
また次のようにコマンドで取得し、環境変数に設定しておくと便利です。
VMIP=$(az vm show --show-details --resource-group $RGNAME --name $SERVERNAME --query publicIps -o tsv)
echo $VMIP
VMのセットアップ
VMへの接続
Cloud Shell上から、sshを用いて接続します。初回は接続を確認されるので、yesと答えてください
ssh azureuser@$VMIP
Nginxのインストール
VMに接続できたら、パッケージのアップデートと、Webサーバー(Nginx)のインストールを行います。
sudo apt update && sudo apt upgrade -y && sudo apt-get install -y nginx
インストール終了後、次のコマンドでHTMLが返って来ればNginxのインストールはは成功です。
curl http://localhost/
Certbotのインストール
Certbotの公式説明(certbot instructions)に従い、次のコマンドでインストールを行います。
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
次にインストールしたcertbotコマンドを利用して証明書を発行します。発行する際には次のURLでcertbotが生成する特殊なファイルにアクセスできる必要があります。
- http://FQDN名/.well-known/acme-challenge/xxxxxxxxxxxxxxxx
それを実現するために、Application Gateway経由でこのVM上のWebサーバー(Nginx)に接続できるように準備が必要です。
(sshをexitで抜けて Cloud Shellに戻ってから、続行してください。)
Application Gatewayへのバックエンドプールの追加
Application Gatewayにバックエンドプールを追加し、certbot用に作ったVMを配置します。
Azure Portal上で、作成済みのApplication Gatewayを表示します。
- 左のメニューから「バックエンドプール」をクリック
- [+追加]ボタンをクリック
- 「バックエンドプール」パネルが表示される
- 名前を指定 ... 例) myCertbotPool
- ターゲットの種類で「仮想マシン」を選択
- ターゲットで、certbot用に作成したVMのネットワークインターフェイス(例:myVMcertbotVMNic)を選択
- [追加]ボタンをクリック
- Application Gatewayの画面に戻る
- 左のメニューから「バックエンド設定」をクリック
- [+追加]ボタンをクリック
- 「バックエンド設定の追加」パネルが表示される
- 名前 ... certbotSetting
- プロトコル ... HTTP
- ポートは ... 80
- 他はそのまま
- [保存]ボタンをクリック
Application Gatewayによるパス別のルーティング
実現したい姿
次のように、パス別に異なるバックエンドに分岐させることを目指します。
- http://FQDN名/.well-known/* ... certbot用に作ったVM(Nginx)
- それ以外の http://FQDN名/* ... 元々あるバックエンドプール(Node.jsを使ったサーバー)
図にすると次のような形です。
経由する姿
ところがAppplication Gatewayの設定変更には下記の制約があり、ストレートに上記の形を実現できません。
- すでに作ってあるルーティング規則(BASICルーティング)に、パスのルールを追加することはできない
- パスのルールを追加するには、新たにルーティング規則を作ってそこに追加する
- ルーティング規則を全て削除することはできない
- 最低1つはルーティング規則が存在している必要あり
- 新しいルーティング規則を追加後、古いルーティング規則を削除する
- リスナーは、複数のルールで使うことはできない
- 新しいルーティング規則用に、新しいリスナーを用意する必要がある
- 古いリーティング規則の削除後は、元々あったリスナーを再利用できる
従って一旦次の形を作ります。
Application Gatewayへの新しいルーティング規則の追加
ダミーのリスナーを追加
Azure Portal上で、作成済みのApplication Gatewayを表示します。
- 左のメニューから「リスナー」をクリック
- [+リスナーの追加]ボタンをクリック
- 「リスナーの追加」パネルが表示される
- 名前 ... dummyListener
- プロントエンドIP ... パブリック
- プロトコル ... HTTP
- ポート ... 8080 (80以外のポートを指定)
- 他はデフォルトのまま
- [追加]ボタンをクリック
- Application Gatewayの画面に戻る
ルーティング規則を追加
Application Gatewayの変更が完了するのを待ってから、引き続きAzure Portal上でApplication Gatewayの設定を行います。
- 左のメニューから「ルール」をクリック
- [+ルーティング規則]ボタンをクリック
- 「ルーティング規則の追加」パネルが表示される
- ルール名 ... myCertbotRule
- 優先度 ... 100
- 「リスナー」タブをクリック
- リスナー ... 先ほど作った「dummyListener」を選択
- 「ルーティング規則の追加」パネルでの操作を継続
- 「バックエンドターゲット」タブをクリック
- ターゲットの種類 ... 「バックエンドプール」を選択
- バックエンドターゲット ... 元々作ってあった「myBackendPool」を指定
- バックエンド設定 ... 元々作ってあった「myHttpSetting」を指定
- 「バックエンドターゲット」タブをクリック
- 「ルーティング規則の追加」パネルでの操作を継続
- 「バックエンドターゲット」タブでの操作を継続
- パスベースの規則
- 「パス ベースの規則を作成するには複数のターゲットを追加します」をクリック
- パスの指定画面が表示される
- パス ... /.well-known/*
- ターゲット名 ... certbot
- バックエンド設定 ... 今回作った「certbotSetting」を指定
- バックエンドターゲット ... 今回作った「myCertbotPool」を指定
- [追加]ボタンをクリック
- パスベースの規則の表示に戻る
- [追加]ボタンをクリック
- パスベースの規則
- 「ルーティング規則」の一覧に戻る
- 「バックエンドターゲット」タブでの操作を継続
ここまでの設定が終わるとブラウザで次のURLにアクセスできるようになっています。
- http://FQDN名:8080/ あるいは
- http://指定したDNS名.japaneast.cloudapp.azure.com:8080/
ルーティングの状態は次のようになっています。
元のルーティング規則を削除
変更が完了するのを待ってから、Azure Portal上でApplication Gatewayの設定を続けます。
- 左のメニューから「ルール」をクリック
- ルールの一覧から、元々あった「myHttpRule」の右端の「…」のメニューから、「削除」をクリック
- 元の「myHttpRule」が削除され、元々あった「myHttpListner」が使えるようになる
新しいルーティング規則を変更
変更が完了するのを待ってから、もう少しAzure Portal上でApplication Gatewayの設定を続けます。
- 左のメニューから「ルール」をクリック
- ルールの一覧から、今回作った「certbotRule」をクリック
- ルール内容のパネルが表示される
- リスナーで「myHttpListner」を選択
- [保存]ボタンをクリック
これで一旦ルーティング規則の設定は終了です。
変更が完了すると、ルーティングの状態は次のようになっています。
certbotによるSSL証明書発行
改めてcertbot用のVM上で操作します。Cloud Shell上から次のコマンドでssh接続してください。(各名称は自分の環境に合わせて設定してください)
RGNAME="myAGgroup"
SERVERNAME="myVMcertbot"
VMIP=$(az vm show --show-details --resource-group $RGNAME --name $SERVERNAME --query publicIps -o tsv)
ssh azureuser@$VMIP
証明書を発行
接続したら、certbotを実行します。
sudo certbot certonly --nginx
- 初回のみ
- emailアドレスを尋ねられるので入力
- 利用条件を了承するか聞かれるので、(読んでから)「y」と入力
- emailアドレスを共有して良いか聞かれるので、「y]か「n」を入力
- domain nameを聞かれるので、DNS名 + リージョンが入ったドメイン名(FQDN)を入力
- この例では「my-dns-name-2022.japaneast.cloudapp.azure.com」
- 次のように表示さればSSL証明書の発行に成功
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/my-dns-name-2022.japaneast.cloudapp.azure.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/my-dns-name-2022.japaneast.cloudapp.azure.com/privkey.pem
メッセージにあるように、「/etc/letsencrypt/live/my-dns-name-2022.japaneast.cloudapp.azure.com/」に証明書ファイルが保存されます
証明書の連結
あとで利用するために、作った2つの証明書を連結します。引き続きcertbot用のVM上で操作します。
# 作業用ディレクトリ作成
mkdir ~/cert
# 連結
sudo openssl pkcs12 -export \
-in /etc/letsencrypt/live/my-dns-name-2022.japaneast.cloudapp.azure.com/fullchain.pem \
-inkey /etc/letsencrypt/live/my-dns-name-2022.japaneast.cloudapp.azure.com/privkey.pem \
-out ~/cert/combined.pfx
※ my-dns-name-2022.japaneast.cloudapp.azure.com の部分は、自分の環境に合わせて変更してください。
実行するとパスワードを2回聞かれるので、同じ値を指定してください。(※あとで使うので記録しておいてください。
アクセス権の変更
このあとCloud Shell上にコピーするために、アクセス権を変更します。
sudo chmod +r ~/cert/combined.pfx
証明書の期限
Let's Encryptで発行したSSL証明書の期限は90日です。期限が切れる前に更新する必要がありますが、その方法は別の機会に整理したいと思います。
HTTPSの設定方法
HTTPSを利用するには、Application GatewayのリスナーにSSL証明書を設定する必要があります。
- (a) 証明書をローカルのダウンロード後、Portal画面からアップロード
- (b) Key Vault経由で設定
今回は(b)のKey Vault経由を使ってみます。
Key Vaultとは
Key Vault は機密情報を格納する器のサービスです。
公式ページ Azure Key Vault について によると、Key Vaultを使うと次のことが可能です。
- シークレットの管理
- キー管理
- 証明書の管理
- Azure および内部の接続されているリソースで使用するためのパブリックおよびプライベートの Transport Layer Security/Secure Sockets Layer (TLS/SSL) 証明書を簡単にプロビジョニング、管理、デプロイできます
今回のようにSSL証明書の管理にぴったりです。
azコマンドによるKey Vault作成
certbot用のVMから抜けてCloud Shellに戻り、次のように操作します。(各名称は自分の環境に合わせて変更してください)
RGNAME="myAGgroup"
VAULTNAME="my-ag-vault"
az keyvault create --name $VAULTNAME --resource-group $RGNAME --location "japaneast"
"my-ag-vault" という名前の Key Vault (機密情報を格納する器)ができました。
ユーザー割り当てマネージド IDの作成
Applicatin GatewayからKey Vaultを利用するために、アクセス権限を付与する仕組みである「ユーザー割り当てマネージド ID(User-assigned managed identity)を利用します。
RGNAME="myAGgroup"
IDNAME="myCertId"
az identity create --resource-group $RGNAME --name $IDNAME
成功すると次のような結果が返ってきます。
{
"clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
"id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx/resourcegroups/myAGgroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myCertId",
"location": "japaneast",
"name": "myCertId",
"principalId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyy",
"resourceGroup": "myAGgroup",
"tags": {},
"tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities"
}
この中の「principalId」を使って、さらに次のように権限を付与します。(シークレットの読み取りと、証明書の一覧/読み取りを許可)
VAULTNAME="my-ag-vault"
ID="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyy"
az keyvault set-policy -n $VAULTNAME --secret-permissions get \
--certificate-permissions get list --object-id $ID
※IDの値は先ほど結果の「principalId」の値を指定してください。
証明書の登録
次はKey Vaultに証明書を登録します。あまりスマートではありませんが、今回はいったんCloud Shell上にコピーしてくることにします。
(リソースグループ名、VM名は自分の環境に合わせて設定してください)
# 作業用ディレクトリの作成
mkdir ~/cert
# VMのIPアドレスを取得
RGNAME="myAGgroup"
SERVERNAME="myVMcertbot"
VMIP=$(az vm show --show-details --resource-group $RGNAME --name $SERVERNAME --query publicIps -o tsv)
# コピーしてくる
scp azureuser@$VMIP:~/cert/combined.pfx ~/cert
次に、azコマンドでKey Vaultに登録します。
VAULTNAME="my-ag-vault"
CERTNAME="myAGcert"
PASSWORD="連結に使ったパスワード"
az keyvault certificate import --vault-name $VAULTNAME --name $CERTNAME --password $PASSWORD -f ~/cert/combined.pfx
証明書の連結で使ったパスワードを指定してください。もし次のようにエラーが表示されたら、パスワードが間違っている可能性があります。
We could not parse the provided certificate as .pem or .pfx. Please verify the certificate with OpenSSL
作業用証明書の削除
作業用に一時的に作成した証明書 ~/cert/combined.pfx は安全のために削除してください。Cloud Shell上、certbot用VM上それぞれで次のように削除してください。
rm ~/cert/combined.pfx
Application GatewayのHTTPS設定
ようやく準備が整いました。Application Gatewayの設定を行い、HTTPS通信ができるようにします。
リスナーの作成
azコマンドでの指定方法が理解できていないので、Portalの画面からHTTPS(ポート443)用のリスナーを新たに作ります。SSL証明書は先ほどKey Vaultに登録したもの利用します。
Azure Portal上で、作成済みのApplication Gatewayを表示します。
- 左のメニューから「リスナー」をクリック
- [+リスナーの追加]ボタンをクリック
- 「リスナーの追加」パネルが表示される
- リスナー名 ... 「myHttpsListner」など(もっと区別しやすい名前が良いかもしれません)
- フロントエンドIP ... パブリックを選択
- プロトコル ... HTTPSを選択
- ポート ... 443
- HTTPS設定 ... 「キーコンテナから証明書を選択する」
- 証明書名 ... 「certbotCert」など、好みの名前を指定
- マネージドID ... [ユーザー割り当てマネージド IDの作成]で作成したID名
- キーコンテナ名 ... 作成たKey Vaultの名前
- 証明書 ... 「証明書の登録」で指定した証明書の名前(CERTNAMEの値)
- その他 ... デフォルトのまま
- [追加]ボタンをクリック
- Application Gatewayの画面に戻る
ルーティング規則の変更
最後にルーティング規則を変更し、HTTPS用のリスナーを利用します。引き続きAzure Portal上でApplication Gatewayの設定を行います。
- 左のメニューから「ルール」をクリック
- ルーティング規則の一覧から、利用中のルール(myCertbotRule)をクリック
- 内容編集パネルが表示される
- 「リスナー」タブを選択
- リスナー ... 先ほど作った「myHttpsListener」を選択
- [保存]ボタンをクリック
- 「リスナー」タブを選択
しばらく待つと(数十秒?)設定が反映され、ルーティングが次の状態になります。これでHTTPSの設定は完了です。
ブラウザからの確認
ブラウザからHTTPSでアクセスできるようになったはずです。
- https://指定したDNS名.japaneast.cloudapp.azure.com/
まとめ
Let's Encrypt を使って Application Gateway をHTTPSで通信できるようになりました。一方、証明書の更新処理が課題として残っていますが、それは別の記事で整理する予定です。
Discussion