最近
ギョームで S3 バケットを更新する作業があったので、ほのぼの Rake タスクで汎用的に管理出来る感じにしてみました。
タスク
Rakefile
require 'aws-sdk' require 'diffy' require 'json' POLICY_DIR='policies/' def s3 Aws.config[:credentials] = Aws::SharedCredentials.new(profile_name: 'あなたのプロファイル') Aws::S3::Client.new(region: 'ap-northeast-1') end def get_bucket_policy(bucket) begin resp = s3.get_bucket_policy({ bucket: bucket }) JSON.parse(resp.policy.read) rescue JSON::ParserError => e puts e end end def open_policy_document(path) begin File.open(POLICY_DIR + path) do |file| JSON.load(file) end rescue JSON::ParserError => e puts e end end def valid_json?(json) begin JSON.parse(json) return true rescue JSON::ParserError => e return false end end namespace :s3 do namespace :policy do desc "S3 バケット policy を取得する" task :export, :bucket do |task, args| puts "#{args[:bucket]} の policy を取得します..." hash = get_bucket_policy(args[:bucket]) puts JSON.pretty_generate(hash) File.open(POLICY_DIR + args[:bucket], "w") do |f| f.puts(JSON.pretty_generate(hash)) end end desc "S3 バケット policy を表示する" task :view, :bucket do |task, args| puts "#{args[:bucket]} の policy を表示します..." hash = get_bucket_policy(args[:bucket]) puts JSON.pretty_generate(hash) end targets = [] Dir.glob(POLICY_DIR + '*').each do |file| target = File.basename(file) target = "_#{target}" if target == "default" targets << target end targets.each do |target| namespace target.to_sym do desc "S3 バケット #{target} の policy を変更する" task :update do resp = s3.put_bucket_policy({ bucket: "#{target}", policy: open_policy_document(target).to_json }) puts resp end desc "S3 バケット #{target} に適用する policy と既存のポリシーを比較する" task :diff do hash = get_bucket_policy(target) old = JSON.pretty_generate(hash) new = JSON.pretty_generate(open_policy_document(target)) puts Diffy::Diff.new(old, new).to_s(:color) end end end end end
使い方
- 初期状態の tasks
$ bundle exec rake -T rake s3:policy:export[bucket] # S3 バケット policy を取得する rake s3:policy:view[bucket] # S3 バケット policy を表示する
- バケットポリシーを export しましょう
$ mkdir policies $ bundle exec rake "s3:policy:export[hage.inokara.com]"
以下のように出力されます。
hage.inokara.com の policy を取得します... { "Version": "2008-10-17", "Statement": [ { "Sid": "AllowPublicRead", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::hage.inokara.com/*" } ] }
デフォルトではカレントディレクトリの policies というディレクトリ以下にバケット名と同じ名前のポリシーファイルが作成されています。
bash-3.2$ ls -l policies/ total 8 -rw-r--r-- 1 syorou staff 253 Nov 23 11:58 hage.inokara.com
tasks も確認しましょう。
bash-3.2$ bundle exec rake -T rake s3:policy:hage.inokara.com:diff # S3 バケット hage.inokara.com に適用する policy と既存のポリシーを比較する rake s3:policy:hage.inokara.com:update # S3 バケット hage.inokara.com の policy を変更する rake s3:policy:export[bucket] # S3 バケット policy を取得する rake s3:policy:view[bucket] # S3 バケット policy を表示する
- バケットポリシーを修正しましょう
bash-3.2$ vim policies/hage.inokara.com
ドキュメントを参考に IP アドレス制限をかけてみました。
{ "Version": "2008-10-17", "Statement": [ { "Sid": "AllowPublicRead", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::hage.inokara.com/*", "Condition": { "IpAddress": {"aws:SourceIp": "54.240.143.0/24"}, "NotIpAddress": {"aws:SourceIp": "54.240.143.188/32"} } } ] }
- 差分を確認しましょう
bash-3.2$ bundle exec rake s3:policy:hage.inokara.com:diff { "Version": "2008-10-17", "Statement": [ { "Sid": "AllowPublicRead", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", - "Resource": "arn:aws:s3:::hage.inokara.com/*" + "Resource": "arn:aws:s3:::hage.inokara.com/*", + "Condition": { + "IpAddress": { + "aws:SourceIp": "54.240.143.0/24" + }, + "NotIpAddress": { + "aws:SourceIp": "54.240.143.188/32" + } + } } ] } \ No newline at end of file
ちゃんと既存の設定との差分を表示してくれます。ありがたい。
- バケットポリシーをツッコミましょう
bash-3.2$ bundle exec rake s3:policy:hage.inokara.com:update #<struct Aws::S3::Types::EmptyStructure>
- 適用したポリシーを見てみましょう
bash-3.2$ bundle exec rake s3:policy:view[hage.inokara.com] hage.inokara.com の policy を表示します... { "Version": "2008-10-17", "Statement": [ { "Sid": "AllowPublicRead", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::hage.inokara.com/*", "Condition": { "NotIpAddress": { "aws:SourceIp": "54.240.143.188/32" }, "IpAddress": { "aws:SourceIp": "54.240.143.0/24" } } } ] }
最後に
バケラッタ
この Rake タスクを書き終わった後に気づきましたが、既に Codenize.tools の Bukelatta というツールがありますので、今後はバケラッタを使っていきたいと思います。
Rake って
楽しいですね。