ALB でリスナーに対してヘッダーの変更、追加ができるようになりました

ALB でリスナーに対してヘッダーの変更、追加ができるようになりました

Clock Icon2025.04.15

2024年11月の少し前のアップデートにはなりますが、ALB でロードバランサーが生成した特定のヘッダーの名前変更特定のレスポンスヘッダーの挿入サーバーレスポンスヘッダーの無効化ができるようになったので、その内容について確認してみました。

https://aws.amazon.com/jp/about-aws/whats-new/2024/11/aws-application-load-balancer-header-modification-enhanced-traffic-control-security/

このアップデートで HTTP または HTTPS のリスナーに対して、いくつかのヘッダー操作が出来るようになっています。
操作できるヘッダーについては、ドキュメントかマネジメントコンソールなどで確認できます。

実際にマネジメントコンソールで確認してみようと思います。

ロードバランサーのリスナーとルールでリスナーを選択します。

vscode-paste-1744619354471-579rh3q994f.png

属性から確認でき、編集ボタンをクリックすることで編集が可能です。

vscode-paste-1744619362752-ledwweofxnp.png

リスナーが HTTP か HTTPS なのかで設定できる項目が変わります。
操作できる内容は大きく以下の3つです。

  1. 変更可能な mTLS/TLS ヘッダー名(特定のヘッダーの名前変更)
  2. 応答ヘッダーの追加(特定のレスポンスヘッダーの挿入)
  3. ALB サーバー応答ヘッダー(サーバーレスポンスヘッダーの無効化)

ヘッダーが存在する場所と条件については以下のようなイメージです。

vscode-paste-1744676964309-05fgcl302v99.png

vscode-paste-1744676978223-hmmgfhr8na8.png

HTTP の場合 2. 3. が、HTTPS の場合 1. 2. 3. が設定可能です。

設定変更した場合の動作を見ながら確認していきたいと思います。

変更可能な mTLS/TLS ヘッダー名

ご利用のアプリケーションによって、下記のリクエストヘッダを処理できない場合、この機能を使って任意のヘッダ名に変更できます。

設定可能なヘッダーのリストと概要は公式ドキュメントで確認できます。

Application Load Balancer の HTTP ヘッダーの変更 - エラスティックロードバランシング

mTLS(相互TLS認証)を実装する場合、ALB -> ターゲット へのHTTPリクエストに以下のヘッダーが付与されます。

  • X-Amzn-Mtls-Clientcert-Serial-Number
  • X-Amzn-Mtls-Clientcert-Issuer
  • X-Amzn-Mtls-Clientcert-Subject
  • X-Amzn-Mtls-Clientcert-Validity
  • X-Amzn-Mtls-Clientcert-Leaf
  • X-Amzn-Mtls-Clientcert

また、ロードバランサー全体の属性の設定で、TLSバージョンと暗号ヘッダー を有効化している場合、ALB -> ターゲット へのHTTPリクエストヘッダーに以下のヘッダーが付与されるようになります。

  • X-Amzn-TLS-Version
  • X-Amzn-TLS-Cipher-Suite

今回は X-Amzn-TLS-VersionX-Amzn-TLS-Cipher-Suite を変更してみます。

まず最初に TLSバージョンと暗号ヘッダー の有効化をしておきます。
有効化については下記のブログを参考にしていただけると良いかと思います。

ALB属性まとめ
https://dev.classmethod.jp/articles/alb-attribute-and-value/

Webアクセスを発生させた後、今回はターゲットが EC2 を想定してHTTPリクエストのヘッダを確認します。

# tcpdump port 80 -nn -A
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enX0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
05:40:52.719833 IP 10.0.1.32.23306 > 10.0.1.84.80: Flags [S], seq 3058337488, win 26883, options [mss 8961,sackOK,TS val 3171257534 ecr 0,nop,wscale 8], length 0
E..<.u@.....
..
..T[
.P.J........i.......#....
............
05:40:52.719863 IP 10.0.1.84.80 > 10.0.1.32.23306: Flags [S.], seq 909698561, ack 3058337489, win 62643, options [mss 8961,sackOK,TS val 1344412121 ecr 3171257534,nop,wscale 7], length 0
E..<..@....H
..T
.. .P[
68...J............#....
P"..........
05:40:52.720338 IP 10.0.1.32.23306 > 10.0.1.84.80: Flags [.], ack 1, win 106, options [nop,nop,TS val 3171257535 ecr 1344412121], length 0
E..4.v@.....
..
..T[
.P.J..68.....j.m.....
....P"..
05:40:52.720338 IP 10.0.1.32.23306 > 10.0.1.84.80: Flags [P.], seq 1:297, ack 1, win 106, options [nop,nop,TS val 3171257536 ecr 1344412121], length 296: HTTP: HEAD / HTTP/1.1
E..\.w@.....
..
..T[
.P.J..68.....jk......
....P"..HEAD / HTTP/1.1
x-amzn-tls-cipher-suite: TLS_AES_128_GCM_SHA256
x-amzn-tls-version: TLSv1.3
X-Forwarded-For: 192.0.2.1
X-Forwarded-Proto: https
X-Forwarded-Port: 443
Host: example.com
X-Amzn-Trace-Id: Root=1-67fc9fe4-148a2ae274ae342a4a806fbd
user-agent: curl/8.7.1
accept: */*

x-amzn-tls-cipher-suitex-amzn-tls-version が確認できます。

設定を変更します。
X-Amzn-TLS-VersionCustom-tls-version に、x-amzn-tls-cipher-suiteCustom-tls-cipher-suite に変更します。

vscode-paste-1744623588121-lwapv07zj8.png

CLIで設定する場合は以下のように実行します。

% aws elbv2 modify-listener-attributes \
--listener-arn <ARN> \
--attributes Key="routing.http.request.x_amzn_tls_cipher_suite.header_name",Value=<CUSTOM_NAME>

% aws elbv2 modify-listener-attributes \
--listener-arn <ARN> \
--attributes Key="routing.http.request.x_amzn_tls_version.header_name",Value=<CUSTOM_NAME>

再度 EC2 でHTTPリクエストのヘッダを確認します。

# tcpdump port 80 -nn -A
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enX0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
08:34:40.807808 IP 10.0.0.144.48328 > 10.0.1.84.80: Flags [S], seq 1561100707, win 26883, options [mss 8961,sackOK,TS val 75192062 ecr 0,nop,wscale 8], length 0
E..<M?@.....
...
..T...P].........i.......#....
.{V.........
08:34:40.807836 IP 10.0.1.84.80 > 10.0.0.144.48328: Flags [S.], seq 2632830354, ack 1561100708, win 62643, options [mss 8961,sackOK,TS val 3891975492 ecr 75192062,nop,wscale 7], length 0
E..<..@.....
..T
....P......].............#....
...D.{V.....
08:34:40.809681 IP 10.0.0.144.48328 > 10.0.1.84.80: Flags [.], ack 1, win 106, options [nop,nop,TS val 75192064 ecr 3891975492], length 0
E..4M@@.....
...
..T...P]..........jAj.....
.{W....D
08:34:40.809681 IP 10.0.0.144.48328 > 10.0.1.84.80: Flags [P.], seq 1:297, ack 1, win 106, options [nop,nop,TS val 75192064 ecr 3891975492], length 296: HTTP: HEAD / HTTP/1.1
E..\MA@....w
...
..T...P]..........j.......
.{W....DHEAD / HTTP/1.1
Custom-tls-cipher-suite: TLS_AES_128_GCM_SHA256
Custom-tls-version: TLSv1.3
X-Forwarded-For: 192.0.2.1
X-Forwarded-Proto: https
X-Forwarded-Port: 443
Host: example.com
X-Amzn-Trace-Id: Root=1-67fcc8a0-562601054d6a3d754dc3bfbc
user-agent: curl/8.7.1
accept: */*

それぞれ Custom-tls-cipher-suiteCustom-tls-version にヘッダーが変更されていることが確認できました。

応答ヘッダーの追加

HSTS(Strict-Transport-Security)CORS(Cross Origin Resource Sharing)CSP(Content Security Policy)のセキュリティ関連の応答ヘッダーを追加することで、アプリケーションのセキュリティを強化できます。

設定可能なヘッダーのリストと概要は公式ドキュメントで確認できます。

Application Load Balancer の HTTP ヘッダーの変更 - エラスティックロードバランシング

中でも、HSTSヘッダー(Strict-Transport-Security) はHTTP→HTTPS接続を強制させるためのレスポンスヘッダーで、ブラウザ内のキャッシュ内に保存され、次回以降の通信をHTTPSに強制できます。
ALB によるSSL化対策は、リスナールールによるリダイレクト(301 Permanently moved)がありますが、リダイレクトではHTTP接続自体は毎回発生するため、MITM(中間者攻撃)などへの対策として万全ではありませんでした。
HSTSを実装することでHTTP接続の機会を減らすことができます。
Webサイトでは積極的に機能実装を行っておきたいところですが、ALB単体ではHSTSのカスタムヘッダーの追加はサポートされていませんでした。

これまでは CloudFront のレスポンスヘッダーポリシーを使って同じことができましたが、ALB だけで実現できるようになって良いですね。

試してみます。

HTTP Strict Transport Security (HSTS) ヘッダーを追加 のスイッチをオンにして、max-age=31536000 (1年間)に設定します。
これで1年間の有効期限に設定された Strict-Transport-Security のレスポンスヘッダーがクライアントのブラウザに返され、サイトへの接続が常にHTTPSとなるように強制できます。

vscode-paste-1744639130668-xovj02lpf8a.jpeg

CLIで設定したい場合は、以下のように設定できます。

aws elbv2 modify-listener-attributes \
--listener-arn <ARN> \
—attributes "routing.http.response.strict_transport_security.header_value",Value="max-age=<time_in_sec>;<includeSubdomains>;<preload>;"

ブラウザのキャッシュとして保存されるので、ブラウザを使って確認します。

http://www.example.com のようにHTTPプロトコルでChromeからアクセスし、Developer Tools で確認してみます。
Strict-Transport-Security 以外のキャッシュ要素がテストに影響を及ぼすため Developer Tools の設定の Disable Cache にチェックを入れています。)
しかし、そのまま http のサイトにアクセスされ、レスポンスヘッダーは返ってきていませんでした。

vscode-paste-1744640752009-4mj07inzd9.png

次に https://www.example.com のようにHTTPSプロトコルでChromeからアクセスし、Developer Tools で確認してみます。

Strict-Transport-Security が返ってきました。

vscode-paste-1744641659961-d4b1gqz7r1i.png

これらの動作の違いは、RFC 6797 に記載されているように、HTTPプロトコルではSTSヘッダーを返してはいけないとなっているからだと思われます。

An HSTS Host MUST NOT include the STS header field in HTTP responses conveyed over non-secure transport.
RFC 6797 - HTTP Strict Transport Security (HSTS)

HSTSヘッダーがChromeにキャッシュされたので、もう一度 http://www.example.com のようにHTTPプロトコルでアクセスしてみます。

最初にHTTPリクエストが発生していますが、307 Internal Redirect となっています。
これは実際の通信は外に出ていかず、ブラウザの内部的にリダイレクト処理が発生している状態です。

vscode-paste-1744643637307-0ub4fo5qbuu.png

そのままHTTPSリクエストが発生し、200 OK のステータスとなっています。
HSTSの設定が効いているようです。

vscode-paste-1744643769697-efaw4wewfmn.png

つまり、前提として、一度はHTTPSサイトにアクセスしたことがある場合に、以降のアクセスをHTTPSサイトに強制します。
一度もHTTPSサイトにアクセスしたことがない状態でのHTTPアクセスをセキュアにしたいという時には、preload が有効です。
また、サブドメインを全てHTTPSサイトに強制すること(includeSubDomains)も可能です。

これらの詳細はStrict-Transport-Security - HTTP | MDNで確認いただけます。

ALB での実際の設定の時はヘッダーの値として max-age=31536000; includeSubDomains; preload のように設定すればOKです。

ただ、これらの設定の注意点として、以下の点は前もって検討が必要です。

  • サブドメイン全てがHTTPSサイトに対応していてHTTPサイトを利用していないこと
  • プリロードの申請・解除に時間がかかる
  • 特に、後から影響が分かり解除したくなることが無いように事前に確認

プリロードの申請は、HSTS Preload List Submission から可能です。

ALB サーバー応答ヘッダー

リスナールールを利用して、リダイレクト処理や固定レスポンスを返す設定している場合、ALBから server:awselb/2.0 のレスポンスヘッダーが返される仕様となっています。
セキュリティ監査などで、ソフトウェアのバージョンを非表示にするなどの対策を求められることがあるかもしれません。
そういった場合、server:awselb/2.0 のレスポンスヘッダーが返らないように削除できます。

これまでは、先ほどと同様CloudFrontのレスポンスポリシーでヘッダーを削除可能でしたが、ALBだけで実現できて良いですね。

まず最初にリスナーのルールで全ての通信で固定レスポンスを返すように設定します。

vscode-paste-1744675614375-vf8yqvbbspk.png

クライアントから curl でアクセステストします。

% curl -I https://www.example.com
HTTP/2 503
server: awselb/2.0
date: Tue, 15 Apr 2025 00:03:13 GMT
content-type: text/plain; charset=utf-8
content-length: 18
strict-transport-security: max-age=31536000

503が返されるようになり、server: awselb/2.0 となりました。

次に、ALB サーバー応答ヘッダー のスイッチをオフにします。
再度、curl でアクセステストします。

% curl -I https://www.example.com
HTTP/2 503
date: Tue, 15 Apr 2025 00:09:16 GMT
content-type: text/plain; charset=utf-8
content-length: 18
strict-transport-security: max-age=31536000

server: awselb/2.0 のレスポンスヘッダーがなくなりました。

CLIで設定したい場合は以下のように設定が可能です。

aws elbv2 modify-listener-attributes \
--listener-arn <ARN> \
--attributes Key="routing.http.response.server.enabled",Value=false

参考文献

Elastic Load Balancing アプリケーションロードバランサー
Application Load Balancer の HTTP ヘッダーの変更 - エラスティックロードバランシング

AWS CLI Command Reference (albv2)
elbv2 — AWS CLI 1.38.33 Command Reference

まとめ

マイナーなアップデートではありますが、これまでもユーザーからよく要望があった機能のようです。
特定の条件で仕様上諦めざるをえなかった要件など、カバーできる範囲が広くなって素敵ですね。
この記事がどなたかの一助になれば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.