その他
    ホーム 技術発信 DoRuby s3cmdでオブジェクトストレージのバケットにIP制限
    s3cmdでオブジェクトストレージのバケットにIP制限
     

    s3cmdでオブジェクトストレージのバケットにIP制限

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

    ‘aws-sdk’のようなgemを使用せずに、s3cmdコマンドを使用して s3のオブジェクトストレージバケットにIP制限を行ったのでメモ代わりに

    s3cmd設定

    ※事前にAWSのアカウント作成してください。

    $ yum -y --enablerepo epel install s3cmd
    $ s3cmd —-configure
    Access Key: xxxx
    Secret Key: xxxx
    (ほかは全てエンターのみでOK)
    

    s3cmd lsで一覧が表示されれば設定完了。
    接続できない場合はここら辺の設定を変えてください。

    $ vim ~/.s3cfg
    host_base = hedgehog
    host_bucket = tegetege
    signature_v2 = True
    
    

    バケットにポリシーが設定されていないことを確認。

    $ s3cmd info バケット名
       Location:  us-east-1
       Payer:     BucketOwner
       Expiration Rule: none
       policy:    none
       cors:      none
       ACL:       xxxx: FULL_CONTROL
    

    実践

    わかりやすいようにバケット名と制限IPのカラムを持つテーブルを用意。

    # Table name: hoges
    #  id                  :integer          not null, primary key
    #  bucket_name :string           not null
    #  limit_ips           :text     # json形式で保持
    #  created_at          :datetime         not null
    #  updated_at          :datetime         not null
    
    class Hoge < ActiveRecord::Base
      def parse_limit_ips
        limit_ips.present? ? JSON.parse(limit_ips) : []
      end
    
      def set_policy_to_bucket
        create_extract_dir
        open(json_tmp_path, 'w') do |io|
          io.puts(tmp_policy_format)
        end
        # s3cmdのsetpolicyオプションを使用して、対象バケットにポリシーを設定する
        `s3cmd setpolicy #{json_tmp_path} s3://#{bucket_name}`
        delete_extract_dir
      end
    
      private
    
      # policyファイルを保持するディレクトリを作成
      def create_extract_dir
        FileUtils.mkdir_p extract_dir
      end
    
      # ディレクトリ名
      def extract_dir
        File.join Rails.root, :tmp.to_s, :bucket_policy.to_s
      end
    
     # ファイルパス
      def json_tmp_path
        File.join extract_dir, 'policy.json'
      end
    
     # ディレクトリごと削除
      def delete_extract_dir
        FileUtils.rm_rf extract_dir
      end
    
      def tmp_policy_format
        <<-"EOS"
        {
          "Id": "#{SecureRandom.hex}",  # 任意の文字列
          "Statement": [
            {
              "Sid": "#{SecureRandom.hex}", # 任意の文字列
              "Action": ["s3:GetObject"],
              "Effect": “Deny”, # 指定した内容に対しアクセスを拒否する <=> Allow
              "Resource": "arn:aws:s3:::#{bucket_name}/*”,
              "Condition": {
                “NotIpAddress": {  # 以下に含まれるIP以外
                  "aws:SourceIp": #{parse_limit_ips}
                }
              },
              "Principal": {
                "AWS": ["*"]
              }
            }
          ]
        }
        EOS
      end
    end
    

    Allowだとなぜか効かない…。なのでDenyとNotIpAddressの組み合わせにしました。
    (原因は不明。他記事にもAllowは効かなかったという記載がちらほら)

    注意点

    • Resourceオプションはダウンロード時とアップロード時によって若干異なる。 上記のコードはダウンロード時のポリシー設定の内容ですが、アップロード時は少し異なります。
    "Action": ["s3:PutObject”, “s3:PutObjectAcl”],
    .
    .
    "Resource": [
      “arn:aws:s3:::#{bucket_name}”,
      “arn:aws:s3:::#{bucket_name}/*”
    ]
    .
    .
    

    Actionはオブジェクトストレージにファイル(Object)を置くのでPut。
    Resourceはバケット自体の記載も必要みたいです。(記載がないと403 or 404)

    • SourceIPに設定できるIPの表記方法はCIDRフォーマット
    可
    123.123.234.123
    123.213.234.21/24
    
    不可
    123.231.23.*
    

    反映確認/ポリシー解除

    バケットにポリシーが設定されているか
    $ s3cmd info バケット名

    ポリシーをデフォルトに戻す
    $ s3cmd delpolicy s3://<バケット名>