LoginSignup
2
1

More than 3 years have passed since last update.

ServerlessでCloudFrontプライベートWebサイトを提供する

Last updated at Posted at 2020-07-18

シナリオ

  • コンテンツはS3へアップロードし、CloudFront経由で配信します
  • 具体的には下記URLアクセスで参照できるようにします
  • ただし、アクセスするためには署名付きCookieが必要とします
  • Cookieなしの場合は閲覧できません

  • 下記URLへアクセスした場合は5分間有効な署名付きCookieを発行します
  • さらに、上記URLへリダイレクトします
  • つまり、このルートでのみコンテンツを参照できることになります

ポイント(何がしたかったのか)

  • 署名付きURLだと単一ファイル(コンテンツ)の応答しかできない
    • Webページの場合、1ファイルで構成するのは現実的ではない
  • 署名付きURLだとURLが長くなる
    • パラメータたくさんなのが美しくない
  • 動的に生成したい
    • 期限付きにしたい(ある程度コントロール可能にしておきたい)
    • しかし、署名用サーバーを設置するほど大げさにしたくはない

構成

自前構成のWebサーバーは設置せずに実現します

  • CloudFront
  • S3
  • LambdaEdge

教材ソース

これに沿った説明にします

$ git clone https://github.com/shinsaka/aws-cf-signedcookie.git
$ cd aws-cf-signedcookie

必要なもの

  • AWSアカウント
    • ルートユーザーでAWSコンソールへログインできる必要があります
  • 手元環境はLinux想定です(私はWSL Ubuntuで実行しています)
  • 教材を使う場合
    • githubへアクセス必要です
    • gitコマンドが必要です
  • 手順中でAWS CLIを使います(コンソールでも可)
  • Serverless FrameWork を使います
    • nodejsが必要になります

デプロイ

コンテンツをS3へアップロード

下記のような構成とします

/index.html
/403.html
/css/style.css

バケット作成してコンテンツをアップロードします

$ aws s3 mb s3://aws-cf-signedcookie-test
make_bucket: aws-cf-signedcookie-test
$ aws s3 sync www/ s3://aws-cf-signedcookie-test/
upload: www/403.html to s3://aws-cf-signedcookie-test/403.html
upload: www/index.html to s3://aws-cf-signedcookie-test/index.html
upload: www/css/style.css to s3://aws-cf-signedcookie-test/css/style.css

CloudFrontで配信設定

AWSコンソールからCloudFront→Distributionを作成します
署名付きCookieしたいので Restrict Viewer Access(Use Signed URLs or Signed Cookies) を Yesにするところがポイントです
Deployedまで10分~15分ぐらいかかると思います

image.png
image.png

参考ページ: CloudFrontの署名付きURLでS3にアクセスする方法
参考ページ: https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#private-content-creating-oai

CloudFront エラーページを設定

アクセスできなかった場合に表示するエラーページを設定します

image.png

CloudFrontキーペア設定

下記ページの手順通り、ルートユーザーでログインし、CloudFrontキーペアを作成します
- AWS マネジメントコンソールで CloudFront キーペアを作成するには

image.png

  • ダウンロードしたプライベートキーファイルを教材ディレクトリへコピーします

設定ファイル記述

sample_settings.jsonsettings.json というファイルにコピーして編集します

{
    "keypairId": "APKXXXXXXXXXXXXX",        キーペアIDです。プライベートキーファイル名と同じはずです
    "privatekeyFile": "pk-APKXXXXXXXXXXXXXXXXX.pem",    プライベートキーファイル名
    "resource": "https://dxxxxxxxxxxxxx.cloudfront.net/*"  デプロイしたCloudFront URL+* (署名付きCookieを保持している状態でアクセスできるパスになります)
}

Lambda Functionをデプロイする

  • (注意)この仕組みではプライベートキーファイルをLambda内にデプロイします
  • LambdaEdgeにするため、必ず us-east-1 へデプロイします(教材では serverless.ymlで指定してあります)
$ serverless deploy --pkfile pk-APKXXXXXXXXXXXXXXXXX.pem

CloudFront Behaviors作成

/enter というパスでアクセスされた場合にLambdaを動作させるための設定を行います

  • Path Pattern
    • /enter
  • Lambda Function Associations
    • CloudFront Event
      • Viewer Request
    • Lamda Function ARN
      • 上記でデプロイしたLambda関数のARNをバージョン付きで設定します

LambdaFunctionの設定部分はLambda側の画面からも操作可能です
設定すると、またCloudFrontはデプロイを始めるので、完了するまで待ちます

image.png

動作確認

直接アクセス

  • アクセスできません

image.png

正規入り口からアクセス

https://***.cloudfront.net/enter へアクセスするとページが表示されます

image.png

Cookieも来ています

image.png

5分経過後、リロードすると「アクセスできません」ページが表示されます

curlで確認

直接アクセス

  • 403エラー
$ curl -I https://dxxxxxxxxxxxxx.cloudfront.net/index.html
HTTP/2 403
content-type: text/html
content-length: 161
date: Sat, 18 Jul 2020 09:03:02 GMT
last-modified: Sat, 18 Jul 2020 07:13:32 GMT
etag: "6cadxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
accept-ranges: bytes
server: AmazonS3
x-cache: Error from cloudfront
via: 1.1 19069xxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT57-C1
x-amz-cf-id: 67Bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
age: 362

正規入り口からアクセス

  • Set-Cookie
  • 302リダイレクト
  • location: /index.html
$ curl -I --cookie-jar cookie.txt https://dxxxxxxxxxxxxx.cloudfront.net/enter
HTTP/2 302
content-length: 0
server: CloudFront
date: Sat, 18 Jul 2020 09:06:53 GMT
location: /index.html
set-cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0_; Path=/; Secure; HttpOnly
set-cookie: CloudFront-Key-Pair-Id=APKXXXXXXXXXXXXXXXXX; Path=/; Secure; HttpOnly
set-cookie: CloudFront-Signature=KxgiTZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX__; Path=/; Secure; HttpOnly
x-cache: LambdaGeneratedResponse from cloudfront
via: 1.1 adxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT57-C1
x-amz-cf-id: fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • cookie付きでリダイレクト先へアクセス
  • 200正常応答
$ curl -I --cookie cookie.txt https://dxxxxxxxxxxxxx.cloudfront.net/index.html
HTTP/2 200
content-type: text/html
content-length: 531
date: Sat, 18 Jul 2020 09:07:04 GMT
last-modified: Sat, 18 Jul 2020 07:13:33 GMT
etag: "fdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
accept-ranges: bytes
server: AmazonS3
x-cache: Miss from cloudfront
via: 1.1 axxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT57-C1
x-amz-cf-id: hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

まとめ

  • できるだけ簡単にするためにかなり手抜きしていますが、一応やりたいことは実現できたと思います
    • /enter で許可していますが、実際はユーザーごとの長めのハッシュ文字列を想定しています
  • LambdaEdgeは制限が多いのですが、別の(not Edge)Lambdaを実行することはできますので、他のサービスとAPI連携などすることはできそうですね
    • 5秒制限、Layers使えない、環境変数使えない等
    • 長時間かかる処理は避けるべきとは思います
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1