Skip to content

Instantly share code, notes, and snippets.

@latesr
Last active November 30, 2021 16:24
Show Gist options
  • Save latesr/f38b2d30803a37d1b73b4c0d1678c3ae to your computer and use it in GitHub Desktop.
Save latesr/f38b2d30803a37d1b73b4c0d1678c3ae to your computer and use it in GitHub Desktop.
AWS cdk for V1 ReplicatingBucket and ReplicaBucket supporting replication of 'soft-delete' and cross account configuration
//References:
//For permissions required for replication:
// https://docs.aws.amazon.com/AmazonS3/latest/dev/setting-repl-config-perm-overview.html
//To understand delete propagation and the differences between V1 and V2 replication:
// https://aws.amazon.com/blogs/storage/managing-delete-marker-replication-in-amazon-s3/
//
//Summary:
//This exposes:
// 1) Two classes that extend s3.Bucket (ReplicatingBucket and ReplicaBucket)
// 2) Two interfaces that extends s3.BucketProps (ReplicatingBucketProps and ReplicaBucketProps)
import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';
import * as iam from '@aws-cdk/aws-iam';
import * as assert from "assert";
interface ReplicationRoleProps {
srcBucketArn: string;
dstBucketArn: string;
}
class ReplicationRole extends iam.Role {
constructor(scope: cdk.Construct, id: string, props: ReplicationRoleProps) {
super(scope, id, {assumedBy: new iam.ServicePrincipal('s3.amazonaws.com')});
this.addToPolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
's3:GetReplicationConfiguration',
's3:ListBucket',
],
resources: [props.srcBucketArn],
}));
this.addToPolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
's3:GetObjectVersion',
's3:GetObjectVersionAcl',
's3:GetObjectVersionTagging'
],
resources: [props.srcBucketArn + '/*'],
}));
this.addToPolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
's3:ReplicateObject',
's3:ReplicateDelete',
's3:ReplicateTags',
's3:ObjectOwnerOverrideToBucketOwner',
],
resources: [props.dstBucketArn + '/*'],
}));
}
}
export interface ReplicatingBucketProps extends s3.BucketProps {
dstBucketArn: string
dstStorageClass: string;
dstAccountId: string;
}
export class ReplicatingBucket extends s3.Bucket {
constructor(scope: cdk.Construct, id: string, props: ReplicatingBucketProps) {
super(scope, id, props);
assert(props.versioned == true);
const role = new ReplicationRole(this, id, {
srcBucketArn: this.bucketArn,
dstBucketArn: props.dstBucketArn,
});
const cfnArchive = this.node.defaultChild as s3.CfnBucket;
cfnArchive.replicationConfiguration = {
role: role.roleArn,
rules: [
{
status: "Enabled",
id: id,
prefix: "",
destination: {
accessControlTranslation: {
owner: "Destination",
},
account: props.dstAccountId,
bucket: props.dstBucketArn,
storageClass: props.dstStorageClass,
}
}
]
};
}
}
export interface ReplicaBucketProps extends s3.BucketProps {
srcAccountId: string;
}
export class ReplicaBucket extends s3.Bucket {
constructor(scope: cdk.Construct, id: string, props: ReplicaBucketProps) {
super(scope, id, props);
assert(props.versioned == true);
this.addToResourcePolicy(new iam.PolicyStatement({
actions: [
"s3:ReplicateDelete",
"s3:ReplicateObject",
"s3:ObjectOwnerOverrideToBucketOwner",
],
effect: iam.Effect.ALLOW,
resources: [
this.bucketArn + '/*'
],
principals: [
new iam.AccountPrincipal(props.srcAccountId),
],
}));
this.addToResourcePolicy(new iam.PolicyStatement({
actions: [
"s3:List*",
"s3:GetBucketVersioning",
"s3:PutBucketVersioning",
],
effect: iam.Effect.ALLOW,
resources: [
this.bucketArn,
],
principals: [
new iam.AccountPrincipal(props.srcAccountId),
],
}));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment