GuardDutyログをS3クロスアカウントレプリケーションしてみた

KMS暗号化されたGuradDutyログを別アカウントへS3レプリケーションする設定を解説してみました
2022.10.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。ネクストモードの倉地です。
業務アプリケーションなどの用途で使用するシステムアカウントのGuardDutyログを、ログ集約アカウントのS3バケットへクロスアカウントレプリケーション設定を実施したのですが、権限周りの理解が難しく実装に苦労しました。今回はこちらを整理しながら技術検証しましたので、内容を共有できればと思います。

やりたいこと

  • GuardDutyからS3バケットへログを出力する (KMS暗号化が必要)
  • システムアカウント側S3バケットからログ集約アカウント側S3バケットへクロスアカウントレプリケーションをする
  • ログ集約アカウント側S3バケットに保存されたGuardDutyログが確認できれば成功

システムアカウント側 GuardDutyのログ出力設定

S3バケット作成

まずシステムアカウント側でGuardDutyログの出力先バケットを作成します。検証のため設定は基本的にデフォルトとしますが、S3レプリケーションをするためバージョニングのみ有効化します。
ここではバケット名をnm-system-account-bucketとします。

GuardDutyからのアクセスを許可するために、こちらのバケットポリシーを設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow GuardDuty to use the getBucketLocation operation",
            "Effect": "Allow",
            "Principal": {
                "Service": "guardduty.amazonaws.com"
            },
            "Action": "s3:GetBucketLocation",
            "Resource": "arn:aws:s3:::システムアカウント側S3バケット名"
        },
        {
            "Sid": "Allow GuardDuty to upload objects to the bucket",
            "Effect": "Allow",
            "Principal": {
                "Service": "guardduty.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::システムアカウント側S3バケット名/*"
        }
    ]
}

KMSキー作成

GuardDutyの仕様上、サーバーサイド暗号化するためにはKMSキーが必要になるため、システムアカウント側に作成します。ここではエイリアス名をnm-system-account-kmsとします。

設定は基本的にデフォルトとし、キーポリシーはGuardDutyからのアクセス権限を追加します。

{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-3",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::システムアカウントID:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "AllowGuardDutyKey",
            "Effect": "Allow",
            "Principal": {
                "Service": "guardduty.amazonaws.com"
            },
            "Action": "kms:GenerateDataKey",
            "Resource": "arn:aws:kms:ap-northeast-1:システムアカウントID:システムアカウント側KMSキーARN",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "システムアカウントID"
                }
            }
        }
    ]
}

GuardDutyのログ出力設定

GuardDutyは有効化している状態を前提としますが、S3バケットへのログ出力設定は「設定」の「検出結果のエクスポートオプション」項目から実施します。「今すぐ設定する」を押下し出力先のS3バケットを設定していきます。

S3バケットやKMSキーなどを選択していきます。KMSキーポリシーやS3バケットポリシーの記載に誤りがあるとエラーになりますのでご注意ください。

「保存」を押下し、バケット名が表示されたら成功です。

GuradDutyのログ出力を確認するために、「検出結果サンプルの生成」を押下します。

検出結果を見ると、このようにいくつかのサンプルが検出されていることがわかります。

GuardDutyのログが正常に出力されていることが確認できました。
念のためログファイルの中身を確認するために、アクションから「S3 Selectを使用したクエリ」を押下します。

入力設定と出力設定の形式を「JSON」に変更し、「SQLクエリの実行」を押下します。

エラーが出ることなくクエリ結果が表示されたら成功です。

ログ集約アカウント側 S3レプリケーション設定

続いてこの記事のテーマでもある、クロスアカウントのレプリケーション設定を実施します。

S3バケット作成

まずはレプリケーション先のS3バケットを作成します。検証のため設定は基本的にデフォルトとしますが、S3レプリケーションのためバージョニングのみ有効化します。
ここではバケット名をnm-log-account-bucketとします。

KMS作成

GuardDutyログをレプリケーション先のS3バケットで暗号化するために、ログ集約アカウント側にもKMSキー(nm-log-account-kms)を作成します。検証のため設定は基本的にデフォルトとします。

S3レプリケーション設定

システムアカウント側S3バケット(nm-system-account-bucket)からログ集約アカウント側S3バケット(nm-log-account-bucket)へのレプリケーション設定をします。設定はシステムアカウント側S3バケットの管理タブ→「レプリケーションルールを作成」から実施します。

ルールスコープはバケット内のすべてのオブジェクトとします。

送信先はログ集約アカウントのアカウントIDとS3バケット名を入力します。
また「オブジェクト所有者を送信先バケット所有者に変更」にチェックを入れます。

S3レプリケーション用のIAMロールは新規作成するため、「新しいロールの作成」を選択します。これにより自動的にIAMロールが作成されます

GuardDutyはKMSで暗号化されたオブジェクトになるので、暗号化は有効化し、「ソースオブジェクトを復号化するためのAWS KMSキー」でシステムアカウント側KMSキー(nm-system-account-kms)を選択します。
また「送信先オブジェクトを暗号化するためのAWS KMSキー」では、ログ集約アカウント側KMSキー(nm-log-account-kms)のARNを入力します。

以降の設定はデフォルトのままとして、保存を押下します。

保存を押下後にこのような画面が表示されますが、既存のオブジェクトはレプリケートしないため、下記の画像の通りに設定します。

自動作成されたIAMロール(s3crr_role_for_nm-system-account-bucket)に付与されたアクセスポリシーに、nm-system-account-kmsのDecrypt権限とnm-log-account-kmsのEncrypt権限が付与されていることを確認します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:ListBucket",
                "s3:GetReplicationConfiguration",
                "s3:GetObjectVersionForReplication",
                "s3:GetObjectVersionAcl",
                "s3:GetObjectVersionTagging",
                "s3:GetObjectRetention",
                "s3:GetObjectLegalHold"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::システムアカウント側S3バケット名",
                "arn:aws:s3:::システムアカウント側S3バケット名/*"
            ]
        },
        {
            "Action": [
                "s3:ReplicateObject",
                "s3:ReplicateDelete",
                "s3:ReplicateTags",
                "s3:GetObjectVersionTagging",
                "s3:ObjectOwnerOverrideToBucketOwner"
            ],
            "Effect": "Allow",
            "Condition": {
                "StringLikeIfExists": {
                    "s3:x-amz-server-side-encryption": [
                        "aws:kms",
                        "AES256"
                    ]
                }
            },
            "Resource": [
                "arn:aws:s3:::ログ集約アカウント側S3バケット名/*"
            ]
        },
        {
            "Action": [
                "kms:Decrypt"
            ],
            "Effect": "Allow",
            "Condition": {
                "StringLike": {
                    "kms:ViaService": "s3.ap-northeast-1.amazonaws.com",
                    "kms:EncryptionContext:aws:s3:arn": [
                        "arn:aws:s3:::システムアカウント側S3バケット名/*"
                    ]
                }
            },
            "Resource": [
                "arn:aws:kms:ap-northeast-1:システムアカウント側ID:key/システムアカウント側KMSキーID"
            ]
        },
        {
            "Action": [
                "kms:Encrypt"
            ],
            "Effect": "Allow",
            "Condition": {
                "StringLike": {
                    "kms:ViaService": [
                        "s3.ap-northeast-1.amazonaws.com"
                    ],
                    "kms:EncryptionContext:aws:s3:arn": [
                        "arn:aws:s3:::ログ集約アカウント側S3バケット名/*"
                    ]
                }
            },
            "Resource": [
                "arn:aws:kms:ap-northeast-1:ログ集約アカウント側ID:key/ログ集約アカウント側KMSキーID"
            ]
        }
    ]
}

ログ集約アカウント側S3バケット(nm-log-account-bucket)のバケットポリシーに、上記で自動作成されたIAMロールからのアクセスを許可するポリシーを追加します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::システムアカウント側ID:role/service-role/s3crr_role_for_システムアカウント側S3バケット名"
            },
            "Action": [
                "s3:ReplicateDelete",
                "s3:ReplicateObject"
            ],
            "Resource": "arn:aws:s3:::システムアカウント側S3バケット名/*"
        }
    ]
}

ログ集約アカウント側KMSキー(nm-log-account-kms)のキーポリシーでも、同じくIAMロールからのアクセスを許可します。

{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-3",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::ログ集約アカウント側ID:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::ログ集約アカウント側ID:role/service-role/s3crr_role_for_ログ集約アカウント側S3バケット名"
            },
            "Action": "kms:Encrypt",
            "Resource": "*"
        }
    ]
}

動作確認

ログ集約アカウント側のS3バケットにログがレプリケートされていることを確認します。

最後にログファイルの中身が確認できるか、S3 Selectで検証します。入力及び出力形式をJSONに変更して、「SQL クエリの実行」を押下します。
このようにログファイルの中身が見られたら成功です。

さいごに

今回はGuardDutyログを別アカウントへレプリケーションする設定方法を解説しました。今後も実案件で苦労した点などを中心にアウトプットしていけたらと思います。この記事がどなたかのお役に立てれば幸いです。

参考記事

AWS公式ドキュメント レプリケート元バケットとレプリケート先バケットが異なるアカウントによって所有されている場合での、レプリケーションの設定
[アップデート] GuardDuty の検出結果を S3 にエクスポート出来るようになりました