翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。
CloudTrail Lake に保存されたクエリ結果を検証する
クエリ結果を CloudTrail 配信した後にクエリ結果が変更、削除、または変更されていないかどうかを判断するには、 CloudTrail クエリ結果の整合性検証を使用できます。この機能は、業界標準のアルゴリズムを使用して構築されています。ハッシュの場合は SHA-256、デジタル署名RSAの場合は SHA-256 です。これにより、 CloudTrail クエリ結果ファイルを検出せずに変更、削除、または偽造することが計算上不可能になります。コマンドラインを使用してクエリ結果ファイルを検証できます。
使用する理由
検証されたクエリ結果ファイルは、セキュリティおよびフォレンシック調査で非常に重要です。たとえば、検証済みのクエリ結果ファイルを使用することで、クエリ結果ファイル自体が変更されていないことを明確に主張できます。 CloudTrail クエリ結果ファイルの整合性検証プロセスでは、クエリ結果ファイルが削除されたか変更されたかもわかります。
で保存されたクエリ結果を検証する AWS CLI
aws cloudtrail verify-query-results
前提条件
コマンドラインを使用してクエリ結果の整合性を検証するには、次の条件を満たしている必要があります。
-
へのオンライン接続が必要です AWS。
-
AWS CLI バージョン 2 を使用する必要があります。
-
ローカルでクエリ結果ファイルを検証してファイルに署名する場合、次の条件が適用されます。
-
指定したファイルパスにクエリ結果ファイルと署名ファイルを配置する必要があります。--local-export-path パラメータの値としてファイルパスを指定します。
-
クエリ結果ファイルと署名ファイルの名前は変更しません。
-
-
S3 バケットでクエリ結果ファイルを検証してファイルに署名する場合、次の条件が適用されます。
-
クエリ結果ファイルと署名ファイルの名前は変更しません。
-
クエリ結果ファイルの署名ファイルを含む Amazon S3 バケットへの読み取りアクセスが必要です。
-
指定した S3 プレフィックスには、クエリ結果ファイルと署名ファイルが含まれている必要があります。--s3-prefix パラメータの値として S3 プレフィックスを指定します。
-
verify-query-results
verify-query-results コマンドは、各クエリ結果ファイルのハッシュ値を署名ファイル内の fileHashValue
と比較し、署名ファイルの hashSignature
を検証することによってクエリ結果ファイルのハッシュ値を検証します。
クエリ結果を検証する場合、--s3-bucket および --s3-prefix のいずれかのコマンドラインオプションを使用して S3 バケットに保存されているクエリ結果ファイルと署名ファイルを検証するか、--local-export-path コマンドラインオプションを使用して、ダウンロードしたクエリ結果ファイルと署名ファイルのローカル検証を実行することができます。
注記
verify-query-results コマンドはリージョン固有です。特定の のクエリ結果を検証するには、--regionグローバルオプションを指定する必要があります AWS リージョン。
verify-query-results コマンドのオプションを以下に示します。
- --s3-bucket
<string>
-
クエリ結果ファイルと署名ファイルを保存する S3 バケット名を指定します。このパラメータは --local-export-path と共に使用できません。
- --s3-prefix
<string>
-
クエリ結果ファイルと署名ファイルを含む S3 フォルダーの S3 パスを指定します (
s3/path/
など)。このパラメータは --local-export-path と共に使用できません。ファイルが S3 バケットのルートディレクトリにある場合は、このパラメータを指定する必要はありません。
- --local-export-path
<string>
-
クエリ結果ファイルと署名ファイルを含むローカルディレクトリを指定します (
/local/path/to/export/file/
など)。このパラメータは --s3-bucket や --s3-prefix と共に使用できません。
例
次の例では、--s3-bucket および --s3-prefix コマンドラインオプションを使用してクエリ結果を検証し、クエリ結果ファイルと署名ファイルを含む S3 バケット名とプレフィックスを指定します。
aws cloudtrail verify-query-results --s3-bucket
amzn-s3-demo-bucket
--s3-prefixprefix
--regionregion
次の例では、--local-export-path コマンドラインオプションを使用して、ダウンロードしたクエリ結果を検証し、クエリ結果ファイルと署名ファイルのローカルパスを指定します。クエリ結果ファイルのダウンロードの詳細については、「 CloudTrail Lake で保存されたクエリ結果をダウンロードする」を参照してください。
aws cloudtrail verify-query-results --local-export-path
local_file_path
--regionregion
検証結果
次の表は、クエリ結果ファイルと書名ファイルの検証メッセージを示しています。
ファイルタイプ | 検証メッセージ | 説明 |
---|---|---|
Sign file |
Successfully validated sign and query result files |
書名ファイルの署名は有効です。参照しているクエリ結果ファイルを確認できます。 |
Query result file |
|
クエリ結果ファイルのハッシュ値が署名ファイルの fileHashValue と一致しなかったため、検証に失敗しました。 |
Sign file |
|
署名が無効なため、署名ファイルの検証に失敗しました。 |
CloudTrail 署名ファイル構造
署名ファイルには、クエリ結果を保存したときに Amazon S3 バケットに送られた各クエリ結果ファイルの名前、各クエリ結果ファイルのハッシュ値、ファイルのデジタル署名が含まれます。デジタル署名とハッシュ値は、クエリ結果ファイルおよび署名ファイル自体の整合性を検証するために使用されます。
署名ファイルの場所
署名ファイルは、次の構文で表される Amazon S3 バケットの場所に送られます。
s3://
amzn-s3-demo-bucket
/optional-prefix/
AWSLogs/aws-account-ID
/CloudTrail-Lake/Query/year
/month
/date
/query-ID
/result_sign.json
署名ファイルのコンテンツの例
次の署名ファイルの例には、 CloudTrail Lake クエリ結果に関する情報が含まれています。
{ "version": "1.0", "region": "us-east-1", "files": [ { "fileHashValue" : "de85a48b8a363033c891abd723181243620a3af3b6505f0a44db77e147e9c188", "fileName" : "result_1.csv.gz" } ], "hashAlgorithm" : "SHA-256", "signatureAlgorithm" : "SHA256withRSA", "queryCompleteTime": "2022-05-10T22:06:30Z", "hashSignature" : "7664652aaf1d5a17a12ba50abe6aca77c0ec76264bdf7dce71ac6d1c7781117c2a412e5820bccf473b1361306dff648feae20083ad3a27c6118172a81635829bdc7f7b795ebfabeb5259423b2fb2daa7d1d02f55791efa403dac553171e7ce5f9307d13e92eeec505da41685b4102c71ec5f1089168dacde702c8d39fed2f25e9216be5c49769b9db51037cb70a84b5712e1dffb005a74580c7fdcbb89a16b9b7674e327de4f5414701a772773a4c98eb008cca34228e294169901c735221e34cc643ead34628aabf1ba2c32e0cdf28ef403e8fe3772499ac61e21b70802dfddded9bea0ddfc3a021bf2a0b209f312ccee5a43f2b06aa35cac34638f7611e5d7", "publicKeyFingerprint" : "67b9fa73676d86966b449dd677850753" }
署名ファイルのフィールドの説明
以下では、署名ファイルの各フィールドについて説明します。
version
-
署名ファイルのバージョン。
region
-
クエリ結果の保存に使用される AWS アカウントのリージョン。
files.fileHashValue
-
圧縮されたクエリ結果ファイルの内容の 16 進エンコードされたハッシュ値です。
files.fileName
-
クエリ結果ファイルの名前。
hashAlgorithm
-
クエリ結果ファイルのハッシュ計算に使用されたハッシュアルゴリズムです。
signatureAlgorithm
-
ファイルの署名に使用されるアルゴリズムです。
queryCompleteTime
-
がクエリ結果を S3 バケットに CloudTrail いつ配信したかを示します。この値を使用してパブリックキーを検索できます。
hashSignature
-
ファイルのハッシュ署名。
publicKeyFingerprint
-
このファイルの署名に使用されたパブリックキーの 16 進エンコードされたフィンガープリントです。
CloudTrail クエリ結果ファイルの整合性検証のカスタム実装
CloudTrail は業界標準の公開されている暗号化アルゴリズムとハッシュ関数を使用するため、独自のツールを作成して CloudTrail クエリ結果ファイルの整合性を検証できます。クエリ結果を Amazon S3 バケットに保存すると、 は署名ファイルを S3 バケットに CloudTrail 配信します。独自の検証ソリューションを実装して、署名ファイルとクエリ結果ファイルを検証できます。署名ファイルの詳細については、「CloudTrail 署名ファイル構造」を参照してください。
このトピックでは、署名ファイルの署名方法について説明し、署名ファイルと、署名ファイルによって参照される署名ファイルを検証するソリューションの実装に必要な手順を詳しく示します。
CloudTrail 署名ファイルの署名方法を理解する
CloudTrail 署名ファイルはRSAデジタル署名で署名されます。署名ファイルごとに、 CloudTrail は以下を実行します。
-
各クエリ結果ファイルのハッシュ値を含むハッシュリストを作成します。
-
リージョンに固有のプライベートキーを取得します。
-
文字列の SHA-256 ハッシュとプライベートキーをRSA署名アルゴリズムに渡し、デジタル署名を生成します。
-
署名のバイトコードを 16 進形式にエンコードします。
-
デジタル署名を署名ファイルに入力します。
データ署名文字列の内容
データ署名文字列は、スペースで区切られた各クエリ結果ファイルのハッシュ値で構成されます。署名ファイルには、各クエリ結果ファイルの fileHashValue
がリストされています。
カスタム検証を実装する手順
カスタム検証ソリューションを実装するときは、最初にダイジェストファイルを検証してから、署名ファイルと参照するクエリ結果ファイルを検証する必要があります。
署名ファイルを検証する
署名ファイルを検証するには、署名、対応するプライベートキーが署名に使用されたパブリックキー、計算したデータ署名文字列が必要です。
-
署名ファイルを入手してください。
-
本来の場所から署名ファイルが取得されたことを確認します。
-
署名ファイルの 16 進エンコードされた署名を取得します。
-
パブリックキー (対応するプライベートキーが署名ファイルの署名に使用された) の 16 進エンコードされたフィンガープリントを取得します。
-
署名ファイルで
queryCompleteTime
に対応する時間範囲のパブリックキーを取得します。時間範囲には、「StartTime
より早いqueryCompleteTime
」および「EndTime
より遅いqueryCompleteTime
」を選択します。 -
取得したパブリックキーの中から、フィンガープリントが署名ファイルの
publicKeyFingerprint
の値と一致するパブリックキーを選択します。 -
各クエリ結果ファイルのハッシュ値をスペースで区切ったハッシュリストを使用して、署名ファイルの署名を検証するために使用するデータ署名文字列を再作成します。署名ファイルには、各クエリ結果ファイルの
fileHashValue
がリストされています。たとえば、署名ファイルの
files
配列に次の 3 つのクエリ結果ファイルが含まれている場合、ハッシュリストは「aaa bbb ccc」になります。“files": [ { "fileHashValue" : “aaa”, "fileName" : "result_1.csv.gz" }, { "fileHashValue" : “bbb”, "fileName" : "result_2.csv.gz" }, { "fileHashValue" : “ccc”, "fileName" : "result_3.csv.gz" } ],
-
文字列の SHA-256 ハッシュ、パブリックキー、および署名をパラメータとして署名検証アルゴリズムに渡して、RSA署名を検証します。結果が true の場合、署名ファイルは有効です。
クエリ結果ファイルを検証する
署名ファイルが有効な場合は、署名ファイルが参照するクエリ結果ファイルを検証します。クエリ結果ファイルの整合性を検証するには、圧縮されたコンテンツで SHA-256 ハッシュ値を計算し、署名ファイルに記録されたfileHashValue
クエリ結果ファイルの と結果を比較します。ハッシュが一致する場合、クエリ結果ファイルは有効です。
以下のセクションではこの検証を詳しく説明します。
A. 署名ファイルを取得する
最初の手順は、署名ファイルを取得し、パブリックキーのフィンガープリントを取得することです。
-
検証するクエリ結果の署名ファイルを Amazon S3 バケットから取得します。
-
次に、署名ファイルから
hashSignature
の値を取得します。 -
署名ファイルで、署名ファイルの署名に使用されたプライベートキーに対応するパブリックキーのフィンガープリントを
publicKeyFingerprint
フィールドから取得します。
B. 署名ファイルの検証のためにパブリックキーを取得する
署名ファイルを検証するためのパブリックキーを取得するには、 AWS CLI または を使用できます CloudTrail API。どちらの場合も、検証しようとする署名ファイルの時間範囲 (開始時刻と終了時刻) を指定します。署名ファイル内の queryCompleteTime
に対応する時間範囲を使用してください。指定した時間範囲について 1 つ以上のパブリックキーが返されることがあります。返されたキーの有効な時間範囲が重複する可能性があります。
注記
CloudTrail はリージョンごとに異なるプライベート/パブリックキーペアを使用するため、各署名ファイルはリージョンに固有のプライベートキーで署名されます。したがって、特定のリージョンの署名ファイルを検証するときは、同じリージョンからパブリックキーを取得する必要があります。
AWS CLI を使用してパブリックキーを取得する
を使用して署名ファイルのパブリックキーを取得するには AWS CLI、 cloudtrail list-public-keys
コマンドを使用します。このコマンドの形式は次のとおりです。
aws cloudtrail list-public-keys [--start-time <start-time>] [--end-time <end-time>]
開始時刻と終了時刻のパラメータはUTCタイムスタンプであり、オプションです。指定しない場合、現在の時刻が使用され、現在アクティブなパブリックキー (1 つまたは複数) が返されます。
レスポンス例
レスポンスは、返されたキー (またはキー) を表すJSONオブジェクトのリストになります。
CloudTrail API を使用してパブリックキーを取得する
を使用して署名ファイルのパブリックキーを取得するには CloudTrail API、開始時刻と終了時刻の値を ListPublicKeys
に渡しますAPI。は、指定された時間範囲内でプライベートキーを使用してファイルに署名したパブリックキーListPublicKeys
APIを返します。パブリックキーごとに、 は対応するフィンガープリントAPIも返します。
ListPublicKeys
このセクションでは、 ListPublicKeys
のリクエストパラメータとレスポンス要素について説明しますAPI。
注記
ListPublicKeys
のバイナリフィールドのエンコードは変更される可能性があります。
リクエストパラメータ
名前 | 説明 |
---|---|
StartTime
|
オプションで、 CloudTrail 署名ファイルのパブリックキーを検索する時間範囲UTCの開始を で指定します。を指定 StartTime しない場合、現在の時刻が使用され、現在のパブリックキーが返されます。 タイプ: DateTime |
EndTime
|
オプションで、 CloudTrail 署名ファイルのパブリックキーを検索する時間範囲UTCの終了を で指定します。が指定されていない場合 EndTime は、現在の時刻が使用されます。 タイプ: DateTime |
レスポンス要素
PublicKeyList
は、次の要素を含む PublicKey
オブジェクトの配列です。
名前 | 説明 |
Value
|
PKCS #1 形式のDERエンコードされたパブリックキー値。 型: Blob |
ValidityStartTime
|
パブリックキーの有効期間の開始時刻。 タイプ: DateTime |
ValidityEndTime
|
パブリックキーの有効期間の終了時刻。 タイプ: DateTime |
Fingerprint
|
パブリックキーのフィンガープリント。フィンガープリントを使用して、署名ファイルの検証に使用する必要があるパブリックキーを特定できます。 型: 文字列 |
C. 検証に使用するパブリックキーを選択する
list-public-keys
または ListPublicKeys
によって取得されたパブリックキーの中から、そのフィンガープリントが署名ファイルの publicKeyFingerprint
フィールドに記録されているフィンガープリントと一致するパブリックキーを選択します。これは署名ファイルの検証に使用するパブリックキーです。
D. データ署名文字列を再作成する
署名ファイルの署名と、関連付けられたパブリックキーを取得しました。次は、データ署名文字列を計算する必要があります。データ署名文字列の計算が完了すると、署名の検証に必要な入力を得られます。
データ署名文字列は、スペースで区切られた各クエリ結果ファイルのハッシュ値で構成されます。この文字列を再作成した後、署名ファイルを検証できます。
E. 署名ファイルを検証する
再作成されたデータ署名文字列、デジタル署名、パブリックキーをRSA署名検証アルゴリズムに渡します。出力が true の場合、署名ファイルの署名が検証され、署名ファイルは有効です。
F. クエリ結果ファイルを検証する
署名ファイルの検証が完了したら、クエリ結果ファイルが参照するログファイルを検証することができます。署名ファイルには、クエリ結果ファイルの SHA-256 ハッシュが含まれています。クエリ結果ファイルの 1 つが CloudTrail 配信後に変更された場合、SHA-256 ハッシュが変更され、署名ファイルの署名が一致しません。
以下の手順を使用して、署名ファイルの files
配列にリストされているクエリ結果ファイルを検証します。
-
署名ファイル内で、
files.fileHashValue
フィールドからファイルの元のハッシュを取得します。 -
hashAlgorithm
で指定されたハッシュアルゴリズムを使用して、クエリ結果ファイルの圧縮されたコンテンツをハッシュします。 -
クエリ結果ファイルごとに生成したハッシュ値を署名ファイルの
files.fileHashValue
と比較します。ハッシュが一致する場合、クエリ結果ファイルは有効です。
署名とクエリ結果ファイルのオフライン検証
署名ファイルとクエリ結果ファイルをオフラインで検証するとき、通常は前のセクションで説明した手順に従います。ただし、パブリックキーに関する次の情報を考慮する必要があります。
パブリックキー
オフラインで検証するには、所定の時間範囲のクエリ結果ファイルの検証に必要なパブリックキーを最初にオンラインで取得し (たとえば、ListPublicKeys
を呼び出す)、オフラインで保存する必要があります。指定した最初の時間範囲外の他のファイルを検証するには、常にこの手順を繰り返す必要があります。
検証のサンプルスニペット
次のサンプルスニペットは、 CloudTrail 署名ファイルとクエリ結果ファイルを検証するためのスケルトンコードを提供します。このスケルトンコードはオンラインでもオフラインでも使用できます。つまり、実装する際に AWSとのオンライン接続を使用するかどうかはユーザーが決めることができます。推奨される実装では、セキュリティプロバイダーとして Java Cryptography Extension (JCE)
サンプルスニペットには次の内容が含まれます。
-
署名ファイルの署名の検証に使用されるデータ署名文字列を作成する方法。
-
署名ファイルの署名を確認する方法。
-
クエリ結果ファイルのハッシュ値を計算し、それを署名ファイルにリストされている
fileHashValue
と比較して、クエリ結果ファイルの信頼性を検証する方法。
import org.apache.commons.codec.binary.Hex; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.RSAPublicKey; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.json.JSONArray; import org.json.JSONObject; import java.security.KeyFactory; import java.security.MessageDigest; import java.security.PublicKey; import java.security.Security; import java.security.Signature; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class SignFileValidationSampleCode { public void validateSignFile(String s3Bucket, String s3PrefixPath) throws Exception { MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); // Load the sign file from S3 (using Amazon S3 Client) or from your local copy JSONObject signFile = loadSignFileToMemory(s3Bucket, String.format("%s/%s", s3PrefixPath, "result_sign.json")); // Using the Bouncy Castle provider as a JCE security provider - http://www.bouncycastle.org/ Security.addProvider(new BouncyCastleProvider()); List<String> hashList = new ArrayList<>(); JSONArray jsonArray = signFile.getJSONArray("files"); for (int i = 0; i < jsonArray.length(); i++) { JSONObject file = jsonArray.getJSONObject(i); String fileS3ObjectKey = String.format("%s/%s", s3PrefixPath, file.getString("fileName")); // Load the export file from S3 (using Amazon S3 Client) or from your local copy byte[] exportFileContent = loadCompressedExportFileInMemory(s3Bucket, fileS3ObjectKey); messageDigest.update(exportFileContent); byte[] exportFileHash = messageDigest.digest(); messageDigest.reset(); byte[] expectedHash = Hex.decodeHex(file.getString("fileHashValue")); boolean signaturesMatch = Arrays.equals(expectedHash, exportFileHash); if (!signaturesMatch) { System.err.println(String.format("Export file: %s/%s hash doesn't match.\tExpected: %s Actual: %s", s3Bucket, fileS3ObjectKey, Hex.encodeHexString(expectedHash), Hex.encodeHexString(exportFileHash))); } else { System.out.println(String.format("Export file: %s/%s hash match", s3Bucket, fileS3ObjectKey)); } hashList.add(file.getString("fileHashValue")); } String hashListString = hashList.stream().collect(Collectors.joining(" ")); /* NOTE: To find the right public key to verify the signature, call CloudTrail ListPublicKey API to get a list of public keys, then match by the publicKeyFingerprint in the sign file. Also, the public key bytes returned from ListPublicKey API are DER encoded in PKCS#1 format: PublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, PublicKey BIT STRING } AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } */ byte[] pkcs1PublicKeyBytes = getPublicKey(signFile.getString("queryCompleteTime"), signFile.getString("publicKeyFingerprint")); byte[] signatureContent = Hex.decodeHex(signFile.getString("hashSignature")); // Transform the PKCS#1 formatted public key to x.509 format. RSAPublicKey rsaPublicKey = RSAPublicKey.getInstance(pkcs1PublicKeyBytes); AlgorithmIdentifier rsaEncryption = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, null); SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(rsaEncryption, rsaPublicKey); // Create the PublicKey object needed for the signature validation PublicKey publicKey = KeyFactory.getInstance("RSA", "BC") .generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded())); // Verify signature Signature signature = Signature.getInstance("SHA256withRSA", "BC"); signature.initVerify(publicKey); signature.update(hashListString.getBytes("UTF-8")); if (signature.verify(signatureContent)) { System.out.println("Sign file signature is valid."); } else { System.err.println("Sign file signature failed validation."); } System.out.println("Sign file validation completed."); } }