KMS キーで S3 オブジェクトを保護する

AWSBeginner
オンラインで実践に進む

はじめに

アプリケーションは、S3 に保存された非公開エクスポートを読み取る必要があります。カスタマー管理のキーで新しいアップロードを暗号化し、読み取り担当にアクセスを許可して、オブジェクト権限とキー権限が実際のダウンロードにどう影響するかをテストします。

先に S3 でファイルを保存して取得する、KMS で非公開エクスポートを暗号化・復号する と、それらの前提となる IAM ラボを完了してください。この新しい VM は、合成エクスポート、読み取りロールのセッション、独立した参照リソースを提供します。

認定試験との関連

このラボでは、次の試験トピックに関連する実践的な演習を行います。

暗号化されたオブジェクトストレージを準備する

このステップでは、カスタマー管理の KMS キーを作成し、新しいバケットがデフォルトでそのキーを使うように設定します。バケットはオブジェクトを保持し、各オブジェクトには exports/private-export.json のようなキーがあります。KMS によるサーバー側暗号化(SSE-KMS)では、S3 が選択したキーを使って保存オブジェクトを暗号化します。デフォルト暗号化は新しいアップロードに適用されるため、すべてのクライアントが暗号化オプションを繰り返し指定する必要はありません。

提供された合成データ private-export.json を使ってください。export-reader ロールのセッションには、最初はオブジェクトやキーへのアクセス権限がありません。参照用バケット、オブジェクト、キーを保持します。Terminal の隣で AWS View を開き、キーとバケットの状態、読み取り担当への権限付与、安全なバイト列の比較を確認します。

プロジェクトディレクトリから始め、提供された操作担当者の識別情報を確認します。cd はディレクトリを変更し、呼び出し元のクエリは認証情報を公開せずに識別情報の ARN を返します。

cd /home/labex/project
aws sts get-caller-identity --query Arn --output text

labex-sec02-operator ユーザーが返るはずです。対称型のカスタマー管理キーと、読みやすいエイリアスを作成します。--query は ARN を選択し、--output text は JSON の引用符を取り除き、$(...) は結果をシェル変数へ保存します。

KEY_ARN=$(aws kms create-key \
  --description labex-sec02-owned-export \
  --query KeyMetadata.Arn \
  --output text)
aws kms create-alias \
  --alias-name alias/labex-sec02-private-export \
  --target-key-id "$KEY_ARN"

名前の衝突を避けるため、タイムスタンプを末尾に付けた使い捨てバケット名を使います。labex-sec02-owned- 接頭辞は、自分のバケットを提供された参照バケットと区別します。このユニットでは us-east-1 を使うため、バケット作成時にロケーション制約は不要です。

BUCKET="labex-sec02-owned-$(date +%s)"
aws s3api create-bucket \
  --bucket "$BUCKET" \
  --region us-east-1 \
  --query Location \
  --output text

正確なキー ARN を使って SSE-KMS を設定します。S3 Bucket Key は、繰り返される KMS リクエストを減らせます。ここでは各オブジェクトが独自の KMS 暗号化コンテキストを使うように、無効のままにします。デフォルトルールを通常の JSON ファイルに書き込みます。ヒアドキュメントは $KEY_ARN を展開し、file:// は保存された設定を読み込みます。

cat > bucket-encryption.json <<EOF
{
  "Rules": [
    {
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "$KEY_ARN"
      },
      "BucketKeyEnabled": false
    }
  ]
}
EOF

aws s3api put-bucket-encryption --bucket "$BUCKET" \
  --server-side-encryption-configuration file://bucket-encryption.json
aws s3api get-bucket-encryption \
  --bucket "$BUCKET" \
  --query ServerSideEncryptionConfiguration

aws:kms、自分のキー ARN、BucketKeyEnabled: false が返るはずです。後続のコマンドのために、この Terminal で KEY_ARN と BUCKET を保持してください。AWS View では所有キーが有効で、バケットにはまだオブジェクトがありません。

読み取り担当に必要な両方の権限を付与する

このステップでは、エクスポートをアップロードし、ロールが元のバイト列を復元できるようにします。アップロードには、選択したキーへの kms:GenerateDataKey が必要です。SSE-KMS はデータキーでオブジェクトのバイト列を暗号化します。KMS はそのデータキーを保護します。S3 は暗号化オブジェクトと暗号化されたデータキーを保存し、認可された読み取り担当がオブジェクトをダウンロードするときに復号をリクエストします。キー素材を CLI 出力に表示する必要はありません。

S3 オブジェクトとキーの権限

この SSE-KMS オブジェクトの読み取りには、オブジェクトへのアクセス権限とキーの復号権限の両方が必要です。

s3api put-object で提供されたファイルをアップロードします。バケットのデフォルトが暗号化設定を提供し、--body private-export.json が指定されたローカルファイルをオブジェクトのバイト列として読み取ります。この小さなエクスポートには、単一パートの API を使います。

aws s3api put-object \
  --bucket "$BUCKET" \
  --key exports/private-export.json \
  --body private-export.json \
  --query '{Encryption:ServerSideEncryption,Key:SSEKMSKeyId,BucketKey:BucketKeyEnabled}'
aws s3api head-object \
  --bucket "$BUCKET" \
  --key exports/private-export.json \
  --query '{Encryption:ServerSideEncryption,Key:SSEKMSKeyId,Bytes:ContentLength}'

aws:kms、所有キーの ARN、元のファイルサイズが返るはずです。メタデータだけでは、読み取り担当が復号できるかは分かりません。まず、オブジェクトへのアクセスだけを許可します。オブジェクト ARN にはバケットとオブジェクトキーが含まれ、バケット ARN とは異なります。以下のヒアドキュメントは、ポリシーファイルを書き込み、その中の $BUCKET を展開します。

cat > read-object.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::$BUCKET/exports/private-export.json"
    }
  ]
}
EOF
aws iam put-role-policy \
  --role-name labex-sec02-export-reader \
  --policy-name ReadExportObject \
  --policy-document file://read-object.json

--profile export-reader で準備済みの読み取り担当のセッションを選択します。この試行は AccessDenied で失敗するはずです。ロールはこのオブジェクトを読み取れますが、KMS の復号権限がまだ付与されていません。

aws \
  --profile export-reader s3api get-object \
  --bucket "$BUCKET" \
  --key exports/private-export.json reader-export.json

このロールに、正確なキーへの kms:Decrypt だけを付与します。ダウンロードにキー管理や kms:GenerateDataKey は必要ありません。

cat > decrypt-key.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "$KEY_ARN"
    }
  ]
}
EOF
aws iam put-role-policy \
  --role-name labex-sec02-export-reader \
  --policy-name DecryptExportKey \
  --policy-document file://decrypt-key.json
aws \
  --profile export-reader s3api get-object \
  --bucket "$BUCKET" \
  --key exports/private-export.json reader-export.json \
  --query '{Encryption:ServerSideEncryption,Key:SSEKMSKeyId}'
chmod 600 reader-export.json
cmp private-export.json reader-export.json

バイト列の内容が一致すると、cmp は何も表示せず成功を返します。AWS View には、保存された暗号文と、返されたバイト列が提供されたエクスポートと一致する読み取り担当の GetObject が表示されるはずです。これらは別々の観察です。暗号化されたストレージは保存時のバイト列を保護し、範囲を限定した権限は取得を制御します。

正確なキーへの権限付与後の AWS View の例:保存された暗号文と、読み取り担当が復元した元のバイト列

権限とキー状態による失敗を診断する

このステップでは、復号権限の不足と無効なキーを区別します。一度に 1 つの条件だけが変わるように、オブジェクト権限を保持してください。

読み取り担当へのキー権限付与を削除し、同じオブジェクトのダウンロードを再試行します。ロールには引き続き s3:GetObject がありますが、リクエストは AccessDenied で失敗するはずです。

aws iam delete-role-policy \
  --role-name labex-sec02-export-reader \
  --policy-name DecryptExportKey
aws \
  --profile export-reader s3api get-object \
  --bucket "$BUCKET" \
  --key exports/private-export.json reader-export.json

残っているオブジェクトポリシーを確認します。このエクスポートオブジェクトだけを指定しているはずです。

aws iam get-role-policy \
  --role-name labex-sec02-export-reader \
  --policy-name ReadExportObject \
  --query PolicyDocument

正確なキーへの権限付与を復元し、自分のキーを無効にします。無効なキーは引き続き存在しますが、暗号処理を実行できません。無関係な参照キーを変更しないでください。

aws iam put-role-policy \
  --role-name labex-sec02-export-reader \
  --policy-name DecryptExportKey \
  --policy-document file://decrypt-key.json
aws kms disable-key --key-id "$KEY_ARN"
aws \
  --profile export-reader s3api get-object \
  --bucket "$BUCKET" \
  --key exports/private-export.json reader-export.json

無効なキーによる失敗が返るはずです。IAM 権限があっても、無効なキーを使用可能にはできません。ネイティブな状態を確認した後、キーを有効にしてオブジェクトを再取得します。

aws kms describe-key --key-id "$KEY_ARN" --query KeyMetadata.KeyState --output text
aws kms enable-key --key-id "$KEY_ARN"
aws \
  --profile export-reader s3api get-object \
  --bucket "$BUCKET" \
  --key exports/private-export.json reader-export.json \
  --query ServerSideEncryption \
  --output text
chmod 600 reader-export.json
cmp private-export.json reader-export.json

aws:kms が返り、比較が成功するはずです。AWS View には、失敗したリクエストと成功した復元がまとめて表示され、参照バケットとキーは引き続き使用できます。権限取り消しと無効なキーによる失敗、およびその後の読み取り成功を示す AWS View の例

ダウンロードの失敗後も古いローカルファイルが残る場合があります。そのため、ファイルの存在だけではリクエストの成功を証明できません。署名付きの読み取りと比較によって復元を確認します。

所有リソースを削除してキーの削除をスケジュールする

このステップでは、対象のエクスポートリソースを後片付けします。先に前のステップの機能確認を終えてください。S3 バケットは削除前に空にする必要があります。カスタマー管理の KMS キーは即座に消えるのではなく、削除待機期間を使います。

自分の指定したエクスポートだけを削除し、その後バケットを削除します。一覧取得が成功することを確認し、自分の $BUCKET が存在せず、labex-sec02-reference が残っていることを確かめます。

aws s3api delete-object --bucket "$BUCKET" --key exports/private-export.json
aws s3api delete-bucket --bucket "$BUCKET"
aws s3api list-buckets --query 'Buckets[].Name'

追加した 2 つの権限と所有エイリアスを削除します。提供された読み取りロールはセッション用の準備リソースです。そのロールや無関係な参照リソースを削除しないでください。

aws iam delete-role-policy \
  --role-name labex-sec02-export-reader \
  --policy-name ReadExportObject
aws iam delete-role-policy \
  --role-name labex-sec02-export-reader \
  --policy-name DecryptExportKey
aws iam list-role-policies --role-name labex-sec02-export-reader --query PolicyNames
aws kms delete-alias --alias-name alias/labex-sec02-private-export

最短の 7 日間で自分のキーの削除をスケジュールし、ネイティブな状態を読み取ります。スケジュール設定によってキーはすぐに使用不可になりますが、すでに削除されたことを証明するものではありません。

aws kms schedule-key-deletion \
  --key-id "$KEY_ARN" \
  --pending-window-in-days 7 \
  --query DeletionDate \
  --output text
aws kms describe-key --key-id "$KEY_ARN" --query KeyMetadata.KeyState --output text
aws kms describe-key \
  --key-id alias/labex-sec02-reference \
  --query KeyMetadata.KeyState \
  --output text

自分のキーは PendingDeletion、参照キーは Enabled となるはずです。名前を指定したローカルファイルを削除します。これらのコマンドは無関係なプロジェクトファイルをそのまま残します。

rm -f private-export.json reader-export.json read-object.json decrypt-key.json bucket-encryption.json

使い捨て CLI プロファイルを削除する前に、このステップの検証を実行してください。後片付けを証明するのは、成功したネイティブな一覧クエリであり、認証エラーではありません。

rm -f /home/labex/.aws/credentials /home/labex/.aws/config
unset KEY_ARN BUCKET

まとめ

バケットのデフォルトとして SSE-KMS を設定し、暗号化されたエクスポートをアップロードして、1 つのオブジェクトと 1 つのキーに限定したロールで元のバイト列を復元しました。kms:Decrypt の取り消しとキーの無効化は、それぞれオブジェクトへの権限付与を変えずに読み取りを阻止しました。アクセスを復元し、所有する S3 リソースだけを削除して、参照バケットとキーを保持しながら、所有する KMS キーの削除をスケジュールしました。