[Azure] Application Gateway (WAF) で HTTP/2 を使うときの SSL ポリシーのお話


TL;DR

  • Application Gateway のフロント側で喋る TLS (SSL ポリシー) の話
  • Application Gateway で HTTP/2 を有効化しただけでは TLSv1.2 の SSL ポリシーに自動的に切り替わらない
  • また、HTTP/2 の RFC でブラックリストに規定された暗号スイートを、自動的に SSL ポリシーから排除することもしない
  • なので HTTP/2 を有効化するときは、下に紹介する PowerShell スクリプトを参考に、HTTP/2 に適した自前の SSL ポリシーを定義しましょう

SSL ポリシーとは?

Application Gateway (SKU によっては WAF とも呼ばれます) のフロント エンドで TLS を喋る場合、その最低 TLS バージョンや、利用可能な暗号スイートをユーザーが自由に決めることが出来ます。


※この図だと TLS 1.1 以上を対応するクライアントじゃないと許可しない構成

Azure Application Gateway では、最低 TLS バージョン、順序に意味のある暗号スイートのリストの組を「SSL ポリシー」と呼んでいます。
SSL ポリシーの概要については、公式ドキュメント を見てもらうのが早いかと思います。

また、各最低 TLS バージョンごとに、Microsoft がおすすめの暗号スイートを定義しており、「定義済み SSL ポリシー」の名前でこれを提供しています。
例えば、最低 TLS バージョンを TLS v1.2 としたとき、その定義済み SSL ポリシーの暗号スイートは以下の通りです。

PS> $policies = Get-AzApplicationGatewaySslPredefinedPolicy
PS> $policies | where MinProtocolVersion -eq TLSv1_2

Name: AppGwSslPolicy20170401S
MinProtocolVersion: TLSv1_2
CipherSuites:
    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
    TLS_RSA_WITH_AES_256_GCM_SHA384
    TLS_RSA_WITH_AES_128_GCM_SHA256
    TLS_RSA_WITH_AES_256_CBC_SHA256
    TLS_RSA_WITH_AES_128_CBC_SHA256
    TLS_RSA_WITH_AES_256_CBC_SHA
    TLS_RSA_WITH_AES_128_CBC_SHA

HTTP/2 × SSL ポリシーにまつわる問題

HTTPS/2 を有効にしたとき SSL ポリシーが変わらない問題

Application Gateway では HTTP/2 がサポートされています。
HTTTP/2 を有効にするには、以下の Powershell コマンドを実行します。

$appgw = Get-AzApplicationGateway -Name appgw-name -ResourceGroupName rg
$appgw.EnableHttp2 = $true
$appgw | Set-AzApplicationGateway

HTTP/2 は RFC 7540 (https://summerwind.jp/docs/rfc7540/) で規定されているように、TLS v1.2 以上を利用しなくてはいけません (RFC での MUST 条件) ので、上のコマンドを叩くと勝手に TLS v1.2 の SSL ポリシーに反映してもらえるのかと思うかもしれませんが、実際はそうなっていません。

9.2. TLS の機能の利用

HTTP/2 の実装は、TLS 上の HTTP/2 に対して TLS バージョン1.2 [TLS12] 以上を使用しなければなりません (MUST)。[TLSBCP] にある TLS の一般的な利用ガイダンスに即すべきであり (SHOULD)、加えて HTTP/2 特有の制限もあります。

試しに、次のような SSL ポリシー状態の Application Gateway (v2 SKU)

に対して HTTP/2 を有効化すると…

SSL ポリシーが変わらない!!!!

これは良くないですね。

HTTP/2 用の SSL ポリシーが提供されていない問題

加えて、HTTP/2 の RFC 7540 の「9.2.2. TLS 1.2 の暗号スイート」を見てもらいたいのですが、RFC 7540 では、セキュリティ上の懸念から、特定の暗号スイートを使用しないよう喚起しています。

9.2.2. TLS 1.2 の暗号スイート

TLS 1.2 上の HTTP/2 のデプロイメントは、暗号スイートブラックリスト (付録A) に記載された暗号スイートを使用すべきではありません (SHOULD NOT)。

上で見た TLS v1.2 の定義済み SSL ポリシーは、HTTP/2 のブラックリストを考慮しておらず、ブラックリストに載っている暗号スイートも使ってしまっています。
HTTP/2 を使う場合は、この点も注意しましょう。

解決策

ということで、HTTP/2 を有効化するときは、一緒に SSL ポリシーも正しく構成しましょう。

方針としては 2 パターンあります。

  1. TLS v1.2 の「定義済み SSL ポリシー」をベースに、ブラックリストの暗号スイートを削除したものを利用する
  2. 自分でカスタマイズした (TLS v1.2 を最低バージョンにもつ) SSL ポリシーをベースに、ブラックリストの暗号スイートを削除したものを利用する

それぞれを PowerShell で実装したスクリプトを紹介しますので、参考にしてみてください。

  1. Set a custom-defined SSL Policy to Application Gateway based on the pre-defined SSL policy (TLS v1.2) but being filtered out cipher suites of the blacklist on HTTP/2 RFC (RFC 7540)
  2. Filter out cipher suites of blacklist in HTTP/2 RFC from custom-defined SSL Policy of Application Gateway.

1 番目のものをちょっと紹介すると、こんな感じのコードになってます。
(定義済み SSL ポリシーを取得してフィルターにかけてるだけなので、解説は要らないかと思います)

$appgw = Get-AzApplicationGateway -Name $Name -ResourceGroupName $ResourceGroupName

$policies = Get-AzApplicationGatewaySslPredefinedPolicy
$policy = $policies | where MinProtocolVersion -eq TLSv1_2

$filteredCipherSuites = $policy.CipherSuites | where { -not ($CipherSuitesBlacklistOnHTTP2 -contains $_) }

Set-AzApplicationGatewaySslPolicy -ApplicationGateway $appgw `
    -PolicyType Custom `
    -MinProtocolVersion "TLSv1_2" `
    -CipherSuite $filteredCipherSuites

Set-AzApplicationGateway -ApplicationGateway $appgw