新規アカウントでもこれ一発!CloudTrailを全リージョンで有効化するスクリプトを書いた
こんにちは。望月です。 先日(といっても結構前ですが)、ついに待望の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を確認してみましょう。
緑色になりました!これで一安心ですね。