シナリオ
- コンテンツは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分ぐらいかかると思います
参考ページ: 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 エラーページを設定
アクセスできなかった場合に表示するエラーページを設定します
CloudFrontキーペア設定
下記ページの手順通り、ルートユーザーでログインし、CloudFrontキーペアを作成します
- ダウンロードしたプライベートキーファイルを教材ディレクトリへコピーします
設定ファイル記述
sample_settings.json
を settings.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をバージョン付きで設定します
- CloudFront Event
LambdaFunctionの設定部分はLambda側の画面からも操作可能です
設定すると、またCloudFrontはデプロイを始めるので、完了するまで待ちます
動作確認
直接アクセス
- アクセスできません
正規入り口からアクセス
https://***.cloudfront.net/enter へアクセスするとページが表示されます
Cookieも来ています
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使えない、環境変数使えない等
- 長時間かかる処理は避けるべきとは思います