SSE-KMS暗号化したS3バケットのクロスアカウントレプリケーションをやってみた
こんにちは。たかやまです。
SSE-KMSで暗号化したS3バケットのレプリケーションをする機会があったので、今回はその時の設定方法をまとめていきたいと思います。
アーキテクチャ
アーキテクチャの概要はこちらです。
やってみた
送信先アカウント
送信先アカウントでは以下のリソースを作成していきます。
- カスタマーマネージドキー
- レプリケーションを許可したS3バケット
カスタマーマネージドキーの作成
クロスアカウントレプリケーションの場合は、以下の注記にあるようにAWSマネージドキーはキーポリシーが変更できないためカスタマーマネージドキーを作成する必要があります。
このあと作成するカスタマーマネージドキーでは送信元アカウントがアクセスできるようなキーポリシーを設定していく必要があります。
AWS マネージドキー で暗号化されたオブジェクトは、キーポリシーを変更できないため、アカウント間で共有することはできません。SSE-KMS データをクロスアカウントに複製する必要がある場合は、AWS KMS の カスタマーマネージドキーを使用する必要があります。
サーバー側の暗号化 (SSE-C、SSE-S3、SSE-KMS) で作成されたオブジェクトをレプリケートする - Amazon Simple Storage Service
S3では非対称暗号化KMSキーはサポートしていないので、対称暗号化KMSキーを作成します。
エイリアスと説明は適当な値を設定してください。
キーの管理アクセス許可
は特に追加不要です。
キーの使用アクセス許可
の設定では、送信元アカウントがアクセスできるよう別のAWSアカウント
の設定で今回送信元となるアカウントIDを追加します。
最終的には以下のようなキーポリシーが定義されます。
{ "Id": "key-consolepolicy-3", "Version": "2012-10-17", "Statement": [ { "Sid": "Enable IAM User Permissions", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<送信先アカウント>:root" }, "Action": "kms:*", "Resource": "*" }, { "Sid": "Allow use of the key", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<送信元アカウント>:root" }, "Action": [ "kms:Encrypt", "kms:Decrypt", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:DescribeKey" ], "Resource": "*" }, { "Sid": "Allow attachment of persistent resources", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<送信元アカウント>:root" }, "Action": [ "kms:CreateGrant", "kms:ListGrants", "kms:RevokeGrant" ], "Resource": "*", "Condition": { "Bool": { "kms:GrantIsForAWSResource": "true" } } } ] }
カスタマーマネージドキーを作成できたら、ARNをコピーしておきます。
送信先S3バケットの作成
次にレプリケーション先のS3バケットを作成します。
バケットを作成するCloudFormationテンプレートを用意しているので、良ければ活用してください。
CloudFormationサンプル
各パラメータは以下のように設定してください。
- ProjectName : 適当な名前
- Environment : 適当な名前
- KmsKeyArn : 作成したカスタマーマネージドキーのARN
- SourceAccountId : 送信元アカウントID
Parameters: ProjectName: Type: String Default: test ConstraintDescription: This parameter is required. Description: (required)The name of the project. MinLength: 1 Environment: Type: String Default: dev ConstraintDescription: This parameter is required. Description: (required)The name of the environment. MinLength: 1 KmsKeyArn: Type: String Default: "" Description: KMS Key ARN of your own account SourceAccountId: Type: String Default: "" Description: Your Source AccountID Resources: DestinationBucket4BECDB47: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - BucketKeyEnabled: true ServerSideEncryptionByDefault: KMSMasterKeyID: Ref: KmsKeyArn SSEAlgorithm: aws:kms BucketName: Fn::Join: - "" - - Ref: ProjectName - "-" - Ref: Environment - -s3 PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true VersioningConfiguration: Status: Enabled UpdateReplacePolicy: Retain DeletionPolicy: Retain DestinationBucketPolicyFCD81088: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: DestinationBucket4BECDB47 PolicyDocument: Statement: - Action: - s3:ReplicateDelete - s3:ReplicateObject Condition: ArnLike: aws:PrincipalArn: arn:aws:iam::522303440560:role/source-dev-role-replication Effect: Allow Principal: AWS: "*" Resource: Fn::Join: - "" - - Fn::GetAtt: - DestinationBucket4BECDB47 - Arn - /* Sid: Set permissions for objects - Action: - s3:GetBucketVersioning - s3:List* - s3:PutBucketVersioning Condition: ArnLike: aws:PrincipalArn: Fn::Join: - "" - - "arn:aws:iam::" - Ref: SourceAccountId - :role/source-dev-role-replication Effect: Allow Principal: AWS: "*" Resource: Fn::GetAtt: - DestinationBucket4BECDB47 - Arn Sid: Set permissions on bucket Version: "2012-10-17"
バケットは以下の設定で作成していきます。
- バケット名 : 適当な名前
- AWSリージョン : 送信元アカウントのS3バケットと同じリージョン
- バケットのバージョニング : 有効
- デフォルト暗号化
- 暗号化キータイプ : AWS Key Management Serviceキー(SSE-KMS)
- AWS KMSキー : AWS KMSキーARNを入力する
- AWS KMSキー ARN : 作成したカスタマーマネージドキーのARN
バケットが作成できたら、送信元アカウントからレプリケーションを許可するバケットポリシーを設定します。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Set permissions for objects", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "s3:ReplicateDelete", "s3:ReplicateObject" ], "Resource": "arn:aws:s3:::<送信先アカウントバケット名>/*", "Condition": { "ArnLike": { "aws:PrincipalArn": "<送信元アカウントのレプリケーションRole ARN>" } } }, { "Sid": "Set permissions on bucket", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "s3:GetBucketVersioning", "s3:List*", "s3:PutBucketVersioning" ], "Resource": "arn:aws:s3:::<送信先アカウントバケット名>", "Condition": { "ArnLike": { "aws:PrincipalArn": "<送信元アカウントのレプリケーションRole ARN>" } } } ] }
公式で案内されているポリシーはPrincipalでアクセス制御を行っています。ただ、Principalに定義できる値は現在存在しているIAM Roleのみ指定でき、将来的に作成されるアカウントIDが入ったIAM Roleを指定することはできません。
ここではワークアラウンド的に、Principalを*
で指定し、ConditionでArnLike
を指定することで、IAM Roleの作成を待たずにレプリケーションを許可を実装しています。
レプリケート元バケットとレプリケート先バケットが異なるアカウントによって所有されている場合での、レプリケーションの設定 - Amazon Simple Storage Service
設定例:
送信元アカウント
送信先アカウントの設定が終えたら、次に送信元アカウントの設定を行います。
送信元アカウントでは以下のリソースを作成していきます。
- IAM Role
- レプリケーションを行うS3バケット
IAM RoleとS3バケットを作成するCloudFormationテンプレートも用意しているので、良ければ活用してください。
CloudFormationサンプル
各パラメータは以下のように設定してください。
- ProjectName : 適当な名前
- Environment : 適当な名前
- DestinationAccountId : 送信先アカウントID
- DestinationBucketName : 送信先のバケット名
- DestinationKmsKeyArn : 送信先アカウントで作成したカスタマーマネージドキーARN
Parameters: ProjectName: Type: String Default: test ConstraintDescription: This parameter is required. Description: (required)The name of the project. MinLength: 1 Environment: Type: String Default: dev ConstraintDescription: This parameter is required. Description: (required)The name of the environment. MinLength: 1 DestinationAccountId: Type: String Default: "" Description: Your Destination AccountID DestinationBucketName: Type: String Default: "" Description: Audit Bucket name of the Destination Account DestinationKmsKeyArn: Type: String Default: "" Description: KMS Key ARN of the Destination Account Resources: SourceBucketDDD2130A: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - BucketKeyEnabled: true ServerSideEncryptionByDefault: SSEAlgorithm: aws:kms BucketName: Fn::Join: - "" - - Ref: ProjectName - "-" - Ref: Environment - -s3 PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true ReplicationConfiguration: Role: Fn::GetAtt: - ReplicationRoleCE149CEC - Arn Rules: - DeleteMarkerReplication: Status: Disabled Destination: AccessControlTranslation: Owner: Destination Account: Ref: DestinationAccountId EncryptionConfiguration: ReplicaKmsKeyID: Ref: DestinationKmsKeyArn Bucket: Fn::Join: - "" - - "arn:aws:s3:::" - Ref: DestinationBucketName Metrics: Status: Enabled ReplicationTime: Status: Disabled Time: Minutes: 15 StorageClass: STANDARD Filter: Prefix: "" Id: Fn::Join: - "" - - Ref: ProjectName - "-" - Ref: Environment - -replication-rule Priority: 1 SourceSelectionCriteria: SseKmsEncryptedObjects: Status: Enabled Status: Enabled VersioningConfiguration: Status: Enabled UpdateReplacePolicy: Retain DeletionPolicy: Retain ReplicationRoleCE149CEC: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: s3.amazonaws.com Version: "2012-10-17" RoleName: Fn::Join: - "" - - Ref: ProjectName - "-" - Ref: Environment - -role-replication ReplicationPolicy48D09A53: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - s3:GetReplicationConfiguration - s3:ListBucket Effect: Allow Resource: Fn::GetAtt: - SourceBucketDDD2130A - Arn - Action: - s3:GetObjectVersionAcl - s3:GetObjectVersionForReplication - s3:GetObjectVersionTagging Effect: Allow Resource: Fn::Join: - "" - - Fn::GetAtt: - SourceBucketDDD2130A - Arn - /* - Action: - s3:ReplicateDelete - s3:ReplicateObject - s3:ReplicateTags Effect: Allow Resource: Fn::Join: - "" - - "arn:aws:s3:::" - Ref: DestinationBucketName - /* - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:GenerateDataKey* - kms:ReEncrypt* Effect: Allow Resource: Ref: DestinationKmsKeyArn Version: "2012-10-17" PolicyName: Fn::Join: - "" - - Ref: ProjectName - "-" - Ref: Environment - -policy-replication Roles: - Ref: ReplicationRoleCE149CEC
IAM Roleの作成
IAM Roleは以下の許可ポリシーと信頼関係のものを作成します。
- 許可ポリシー
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:GetReplicationConfiguration", "s3:ListBucket" ], "Resource": "arn:aws:s3:::<送信元アカウントバケット名>", "Effect": "Allow" }, { "Action": [ "s3:GetObjectVersionAcl", "s3:GetObjectVersionForReplication", "s3:GetObjectVersionTagging" ], "Resource": "arn:aws:s3:::<送信元アカウントバケット名>/*", "Effect": "Allow" }, { "Action": [ "s3:ReplicateDelete", "s3:ReplicateObject", "s3:ReplicateTags" ], "Resource": "arn:aws:s3:::<送信先アカウントバケット名>/*", "Effect": "Allow" }, { "Action": [ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", "kms:GenerateDataKey*", "kms:ReEncrypt*" ], "Resource": "<送信先アカウントで作成したカスタマーマネージドキーARN>", "Effect": "Allow" } ] }
許可のセットアップ - Amazon Simple Storage Service
- 信頼関係
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "s3.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
送信元S3バケットの作成
レプリケーション元のS3バケットは以下の設定で作成していきます。
- バケット名 : 適当な名前
- AWSリージョン : 送信元アカウントのS3バケットと同じリージョン
- バケットのバージョニング : 有効
- デフォルト暗号化
- 暗号化キータイプ : AWS Key Management Serviceキー(SSE-KMS)
- AWS KMSキー : AWS KMSキーARNを入力する
- AWS KMSキー ARN : AWSマネージド型キー aws/s3のARN
バケットが作成できたら、送信先アカウントのS3バケットにレプリケーションを行うための設定をしていきます。
バケットの管理
タブ -> レプリケーションルールを作成
を選択します。
レプリケーションルールは以下の設定で作成していきます。
- レプリケーションルール名 : 適当な名前
- 送信先
- 送信先 : 別のアカウントのバケットを指定する
- アカウントID : 送信先アカウントID
- バケット名 : 送信先バケット名
- オブジェクト所有者を送信先バケット所有者に変更 : 有効
- IAMロール
- IAMロールARN : 作成したIAM Role ARN
- 暗号化
- AWS KMSで暗号化されたオブジェクトをレプリケートする : 有効
- AWS KMSキーARN : 送信先アカウントで作成したカスタマーマネージドキーARN
- 追加のレプリケーションオプション
- レプリケーションメトリクス : 有効
追加のレプリケーションオプションは必要に応じて設定していただければと思いますが、レプリケーションメトリクスはレプリケーションの状態を確認するために設定しておくと良いかと思います。
レプリケーションの確認
送信先アカウントと送信元アカウントの設定が完了したら、送信元アカウントにオブジェクトをアップロードし、送信先アカウントのバケットにレプリケーションされているか確認していきます。
送信元アカウントにオブジェクトをアップロードします。
数秒〜数分後、オブジェクトのプロパティを確認するとレプリケーションステータスがCOMPLETED
でレプリケーションできていることが確認できます。
また、この時オブジェクトは送信元のKMSキーで暗号化されていることがわかります。
送信先アカウントを確認すると、送信元アカウントのオブジェクトがレプリケーションされていることが確認できます。
レプリケーションされたオブジェクトを確認すると、こちらは送信先アカウントのKMSキーで暗号化されていることがわかります。
もちろんオブジェクトは送信先アカウントがアクセスできるKMSキーで暗号化されているため正常にダウンロードすることができます。
誤ったKMSキーを指定した場合
ちなみに、送信先アカウントがアクセスできないKMSキーでもレプリケーションすることができてしまいます。
この状態でレプリケーションすると、送信先アカウントにレプリケーションされたオブジェクトは送信元アカウントのKMSキーで暗号化されていることが確認できます。
このオブジェクトを送信先アカウントでダウンロードしようとすると、KMSキーにアクセスできないためダウンロードすることができません。
なのでレプリケーションの成功だけでなく、送信先アカウントで問題なくダウンロードできることも確認していただければと思います。
<Error> <Code>AccessDenied</Code> <Message>The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access.</Message> <RequestId>MA5ZER5X2EZPV05K</RequestId> <HostId>jLSg9zEMEjTpO4dbH06xYaroZ7ps9pyAzAWADURuDCxPvk3h0l8DwASfl31BOBc6exijoV3CZJwmQTfOdL0EMQ==</HostId> </Error>
最後に
SSE-KMSを利用したクロスアカウントレプリケーションの設定方法を紹介しました。
KMSが絡んでくると思わぬところでアクセスできない問題が起きたりするので、レプリケーションしたオブジェクトは送信先アカウントで問題なくダウンロードできることも確認しておくと良いかと思います。
以上、たかやま(@nyan_kotaroo)でした。