EC2 で作った LAMP 環境 + Application Load Balancer で常時 SSL を実現しようとした際に、 http → https のリダイレクトがループしてしまったときの対処方法です。

前提

  • SSL証明書はAWSのCertificate Managerで取得
  • 取得したSSL証明書は、 ELB (Application Load Balancer) で使用

詰まった点

単純にhttp→httpsリダイレクトをすると無限ループに陥る

常時SSLにするためには、httphttps のリダイレクトが必要ですが、上記の前提で実現しようとするとこのリダイレクトが無限ループとなってしまいます。

AWSのELBを使用している場合、クライアントからサーバ(EC2インスタンス)へのアクセスの間にELBが入ります。 ここで注意が必要なのが、ELBからEC2への通信はhttpだということです。 つまり、クライアントがhttpsでアクセスしていても、ELBからEC2への通信はhttpとなります。その結果、Apache(EC2)でプロトコルのチェックをしても常にhttp通信だということになります。 そのため、「httpならhttpsへリダイレクト」という条件が無限ループとなってしまうわけです。

これを回避するため、常時SSLにしたいディレクトリの.htaccessは下記のように記述します。

RewriteEngine On

RewriteCond %{HTTP_USER_AGENT} !^ELB-HealthChecker
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteRule ^/?(.*) https://%{HTTP_HOST}/$1 [R=301,L]

この記述では、以下の条件に当てはまる場合はhttpsでリダイレクトする という記述です。 1. RewriteCond %{HTTP_USER_AGENT} !^ELB-HealthChecker ユーザーエージェントがELB-HealthCheckerから始まらない 2. RewriteCond %{HTTPS} !=on 通信プロトコルがhttpsではない 3. RewriteCond %{HTTP:X-Forwarded-Proto} !=https HTTPヘッダーX-Forwarded-Proto の値が httpsではない

1については後ほど書きます。

2, 3が常時SSLに関わる部分です。 特に3つ目の条件は、AWSでELBを使用してhttps通信を実現する際の回避策としては必須となっているようです。(現状では) HTTPヘッダーX-Forwarded-Protoは、ELBからEC2へ通信する際に付与されるヘッダー情報で、クライアントからELBへの通信がhttpだった場合のみ、httpという値になる というものです。 この値を判定して、httpsへのリダイレクトを実現します。

(2はELBを通している以上、不要?かもしれません)

ELBのヘルスチェックがエラーになる

単純にhttphttpsのリダイレクトを実現するためには前項の2, 3のみでよいのですが、その状態で運用しているとELBのヘルスチェックがエラーとなってしまいます。

ELBのヘルスチェックとは、定期的にELBからEC2に通信を行い、返ってくるレスポンスコードによって正常かどうかを判定しています。 ヘルスチェックでは、返ってくるコードが200以外の場合はエラーとするようです。 前項で書いた1の条件が無いと、ヘルスチェックのための通信もhttphttpsリダイレクトされ、ELBに返すコードとしては301になってしまいます。

1は、これを回避するためにアクセス元のUserAgentを見て「ヘルスチェックの際のUserAgentであるELB-HealthCheckerの場合はリダイレクトをしない」という記述になります。

参考URL


以上、よっしー (michimani) でした。

Share to ...

0

Follow on Feedly

comments powered by Disqus