はじめに
前回では、「AWS Budgets」のアラートをSNS経由でSlackに通知する仕組みを構築しました。これでコスト管理の自動化体制が整いました。
インフラの運用フェーズでは、コスト管理と同じくらい重要な課題があります。それがセキュリティと監査です。AWSアカウント内で「誰が・いつ・何を操作したか」を記録して監視することは、以下の課題に対応するために必要です。
- 予期しないリソース変更が起きた場合、その変更を誰が実施したかを特定できない
- セキュリティインシデント発生時、どのような操作が実施されたかを調査できない
- コンプライアンス監査で、操作ログの提出を求められても対応できない
本記事では「AWS CloudTrail」を使ってAWSアカウント上のすべてのAPI操作を記録し、CloudWatch Logsと連携させて不審な操作を自動検知する仕組みを構築します。
AWS CloudTrailとは
AWS CloudTrailは、AWSアカウント内のすべてのAPI呼び出しを記録するサービスです。ユーザーがコンソール、CLI、SDK、またはAWS管理サービスを通じて実施した操作がイベントとして記録されます。
CloudTrailが記録する主な要素は以下のとおりです。
- イベントソース: どのサービスで操作が実施されたか(EC2、S3、IAMなど)
- 操作(アクション): 実施された具体的な操作(例:StartInstances、PutObject)
- 呼び出し元: 操作を実施したユーザー、IAMロール、またはAWSサービス
- タイムスタンプ: 操作が実施された日時
- リクエスト・レスポンスパラメータ: 操作の詳細情報
CloudTrailには90日間のイベント履歴がデフォルトで有効化されており、コンソールから確認できます。ただし、長期保存が必要な場合は証跡(Trail)を作成し、ログをS3バケットに保存する必要があります。
CloudTrail証跡の作成
証跡とは
「証跡」はAPIイベントをS3バケットに継続的に記録する設定です。証跡を作成することで、90日を超えて操作ログを保存・分析できます。
S3バケットの作成
まず、CloudTrailのログを保存するS3バケットを作成します。本連載で構築してきたterraform/environments/dev/main.tfに以下のコードを追加します。
# terraform/environments/dev/main.tf
resource "aws_s3_bucket" "cloudtrail_logs" {
bucket = "cloudtrail-logs-${data.aws_caller_identity.current.account_id}"
}
resource "aws_s3_bucket_versioning" "cloudtrail_logs" {
bucket = aws_s3_bucket.cloudtrail_logs.id
versioning_configuration {
status = "Enabled"
}
}
# CloudTrailがバケットに書き込み可能なポリシー
resource "aws_s3_bucket_policy" "cloudtrail_logs" {
bucket = aws_s3_bucket.cloudtrail_logs.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AWSCloudTrailAclCheck"
Effect = "Allow"
Principal = {
Service = "cloudtrail.amazonaws.com"
}
Action = "s3:GetBucketAcl"
Resource = aws_s3_bucket.cloudtrail_logs.arn
},
{
Sid = "AWSCloudTrailWrite"
Effect = "Allow"
Principal = {
Service = "cloudtrail.amazonaws.com"
}
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.cloudtrail_logs.arn}/*"
Condition = {
StringEquals = {
"s3:x-amz-acl" = "bucket-owner-full-control"
}
}
}
]
})
}
data "aws_caller_identity" "current" {}CloudTrail証跡の作成
次に、CloudTrail証跡を作成します。is_multi_region_trail = trueを設定することで、すべてのリージョンのAPI操作を記録できます。同じくmain.tfに追加します。
# terraform/environments/dev/main.tf
resource "aws_cloudtrail" "main" {
name = "organization-trail"
s3_bucket_name = aws_s3_bucket.cloudtrail_logs.id
include_global_service_events = true
is_multi_region_trail = true
enable_log_file_validation = true
# CloudWatch Logsへのログ送信設定
cloud_watch_logs_group_arn = "${aws_cloudwatch_log_group.cloudtrail_logs.arn}:*"
cloud_watch_logs_role_arn = aws_iam_role.cloudtrail_cloudwatch_logs.arn
depends_on = [
aws_s3_bucket_policy.cloudtrail_logs,
aws_iam_role_policy.cloudtrail_cloudwatch_logs
]
# 管理イベント(API操作)を記録
event_selector {
read_write_type = "All"
include_management_events = true
}
}enable_log_file_validation = trueを設定すると、CloudTrailがログファイルのダイジェストを作成し、ログが改ざんされていないことを検証できます。
terraform applyを実行して証跡を作成すると、AWSアカウント内のすべてのAPI操作がS3に記録されるようになります。
イベント履歴の確認
CloudTrailコンソールでイベント履歴を閲覧
CloudTrailコンソールを開き、左側メニューから「イベント履歴」をクリックすると、過去90日間のイベント一覧が表示されます。
マルチリージョン証跡で記録されたイベントを確認するには、AWSマネジメントコンソール右上のリージョンセレクターで確認対象リージョンを変更してください。rootユーザーのコンソールログインイベント(ConsoleLogin)は米国東部(バージニア北部、us-east-1)に記録されるため、そのリージョンに変更してからイベント履歴を確認します。
イベント一覧には各操作のタイムスタンプ、ユーザー、イベント名、リソースが表示されます。任意のイベントをクリックして詳細情報(リクエストパラメータ、レスポンスパラメータ)を確認できます。
フィルタリングで特定の操作を検索
イベント履歴は、以下の条件でフィルターできます。
- ユーザー名: 特定のIAMユーザー、ロール、またはrootアカウントで実施した操作
- イベント名: StartInstances、CreateBucketなど具体的な操作
- リソースタイプ: EC2、S3、RDSなど特定サービスのリソース
- リソースID: 特定のインスタンスID、バケット名など
例えば、今回terraform applyで作成したCloudTrailリソースがどのように記録されているか確認したい場合を考えます。複数のCreateイベント(CreateTrail、CreateBucket、CreateLogGroupなど)とリソースタイプ(CloudTrail、S3、CloudWatch Logsなど)を確認する必要があります。
CloudTrailのフィルター機能では複数値を同時検索できないため、各イベント名またはリソースタイプで個別にフィルター検索します。例えば、「CreateTrail」でフィルターするとCloudTrail証跡の作成イベントだけが表示されます。
任意のイベントをクリックすると、リクエストパラメータやレスポンスパラメータなど詳細情報を確認できます。
CloudWatch Logsとの連携で監視を自動化
90日間の手動確認では運用コストが高いため、CloudWatch Logsに証跡を送信して自動監視を設定します。
CloudWatch Logsへのログ送信設定
CloudWatch LogsグループとIAMロールを作成し、CloudTrailがログを送信するよう設定します。main.tfに以下を追加します。
# terraform/environments/dev/main.tf
resource "aws_cloudwatch_log_group" "cloudtrail_logs" {
name = "/aws/cloudtrail/organization"
retention_in_days = 30
}
resource "aws_iam_role" "cloudtrail_cloudwatch_logs" {
name = "cloudtrail-cloudwatch-logs-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "cloudtrail.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy" "cloudtrail_cloudwatch_logs" {
name = "cloudtrail-cloudwatch-logs-policy"
role = aws_iam_role.cloudtrail_cloudwatch_logs.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = "${aws_cloudwatch_log_group.cloudtrail_logs.arn}:*"
}]
})
}不審な操作を検知するメトリクスフィルター
CloudWatch Logsメトリクスフィルターを使うと、特定のパターンのイベントを検出してメトリクスに変換できます。例えば、rootアカウントでのログインを検知する設定は以下のとおりです。rootのコンソールログインイベント(ConsoleLogin)は米国東部(バージニア北部、us-east-1)に記録されます。
main.tfに追加します。
# terraform/environments/dev/main.tf
# rootアカウントのログイン検知
resource "aws_cloudwatch_log_metric_filter" "root_account_login" {
name = "RootAccountLogin"
log_group_name = aws_cloudwatch_log_group.cloudtrail_logs.name
pattern = "{ $.userIdentity.type = \"Root\" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != \"AwsServiceEvent\" }"
metric_transformation {
name = "RootAccountLoginCount"
namespace = "CloudTrailMetrics"
value = "1"
}
}
# rootログインのアラーム
resource "aws_cloudwatch_metric_alarm" "root_account_login" {
alarm_name = "RootAccountLogin"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "1"
metric_name = "RootAccountLoginCount"
namespace = "CloudTrailMetrics"
period = "300"
statistic = "Sum"
threshold = "1"
alarm_description = "Alert when root account login is detected"
alarm_actions = [aws_sns_topic.security_alerts.arn]
}
resource "aws_sns_topic" "security_alerts" {
name = "security-alerts"
}このメトリクスフィルターは、rootアカウントがコンソールやAPIを通じてログインするたびに検知し、CloudWatch Logsメトリクスをインクリメントします。アラームがトリガーされるとSNS経由で通知を送信します。
rootのコンソールログインイベント(ConsoleLogin)はCloudTrailで米国東部(バージニア北部、us-east-1)に記録されます。CloudTrailコンソールでこのイベントを確認するには、AWSマネジメントコンソール右上のリージョンセレクターをus-east-1に変更してからイベント履歴を検索します。
定期的なコンプライアンスチェック
CloudTrailログから定期的にコンプライアンスレポートを生成することで、監査に備えることができます。S3に保存されたログはAWSアテナ(Athena)でSQL検索できます。
SELECT eventtime, useridentity.principalid, eventname, sourceipaddress
FROM cloudtrail_logs
WHERE eventname IN ('DeleteBucket', 'DeleteObject', 'StopInstances')
AND eventtime >= '2026-05-01'
ORDER BY eventtime DESC;このクエリで過去30日間に実施された危険度の高い操作(削除操作など)を一覧化できます。月次または四半期ごとにこのレポートを確認することで、運用上の問題を早期に検出できます。
おわりに
本記事では、AWS CloudTrailを使ってAWSアカウント上の操作ログを記録し、監視体制を構築しました。
CloudTrail証跡によるS3への長期保存で、90日を超えるログの保持が可能になりました。CloudWatch Logsとメトリクスフィルターの組み合わせにより、rootアカウントのログインなど不審な操作を自動検知できるようになりました。
本記事で紹介したメトリクスフィルターはCloudTrailの活用例の1つです。rootログイン検知の場合、CloudWatch Logsでの自動検知の他に「AWS Personal Health Dashboard」や「Notifications Center」でも検知できます。CloudTrailの強みは、こうした重要イベントだけでなく、予期しないリソース変更やオペレーターのミスなど、様々な異常な動きを「誰が・いつ・何をしたか」という記録を通じて把握できることです。監視通知と合わせて、CloudTrailのイベント履歴を定期的に確認することで、セキュリティと運用の両面から対応できます。
本シリーズを通じて、以下の運用体制が完成しました。
- 可視化: Cost Explorerでコストを可視化(第23回)
- アラート: CloudWatch Alarmsでインフラ状態を監視、SNS経由でSlackに通知(第20回・第24回)
- 監査ログ: CloudTrailで操作ログを記録・監視(本記事)
これにより、AWSインフラのコスト・パフォーマンス・セキュリティの3面から運用できる基盤が整いました。
次回(第26回)は、「AWS Security Hub」と「GuardDuty」を活用して、セキュリティ脅威を自動検知する仕組みについて解説します。
- この記事のキーワード
