この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。望月です。 先日(といっても結構前ですが)、ついに待望のCloudTrailの全リージョン対応が発表されました。 その前からそうだったかは未調査ですが、CloudTrailを有効にしていない場合に、AWSのTrusted Advisorで警告が出るようになりました。
この警告を消すためにも、全リージョンでCloudTrailを有効にしましょう!
スクリプト化してみた
ですが、手作業でぽちぽちやるのはアレなので、自動化しました。既にj3tm0t0さんがAWS - 全リージョンのCloudTrailロギングを有効にするワンライナー - Qiitaにてワンライナーを公開されていますので、そちらを使うのもいいと思います。このワンライナーではS3バケットと適切なBucket Policyが設定されていることが大前提なので、まだBucketを作成していないアカウントでは、先にS3バケットを公式ドキュメントに従って作成しておく必要があります。
そんなに大変な作業ではないのですが、それすら面倒臭がる私のような人向けにS3バケットの作成とBucket Policyの設定まで一発でやってくれるスクリプトを書いてみました。
ソースはGistにもあげてあります。
#!/usr/bin/env ruby
# Activate Cloudtrail and create S3 Bucket in each region.
# Usage: ./activate.rb --profile <profile_name>
# or
# Usage: ./activate.rb -k <access_key> -s <secret_key>
require 'aws-sdk-v1'
require 'optparse'
# get account ID from yourself ARN.
# even if you have no permission to IAM, you can get your account ID from error message
# because it contains IAM User ARN.
def get_account_id
iam = AWS::IAM::Client.new
begin
iam.get_user.user.arn =~ /arn:aws:iam::(\d{12}):user\/.*/
rescue => e
e.message =~ /arn:aws:iam::(\d{12}):user\/.*/
end
# return 12 digits account number
# if failed, raise RuntimeError
if $1.nil?
raise RuntimeError
end
$1
end
# Set Bucket Policy for CloudTrail
# Ref : https://docs.aws.amazon.com/awscloudtrail/latest/userguide/create_trail_bucket_policy.html
def cloudtrail_bucket_policy bucket_name, account_id
policy_hash = {
"Version" => "2012-10-17",
"Statement" => [
{
"Sid" => "AWSCloudTrailAclCheck20131101",
"Effect" => "Allow",
"Principal" => {
"AWS" => [
"arn:aws:iam::903692715234:root",
"arn:aws:iam::859597730677:root",
"arn:aws:iam::814480443879:root",
"arn:aws:iam::216624486486:root",
"arn:aws:iam::086441151436:root",
"arn:aws:iam::388731089494:root",
"arn:aws:iam::284668455005:root",
"arn:aws:iam::113285607260:root",
"arn:aws:iam::035351147821:root"
]
},
"Action" => "s3:GetBucketAcl",
"Resource" => "arn:aws:s3:::#{bucket_name}"
},
{
"Sid" => "AWSCloudTrailWrite20131101",
"Effect" => "Allow",
"Principal" => {
"AWS" => [
"arn:aws:iam::903692715234:root",
"arn:aws:iam::859597730677:root",
"arn:aws:iam::814480443879:root",
"arn:aws:iam::216624486486:root",
"arn:aws:iam::086441151436:root",
"arn:aws:iam::388731089494:root",
"arn:aws:iam::284668455005:root",
"arn:aws:iam::113285607260:root",
"arn:aws:iam::035351147821:root"
]
},
"Action" => "s3:PutObject",
"Resource" => "arn:aws:s3:::#{bucket_name}/AWSLogs/#{account_id}/*",
"Condition" => {
"StringEquals" => {
"s3:x-amz-acl" => "bucket-owner-full-control"
}
}
}
]
}
AWS::S3::Policy.from_json(policy_hash.to_json)
end
ARGV.options do |opt|
begin
aws_opts = {}
is_debug = false
opt.on('-h', '--help') { puts opt.help; exit 0 }
opt.on('-k', '--access-key ACCESS_KEY') { |v| aws_opts[:access_key_id] = v }
opt.on('-s', '--secret-key SECRET_KEY') { |v| aws_opts[:secret_access_key] = v }
opt.on('--debug') { is_debug = true }
opt.on('--profile PROFILE') { |v| aws_opts[:credential_provider] = AWS::Core::CredentialProviders::SharedCredentialFileProvider.new(profile_name: v) }
opt.parse!
if aws_opts.empty?
puts opt.help
exit 1
end
if is_debug
aws_opts[:logger] = Logger.new($stdout)
aws_opts[:log_level] = :debug
end
AWS.config(aws_opts)
rescue => e
$stderr.puts e
exit 1
end
end
account_id = get_account_id
AWS.regions.each do |region|
AWS.config(region: region.name)
ct = AWS::CloudTrail::Client.new
# Skip if CloudTrail is already enabled in current region
unless ct.describe_trails.data[:trail_list].count == 0
puts "CloudTrail is already activated in #{region.name}. Skipping this region."
next
end
s3 = AWS::S3.new
bucket_name = "cloudtrail-#{region.name}-#{account_id}"
begin
unless s3.buckets[bucket_name].exists?
s3.buckets.create(bucket_name)
puts "Created S3 Bucket #{bucket_name}"
s3.buckets[bucket_name].policy = cloudtrail_bucket_policy(bucket_name, account_id)
puts "Successfully Attached S3 Bucket Policy"
else
puts "S3 bucket #{bucket_name} already exists."
end
option = {
:name => 'Default',
:s3_bucket_name => bucket_name,
:s3_key_prefix => '',
:include_global_service_events => false,
}
option[:include_global_service_events] = true if region.name == "ap-northeast-1"
ct.create_trail(option)
ct.start_logging({:name => "Default"})
puts "Successfully enabled trailing in #{region.name}"
rescue => e
$stderr.puts e.message
next
end
end
スクリプトを実行した後、もう一度Trusted Advisorを確認してみましょう。
緑色になりました!これで一安心ですね。