「一時的セキュリティ認証情報」とは:
http://aws.amazon.com/jp/iam/faqs/#How_can_temporary_security_credentials_be_used_to_call_AWS_service_APIs
Q: 一時的セキュリティ認証情報とは何ですか?
一時的なセキュリティ認証情報は、アクセスキー ID、シークレットアクセスキー、およびセキュリティトークンで構成されています。これらは指定された期間と特定のアクセス許可一式に有効です。一時的なセキュリティ証明書は、単に「トークン」と呼ばれることがあります。トークンは、IAM ユーザー用に、または自身の社内ディレクトリで管理するフェデレーティッドユーザー用にリクエストすることができます。
準備
リソース作成
以下のリソースを、CloudFormationで作成する。
- アップロード先のS3バケット
- クレデンシャルを発行するIAMユーザー
sample.template
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Sample Template S3_Bucket and IAM_User for federation.",
"Resources" : {
"S3PrivateBucket" : {
"Type" : "AWS::S3::Bucket",
"Properties" : { "AccessControl" : "Private" }
},
"Publisher" : { "Type" : "AWS::IAM::User" },
"PublisherPolicy" : {
"Type" : "AWS::IAM::Policy",
"Properties" : {
"Users" : [ { "Ref" : "Publisher" } ],
"PolicyName" : "PublisherPolicy",
"PolicyDocument" : {
"Statement" : [
{
"Effect" : "Allow",
"Action" : [ "sts:GetFederationToken" ],
"Resource" : [ "*" ]
},
{
"Effect" : "Allow",
"Action" : [ "s3:PutObject" ],
"Resource" : [ "arn:aws:s3:::*" ]
}
]
}
}
},
"PublisherKeys" : {
"Type" : "AWS::IAM::AccessKey",
"Properties" : { "UserName" : { "Ref": "Publisher" } }
}
},
"Outputs" : {
"S3BucketName" : {
"Description" : "Name of S3 bucket",
"Value" : { "Ref" : "S3PrivateBucket" }
},
"AccessKey" : {
"Description" : "AWSAccessKeyId of new user",
"Value" : { "Ref" : "PublisherKeys" }
},
"SecretKey" : {
"Description" : "AWSSecretKey of new user",
"Value" : { "Fn::GetAtt" : ["PublisherKeys", "SecretAccessKey"]}
}
}
}
補足
IAMユーザー(Publisher)にもS3バケットへアップロード可能な権限が必要。
言い換えると、発行するトークンには発行者以上の操作権限を付与できない。
トークンの発行時にはエラーにならないので、ハマりやすいポイント。
実行結果
投稿
実際に投稿確認してみる。
サンプルコード
sample.rb
require 'logger'
require 'aws'
(file_path, bucket_name, object_key_prefix) = ARGV
unless file_path && bucket_name && object_key_prefix
puts "Usage: #{File.basename(__FILE__)} <FILE_PATH> <BUCKET_NAME> <OBJECT_KEY_PREFIX>"
exit 1
end
raise "File(#{file_path}) not found" unless File.exist?(file_path)
username = "TemporaryUser"
duration = 900
s3_arn = "arn:aws:s3:::#{bucket_name}/#{object_key_prefix}/*"
s3_object_key = File.basename(file_path)
AWS.config(logger: Logger.new($stdout))
upload_policy = AWS::STS::Policy.new {|policy| policy.allow( actions: ['s3:PutObject'], resources: s3_arn) }
upload_session = AWS::STS.new.new_federated_session(username, policy: upload_policy, duration: duration)
s3 = AWS::S3.new(upload_session.credentials.select {|k,v| [:access_key_id, :secret_access_key, :session_token].include?(k) })
bucket = s3.buckets[bucket_name]
raise 'Bucket not exists' unless bucket.exists?
# success
s3_object_key = "#{object_key_prefix}/" + File.basename(file_path)
bucket.objects[s3_object_key].write(file: file_path)
# deny path
s3_object_key = "deny_#{object_key_prefix}/" + File.basename(file_path)
bucket.objects[s3_object_key].write(file: file_path)
実行結果
$ ruby sample.rb upload_file s3bukect_name object_key_prefix
I, [2014-06-05T02:38:33.113917 #18497] INFO -- : [AWS STS 200 1.202314 0 retries] get_federation_token(:duration_seconds=>900,:name=>"TemporaryUser",:policy=>"{\"Version\":\"2008-10-17\",\"Statement\":[{\"Sid\":\"****\",\"Effect\":\"Allow\",\"Resource\":[\"arn:aws:s3:::s3bukect_name/object_key_prefix/*\"],\"Action\":[\"s3:PutObject\"]}]}")
I, [2014-06-05T02:38:34.012440 #18497] INFO -- : [AWS S3 200 0.149033 0 retries] put_object(:bucket_name=>"s3bukect_name",:content_length=>0,:data=>#<File:upload_file (0 bytes)>,:key=>"object_key_prefix/upload_file")
I, [2014-06-05T02:38:34.147673 #18497] INFO -- : [AWS S3 403 0.134181 0 retries] put_object(:bucket_name=>"s3bukect_name",:content_length=>0,:data=>#<File:upload_file (0 bytes)>,:key=>"deny_object_key_prefix/upload_file") AWS::S3::Errors::AccessDenied Access Denied