S3への署名バージョン2を使用したアクセスをCloudTrail、CloudWatch Events、CloudWatch Logsでロギングしてみた
こんにちは、佐伯です。
S3の署名バージョン2(SigV2)の廃止は延期されましたが、2019年6月24日以降SigV2のサポートがS3バケットに依存することになります。また、既存バケットにおいてもいつまでSigV2がサポートされるのかについてはアナウンスされておらず、延期されたことで対応優先度が下がりましたが、SigV2の廃止が中止されたわけではありませんので対応しなくて良いといったものではないと考えています。
S3の署名バージョン2(SigV2)の廃止スケジュールが延期、2020年6月以降も既存のS3バケットはSigV2が継続サポートとなりました!!
今回は、先日CloudWatch Eventsのアップデートがあり、CloudWatch EventsからCloudWatch Logsへの直接出力できるようになったのでS3へのSigV2を使用したアクセスをロギングする仕組みをCloudFormationテンプレートで作成しました。
[アップデート] CloudWatch EventsのターゲットとしてCloudWatch Logsがサポートされました!
ざっくり言うと以下エントリのAmazon SNS、AWS Lambdaがないバージョンです。
やってみた
概要図
CloudFormationテンプレート
注意点
このCloudFormationテンプレートはひとつのS3バケットのデータイベントを記録するCloudTrailを作成します。複数のS3バケットを対象としたい場合は手動でCloudTrailを編集してください。また、CloudTrailのデータイベントは100,000件のイベントあたり0.10USDが課金されます。S3へのリクエストが極端に多いことが予想できる場合はCloudTrailの利用料にご注意ください。
--- AWSTemplateFormatVersion: '2010-09-09' Description: Logging of S3 access using SigV2 (CloudTrail,CloudWatchEvent,CloudWatchLogs) Parameters: LogTargetS3Name: Description: S3 bucket name that enabled logging of S3 object API Type: String Default: s3-bucket-name Resources: S3Bucket: DeletionPolicy: Retain Type: AWS::S3::Bucket Properties: LifecycleConfiguration: Rules: - Id: AutoDelete Status: Enabled ExpirationInDays: 7 BucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref 'S3Bucket' PolicyDocument: Version: '2012-10-17' Statement: - Sid: AWSCloudTrailAclCheck Effect: Allow Principal: Service: cloudtrail.amazonaws.com Action: s3:GetBucketAcl Resource: !Sub 'arn:aws:s3:::${S3Bucket}' - Sid: AWSCloudTrailWrite Effect: Allow Principal: Service: cloudtrail.amazonaws.com Action: s3:PutObject Resource: !Sub 'arn:aws:s3:::${S3Bucket}/AWSLogs/${AWS::AccountId}/*' Condition: StringEquals: s3:x-amz-acl: bucket-owner-full-control TrailS3Event: DependsOn: - BucketPolicy Type: AWS::CloudTrail::Trail Properties: S3BucketName: !Ref 'S3Bucket' IsLogging: true IsMultiRegionTrail: false IncludeGlobalServiceEvents: false EventSelectors: - IncludeManagementEvents: false DataResources: - Type: AWS::S3::Object Values: - !Sub 'arn:aws:s3:::${LogTargetS3Name}/' ReadWriteType: All CloudWatchLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: /aws/events/s3-sigv2-access-log CloudwatchEventRule: Type: AWS::Events::Rule Properties: Description: EventRule EventPattern: detail-type: - AWS API Call via CloudTrail detail: eventSource: - s3.amazonaws.com additionalEventData: SignatureVersion: - SigV2 State: ENABLED Targets: - Arn: !GetAtt CloudWatchLogGroup.Arn Id: EventRule
CloudWatch Logsを確認
AmazonLinux(2016.09)(amzn-ami-hvm-2016.09.0.20160923-x86_64-gp2)からEC2インスタンスを作成してS3へのファイルコピーを実施し、CloudWatch Logs: /aws/events/s3-sigv2-access-log
へログが出力されることを確認します。
各種IDなどはマスキングしていますが、EC2インスタンスにIAMロールをアタッチしてアクセスしている場合は、以下のようなJSONが出力されます。アクセスキーを使用したリクエストがある場合は、detail.userIdentityの出力フォーマットが若干違うのでご注意ください。
detail.userIdentity.arnから対象のインスタンスを、detail.userAgentからリクエスト元のエージェントをある程度絞り込むことができます。今回の場合はAWS CLIからのアクセスです。
{ "version": "0", "id": "5b7b3c0c-8cf7-XXXX-1125-XXXXXXXXXXXX", "detail-type": "AWS API Call via CloudTrail", "source": "aws.s3", "account": "XXXXXXXXXXXX", "time": "2019-06-30T10:20:03Z", "region": "ap-northeast-1", "resources": [], "detail": { "eventVersion": "1.05", "userIdentity": { "type": "AssumedRole", "principalId": "AROAJHX4LXXXXXXXXXXXX:i-00136XXXXXXXXXXXX", "arn": "arn:aws:sts::XXXXXXXXXXXX:assumed-role/AmazonEC2RoleForSSM/i-00136XXXXXXXXXXXX", "accountId": "XXXXXXXXXXXX", "accessKeyId": "ASIA27MRXXXXXXXXXXXX", "sessionContext": { "sessionIssuer": { "type": "Role", "principalId": "AROAJHX4LXXXXXXXXXXXX", "arn": "arn:aws:iam::XXXXXXXXXXXX:role/AmazonEC2RoleForSSM", "accountId": "XXXXXXXXXXXX", "userName": "AmazonEC2RoleForSSM" }, "attributes": { "creationDate": "2019-06-30T10:04:16Z", "mfaAuthenticated": "false" } } }, "eventTime": "2019-06-30T10:20:03Z", "eventSource": "s3.amazonaws.com", "eventName": "PutObject", "awsRegion": "ap-northeast-1", "sourceIPAddress": "54.249.95.0", "userAgent": "[aws-cli/1.10.56 Python/2.7.12 Linux/4.4.19-29.55.amzn1.x86_64 botocore/1.4.46]", "requestParameters": { "bucketName": "example-bucket-XXXXXXXXXXXX", "Host": "example-bucket-XXXXXXXXXXXX.s3.amazonaws.com", "key": "test" }, "responseElements": null, "additionalEventData": { "SignatureVersion": "SigV2", "CipherSuite": "ECDHE-RSA-AES128-GCM-SHA256", "bytesTransferredIn": 0, "AuthenticationMethod": "AuthHeader", "x-amz-id-2": "LXLyJXqrMg9wWTXsiyQNMTJEDZM3jqGFBcHzCfGzzFnvOmfkAtvohkXCbKXXXXXXXXXXXXXXXX=", "bytesTransferredOut": 0 }, "requestID": "D2A9XXXXXXXXXXXX", "eventID": "f54a8cfd-c2f0-4a20-9d76-XXXXXXXXXXXX", "readOnly": false, "resources": [ { "type": "AWS::S3::Object", "ARN": "arn:aws:s3:::example-bucket-XXXXXXXXXXXX/test" }, { "accountId": "XXXXXXXXXXXX", "type": "AWS::S3::Bucket", "ARN": "arn:aws:s3:::example-bucket-XXXXXXXXXXXX" } ], "eventType": "AwsApiCall", "recipientAccountId": "XXXXXXXXXXXX" } }
CloudWatch Logs Insightsで検索
CloudWatch Logsに出力したログはCloudWatch Logs Insightsで検索することができます。CloudWatch Logs Insightsはスキャンされたデータ1GBあたり0.0076USDの課金が発生する点にご注意ください。
IAMロールを使用したEC2からのアクセスであれば、以下のクエリを実行することでリクエスト元のEC2インスタンスやエージェント(AWS SDK, AWS CLI)などを特定することができます。アクセスキーを使用したアクセスの場合はキーが変わると思われますので、ご注意ください。
stats count(*) by detail.userIdentity.arn, detail.userAgent, detail.requestParameters.bucketName
調査後のリソース削除
CloudFormationスタックを削除します。CloudTrailのログデータを保存しているS3バケットは手動で削除が必要です。S3バケット内のデータを削除し、S3バケットを削除してください。
最後に
CloudWatch EventsからCloudWatch Logsへ直接出力がサポートされ、AWS Lambdaなどを作成せずともロギングの仕組みを作ることができるようになりました。繰り返しとなりますが、S3署名バージョン2(SigV2)の廃止は延期となりましたが、対応が必要であることは変わらないと考えています。