Amazon S3 でパブリックアクセスできるスクリプトを公開する

AWS CloudFormation で環境構築を自動化しているのだが、EC2 インスタンス内の設定を自動化するには CloudFormation では無理。自動化用スクリプトをつくっといて、これをインスタンスから実行させる必要がある。

※UserData はデバッグしづらいのでいったん除く。

今回は「Amazon S3 にスクリをアップ」して、これを「インスタンスから curl などでゲット」というやり方を試してみた。まともに S3 を使ったのはじめてなので、S3 についてまとめておく。

データ構造

「バケット」という入れ物の中に「ファイル」と「フォルダ」を入れる感じ。

※ファイルは AWS では「オブジェクト」と呼ばれる。

URL

https://(バケット名).s3-(リージョン).amazonaws.com/(パス)

つくる

バケットをつくる

  • バケット名はグローバルで一意
  • デフォでは index.html の補完は効かない
    • static website hosting を有効する必要アリ

ファイルを入れる

管理コンソールの「アップロード」から。D&D アップロードもできて便利。

  • アクセス権
    • パブリックにしたいなら「このオブジェクトにパブリック読み取りアクセス権限を付与する」を選択
    • 別にここで選択しなくても良い(あとで変更できる 下記参照)
  • ストレージクラス
    • スタンダードでいい
    • 他の選択肢は「安くなるけどアクセス遅い」系で普段使い用ではない

URL は各ファイルページの概要タブに表示される。

フォルダをつくる

管理コンソールの「フォルダの作成」ボタンから。

パブリックアクセスを実現するためのアクセス権

パブリックアクセスを実現するための付け方。

  • バケット
    • アクセス権限 > ブロックパブリックアクセス
    • パブリックアクセスをすべてブロック以下を 全部オフ
  • ファイル
    • アクセス権限 > パブリックアクセス
    • Everyone の「オブジェクトの読み取り」を はい

つまりバケットのフル解放とファイル単位の読み取りオンが必要。

アップしたスクリプトを EC2 から使う

NAT や Internet Gateway などでインターネットを見に行ける Linux の EC2 インスタンスがあるとしたら。

たとえば curl で、こんな感じで使える。

$ curl "https://(BucketName).s3-(RegionName).amazonaws.com/(Filename.Ext)" -o "Filename.Ext"
$ chmod 775 Filename.Ext
$ ./Filename.Ext

既にアップロードしたファイルの CRUD

削除したい

→ 管理コンソールから当該ファイルを選択して、概要 > アクション > 削除

内容を変更したい

→ 同名で再度アップロードすれば良い。

別名にリネームしたい

→ リネーム前ファイルを削除し、リネーム後ファイルをアップロード。

アクセス時の挙動

URL にアクセスした時の挙動。ここでは Firefox を使用。

バケットが見つからない場合:

  • XML で返される
    • NoSuchBucket
    • The specified bucket does not exist

バケットは存在するが、ファイルが存在しない or アクセス許可が無い場合:

  • XML で返される
    • AccessDenied

バケットが存在し、ファイルも存在して、アクセス許可がある場合:

  • 当該ファイルが RAW リンクで返される

運用時の懸念など

Q: 料金はどのくらい?

Ans: 詳しく調べてない

ただ個人やチームの評価・省力化目的で「自動化用スクリをアップしといて、EC2 から curl でダウンロードして使う」程度なら誤差の範囲内。

料金が何百円何千年と牙をむく規模は、ウェブサイト運用や MB 単位のデータを月何千何万リクエストするとか、そういうレベルみたい?

Q: DDoS が怖いのでガードしたいんですが?

DDoS で GET リクエスト大量に食らえばエグい料金請求されるんじゃないかという懸念。

Ans: 二通りあると思われる。

1つ目は CloudFront を使う方法。利用者側の利用の仕方を S3 URL 直アクセスではなく、CloudFront 経由にさせる。設定は煩雑そうなので割愛する(よく調べてないし)が、どうも S3 に対する細かい制御がしたいなら「CloudFront というラッパー?入り口?を立ててそっちで色々やれ」という感じみたい。

2つ目は運用回避だが、使ってない時は「バケットのパブリックアクセスをオフにする」こと。バケット自体をオフにしちゃえば、その中のファイルは全部アクセスできなくなる。いちいちオフにするのは面倒だが、EC2 インスタンスも使ってない時は電源オフにするし、そういうものなのかな。

Q: 特定 EC2 インスタンスからのみアクセス可能にするには?

Ans: S3のバケットポリシーを使うっぽい

詳しくは S3のバケットポリシーでハマったので、S3へのアクセスを許可するPrincipalの設定を整理する | Developers.IO を。

どうも「AWS アカウント ID」と「IAM ユーザー」の二つが必要みたい。この二つがあれば、バケットに以下バケットポリシーを設定することで、

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::(アカウントID):user/(IAM ユーザー名)"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}"
        }
    ]
}

指定アクション(ここでは ListBucket)を許可できる。なんか Principal の書き方がハマりどころみたい?

おわりに

簡単に試してみたが、使いやすくて良い感じ。かなり大雑把なので間違い等あったらぜひ教えて下さい!

今回は画面ベースだったが、省力化したいなら AWS CLI や REST API が使えるだろう。

実運用については、細かいアクセス管理とお金の面をもっとちゃんと調べて考える必要がありそうか。追々。