こちらからの転載です。
最近
ギョームで 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 というツールがありますので、今後はバケラッタを使っていきたいと思います。
[https://github.com/winebarrel/bukelatta:embed:cite]
Rake って
楽しいですね。