2021年7月4日日曜日

S3のETagの確認をboto3で

S3にデータをアップロードしたときに、ファイルが同一であるかを確認する方法として、前後でETagを比較して判定することができます。実際に手を動かしてやってみました。

(環境: コマンドラインはUbuntu20.4, Python 3.7)

公式の記事にはCLIでのチェックサムによるアップロード時の整合性検証の解説があります。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/data-integrity-s3/

ETagとは

ETagはオブジェクトのハッシュタグと同等で、ファイルの内容を反映しています。 32桁のhexで表すことができます(MD5)。

上の記事にはこんな注意書きが。

注意: エンティティタグ (ETag) はオブジェクトのハッシュで、オブジェクトデータの MD5 ダイジェストではない場合があります。ETag が MD5 ダイジェストであるかどうかは、オブジェクトの作成方法と暗号化方法によって異なります。ETag は常に MD5 ダイジェストではないため、アップロードされたファイルの整合性の検証に常に使用できるとは限りません。

ともあれ、AWSのS3のETagはローカルのMD5 ダイジェストと同一であるはずといういうことで、 アップロード後に比較して、整合性を確認します。

ファイルの準備

test.txt というファイルに文字列を書き込みます。なんでもよいです。

echo "This is a test for comparing MD5 hash and S3 Etag." > test.txt
ローカルでのMD5値 opensslコマンドでmd5ハッシュを取得します。
openssl test.txt

Out:
MD5(test.txt)= 617e1d5baa89ead4962dc5469c649f16
抜き出すために grepします。
 openssl md5 test.txt | grep -oP "=\s+\K\w+"
Out:
617e1d5baa89ead4962dc5469c649f16
https://unix.stackexchange.com/questions/207171/get-value-after-specific-word -o ==> option for printing only the matching part of the line -P ==> use perl-regexp \K ==> do not print that comes before \K (zero-width look-behind assertion) \w ==> match word characters もうひとつやり方
md5sum test.txt
Out:
617e1d5baa89ead4962dc5469c649f16  test.txt
test.txtが邪魔なので、こうすると、ハッシュだけを取り出せます。
md5sum test.txt | grep -oP "\w+(?=\s)"

S3にアップロードする

バケットに移動、ドラッグアンドドロップでアップロードします。Etagの項目を見てみると、確かに同じになっています。目視で確認してもいいですね。

boto3 Pythonスクリプトで確認する

次はboto3でローカルおよびS3バケットにアクセスしてEtagの値を取得します。
import boto3
import base64
import hashlib

file_name = "test.txt"
bucket_name = 'your-bucket'
region = 'your-region'
ファイル名、バケット名、リージョンを設定します。

ローカルファイルのmd5 をpythonから確認する

m = hashlib.md5()
with open(file_name, "rb") as f:
    read = f.read()
    m.update(read)

local_md5 = m.hexdigest()
print(local_md5)

Out:
617e1d5baa89ead4962dc5469c649f16
ここでバケットを作ったりファイルのアップロードをboto3でやる場合は、 boto3-s3のドキュメントにある、create_bucket()やupload_file()を使えばよいです。

オブジェクトのヘッダを取得して、ETagを探します。
header['ResponseMetadata']['HTTPHeaders']['etag']

header['ETag']
に同じETagの値が入っています。これが2つなのは、HTTPで送信されてきたときのヘッダと、取得してからのヘッダだからなのでは、と思っていますが自信ないです。(TODO)
s3_client = boto3.client('s3')
header = s3_client.head_object(Bucket=bucket_name, Key=file_name)
ETag = header['ETag'].strip('""')
ETag = get_ETag(bucket_name, file_name)

print(ETag)
print(local_md5)
print(ETag == local_md5)

Out:
617e1d5baa89ead4962dc5469c649f16
617e1d5baa89ead4962dc5469c649f16
True
まとめ S3にアップロードしたオブジェクトのEtagを確認して、ファイルの同一性を確認しました。確認には、boto3を使いました。

0 件のコメント:

コメントを投稿