After much research, I have realized that there isn’t really a concise, straight to the point guide on designing replication in S3, using SSE-KMS, and cross-account ownership. So, a quick guide on what has worked for me:
In your ORIGIN ACCOUNT
- Create origin Bucket
- Create origin IAM role
- Create origin IAM Policy
- Create origin KMS key
- Set up origin bucket replication
In your TARGET ACCOUNT
- Create target bucket
- Create target bucket policy
- Create target KMS Key
- Create target KMS policy
- Create Target IAM Role
Things to make
ORIGIN.IAM.ROLE (Assume Role Policy)
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
ORIGIN.IAM.POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:ListBucket",
"s3:GetReplicationConfiguration",
"s3:GetObjectVersionForReplication",
"s3:GetObjectVersionAcl",
"s3:GetObjectVersionTagging",
"s3:GetObjectRetention",
"s3:GetObjectLegalHold",
"s3:GetObjectVersion",
"s3:ObjectOwnerOverrideToBucketOwner"
],
"Effect": "Allow",
"Resource": [
"ORIGIN.BUCKET.ARN",
"ORIGIN.BUCKET.ARN/*"
]
},
{
"Action": [
"s3:ReplicateObject",
"s3:ReplicateDelete",
"s3:ReplicateTags",
"s3:GetObjectVersionTagging",
"s3:ObjectOwnerOverrideToBucketOwner"
],
"Effect": "Allow",
"Resource": "TARGET.BUCKET.NAME/*"
},
{
"Action": [
"kms:Decrypt"
],
"Effect": "Allow",
"Resource": "ORIGIN.KMS.KEY.ARN"
},
{
"Action": [
"kms:Encrypt"
],
"Effect": "Allow",
"Resource": "TARGET.KMS.KEY.ARN"
}
]
}
ORIGIN.BUCKET
Set up Replication through the GUI, Cloudformation, or another functionality. I use Terraform for a lot of stuff so here is a Terraform version of the S3 bucket I would deploy for my origin:
resource "aws_s3_bucket" "INSERTUNIQUENAME" {
bucket = "INSERTBUCKETNAME"
acl = "private"
lifecycle_rule {
id = "SaveMoney"
enabled = true
expiration {
days = 30
}
}
versioning {
enabled = true
}
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
kms_master_key_id = "ORIGIN.KMS.KEY.ID"
sse_algorithm = "aws:kms"
}
}
}
replication_configuration {
role = "ORIGIN.IAM.ROLE.ARN"
rules {
id = "replicate_to_other_bucket"
status = "Enabled"
source_selection_criteria {
sse_kms_encrypted_objects {
enabled = "true"
}
}
destination {
bucket = TARGET.BUCKET.NAME
storage_class = "STANDARD"
replica_kms_key_id = "TARGET.KMS.ARN"
access_control_translation {
owner = "Destination"
}
account_id = "TARGET.ACCOUNT.ID"
}
}
}
tags = {
Name = "Value"
}
}
TARGET.KMS
statement {
sid = "AllowExternalAccountUse"
effect = "Allow"
principals {
type = "AWS"
identifiers = [
"ORIGIN.ROLE.ARN"
]
}
actions = [
"kms:Encrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
resources = ["*"]
}
statement {
sid = "AllowAdmin"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:aws:iam::TARGET.ACCOUNTID:root"]
}
actions = ["kms:*"]
resources = ["*"]
}
TARGET.BUCKETPOLICY
{
"Version": "2012-10-17",
"Statement": [
"Sid": "S3ReplicationPolicy",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::ORIGIN.ACCOUNTID:root"
]
},
"Action": [
"s3:GetBucketVersioning",
"s3:PutBucketVersioning",
"s3:ReplicateObject",
"s3:ObjectOwnerOverrideToBucketOwner"
],
"Resource": [
"TARGET.BUCKET.ARN",
"TARGET.BUCKET.ARN/*"
]
}
]
}