Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
addS3(bucketName: string, role?: IAM.IPrincipal, keepBucket = true) {
const removalPolicy = keepBucket ? RemPolicy.Orphan : RemPolicy.Destroy
const s3Props = { bucketName, removalPolicy }
const bucket = new S3.Bucket(this, `${this.id}-${bucketName}`, s3Props)
// tslint:disable-next-line:no-unused-expression
role && bucket.grantReadWrite(role)
return bucket
}
async function buildMyStack(scope: cdk.Construct, id: string, props: {}) {
const stack = new cdk.Stack(scope, id, props);
// TODO: inject environment variables
// should be via SSM. See here:
// https://docs.aws.amazon.com/cdk/latest/guide/get_ssm_value.html
await execute("./node_modules/.bin/next", ["build"]);
const manifest = await getBuildManifest();
const staticPages = Object.values(manifest.pages.html);
const bucket = new s3.Bucket(scope, `${id}-bucket`, {
publicReadAccess: true
});
new s3Upload.BucketDeployment(stack, `${id}-s3-static-pages`, {
// TODO: these files might already be prefixed with `pages/${page}`? This will need to be removed if so.
sources: staticPages.map(page =>
s3Upload.Source.asset(`./.next/serverless/${page}`)
),
destinationBucket: bucket,
destinationKeyPrefix: "static-pages"
});
new s3Upload.BucketDeployment(stack, `${id}-s3-next-static-files`, {
sources: [s3Upload.Source.asset("./.next/static")],
destinationBucket: bucket,
destinationKeyPrefix: "_next/static"
});
new s3Upload.BucketDeployment(stack, `${id}-s3-public-files`, {
constructor(parent, id, props) {
super(parent, id, props);
// Create a network for the application to run in
this.vpc = new ec2.VpcNetwork(this, 'vpc', {
maxAZs: 2,
natGateways: 1
});
// Create an ECS cluster
this.cluster = new ecs.Cluster(this, 'cluster', {
vpc: this.vpc
});
// Create S3 bucket
this.screenshotBucket = new s3.Bucket(this, 'screenshot-bucket', {
publicReadAccess: true
});
// Create queue
this.screenshotQueue = new sqs.Queue(this, 'screenshot-queue');
// Create DynamoDB table
this.screenshotTable = new dynamodb.Table(this, 'screenshots', {
partitionKey: { name: 'id', type: dynamodb.AttributeType.String },
billingMode: dynamodb.BillingMode.PayPerRequest
});
}
}
let encryptionKey: kms.IKey | undefined;
if (encryption === TableEncryption.CLIENT_SIDE_KMS && props.encryptionKey === undefined) {
// CSE-KMS should behave the same as SSE-KMS - use the provided key or create one automatically
// Since Bucket only knows about SSE, we repeat the logic for CSE-KMS at the Table level.
encryptionKey = new kms.Key(table, 'Key');
} else {
encryptionKey = props.encryptionKey;
}
// create the bucket if none was provided
if (!bucket) {
if (encryption === TableEncryption.CLIENT_SIDE_KMS) {
bucket = new s3.Bucket(table, 'Bucket');
} else {
bucket = new s3.Bucket(table, 'Bucket', {
encryption: encryptionMappings[encryption],
encryptionKey
});
encryptionKey = bucket.encryptionKey;
}
}
return {
bucket,
encryption,
encryptionKey
};
}
throw new Error('you can not specify encryption settings if you also provide a bucket');
}
let encryptionKey: kms.IKey | undefined;
if (encryption === TableEncryption.CLIENT_SIDE_KMS && props.encryptionKey === undefined) {
// CSE-KMS should behave the same as SSE-KMS - use the provided key or create one automatically
// Since Bucket only knows about SSE, we repeat the logic for CSE-KMS at the Table level.
encryptionKey = new kms.Key(table, 'Key');
} else {
encryptionKey = props.encryptionKey;
}
// create the bucket if none was provided
if (!bucket) {
if (encryption === TableEncryption.CLIENT_SIDE_KMS) {
bucket = new s3.Bucket(table, 'Bucket');
} else {
bucket = new s3.Bucket(table, 'Bucket', {
encryption: encryptionMappings[encryption],
encryptionKey
});
encryptionKey = bucket.encryptionKey;
}
}
return {
bucket,
encryption,
encryptionKey
};
}
if (columns.length === 0) {
throw new Error('you must specify at least one column for the table');
}
// Check there is at least one column and no duplicated column names or partition keys.
const names = new Set();
(columns.concat(partitionKeys || [])).forEach(column => {
if (names.has(column.name)) {
throw new Error(`column names and partition keys must be unique, but 'p1' is duplicated`);
}
names.add(column.name);
});
}
// map TableEncryption to bucket's SSE configuration (s3.BucketEncryption)
const encryptionMappings = {
[TableEncryption.S3_MANAGED]: s3.BucketEncryption.S3_MANAGED,
[TableEncryption.KMS_MANAGED]: s3.BucketEncryption.KMS_MANAGED,
[TableEncryption.KMS]: s3.BucketEncryption.KMS,
[TableEncryption.CLIENT_SIDE_KMS]: s3.BucketEncryption.UNENCRYPTED,
[TableEncryption.UNENCRYPTED]: s3.BucketEncryption.UNENCRYPTED,
};
// create the bucket to store a table's data depending on the `encryption` and `encryptionKey` properties.
function createBucket(table: Table, props: TableProps) {
const encryption = props.encryption || TableEncryption.UNENCRYPTED;
let bucket = props.bucket;
if (bucket && (encryption !== TableEncryption.UNENCRYPTED && encryption !== TableEncryption.CLIENT_SIDE_KMS)) {
throw new Error('you can not specify encryption settings if you also provide a bucket');
}
let encryptionKey: kms.IKey | undefined;
}
// Check there is at least one column and no duplicated column names or partition keys.
const names = new Set();
(columns.concat(partitionKeys || [])).forEach(column => {
if (names.has(column.name)) {
throw new Error(`column names and partition keys must be unique, but 'p1' is duplicated`);
}
names.add(column.name);
});
}
// map TableEncryption to bucket's SSE configuration (s3.BucketEncryption)
const encryptionMappings = {
[TableEncryption.S3_MANAGED]: s3.BucketEncryption.S3_MANAGED,
[TableEncryption.KMS_MANAGED]: s3.BucketEncryption.KMS_MANAGED,
[TableEncryption.KMS]: s3.BucketEncryption.KMS,
[TableEncryption.CLIENT_SIDE_KMS]: s3.BucketEncryption.UNENCRYPTED,
[TableEncryption.UNENCRYPTED]: s3.BucketEncryption.UNENCRYPTED,
};
// create the bucket to store a table's data depending on the `encryption` and `encryptionKey` properties.
function createBucket(table: Table, props: TableProps) {
const encryption = props.encryption || TableEncryption.UNENCRYPTED;
let bucket = props.bucket;
if (bucket && (encryption !== TableEncryption.UNENCRYPTED && encryption !== TableEncryption.CLIENT_SIDE_KMS)) {
throw new Error('you can not specify encryption settings if you also provide a bucket');
}
let encryptionKey: kms.IKey | undefined;
if (encryption === TableEncryption.CLIENT_SIDE_KMS && props.encryptionKey === undefined) {
// CSE-KMS should behave the same as SSE-KMS - use the provided key or create one automatically
const permissionId = `AllowBucketNotificationsFrom${bucket.node.uniqueId}`;
if (this.fn.node.tryFindChild(permissionId) === undefined) {
this.fn.addPermission(permissionId, {
sourceAccount: Stack.of(bucket).account,
principal: new iam.ServicePrincipal('s3.amazonaws.com'),
sourceArn: bucket.bucketArn
});
}
// if we have a permission resource for this relationship, add it as a dependency
// to the bucket notifications resource, so it will be created first.
const permission = this.fn.node.findChild(permissionId) as CfnResource;
return {
type: s3.BucketNotificationDestinationType.LAMBDA,
arn: this.fn.functionArn,
dependencies: permission ? [ permission ] : undefined
};
}
}
}
}));
// if this queue is encrypted, we need to allow S3 to read messages since that's how
// it verifies that the notification destination configuration is valid.
if (this.queue.encryptionMasterKey) {
this.queue.encryptionMasterKey.addToResourcePolicy(new iam.PolicyStatement({
principals: [new iam.ServicePrincipal('s3.amazonaws.com')],
actions: ['kms:GenerateDataKey*', 'kms:Decrypt'],
resources: ['*'],
}), /* allowNoOp */ false);
}
return {
arn: this.queue.queueArn,
type: s3.BucketNotificationDestinationType.QUEUE,
dependencies: [ this.queue ]
};
}
public bind(_scope: Construct, bucket: s3.IBucket): s3.BucketNotificationDestinationConfig {
this.topic.addToResourcePolicy(new iam.PolicyStatement({
principals: [new iam.ServicePrincipal('s3.amazonaws.com')],
actions: ['sns:Publish'],
resources: [this.topic.topicArn],
conditions: {
ArnLike: { "aws:SourceArn": bucket.bucketArn }
}
}));
return {
arn: this.topic.topicArn,
type: s3.BucketNotificationDestinationType.TOPIC,
dependencies: [ this.topic ] // make sure the topic policy resource is created before the notification config
};
}
}