Skip to content

Commit

Permalink
Add DR Bucket to melbourne
Browse files Browse the repository at this point in the history
  • Loading branch information
johnf committed Sep 21, 2024
1 parent affd741 commit 18cc6cb
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 3 deletions.
25 changes: 22 additions & 3 deletions cdk/bin/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as cdk from 'aws-cdk-lib';
import { AwsSolutionsChecks, NagSuppressions } from 'cdk-nag';

import { MainStack } from '../lib/main-stack';
import { DrStack } from '../lib/dr-stack';
import { AppStack } from '../lib/app-stack';
import type { AppProps, Environment } from '../lib/types';

Expand Down Expand Up @@ -42,10 +43,28 @@ if (!prod) {

const app = new cdk.App();

const prodEnvironment = environments.find((env) => env.env === 'prod');
if (!prodEnvironment) {
throw new Error('No prod environment found');
}
const drStack = new DrStack(
app,
`${prodEnvironment.appName}-drstack-${prodEnvironment.env}`,
{ ...prodEnvironment, region: 'ap-southeast-4' },
{
env: { account: prodEnvironment.account, region: 'ap-southeast-4' },
},
);

environments.forEach((environment) => {
const mainStack = new MainStack(app, `${environment.appName}-stack-${environment.env}`, environment, {
env: { account: environment.account, region: environment.region },
});
const mainStack = new MainStack(
app,
`${environment.appName}-stack-${environment.env}`,
{ drBucket: environment.env === 'prod' ? drStack.drBucket : undefined, ...environment },
{
env: { account: environment.account, region: environment.region },
},
);

const props: AppProps = {
...environment,
Expand Down
78 changes: 78 additions & 0 deletions cdk/lib/main-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import * as cdk from 'aws-cdk-lib';
import type { Construct } from 'constructs';

import * as acm from 'aws-cdk-lib/aws-certificatemanager';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as route53 from 'aws-cdk-lib/aws-route53';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as ssm from 'aws-cdk-lib/aws-ssm';

import type { Environment } from './types';
import { NagSuppressions } from 'cdk-nag';
import { CfnBucket } from 'aws-cdk-lib/aws-s3';

export class MainStack extends cdk.Stack {
public catalogBucket: s3.IBucket;
Expand All @@ -26,6 +28,7 @@ export class MainStack extends cdk.Stack {
// account,
// region,
// railsEnv,
drBucket,
env,
acmeValue,
zoneName,
Expand Down Expand Up @@ -97,6 +100,7 @@ export class MainStack extends cdk.Stack {
// intelligentTieringConfigurations: [ ],
// TODO: Decide on lifecycle rules
lifecycleRules: [{ abortIncompleteMultipartUploadAfter: cdk.Duration.days(7) }],
versioned: env === 'prod',
inventories: [
{
destination: {
Expand Down Expand Up @@ -128,6 +132,80 @@ export class MainStack extends cdk.Stack {
serverAccessLogsPrefix: `s3-access-logs/${appName}-catalog-${env}`,
});

if (env === 'prod') {
if (!drBucket) {
throw new Error('DR bucket is required in prod environment');
}

const replicationRole = new iam.Role(this, 'CatalogBucketReplicationRole', {
roleName: 'catalog-bucket-replication-role',
assumedBy: new iam.ServicePrincipal('s3.amazonaws.com'),
});

replicationRole.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:GetReplicationConfiguration', 's3:ListBucket'],
resources: [this.catalogBucket.bucketArn],
}),
);

replicationRole.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
's3:GetObjectVersionForReplication',
's3:GetObjectVersionAcl',
's3:GetObjectVersionTagging',
's3:GetObjectVersion',
's3:GetObjectLegalHold',
's3:GetObjectRetention',
],
resources: [this.catalogBucket.arnForObjects('*')],
}),
);

NagSuppressions.addResourceSuppressions(
replicationRole,
[
{
id: 'AwsSolutions-IAM5',
reason: 'All wildcard permission are on purpose for replication',
},
],
true,
);

replicationRole.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:ReplicateObject', 's3:ReplicateDelete', 's3:ReplicateTags', 's3:GetObjectVersionTagging'],
resources: [`${drBucket.bucketArn}/*`],
}),
);

const cfnBucket = this.catalogBucket.node.defaultChild as CfnBucket;
cfnBucket.replicationConfiguration = {
role: replicationRole.roleArn,
rules: [
{
id: drBucket.bucketArn,
status: 'Enabled',
priority: 1,
filter: {},
destination: {
bucket: drBucket.bucketArn,
storageClass: s3.StorageClass.GLACIER_INSTANT_RETRIEVAL.toString(),
},

deleteMarkerReplication: {
status: 'Enabled',
},
},
],
};
}

cdk.Tags.of(this).add('uni:billing:application', 'para');
}
}
1 change: 1 addition & 0 deletions cdk/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type Environment = {
readonly zoneName: string,
readonly acmeValue: string,
readonly cloudflare: string,
readonly drBucket?: IBucket,
};

export type AppProps = Environment & {
Expand Down

0 comments on commit 18cc6cb

Please sign in to comment.