AWS CloudTrail ログを1つのAWSアカウントに集約する
こんにちは、インフラストラクチャー部の沼沢です。
複数の AWS アカウントを運用していると、それぞれのアカウントの S3 バケットに CloudTrail のログが溜まっていきますが、そのログ、1箇所に集約して監視や可視化をしたくはありませんか?
そこで今回は、複数の AWS アカウント上にそれぞれ保存されている CloudTrail ログを集約・可視化する仕組みについてです。
構成図
① CloudTrail が S3 にログを Put したのをトリガーに、集約先に用意している Lambda を起動
② Lambda から S3 へログを取りに行く(Roleで権限委譲して取得)
③ Lambda でログファイルを展開し、内容を無加工で CloudWatch Logs に投入
④ CloudWatch Logs からストリーミングで Elasticsearch Service にログを流す
では、これを構築する手順を解説していきます。
構築手順
- 000000000000 は A環境(集約元)の AWS アカウント ID で読み替えましょう
- 999999999999 は B環境(集約先)の AWS アカウント ID で読み替えましょう
- 今回は東京リージョン(ap-northeast-1)に構築することを前提としています
- ② に関しては某ブログの会社の「S3保管したCloudTrailログに別アカウントのLambdaからアクセスする」を大いに参考にしています
B環境に Elasticsearch Service のドメイン作成
- AccessPolicy ↓
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:ap-northeast-1:999999999999:domain/<設定したドメイン名>/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "xxx.xxx.xxx.xxx/32"
}
}
}
]
}
- Condition -> IpAddress で、Kibana へのアクセスを xxx.xxx.xxx.xxx のみに制限
- AccessPolicy 以外は全て任意に設定
B環境に CloudWatch Logs のロググループ作成
- ロググループ名: 任意のロググループ名
- ログストリーム名: 任意のログストリーム名
- 作成したロググループにチェックを入れ、以下の通り設定
- アクションから「Amazon Elasticsearch Service へのストリーミングの開始」を選択
- Amazon ES クラスター: ↑で作成した Elasticsearch Service のドメインを指定
- ログの形式: AWS CloudTrail
A環境で権限委譲用の IAM ロール/カスタムポリシーを作成
- 以下の条件でカスタムポリシーを作成
- ポリシー名: 任意
- ポリシーJSON ↓
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": "arn:aws:s3:::<CloudTrailのログ出力先のバケット名>/*"
}
]
}
- 以下の条件でロールを作成
- ロール名: 任意
- ロールタイプ: クロスアカウントアクセスのロール -> 所有している AWS アカウント間のアクセスを提供します
- アカウントID: 999999999999
- ポリシー
- ↑で作成したカスタムポリシー
B環境の Lambda 用の IAM ロール/カスタムポリシーを作成
- 以下の条件でカスタムポリシーを作成
- ポリシー名: 任意
- ポリシーJSON ↓
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Resource": [
"*"
]
}
]
}
- 以下の条件でロールを作成
- ロール名: 任意
- ロールタイプ: AWS サービスロール -> AWS Lambda
- ポリシー
- ↑で作成したカスタムポリシー
- AmazonS3FullAccess ※バケットを絞るなどは適宜行ってください
- AWSLambdaExecute
B環境に Lambda ファンクション作成
- ファンクション名: 任意
- Runtime: Python2.7
- Handler: lambda_function.handler
- Role: B環境に作成した Lambda 用の IAM ロール
- Timeout: 10 sec
- ソースコードはこちら
作成されたファンクションの ARN のメモを取っておきましょう
A環境の S3 バケットから B環境の Lambda を実行するための権限を Lambda に付与する
2016年09月現在、ManagementConsole からではからこの設定ができないため、CLI で権限を付与
$ aws lambda add-permission \
--region ap-northeast-1 \
--function-name <対象のLambdaFunction名> \
--statement-id <任意で一意となるID> \
--principal s3.amazonaws.com \
--action lambda:InvokeFunction \
--source-arn arn:aws:s3:::<CloudTrailのログ出力先のバケット名> \
--source-account 000000000000
A環境の CloudTrail 用 S3 バケットにイベント登録
- 対象のバケットを選択し、プロパティを表示
- イベント -> 「通知の追加」 -> 以下を入力/選択して「保存」
- 名前: 任意
- イベント: Put
- 送信先: Lambda 関数
- Lambda 関数の ARN を追加
- Lambda 関数の ARN: 作成したB環境の Lambda ファンクションの ARN
CloudTrail のログが複数のバケットにある場合は必要な分だけ上記を登録
まとめ
上記の設定が完了すると、S3 に CloudTrail のログが出力される度に Lambda が起動し、CloudWatch Logs を経由して Elasticsearch にログが放り込まれることになります。
あとは、Elasticsearch の Kibana の URL にアクセスし、好きに閲覧してみてください。
なお、途中に CloudWatch Logs を経由していますので、ここでログ監視を入れることも可能です。
また、今回は簡単に可視化を実現するために Elasticsearch Service を利用しましたが、Elasticsearch Service では、構築時にディスクサイズを決める必要があるため、集約したい環境が増えていくと、ディスクが足りなくなる可能性があります。
可視化部分を自分で実装する手間をかけられるのであれば、Lambda から DynamoDB にログを放り込んで、可視化部分を自力で実装するようにすれば、ディスクサイズを気にしなくて済みますね。
この構成をもとに、いろいろアレンジしてみてください。
