この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、佐伯です。
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)の廃止は延期となりましたが、対応が必要であることは変わらないと考えています。