GuardDutyの有効化手順

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、ルートアカウント使用制限の方法について解説します。この記事では、GuardDutyが有効化されていない状態について、そのリスクと対策を解説します。

ポリシーの説明
まず、AWS Security Hubによるポリシーの説明は以下の通りです。
GuardDuty の Security Hub コントロール – AWS Security Hub
リスクとしては、Amazon GuardDuty が無効になっている場合、不正なアクティビティやセキュリティ脅威をリアルタイムで検出できず、潜在的な攻撃や侵害を見逃す可能性があります。これにより、セキュリティインシデントの早期発見と対応が遅れ、被害が拡大するリスクがあります。
とのことですので、すべての AWS リージョンで GuardDuty を有効にすることが望ましいです。これにより、各リージョンでの不正なアクティビティやセキュリティ脅威を検出し、迅速に対応することが可能となります。
修復方法
単一アカウントであれば、GuardDutyの有効化及び通知などの設定を適切に行なっていくことになります。
AWS Organizations環境の場合であれば、組織的に有効にする必要があるためそれぞれの修復手順について以下にまとめます。
単一アカウントでの有効化手順
AWS コンソールでの修復手順
① GuardDutyに移動し「GuardDutyを有効にする」をクリック

Terraformでの修復手順
# Enable GuardDuty
resource "aws_guardduty_detector" "main" {
enable = true
datasources {
s3_logs {
enable = true
}
kubernetes {
audit_logs {
enable = true
}
}
malware_protection {
scan_ec2_instance_with_findings {
ebs_volumes {
enable = true
}
}
}
}
}
# Create an S3 bucket for GuardDuty findings
resource "aws_s3_bucket" "guardduty_findings" {
bucket = "guardduty-findings-${data.aws_caller_identity.current.account_id}"
force_destroy = true
}
# Create a KMS key for encrypting GuardDuty findings
resource "aws_kms_key" "guardduty_key" {
description = "KMS key for GuardDuty findings"
deletion_window_in_days = 7
enable_key_rotation = true
}
# Configure GuardDuty to publish findings to S3
resource "aws_guardduty_publishing_destination" "s3" {
detector_id = aws_guardduty_detector.main.id
destination_arn = aws_s3_bucket.guardduty_findings.arn
destination_type = "S3"
kms_key_arn = aws_kms_key.guardduty_key.arn
}
# Create an SNS topic for GuardDuty notifications
resource "aws_sns_topic" "guardduty_findings" {
name = "guardduty-findings-topic"
}
# Create an S3 event notification to SNS
resource "aws_s3_bucket_notification" "bucket_notification" {
bucket = aws_s3_bucket.guardduty_findings.id
topic {
topic_arn = aws_sns_topic.guardduty_findings.arn
events = ["s3:ObjectCreated:*"]
}
}
# Create an SNS topic policy
resource "aws_sns_topic_policy" "default" {
arn = aws_sns_topic.guardduty_findings.arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Allow S3 to publish to SNS topic"
Effect = "Allow"
Principal = {
Service = "s3.amazonaws.com"
}
Action = "SNS:Publish"
Resource = aws_sns_topic.guardduty_findings.arn
Condition = {
ArnLike = {
"aws:SourceArn" = aws_s3_bucket.guardduty_findings.arn
}
}
},
]
})
}
# Ensure CloudTrail is enabled for GuardDuty to function optimally
resource "aws_cloudtrail" "main" {
name = "guardduty-cloudtrail"
s3_bucket_name = aws_s3_bucket.cloudtrail.id
include_global_service_events = true
is_multi_region_trail = true
enable_logging = true
}
# S3 bucket for CloudTrail logs
resource "aws_s3_bucket" "cloudtrail" {
bucket = "guardduty-cloudtrail-logs-${data.aws_caller_identity.current.account_id}"
force_destroy = true
}
# S3 bucket policy for CloudTrail
resource "aws_s3_bucket_policy" "cloudtrail" {
bucket = aws_s3_bucket.cloudtrail.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.arn
},
{
Sid = "AWSCloudTrailWrite"
Effect = "Allow"
Principal = {
Service = "cloudtrail.amazonaws.com"
}
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.cloudtrail.arn}/*"
Condition = {
StringEquals = {
"s3:x-amz-acl" = "bucket-owner-full-control"
}
}
}
]
})
}
# Get current account ID
data "aws_caller_identity" "current" {}
AWS Organizations環境での有効化手順
こちらのほうがより一般的かなと思います。複数アカウントで運用するケースにおいてはOrganizationから設定したほうが楽だと思いますのでサンプルのTerraformを以下に記します。
Terraformでの修復手順
provider "aws" {
region = "ap-northeast-1" # Change this to your desired region
alias = "management"
}
# Configure the AWS Provider for the delegated admin account
provider "aws" {
region = "ap-northeast-1" # Change this to your desired region
alias = "security"
assume_role {
role_arn = "arn:aws:iam::${var.security_account_id}:role/OrganizationAccountAccessRole"
}
}
variable "security_account_id" {
description = "The account ID of the security account to be used as GuardDuty delegated admin"
type = string
}
# Enable GuardDuty in the management account
resource "aws_guardduty_organization_admin_account" "main" {
provider = aws.management
admin_account_id = var.security_account_id
}
# Enable GuardDuty in the delegated admin account
resource "aws_guardduty_detector" "security" {
provider = aws.security
enable = true
datasources {
s3_logs {
enable = true
}
kubernetes {
audit_logs {
enable = true
}
}
malware_protection {
scan_ec2_instance_with_findings {
ebs_volumes {
enable = true
}
}
}
}
depends_on = [aws_guardduty_organization_admin_account.main]
}
# Enable GuardDuty for the organization
resource "aws_guardduty_organization_configuration" "main" {
provider = aws.security
auto_enable = true
detector_id = aws_guardduty_detector.security.id
datasources {
s3_logs {
auto_enable = true
}
kubernetes {
audit_logs {
enable = true
}
}
malware_protection {
scan_ec2_instance_with_findings {
ebs_volumes {
auto_enable = true
}
}
}
}
}
# Create an S3 bucket for GuardDuty findings
resource "aws_s3_bucket" "guardduty_findings" {
provider = aws.security
bucket = "org-guardduty-findings-${data.aws_caller_identity.security.account_id}"
force_destroy = true
}
# Create a KMS key for encrypting GuardDuty findings
resource "aws_kms_key" "guardduty_key" {
provider = aws.security
description = "KMS key for GuardDuty findings"
deletion_window_in_days = 7
enable_key_rotation = true
}
# Configure GuardDuty to publish findings to S3
resource "aws_guardduty_publishing_destination" "s3" {
provider = aws.security
detector_id = aws_guardduty_detector.security.id
destination_arn = aws_s3_bucket.guardduty_findings.arn
destination_type = "S3"
kms_key_arn = aws_kms_key.guardduty_key.arn
}
# Create an SNS topic for GuardDuty notifications
resource "aws_sns_topic" "guardduty_findings" {
provider = aws.security
name = "org-guardduty-findings-topic"
}
# Create an S3 event notification to SNS
resource "aws_s3_bucket_notification" "bucket_notification" {
provider = aws.security
bucket = aws_s3_bucket.guardduty_findings.id
topic {
topic_arn = aws_sns_topic.guardduty_findings.arn
events = ["s3:ObjectCreated:*"]
}
}
# Create an SNS topic policy
resource "aws_sns_topic_policy" "default" {
provider = aws.security
arn = aws_sns_topic.guardduty_findings.arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Allow S3 to publish to SNS topic"
Effect = "Allow"
Principal = {
Service = "s3.amazonaws.com"
}
Action = "SNS:Publish"
Resource = aws_sns_topic.guardduty_findings.arn
Condition = {
ArnLike = {
"aws:SourceArn" = aws_s3_bucket.guardduty_findings.arn
}
}
},
]
})
}
# Get current account ID for the security account
data "aws_caller_identity" "security" {
provider = aws.security
}
最後に
今回は、Amazon GuardDuty を有効にしていない場合のリスクとその対策についてご紹介しました。GuardDuty が無効になっていると、不正なアクティビティやセキュリティ脅威の検出が困難になり、セキュリティインシデントの早期発見と対応が遅れる可能性があります。設定を確認し、GuardDuty が有効になっていない場合は、本記事を参考に修正してみてください。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。
運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。