CloudTrailの証跡が存在しない場合の設定手順

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、CloudTrailの証跡が存在しない場合について、そのリスクと対策を解説します。

ポリシーの説明
まず、AWS Security Hubによるポリシーの説明は以下の通りです。
[CloudTrail.3] 少なくとも 1 つの CloudTrail 証跡を有効にする必要があります
CloudTrail の Security Hub コントロール – AWS Security Hub
このコントロールは、 でAWS CloudTrail 証跡が有効になっているかどうかを確認します AWSアカウント。アカウントに少なくとも 1 つの CloudTrail 追跡が有効になっていない場合、コントロールは失敗します。
リスクとしては、AWSアカウントで CloudTrail 証跡が有効になっていない場合、API コールやユーザーアクティビティの履歴が記録されず、セキュリティインシデントの検出や調査が困難になる可能性があります。これにより、コンプライアンス要件を満たさないリスクも生じます。
とのことですので、少なくとも 1 つの CloudTrail 証跡を有効にし、アカウント内のすべての API コールを記録することが望ましいです。これにより、セキュリティ分析や監査が容易になり、コンプライアンス要件を満たすことができます。
修復方法
AWSコンソールでの修正手順
① AWS CloudTrailに移動し、「証跡の作成」をクリック ② クイック証跡の作成で作成し、有効にします。

Terraformでの修復手順
# S3 bucket for CloudTrail logs
resource "aws_s3_bucket" "cloudtrail_logs" {
bucket = "your-organization-cloudtrail-logs-${data.aws_caller_identity.current.account_id}"
force_destroy = true
}
# S3 bucket policy
resource "aws_s3_bucket_policy" "cloudtrail_bucket_policy" {
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"
}
}
}
]
})
}
# Enable S3 bucket versioning
resource "aws_s3_bucket_versioning" "cloudtrail_bucket_versioning" {
bucket = aws_s3_bucket.cloudtrail_logs.id
versioning_configuration {
status = "Enabled"
}
}
# Enable S3 bucket encryption
resource "aws_s3_bucket_server_side_encryption_configuration" "cloudtrail_bucket_encryption" {
bucket = aws_s3_bucket.cloudtrail_logs.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
# KMS key for CloudTrail logs encryption
resource "aws_kms_key" "cloudtrail" {
description = "KMS key for CloudTrail logs encryption"
deletion_window_in_days = 7
enable_key_rotation = true
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
}
Action = "kms:*"
Resource = "*"
},
{
Sid = "Allow CloudTrail to encrypt logs"
Effect = "Allow"
Principal = {
Service = "cloudtrail.amazonaws.com"
}
Action = [
"kms:GenerateDataKey*",
"kms:Decrypt"
]
Resource = "*"
}
]
})
}
# Create CloudWatch log group for CloudTrail
resource "aws_cloudwatch_log_group" "cloudtrail_log_group" {
name = "/aws/cloudtrail/logs"
retention_in_days = 30
}
# IAM role for CloudTrail to CloudWatch Logs
resource "aws_iam_role" "cloudtrail_cloudwatch_role" {
name = "cloudtrail-cloudwatch-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "cloudtrail.amazonaws.com"
}
}
]
})
}
# IAM role policy for CloudTrail to CloudWatch Logs
resource "aws_iam_role_policy" "cloudtrail_cloudwatch_policy" {
name = "cloudtrail-cloudwatch-policy"
role = aws_iam_role.cloudtrail_cloudwatch_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = "${aws_cloudwatch_log_group.cloudtrail_log_group.arn}:*"
}
]
})
}
# Create CloudTrail
resource "aws_cloudtrail" "organization_trail" {
name = "organization-trail"
s3_bucket_name = aws_s3_bucket.cloudtrail_logs.id
include_global_service_events = true
is_multi_region_trail = true
enable_logging = true
kms_key_id = aws_kms_key.cloudtrail.arn
cloud_watch_logs_group_arn = "${aws_cloudwatch_log_group.cloudtrail_log_group.arn}:*"
cloud_watch_logs_role_arn = aws_iam_role.cloudtrail_cloudwatch_role.arn
event_selector {
read_write_type = "All"
include_management_events = true
}
depends_on = [
aws_s3_bucket_policy.cloudtrail_bucket_policy,
aws_s3_bucket_versioning.cloudtrail_bucket_versioning
]
}
# Get current account ID
data "aws_caller_identity" "current" {}
最後に
今回は、AWSアカウントで CloudTrail 証跡が有効になっていない場合のリスクとその対策についてご紹介しました。証跡が無効の場合、API コールやユーザーアクティビティの追跡ができず、セキュリティインシデントの検出や調査が困難になる可能性があります。設定を確認し、証跡が有効になっていない場合は、本記事を参考に修正してみてください。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。
運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。