【AWS】CloudFrontで署名付きURLの設定方法（プライベートコンテンツの配信）

## 導入
CloudFrontでプライベートコンテンツを配信する場合、署名付きURLを発行する必要性がある。
署名付きURLを発行することによって、下記のことを設定することが出来る。

- URLに期限をつけることが出来る。
- URLを知っているだけではアクセス出来ない。

また、CloudFrontで署名付きURLを発行するためには、2つの方法がある。

1. CloudFrontキーペアを使用する方法
2. 信頼されたキーグループを使用した方法

1の方法は、以前から存在していたが、
CloudFrontキーペアを作成するにあたって、AWSのrootユーザーを使用しなければならないということもあり、現在は **非推奨** の方法となっている。

2の方法は、最近追加された方法で、
CloudFrontのAPIを使用すれば、キーペアの作成やローテーションの自動化をすることができ、AWSのrootユーザーを使用せずに（IAMユーザーで）使用することが可能となっている。

今回は、2の方法を使用し署名付きURLを発行してみる。

## キーペアの作成
1. 公開・秘密鍵の作成
2. CloudFrontに公開鍵のアップロード
3. CloudFrontキーグループに公開鍵の追加

### 1. 公開・秘密鍵の作成
```shell
# 2048ビット長のRSAキーペアをprivate_key.pemという名称で保存
$ openssl genrsa -out private_key.pem 2048

# private_key.pemから公開鍵をpublic_key.pemという名称で出力
$ openssl rsa -pubout -in private_key.pem -out public_key.pem

# 公開鍵の登録で使用するのでクリップボードにコピー
$ cat public_key.pem | pbcopy
```

次から、AWSのコンソールで操作します。

### 2. CloudFrontに公開鍵のアップロード
CloudFrontのパブリックキーページにアクセスし、「Add public key」をクリック。
https://console.aws.amazon.com/cloudfront/home#publickey:

Key name：任意の名称
Key value：public_key.pemの内容
Comment：コメント（任意）

### 3. CloudFrontキーグループに公開鍵の追加
CloudFrontのキーグループページにアクセス、「Add key group」をクリック。
https://console.aws.amazon.com/cloudfront/home#kgconfig:

Key group name：任意の名称（識別子として使用される）
Comment：コメント（任意）
Public keys：先程追加した、公開鍵を選択肢、「Add」をクリック。

## CloudFront DistributionsにSignerの追加
これで、URLを署名するために必要なキーペアを作成できたので、
次はそれをCloudFrontに適用させる。

適用させるには、
1. 適用させるCloudFrontのDistributionを選択
2.  Behaviorの編集で、閲覧者アクセスの制限の設定

### 1. 適用させるCloudFrontのDistributionを選択
![cloudfront.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120764/34f2da6f-4ddd-e3e1-48f5-04b82af39e61.png)

### 2. Behaviorの編集で、閲覧者アクセスの制限の設定
「Behaviors」タブから適用させたいBehaviorsを選択し、「Edit」をクリック。
下記、項目の選択をする。

項目 | 選択
--------- | ---------
Restrict Viewer Access | Yes
Trusted Key Group or Trusted Signer | Trusted Key Group
Trusted Key Groups | 作成したキーグループを選択し「Add」

※ オレンジ色で囲まれた部分

![behaviors.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120764/cc04b3be-0114-37fa-f5ec-e2fe72c937dc.png)

## 検証
1. 署名なしで、アクセス
2. 署名ありで、有効期限内にアクセス
3. 署名ありで、有効期限外でアクセス

### 署名付きURLの生成
```shell
$ aws cloudfront sign \
--url https://xxxx.cloudfront.net/index.html \
--key-pair-id K3XXXXXXXXXXXX \
--private-key file://PATH/TO/YOUR/private_key.pem \
--date-less-than 2020-11-18T19:30:00+09:00
```

※ AWS CLIを使用して作成している。
※ 他にもIPアドレス制限や有効開始時刻の設定などのオプションがある。
※ 詳しくは ↓
[CloudFront Command Reference](https://docs.aws.amazon.com/cli/latest/reference/cloudfront/sign.html)


### 1. 署名なしで、アクセス
エラーになった。

```shell
$ curl https://xxxx.cloudfront.net/index.html
<?xml version="1.0" encoding="UTF-8"?><Error><Code>MissingKey</Code><Message>Missing Key-Pair-Id query parameter or cookie value</Message></Error>
```

### 2. 署名ありで、有効期限内にアクセス
アクセス出来た。

```shell
$ curl https://xxxx.cloudfront.net/index.html?Expires=XXXX&Signature=XXXX&Key-Pair-Id=XXXX
index
```

### 3. 署名ありで、有効期限外でアクセス
アクセスが拒否された。

```shell
$ curl https://xxxx.cloudfront.net/index.html?Expires=XXXX&Signature=XXXX&Key-Pair-Id=XXXX
<?xml version="1.0" encoding="UTF-8"?><Error><Code>AccessDenied</Code><Message>Access denied</Message></Error>
```

## 補足
キーペア（公開鍵と秘密鍵）
秘密鍵：URLやCookieを署名
公開鍵：署名の検証

## 参考
- [Specifying the signers that can create signed URLs and signed cookies](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html)
- [[アップデート] root ユーザー作業が不要に！Amazon CloudFront で署名付き URL/Cookie 向け公開鍵を IAM ユーザー権限で管理できるようになりました。](https://dev.classmethod.jp/articles/cloudfront-iam-signed-url/)

## 関連
[【Rails】CloudFrontの署名付きURLの作成方法](https://qiita.com/may-solty/items/1bfa6a9e9d50e8b615e1)