IAM グローバル条件キーに aws:SourceOrgPaths が追加されて OU 単位の AWS CloudTrail ログ集約を実施しやすくなりました

2023.11.21

先日、IAM グローバル条件キーにaws:SourceOrgID aws:SourceOrgPathsが追加されました。

これにより、AWS Organizations 環境において、特定の OU 配下のアカウントを対象にした AWS CloudTrail ログの S3 バケット集約が実施しやすくなりました。下記ブログでは VPC フローログを組織単位で集約する例が記載されています。

AWS CloudTrail ログの集約を組織単位ではなく、OU 単位で実施したい場合があります。例えば、OU を環境別に分けており、環境毎にログを集約したい場合や OU 毎に組織やプロダクト種別を分けており、その単位で集約したい場合です。下図は環境別に集約する場合のイメージ図です。

これまで、OU 配下のアカウントを集約する S3 バケットのバケットポリシーは 下記に抜粋したユーザーガイドの記載例 の通り、Condtion の条件として複数のアカウントの証跡情報を記載する方法がありました。ただし、この例では集約対象のアカウントが増える度にバケットポリシーを修正する必要があります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailAclCheck20131101",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::myBucketName",
      "Condition": {
          "StringEquals": {
            "aws:SourceArn": [
              "arn:aws:cloudtrail:region:111111111111:trail/primaryTrailName",
              "arn:aws:cloudtrail:region:222222222222:trail/secondaryTrailName"
            ]
          }
       }
    },
    {
      "Sid": "AWSCloudTrailWrite20131101",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": [
        "arn:aws:s3:::myBucketName/optionalLogFilePrefix/AWSLogs/111111111111/*",
        "arn:aws:s3:::myBucketName/optionalLogFilePrefix/AWSLogs/222222222222/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:SourceArn": [
            "arn:aws:cloudtrail:region:111111111111:trail/primaryTrailName",
            "arn:aws:cloudtrail:region:222222222222:trail/secondaryTrailName"
          ],
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}

もしくは、Principal に S3 バケットに書き込めるサービス(AWS CloudTrail)だけを記載してアカウントレベルの制限まで実施しない方法もありますが、この場合は集約対象以外のアカウントからも転送できてしまう課題がありました。

アップデートにより、今後は次のポリシー例のように OU 指定による制限の記載ができるようになりました。この例は対象とする OU の子 OU まで含めている例です。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::myBucketName",
            "Condition": {
                "Null": {
                    "aws:SourceOrgPaths": "false"
                },
                "ForAllValues:StringLike": {
                    "aws:SourceOrgPaths": "o-a1b2c3d4e5/r-ab12/ou-ab12-11111111/*"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::myBucketName/*",
            "Condition": {
                "Null": {
                    "aws:SourceOrgPaths": "false"
                },
                "ForAllValues:StringLike": {
                    "aws:SourceOrgPaths": "o-a1b2c3d4e5/r-ab12/ou-ab12-11111111/*"
                },
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}


OU 単位で CloudTrail ログを集約してみる

下記の OU 配下のアカウントの AWS CloudTrail ログを集約してみます。

  • 【OU 名】Sandbox
    • 【アカウント】Sandbox-01 (ログ集約用 S3 バケットを作成)
    • 【アカウント】Sandbox-02
    • 【アカウント】Sandbox-03


集約用 S3 バケットの設定

まずは、集約用 S3 バケットを作成します。今回は他の設定はデフォルトのまま作成しています。

ログの保管期間を設定するライフサイクルルールはテスト目的であったため今回は設定しませんでした。

バケットポリシーは次の内容としました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::test-cloudtrail-20131118",
            "Condition": {
                "Null": {
                    "aws:SourceOrgPaths": "false"
                },
                "ForAllValues:StringLike": {
                    "aws:SourceOrgPaths": "o-a1b2c3d4e5/r-ab12/ou-ab12-11111111//*"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::test-cloudtrail-20131118/*",
            "Condition": {
                "Null": {
                    "aws:SourceOrgPaths": "false"
                },
                "ForAllValues:StringLike": {
                    "aws:SourceOrgPaths": "o-a1b2c3d4e5/r-ab12/ou-ab12-11111111//*"
                },
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}


集約対象の OU の子 OU も含める記載としています。

Condition のaws:SourceOrgPaths条件は次の AWS ブログを参考に設定しました。

aws:SourceOrgPathsは Multivalued context keys 扱いであることからForAllValuesを利用して判定するようです。また、下記引用の通り、ForAllValuesはキーコンテキストがない場合は true 扱いとなるため、それを防ぐために Conditon にNull条件を追加しているとのことです。

Note: The reason for the null check is that set operator ForAllValues returns true when a condition key resolves to null. With an Allow effect and the null check in place, access is denied if the request originates from an account that’s not in an organization.

(引用元)Use scalable controls for AWS services accessing your resources | AWS Security Blog


AWS CloudTrail の設定

次に、 AWS CloudTrail を設定する次の CloudFormation テンプレートを、StackSets を用いて OU に配下のアカウントに展開します。

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  S3BucketName:
    Description: "Amazon S3 bucket name for AWS CloudTrail"
    Type: String

Resources:
  CloudTrail:
    Type: AWS::CloudTrail::Trail
    Properties:
      TrailName: "management-events"
      EnableLogFileValidation: True
      IncludeGlobalServiceEvents: True
      IsLogging: True
      IsMultiRegionTrail: True
      S3BucketName: !Ref S3BucketName


CloudFromation のメニューから StackSets を選択して作成します。

ステップ 2 では、StackSets 名とパラメータである集約用 S3 バケット名を入力して進みます。

ステップ 3 は、今回はデフォルト設定のまま進めます。

ステップ 4 では、展開する OU を指定します。自動デプロイを有効にして OU 配下にアカウントが追加された場合にテンプレートが展開されるようにしています。「リージョンの指定」は東京リージョンのみにしています。展開するテンプレートではマルチリージョンの証跡を有効化しているため、東京リージョンのみに展開した場合でも全てのリージョンのログを記録します。

最後に、内容を確認して問題なければ「送信」をクリックして展開します。

指定した OU に含まれる 3 アカウントに展開できました。

集約用 S3 バケットへのログ配信も確認できました。下記の画像は1つのアカウントのログ転送結果です。

また、S3 のバケットポリシーで指定した OU 以外のアカウントから CloudTrail ログを集約用 S3 バケットに配信しようとすると期待通りエラーとなりました。

以上で確認は終わりです。

さいごに

IAM グローバル条件キーにaws:SourceOrgPathsが追加されたため試してみました。

これまで、OU 単位で AWS CloudTrail のログを集約しようとすると、集約用 S3 バケットのバケットポリシーに対してアカウント追加の度に新しい証跡を許可する追記をするか、AWS CloudTrail サービス全体に対して広く許可するかの方法がありましたが、今回のアップデートでアカウントが追加される度にバケットポリシーを修正しなくても許可するアカウントを OU 単位で制限できるようになりました。

以上、このブログがどなたかのご参考になれば幸いです。