-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0e09ca6
commit 46a6641
Showing
10 changed files
with
522 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module.exports = { | ||
root: true, | ||
// This tells ESLint to load the config from the package `eslint-config-inception` | ||
extends: ["eslint-config-cdk-inception"], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# @inception-health/cdk-secure-bucket | ||
|
||
Provides a construct that extends an s3 bucket. This is different than a lot of our constructs that wrap aws resources. | ||
|
||
This bucket implementation handles security best practices. Use can use it instead of a standard s3 bucket by default but you must use it if you're storing PII/PHI. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require("@inception-health/cdk-jest"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./s3.secure"; | ||
export * from "./lifecycle"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { aws_s3, Duration } from "aws-cdk-lib"; | ||
|
||
// The lifecycle policy for items should be managed cohesively | ||
export class LifecycleMode { | ||
static readonly NONE = new LifecycleMode(); | ||
|
||
static readonly BASIC = new LifecycleMode({ | ||
enabled: true, | ||
transitions: [ | ||
{ | ||
storageClass: aws_s3.StorageClass.INFREQUENT_ACCESS, | ||
transitionAfter: Duration.days(360), | ||
}, | ||
{ | ||
storageClass: aws_s3.StorageClass.GLACIER, | ||
transitionAfter: Duration.days(360 * 3), | ||
}, | ||
], | ||
}); | ||
|
||
static readonly INTELLIGENT = new LifecycleMode({ | ||
enabled: true, | ||
transitions: [ | ||
{ | ||
storageClass: aws_s3.StorageClass.INTELLIGENT_TIERING, | ||
transitionAfter: Duration.days(360), | ||
}, | ||
{ | ||
storageClass: aws_s3.StorageClass.GLACIER, | ||
transitionAfter: Duration.days(360 * 3), | ||
}, | ||
], | ||
}); | ||
|
||
private constructor(public readonly rule?: aws_s3.LifecycleRule) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
import { aws_kms, aws_s3 } from "aws-cdk-lib"; | ||
import * as cdk from "aws-cdk-lib"; | ||
import { Construct } from "constructs"; | ||
|
||
import { LifecycleMode } from "./lifecycle"; | ||
|
||
export interface SecureStoreProps | ||
extends Pick<aws_s3.BucketProps, "bucketName"> { | ||
/** | ||
* External KMS key to use for bucket encryption. | ||
* | ||
* The `encryption` property must be specified. | ||
* | ||
*/ | ||
encryptionKey: string; | ||
|
||
/** | ||
* Type of Bucket lifecycle to use. | ||
* | ||
* - Basic: simple basic lifecycle | ||
* - Intelligent: intelligent lifecycle | ||
* - None: no lifecycle (not recommended) | ||
* | ||
*@defaultValue BASIC | ||
*/ | ||
lifecycleMode?: LifecycleMode; | ||
|
||
/** | ||
* Bucket removal policy. | ||
* | ||
*@defaultValue RemovalPolicy.RETAIN | ||
*/ | ||
removalPolicy?: cdk.RemovalPolicy; | ||
} | ||
|
||
const defaultProps = { | ||
lifecycleMode: LifecycleMode.BASIC, | ||
removalPolicy: cdk.RemovalPolicy.RETAIN, | ||
}; | ||
|
||
/** | ||
* A secure S3 Bucket that follows Inception Health HIPAA policies | ||
* | ||
* References: | ||
* - https://docs.aws.amazon.com/AmazonS3/latest/userguide/security-best-practices.html | ||
*/ | ||
export class SecureBucket extends aws_s3.Bucket { | ||
private readonly props: SecureStoreProps; | ||
public readonly kmsKey: aws_kms.IKey; | ||
|
||
constructor(scope: Construct, id: string, props: SecureStoreProps) { | ||
const customKmsKey = aws_kms.Key.fromKeyArn( | ||
scope, | ||
`${id}-kms`, | ||
props.encryptionKey, | ||
); | ||
const config = Object.assign({}, defaultProps, props); | ||
|
||
// validation | ||
if (!config || !config.lifecycleMode) | ||
throw new Error("Construct requires default lifecycle"); | ||
|
||
super(scope, id, { | ||
bucketName: props.bucketName, | ||
// ================================================ | ||
// Lifecycle Management | ||
// ================================================ | ||
lifecycleRules: config.lifecycleMode.rule | ||
? [config.lifecycleMode.rule] | ||
: undefined, | ||
removalPolicy: config.removalPolicy, | ||
|
||
//autoDeleteObjects: false, // this is applicable only when removalPolicy` to be set to `RemovalPolicy.DESTROY` | ||
|
||
// ================================================ | ||
// Inventory Management | ||
// ================================================ | ||
// References: | ||
// - https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-inventory.html | ||
// inventories: , | ||
|
||
// ================================================ | ||
// Preventative Security Best Practices | ||
// ================================================ | ||
// Step 1- Use Amazon S3 block public access. | ||
blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL, | ||
// Step 2- Encryption | ||
encryption: aws_s3.BucketEncryption.KMS, | ||
// S3 Bucket Keys decrease the request traffic from Amazon S3 to AWS Key Management Service (AWS KMS) and reduce the cost of SSE-KMS | ||
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-key.html | ||
bucketKeyEnabled: true, | ||
encryptionKey: customKmsKey, | ||
// Step 3 - Enforce encryption of data in transit | ||
enforceSSL: true, | ||
// Step 4 - Versioning | ||
// Versioning is a means of keeping multiple variants of an object in the same bucket. | ||
// You can use versioning to preserve, retrieve, and restore every version of every | ||
// object stored in your Amazon S3 bucket. With versioning, you can easily recover | ||
// from both unintended user actions and application failures. | ||
// TODO: Also consider implementing on-going detective controls using | ||
// the s3-bucket-versioning-enabled managed AWS Config rule. | ||
versioned: true, | ||
|
||
// Step 5 - Cross-region replication | ||
// TODO: Consider Amazon S3 cross-region replication | ||
|
||
// Step 6 - VPC endpoints for Amazon S3 access | ||
// | ||
// TODO: Consider VPC endpoints for Amazon S3 access VPC endpoints for | ||
// Amazon S3 provide multiple ways to control access to your Amazon S3 | ||
// data: | ||
// - You can control the requests, users, or groups that are allowed | ||
// through a specific VPC endpoint. | ||
// - You can control which VPCs or VPC endpoints have access to your S3 | ||
// buckets by using S3 bucket policies. | ||
// - You can help prevent data exfiltration by using a VPC that does not | ||
// have an internet gateway. | ||
|
||
// ================================================ | ||
// Monitoring and Auditing Best Practices | ||
// ================================================ | ||
// Step 1 - Identify and audit all your Amazon S3 buckets | ||
|
||
// Step 3 - Enable Amazon S3 server access logging | ||
// TODO: should we build a custom s3 access log destination | ||
serverAccessLogsPrefix: "accesslogs", | ||
}); | ||
|
||
// ================================================ | ||
// Monitoring and Auditing Best Practices | ||
// ================================================ | ||
// Step 2 - Implement monitoring using AWS monitoring tools | ||
// Monitoring is an important part of maintaining the reliability, | ||
// security, availability, and performance of Amazon S3 and your AWS | ||
// solutions. AWS provides several tools and services to help you | ||
// monitor Amazon S3 and your other AWS services. For example, you can | ||
// monitor CloudWatch metrics for Amazon S3, particularly PutRequests, | ||
// GetRequests, 4xxErrors, and DeleteRequests. For more information, see | ||
// Monitoring metrics with Amazon CloudWatch and, Monitoring Amazon S3. | ||
// For a second example, see Example: Amazon S3 Bucket Activity. This | ||
// example describes how to create an Amazon CloudWatch alarm that is | ||
// triggered when an Amazon S3 API call is made to PUT or DELETE bucket | ||
// policy, bucket lifecycle, or bucket replication, or to PUT a bucket ACL. | ||
// const putRequestMetric = this.mm({ id: 'PutRequests' }); | ||
// putRequestMetric. | ||
|
||
// Step 4 - Use AWS CloudTrail | ||
|
||
// Step 5 - Enable AWS Config | ||
|
||
// Step 6 - Consider using Amazon Macie with Amazon S3 | ||
|
||
// Step 7 - Monitor AWS security advisories | ||
|
||
// ================================================ | ||
// Props | ||
// ================================================ | ||
this.props = config; | ||
this.kmsKey = customKmsKey; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
{ | ||
"name": "@inception-health/cdk-secure-bucket", | ||
"version": "0.0.1", | ||
"license": "MIT", | ||
"main": "./dist/index.js", | ||
"module": "./dist/index.mjs", | ||
"types": "./dist/index.d.ts", | ||
"files": [ | ||
"dist/**" | ||
], | ||
"scripts": { | ||
"build": "tsup lib/index.ts --format esm,cjs --dts", | ||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", | ||
"dev": "tsup lib/index.ts --format esm,cjs --watch --dts", | ||
"lint": "TIMING=1 eslint 'lib/**/*.{js,ts}'", | ||
"lint:fix": "TIMING=1 eslint 'lib/**/*.{js,ts}' --fix", | ||
"test": "jest --coverage", | ||
"test:u": "jest --coverage -u" | ||
}, | ||
"peerDependencies": { | ||
"aws-cdk": "2.x.x", | ||
"aws-cdk-lib": "2.x.x", | ||
"constructs": "10.x.x" | ||
}, | ||
"devDependencies": { | ||
"@inception-health/cdk-jest": "workspace:*", | ||
"@inception-health/cdk-tsconfig": "workspace:*", | ||
"@types/jest": "29.5.12", | ||
"@types/node": "20.11.19", | ||
"aws-cdk": "2.128.0", | ||
"aws-cdk-lib": "2.128.0", | ||
"constructs": "10.3.0", | ||
"eslint": "8.56.0", | ||
"eslint-config-cdk-inception": "workspace:*", | ||
"jest": "29.7.0", | ||
"ts-jest": "29.1.2", | ||
"tsup": "8.0.2", | ||
"typescript": "5.3.3" | ||
}, | ||
"repository": "git@github.com:inception-health/cdk.git", | ||
"sideEffects": false | ||
} |
Oops, something went wrong.