AWS Transfer Family 接続時のPermission Denied等のエラーに対して、AthenaでS3 アクセスログを分析してみた
はじめに
AWS Transfer Familyへの接続時に、Permission Deniedになる連絡を受けた際、S3のアクセスログからリクエストの詳細を調査してエラー解決することができますので、その手順をまとめました。
Transfer Familyでは、標準設定でCloudWatch Logsに以下のようにログを出力されます。
{ "path": "/S3バケット名/test.py", "activity-type": "ERROR", "resource-arn": "arn:aws:transfer:ap-northeast-1:xxxx:server/s-aacfeafc8f2840b9a", "message": "Access denied", "bytes-in": "8405", "operation": "CLOSE", "session-id": "03bf7ddc20e33b8c" }
{ "activity-type": "ERROR", "resource-arn": "arn:aws:transfer:ap-northeast-1:xxxx:server/s-xxxxxxxxx", "message": "Access denied", "session-id": "03bf7ddc20e33b8c" }
ただし、このログではエラーメッセージや対象のパスは確認できますが、ユーザー情報は記載されていません。そのため、ユーザー情報も含めて確認するためにはS3のアクセスログを見ることをおすすめします。
ちなみに、CloudTrailでも確認しましたが、エラーに関するログは取得されていませんでした。
事前準備
構成は下記の通りです。
Transfer Familyは、下記の仕様で作成済です。
- エンドポイント:パブリック
- プロトコル:SFTP
- Transfer Familyのファイル転送先(ドメイン): S3バケット
- ユーザー管理方法:サービスマネージド
ファイル転送先S3バケットとアクセスログ用のS3バケットを事前に構築しておきます。
手順
手順は下記の通りです。
- S3バケットのアクセスログを有効化
- Athenaで分析する
S3バケットのアクセスログを有効化
Transfer Family経由で転送するS3バケットのアクセスログを有効化します。保存先は別のS3バケットを指定します。
ドキュメントにも記載されている通り、アクセスログが有効になるまでには時間がかかるため注意が必要です。
バケットのログ記録ステータスの変更がログファイルの配信に反映されるまでには時間がかかります。例えば、バケットのログを有効にする場合、その後数時間に行われるリクエストは記録される場合もあれば、されない場合もあります。ログ記録の送信先バケットをバケット A からバケット B に変更すると、その後 1 時間は一部のログがバケット A に引き続き配信されたり、新しいターゲットバケット B に配信されたりします。引用
Athenaで分析
S3のアクセスログをAthenaで分析します。
本記事のAthenaのクエリは、AWSドキュメントを参考にしています。
まず、データベースを作成します。
CREATE DATABASE s3_access_logs_db
次に、データベースのテーブルスキーマを作成します。クエリ内のLOCATION
は、実際のS3バケット名に変更してください。
CREATE EXTERNAL TABLE `s3_access_logs_db.mybucket_logs`( `bucketowner` STRING, `bucket_name` STRING, `requestdatetime` STRING, `remoteip` STRING, `requester` STRING, `requestid` STRING, `operation` STRING, `key` STRING, `request_uri` STRING, `httpstatus` STRING, `errorcode` STRING, `bytessent` BIGINT, `objectsize` BIGINT, `totaltime` STRING, `turnaroundtime` STRING, `referrer` STRING, `useragent` STRING, `versionid` STRING, `hostid` STRING, `sigv` STRING, `ciphersuite` STRING, `authtype` STRING, `endpoint` STRING, `tlsversion` STRING, `accesspointarn` STRING, `aclrequired` STRING) ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' WITH SERDEPROPERTIES ( 'input.regex'='([^ ]*) ([^ ]*) \\[(.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) (-|[0-9]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) ([^ ]*)(?: ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*))?.*$') STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://DOC-EXAMPLE-BUCKET1-logs/prefix/'
ステータスが200以外のログを出力するクエリを実行します。
SELECT bucket_name, requestdatetime, requester, httpstatus, errorcode, operation, key, request_uri, useragent FROM s3_access_logs_db.mybucket_logs WHERE httpstatus <> '200' ORDER BY requestdatetime DESC;
クエリ結果から、Transfer-Family-Role
というIAMロールのtest1
というユーザーがAccessDeniedを発生させていることがわかりました。
IAMロールがTransfer-Family-Role
かつ、AccessDenied
エラーのログのみを出力するクエリを実行します。
SELECT bucket_name, requestdatetime, requester, httpstatus, errorcode, operation, key, request_uri, useragent FROM s3_access_logs_db.mybucket_logs WHERE requester LIKE '%Transfer-Family-Role%' AND errorcode = 'AccessDenied' ORDER BY requestdatetime DESC;
ちなみに、下記のように時間範囲を指定することも可能です。
SELECT bucket_name, requestdatetime, requester, httpstatus, errorcode, operation, key, request_uri, useragent FROM s3_access_logs_db.mybucket_logs WHERE requester LIKE '%Transfer-Family-Role%' AND errorcode = 'AccessDenied' AND parse_datetime(RequestDateTime,'dd/MMM/yyyy:HH:mm:ss Z') BETWEEN timestamp '2024-02-01 00:00:00' AND timestamp '2024-02-01 02:00:00' ORDER BY requestdatetime DESC;
結果から複数のエラーが確認できました。
赤枠部分からは、Transfer-Family-Role
のtest1
というユーザーがtest.pyファイルをS3バケットにアップロードしようとした際、AccessDeniedが発生したことがわかります。
よって、赤枠のAccessDeniedエラーは、IAMロールTransfer-Family-Role
にs3:PutObject
の権限を許可することで解決できます。
Transfer Family経由のアクセスログ
ちなみに、「AWSマネジメントコンソール上からS3バケットにアクセスした場合」と「Transfer Family経由でS3バケットにアクセスした場合」では、S3のアクセスログのrequester
やuseragent
から前者もしくは後者と判断できます。
例えば、下記の違いがあります。
- AWSマネジメントコンソール上からS3バケットにアクセスした時
requester
:arn:aws:sts::xxx:assumed-role/スイッチ元IAMユーザ名/スイッチ先IAMロール名useragent
:S3Console/0.4, aws-internal/...省略
- Transfer Family経由でS3バケットにアクセス時
requester
:arn:aws:sts::xxx:assumed-role/Transfer Familyのユーザー用のIAMロール/Transfer Familyのユーザー名.セッションID@Transfer FamilyのサーバーIDuseragent
:aws-transfer, aws-internal/...省略
最後に
今回は、AWS Transfer Familyへの接続時に発生したPermission Denied エラーを、S3のアクセスログを分析することで解決する方法について解説しました。
アクセスログの有効化とAthenaでの分析のみで容易に調査が可能であることがお分かりいただけたかと思います。
どなたかの参考になれば幸いです。