【S3】Web アクセス制限いろいろ (CloudFront もあるよ)

一般公開

だれでもアクセス可のバケットポリシーをバケットへ設定すれば良い。

{
    "Version": "2008-10-17",
    "Id": "AccessRestriction",
    "Statement": [
        {
            "Sid": "PublicAccess",
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Principal": {
                "AWS": "*"
            },
            "Resource": "arn:aws:s3:::<your_bucket_name>/public/*"
        }
    ]
}

IP 制限

特定ネットワーク限定アクセス許可のバケットポリシーをバケットへ設定すれば良い。

{
    "Version": "2008-10-17",
    "Id": "AccessRestriction",
    "Statement": [
        {
            "Sid": "IPRestriction",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your_bucket_name>/intranet/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "xxx.xxx.xxx.xxx/32"
                }
            }
        }
    ]
}

特定 CloudFront ディストリビューション限定に対する公開

下記を組み合わせて制限。

  • ビューアーと CloudFront 間の制限: CloudFront の Behavior 設定にて、署名付き URL 、もしくは署名付き Cookie 限定のアクセス許可設定を施してアクセス制限
  • CloudFront と S3 オリジン間の制限: CloudFront の オリジンアクセスアイデンティティ (OAI) 設定と S3 のバケットポリシーの組み合わせにより、CloudFront に対して限定的に S3 へのアクセスを許可

参考: 署名付き URL と署名付き Cookie を使用してプライベートコンテンツを供給する – Amazon CloudFront

CloudFront の OAI 作成

OAI は、特定 CloudFront ディストリビューション限定のアクセス許可を設定する際に、CloudFront ディストリビューションを識別するための ID。

マネジメントコンソールの CloudFront 画面から作成できる。
要はただの名前なので、その作成画面はすごくあっさり。

CloudFront の Origin 設定

  • Restrict Bucket Access: Yes
  • Origin Access Identity: Use an Existing Identity
    • Create a New Identity で自動作成しても良い
  • Your Identities: 先に作成した OAI を指定
  • Grant Read Permissions on Bucket: Yes を選択すると、自動的に適切な S3 のバケットポリシーを設定してくれる

CloudFront の Behavior 設定

  • Restrict Viewer Access (Use Signed URLs or Signed Cookies): Yes
  • Trusted Signers: Self
    • 他の AWS アカウントの署名キーを使う場合は Specify Accounts を適宜設定

S3 のバケットポリシー設定

先程 Grant Read Permissions on Bucket = Yes とした場合、S3 バケットに下記のようなバケットポリシーが設定されているはず。

{
    "Version": "2008-10-17",
    "Id": "AccessRestriction",
    "Statement": [
        {
            "Sid": "OriginAccessIdentityForCloudFront",
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXXXXXX"
            },
            "Resource": "arn:aws:s3:::<your_bucket_name>/private/*"
        }
    ]
}

Resource 部分を調整して、特定パスだけ制限するなど調整可。

署名用の CloudFront キーペア作成

署名付きリクエストの署名を作る際に必要となるキー。

AWS のルートアカウントのみで作成できる。

忘れずにキー一式をダウンロード。

署名の作成

参考: 署名付き URL の署名を作成するためのコード例 – Amazon CloudFront

自分で頑張ってイチから作ることもできるが、AWS SDK を使うと手っ取り早い。

Node.js でカスタムポリシーを使った署名の例。
見ればわかるが、特定の URL パス配下に 1 日間だけ許可を与えるポリシーの署名。

署名付き Cookie の使用

参考: カスタムポリシーを使用した署名付き Cookie の設定 – Amazon CloudFront

Set-Cookie:
Domain=optional domain name;
Path=/optional directory path;
Secure;
HttpOnly;
CloudFront-Policy=base64 encoded version of the policy statement

Set-Cookie:
Domain=optional domain name;
Path=/optional directory path;
Secure;
HttpOnly;
CloudFront-Signature=hashed and signed version of the policy statement

Set-Cookie:
Domain=optional domain name;
Path=/optional directory path;
Secure;
HttpOnly;
CloudFront-Key-Pair-Id=active CloudFront key pair Id for the key pair that you are using to generate the signature

アプリケーションにて、こんな感じで 3 つの Cookie を食わせた状態で CloudFront へアクセスすれば良い。

ちなみに、API Gateway でやろうとすると複数のSet-Cookieを発行できない (厳密には、ダーティハック的な方法でできるといえばできるが……) ので詰む。

署名付き URL の使用

参考: カスタムポリシーを使用して署名付き URL を作成する – Amazon CloudFront

http://xxxxxxxxxxx.cloudfront.net/image.jpg?Policy=eyANCiA...Signature=nitfH...&Key-Pair-Id=APKA9...

こんな感じで URL のケツに署名をつけてあげれば良い。