paperclipで画像をアップロードしてた場合、S3に移行するのは簡単。paperclipはDB内にファイルのパスを持ってるわけじゃないので、サーバーファイルシステム上の画像を全部S3にコピーした上でアプリの設定を変えれば良い。

# Gemfile:
gem 'paperclip'
gem 'aws-s3'
gem 'aws-sdk'
# config/initializers/paperlicp.rb:
if Rails.env.production?       
  Paperclip::Attachment.default_options.update(
    storage: :s3,              
    s3_credentials: "#{Rails.root}/config/s3.yml",
    s3_host_alias: Settings.cdn_host,
    path: ":class/:id/:attachment/:style",
    url: ':s3_alias_url'
  )   
end
# config/s3.yml:
production:
  bucket: kowabana-jp
  access_key_id: xxx
  secret_access_key: xxx
  s3_host_name: s3-ap-northeast-1.amazonaws.com

development:
  bucket: bucket_name
  access_key_id: xxx
  secret_access_key: xxx
  s3_host_name: s3-ap-northeast-1.amazonaws.com

test:
  bucket: bucket_name
  access_key_id: xxx
  secret_access_key: xxx
  s3_host_name: s3-ap-northeast-1.amazonaws.com

modelのhas_attached_fileに渡すオプションが環境毎に違ってたりする場合はinitializers以下に書いた方がスッキリする。productionでだけS3(ここではCloudFrontを使うのもの一緒にやってます)にする場合は上記。(staging環境で何か動かす時にもS3に影響が出ちゃうので注意する)

S3を触っています。S3に独自のユーザー管理の仕組みを組み込む方法がわからず困ってます。(@junyaさんや@yagi_さんに色々教えてもらいました。ありがとうございます。)

例えば、Webサービスを作ったとして、そのサービスのアカウント毎にS3に領域を作ってファイルにアクセスさせたい場合に、そのサービス経由でファイルをダウンロードしては不必要なトラフィックが発生してしまうのでS3から直接ダウンロードして欲しいハズです。

PROXY的な手法は使えないのでS3自身にユーザーを作成したり、そのユーザー毎に権限を設定したりが可能である必要があります。

S3の認証方法は色々あるんですが、Webサービスのユーザーと同期させるような大量ユーザーを想定のものは無いっぽいです。(もしあればホント教えて欲しいです・・・)

色々な認証方法:

  • Access Credentials
    • Access Keys --- 大量に発行できない
    • X.509 certificates --- エンドユーザーに使わせるのは無理
    • Key Pairs --- エンドユーザーに使わせるのは無理
  • Sign-In Credentials --- AWSユーザー登録必要
  • Multi-Factor Authentication --- セキュリティを高めるためだけ
  • Account Identifiers --- AWSユーザー登録必要。Sign-In Credentialsとどう違うんだ。
  • IAM --- 5000ユーザーまで。

今Preview Beta中のIAM(Identity and Access Management)という仕組みもユーザー数は最大5000となっていて、企業内とか開発者とかのアクセス権限を細かく設定するための仕組みっぽいです。

そこで気になっていたのがHeroku PG Backupsでdumpファイルのダウンロード方法が期限付きのS3のURLになってた仕組みです。ちょっとわかり辛いんですが、"Query String Authentication"とか"Signed URLs"とかでググると出てきます。

require 'aws/s3'

AWS::S3::Base.establish_connection!(
  :access_key_id => 'XXXXXXXXXXXXXX',
  :secret_access_key => 'XXXXXXXXXXXXXXXXXX')
puts AWS::S3::S3Object.url_for(
  'foo.jpg',
  'my-bucket-name',
  :expires_in => 60 * 10)
http://s3.amazonaws.com/my-bucket-name/foo.jpg?AWSAccessKeyId=xxxxxxxx&Expires=1293402048&Signature=xxxxxxxx

aws-s3だとurl_forというメソッドで認証済みのURLが簡単に取得できます。Signatureの生成方法はちゃんと見てないんですが、このオブジェクトだけに通用するSignatureなので前述したような"独自のユーザー管理を使いつつS3から直接ダウンロードさせたい"という場合に使えそうです。

しかし、ダウンロードはこれでいいとしてもアップロードの方はどうすればいいんでしょう。根本的な解決にはなってない気がします。せいぜい、アップロード専用の制限されたアカウントでアップロードして、別アカウントからmoveするぐらいしか思いつきません・・・。