【Azure】WebサーバをいじらずにHTTPレスポンスヘッダを追加/変更する(Front Door編):Tech TIPS
WebサイトやWeb APIが返すHTTPレスポンスヘッダを追加/変更しようとしても、設定が難しかったり、そもそも変更できなかったりすることがある。AzureのCDN/リバースプロキシである「Front Door」を利用すると、比較的簡単にレスポンスヘッダを改変できる。その方法と注意点は?
対象:Azure Front Door、Bicep
もっと簡単にHTTPレスポンスヘッダを追加/変更できないの?
WebサイトやWeb APIでは、特定の「HTTPレスポンスヘッダ」をクライアントに返さなければならないことがある。代表的なものとしては、脆弱(ぜいじゃく)性を生じさせないセキュリティ対策としてのヘッダや、クライアントキャッシュの寿命などが挙げられる。
しかし、Azureに限ったことではないが、Webサーバなど直接レスポンスを生成するリソースでレスポンスヘッダをカスタマイズしようとすると、意外に面倒なことがある。例えばApp Serviceでは、nginxやIISの設定ファイルに手を加えなければならない。そもそもリソースによっては、レスポンスヘッダを変えられないこともよくある。
そのような場合、AzureのCDN/リバースプロキシの統合サービス「Front Door」の「ルールセット」という機能を利用すると、レスポンスヘッダを比較的簡単に改変できる。本Tech TIPSではその方法と注意点を説明する。
前提として、Front DoorはStandard/Premiumエディションのいずれかとする。また、Azureリソーステンプレート(ARM)でデプロイする際のBicepのコードを中心として解説する。既存のWebシステムにFront Doorを新たに追加する方法までは踏み込まない。詳しくはMicrosoft Learnの「Azure Front Door とは」「クイックスタート: Azure Front Door プロファイルを作成する - Azure portal」を参照していただきたい。
■執筆時の各種ツール/APIのバージョン
- Azure CLI: Ver. 2.53.0
- Bicep CLI: Ver. 0.22.6
- Bicepでのデプロイ時のAPIバージョン: 2022-11-01-preview(Front Door)
Azure Front Doorでヘッダ書き換えに使える「ルールセット」とは?
Front Doorの「ルールセット」を簡単に説明するなら、カスタマイズ可能な「ルール(規則)」に従って、クライアントと配信元(オリジン。コンテンツを生成/送信するサーバ)の間の通信内容を加工する機能といえる。
1つ1つのルールは、「アクション(改変の内容)」と「条件」で構成される。クライアントからのリクエストや配信元からのレスポンスが特定の「条件」を満たしたら、自動で特定の「アクション」を実行する、という仕組みだ。
アクションとしては以下のようなものが指定できる。
- (配信元へ送る)リクエストヘッダの変更
- (クライアントに返す)レスポンスヘッダの変更
- URLのリライト(リクエストされたURLを動的に変えて配信元へ送る)
- URLのリダイレクト(クライアントに30xのステータスコードとリダイレクト先URLを返す)
- ルートの動的な変更(配信元の選択やキャッシュ構成を動的に変更する)
また、条件としては主に以下のようなものが指定できる。
- TLSやHTTPのバージョン
- クライアントの種類(デスクトップかモバイルか)
- リクエストメソッド/ヘッダ/Cookie
- リクエストURL/スキーム(プロトコル)/パス/クエリ文字列
- リクエストボディ/ファイル名/ファイル拡張子
- POSTデータ
- ホスト名
- クライアント/ソケットIPアドレス
- クライアント/サーバポート番号
Azureリソーステンプレート(ARM)でFront Doorを設定してレスポンスヘッダを追加/変更する
Azureリソーステンプレート(ARM)を用いると、レスポンスヘッダの改変ルールを組み込んだ状態でFront Doorプロファイルをデプロイできる。以下では、ルールとリソース生成でリストを分けて説明する。
var rulesAddHeaders = [ // HTTPレスポンスヘッダを追加するための各ルール
{
// ルールその1
name: 'AddFrameHeaders' // ルールを表す任意のテキストを指定
conditions: [] // 無条件
actions: [ // 実行内容
{
headerAction: 'Append' // 配信元から同一ヘッダが届いたら、その値に追記
headerName: 'Content-Security-Policy' // ヘッダ名
value: 'frame-ancestors \'self\';' // 追記するヘッダの値
}
{
headerAction: 'Overwrite' // 配信元からの値は捨てて上書き
headerName: 'X-Frame-Options'
value: 'SAMEORIGIN'
}
]
matchProcessingBehavior: 'Continue' // 以降のルールも続けて処理する
}
{
// ルールその2
name: 'AddHSTSHeader' // HTTP Strict Transport Security用ヘッダ
conditions: [ // 条件
{
name: 'RequestScheme' // スキーム(httpやhttpsなどのプロトコル名)で判定
parameters: {
typeName: 'DeliveryRuleRequestSchemeConditionParameters'
matchValues: [
'HTTPS' // スキーム(プロトコル)はHTTPS限定(HTTPは不可)
]
operator: 'Equal' // 一致
negateCondition: false
transforms: []
}
}
]
actions: [ // 実行内容
{
headerAction: 'Overwrite'
headerName: 'Strict-Transport-Security'
value: 'max-age=31536000'
}
]
matchProcessingBehavior: 'Continue'
}
]
ヘッダを改変するルールを配列「rulesAddHeaders」にまとめている。これを用いたリソース生成は後述。
※Microsoftのレファレンス: Front Doorルール
ここではレスポンスヘッダを改変するためのルールを、「rulesAddHeaders」という配列にまとめている。後述のリストでは、この配列の要素を1つずつLoop構文(for)で読み出して、ルールを生成している。Front Doorがレスポンスをクライアントに返す際、各ルールを処理する順序は、この配列の先頭要素から1、2、3、……という順番だ。
上記リストの各ルールのオブジェクトでは、「conditions」が条件を、「actions」が実行内容をそれぞれ表している。どちらも複数の条件/実行内容を指定できるよう、配列で指定する必要がある。
「conditions」の方は設定可能な条件が多岐にわたるため、ルールのリソース生成における「conditions」と全く同じ構成で記述している(重複排除や省略をしていない)。一方、「actions」ではレスポンスヘッダ改変の場合、構成がほぼ単一となるため、ヘッダ名とその値、挙動(上書きか追加か)の3つに絞って配列に保存している。
ルールやルールセットのリソースを生成するためのコードは以下の通りだ。
param fdProfileName string // Front Doorプロファイルの名称
param fdEndpointName string // Front Doorエンドポイントの名称
param fdSKUName string = 'Standard_AzureFrontDoor' // または「Premium_AzureFrontDoor」
// リソース生成: Front Doorプロファイル
resource fdProfile 'Microsoft.Cdn/profiles@2022-11-01-preview' = {
name: fdProfileName
location: 'global'
sku: { name: fdSKUName }
properties: { /* ……<省略>…… */ }
}
// リソース生成: Front Doorエンドポイント
resource fdEndpoint 'Microsoft.Cdn/profiles/afdEndpoints@2022-11-01-preview' = {
name: fdEndpointName
parent: fdProfile
location: 'global'
properties: { /* ……<省略>…… */ }
}
// リソース生成: ルールセット。ヘッダ改変ルールをまとめている
resource fdRuleSetsAddResponseHeaders 'Microsoft.Cdn/profiles/ruleSets@2022-11-01-preview' = {
parent: fdProfile // Front Doorプロファイルのリソースを指定
name: 'AddResponseHeaders' // ルールセット名
}
// リソース生成: 個々のヘッダ改変ルール。元は配列「rulesAddHeaders」
resource fdRuleAddResponseHeaders 'Microsoft.Cdn/profiles/rulesets/rules@2022-11-01-preview' = [for (rule, i) in rulesAddHeaders: {
parent: fdRuleSetsAddResponseHeaders // ルールセット本体のリソースを指定
name: rule.name // ルール名
properties: {
order: i+1 // 処理される順序。配列「rulesAddHeaders」の先頭から1、2、……
conditions: rule.conditions
actions: [for action in rule.actions: {
name: 'ModifyResponseHeader' //ヘッダ改変の場合はこれで決め打ち
parameters: {
typeName: 'DeliveryRuleHeaderActionParameters' // ModifyResponseHeaderの場合、これで決め打ち
headerAction: action.headerAction
headerName: action.headerName
value: action.value
}
}]
matchProcessingBehavior: rule.matchProcessingBehavior
}
}]
// リソース生成: ルート(デフォルト)
resource fdDefaultRoute 'Microsoft.Cdn/profiles/afdEndpoints/routes@2022-11-01-preview' = {
name: 'default-forwarding-route'
parent: fdEndpoint // 親はFront Doorエンドポイント
properties: {
ruleSets: [
{
id: fdRuleSetsAddResponseHeaders.id // ルールセットのひも付け
}
]
/* ……<省略>…… */
}
/* ……<省略>…… */
}
Front Doorの配信元グループと各配信元、カスタムドメイン、シークレット(SSLサーバ証明書)などのリソース生成は、ルールセットと直接関係がないので省略している。
※Microsoftのレファレンス: Front Doorプロファイル、ルールセット、ルール、ルート
まず、ルールセットの親(parent)にはFront Doorプロファイルを、各ルールの親にはルールセットの各リソースを指定する必要がある。
もしレスポンスヘッダ改変とは別のルールも設定したい場合は、ルールセットを別に用意した方がよいだろう。その場合、「Microsoft.Cdn/profiles/ruleSets」のリソースを併せて増やす必要がある。
1つのルールセットに複数のルールを設定するのはよくあることだ。そのため、上記リストの「Microsoft.Cdn/profiles/rulesets/rules」リソース生成のように、配列またはオブジェクトとLoop構文(for)を組み合わせて、複数のルールを単一の記述で生成できるようにした方が便利だろう。
ルールセットを実際に適用するには、いずれかのルートにそれをひも付ける必要がある。それには上記リストのように、ルートのリソースの「properties.ruleSets」にルールセットのリソースIDを指定する。
上記リストで生成されたルールセットをAzureポータルで見ると、以下のスクリーンショットのようになる。
Copyright© Digital Advantage Corp. All Rights Reserved.