Skip to content

Commit

Permalink
feat(efs): graduate to stable 馃殌 (aws#14033)
Browse files Browse the repository at this point in the history
Following aws#11242, we also want to enable encryption at rest by default. 
Since switching to `true` requires a resource replacement, this PR introduces the default change behind a feature flag. 

New projects created with `cdk init` will have encryption enabled by default, and existing projects won't be affected. 

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
iliapolo authored and hollanddd committed Aug 26, 2021
1 parent 14bbf29 commit 22f96ed
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 25 deletions.
14 changes: 2 additions & 12 deletions packages/@aws-cdk/aws-efs/README.md
Expand Up @@ -5,17 +5,7 @@

![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)

> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use.
>
> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib
![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge)

> The APIs of higher level constructs in this module are experimental and under active development.
> They are subject to non-backward compatible changes or removal in any future version. These are
> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be
> announced in the release notes. This means that while you may use them, you may need to update
> your source code when upgrading to a newer version of this package.
![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge)

---

Expand Down Expand Up @@ -44,10 +34,10 @@ Access (IA) storage class.
```ts
const fileSystem = new efs.FileSystem(this, 'MyEfsFileSystem', {
vpc: new ec2.Vpc(this, 'VPC'),
encrypted: true, // file system is not encrypted by default
lifecyclePolicy: efs.LifecyclePolicy.AFTER_14_DAYS, // files are not transitioned to infrequent access (IA) storage by default
performanceMode: efs.PerformanceMode.GENERAL_PURPOSE, // default
});

```

鈿狅笍 An Amazon EFS file system's performance mode can't be changed after the file system has been created.
Expand Down
14 changes: 12 additions & 2 deletions packages/@aws-cdk/aws-efs/lib/efs-file-system.ts
@@ -1,6 +1,10 @@
import * as ec2 from '@aws-cdk/aws-ec2';
import * as kms from '@aws-cdk/aws-kms';
import { ConcreteDependable, IDependable, IResource, RemovalPolicy, Resource, Size, Tags } from '@aws-cdk/core';
// keep this import separate from other imports to reduce chance for merge conflicts with v2-main
// eslint-disable-next-line no-duplicate-imports
import { FeatureFlags } from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
import { Construct } from 'constructs';
import { AccessPoint, AccessPointOptions } from './access-point';
import { CfnFileSystem, CfnMountTarget } from './efs.generated';
Expand Down Expand Up @@ -122,7 +126,8 @@ export interface FileSystemProps {
/**
* Defines if the data at rest in the file system is encrypted or not.
*
* @default false
* @default - If your application has the '@aws-cdk/aws-efs:defaultEncryptionAtRest' feature flag set, the default is true, otherwise, the default is false.
* @link https://docs.aws.amazon.com/cdk/latest/guide/featureflags.html
*/
readonly encrypted?: boolean;

Expand Down Expand Up @@ -249,8 +254,13 @@ export class FileSystem extends Resource implements IFileSystem {
throw new Error('Property provisionedThroughputPerSecond is required when throughputMode is PROVISIONED');
}

// we explictly use 'undefined' to represent 'false' to maintain backwards compatibility since
// its considered an actual change in CloudFormations eyes, even though they have the same meaning.
const encrypted = props.encrypted ?? (FeatureFlags.of(this).isEnabled(
cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST) ? true : undefined);

const filesystem = new CfnFileSystem(this, 'Resource', {
encrypted: props.encrypted,
encrypted: encrypted,
kmsKeyId: props.kmsKey?.keyArn,
lifecyclePolicies: (props.lifecyclePolicy ? [{ transitionToIa: props.lifecyclePolicy }] : undefined),
performanceMode: props.performanceMode,
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-efs/package.json
Expand Up @@ -103,8 +103,8 @@
"resource-attribute:@aws-cdk/aws-efs.FileSystem.fileSystemArn"
]
},
"stability": "experimental",
"maturity": "experimental",
"stability": "stable",
"maturity": "stable",
"awscdkio": {
"announce": false
},
Expand Down
50 changes: 49 additions & 1 deletion packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts
@@ -1,7 +1,8 @@
import { expect as expectCDK, haveResource, ResourcePart, countResources } from '@aws-cdk/assert-internal';
import { ABSENT, expect as expectCDK, haveResource, ResourcePart, countResources } from '@aws-cdk/assert-internal';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as kms from '@aws-cdk/aws-kms';
import { RemovalPolicy, Size, Stack, Tags } from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
import { FileSystem, LifecyclePolicy, PerformanceMode, ThroughputMode } from '../lib';

let stack = new Stack();
Expand All @@ -12,6 +13,53 @@ beforeEach(() => {
vpc = new ec2.Vpc(stack, 'VPC');
});

test(`when ${cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST} is enabled, encryption is enabled by default`, () => {

const customStack = new Stack();
customStack.node.setContext(cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST, true);

const customVpc = new ec2.Vpc(customStack, 'VPC');
new FileSystem(customVpc, 'EfsFileSystem', {
vpc: customVpc,
});

expectCDK(customStack).to(haveResource('AWS::EFS::FileSystem', {
Encrypted: true,
}));

});

test(`when ${cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST} is disabled, encryption is disabled by default`, () => {

const customStack = new Stack();
customStack.node.setContext(cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST, false);

const customVpc = new ec2.Vpc(customStack, 'VPC');
new FileSystem(customVpc, 'EfsFileSystem', {
vpc: customVpc,
});

expectCDK(customStack).to(haveResource('AWS::EFS::FileSystem', {
Encrypted: ABSENT,
}));

});

test(`when ${cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST} is missing, encryption is disabled by default`, () => {

const customStack = new Stack();

const customVpc = new ec2.Vpc(customStack, 'VPC');
new FileSystem(customVpc, 'EfsFileSystem', {
vpc: customVpc,
});

expectCDK(customStack).to(haveResource('AWS::EFS::FileSystem', {
Encrypted: ABSENT,
}));

});

test('default file system is created correctly', () => {
// WHEN
new FileSystem(stack, 'EfsFileSystem', {
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-efs/test/integ.efs.expected.json
Expand Up @@ -453,6 +453,7 @@
"FileSystem8A8E25C0": {
"Type": "AWS::EFS::FileSystem",
"Properties": {
"Encrypted": true,
"FileSystemTags": [
{
"Key": "Name",
Expand Down
Expand Up @@ -453,6 +453,7 @@
"Efs9E8BF36B": {
"Type": "AWS::EFS::FileSystem",
"Properties": {
"Encrypted": true,
"FileSystemTags": [
{
"Key": "Name",
Expand Down Expand Up @@ -738,17 +739,14 @@
"Code": {
"ZipFile": "\nimport json\nimport os\nimport string\nimport random\nimport datetime\n\nMSG_FILE_PATH = '/mnt/msg/content'\n\ndef randomString(stringLength=10):\n letters = string.ascii_lowercase\n return ''.join(random.choice(letters) for i in range(stringLength))\n\ndef lambda_handler(event, context):\n with open(MSG_FILE_PATH, 'a') as f:\n f.write(f\"{datetime.datetime.utcnow():%Y-%m-%d-%H:%M:%S} \" + randomString(5) + ' ')\n\n file = open(MSG_FILE_PATH, \"r\")\n file_content = file.read()\n file.close()\n\n return {\n 'statusCode': 200,\n 'body': str(file_content)\n }\n"
},
"Handler": "index.lambda_handler",
"Role": {
"Fn::GetAtt": [
"MyLambdaServiceRole4539ECB6",
"Arn"
]
},
"Runtime": "python3.7",
"FileSystemConfigs": [
{
"LocalMountPath": "/mnt/msg",
"Arn": {
"Fn::Join": [
"",
Expand All @@ -771,9 +769,12 @@
}
]
]
}
},
"LocalMountPath": "/mnt/msg"
}
],
"Handler": "index.lambda_handler",
"Runtime": "python3.7",
"VpcConfig": {
"SecurityGroupIds": [
{
Expand Down Expand Up @@ -983,17 +984,14 @@
"Code": {
"ZipFile": "\nimport json\nimport os\nimport string\nimport random\nimport datetime\n\nMSG_FILE_PATH = '/mnt/msg/content'\n\ndef randomString(stringLength=10):\n letters = string.ascii_lowercase\n return ''.join(random.choice(letters) for i in range(stringLength))\n\ndef lambda_handler(event, context):\n with open(MSG_FILE_PATH, 'a') as f:\n f.write(f\"{datetime.datetime.utcnow():%Y-%m-%d-%H:%M:%S} \" + randomString(5) + ' ')\n\n file = open(MSG_FILE_PATH, \"r\")\n file_content = file.read()\n file.close()\n\n return {\n 'statusCode': 200,\n 'body': str(file_content)\n }\n"
},
"Handler": "index.lambda_handler",
"Role": {
"Fn::GetAtt": [
"MyLambda2ServiceRoleD09B370C",
"Arn"
]
},
"Runtime": "python3.7",
"FileSystemConfigs": [
{
"LocalMountPath": "/mnt/msg",
"Arn": {
"Fn::Join": [
"",
Expand All @@ -1016,9 +1014,12 @@
}
]
]
}
},
"LocalMountPath": "/mnt/msg"
}
],
"Handler": "index.lambda_handler",
"Runtime": "python3.7",
"VpcConfig": {
"SecurityGroupIds": [
{
Expand Down
8 changes: 8 additions & 0 deletions packages/@aws-cdk/cx-api/lib/features.ts
Expand Up @@ -135,6 +135,12 @@ export const RDS_LOWERCASE_DB_IDENTIFIER = '@aws-cdk/aws-rds:lowercaseDbIdentifi
*/
export const APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID = '@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId';

/**
* Enable this feature flag to have elastic file systems encrypted at rest by default.
*
* Encryption can also be configured explicitly using the `encrypted` property.
*/
export const EFS_DEFAULT_ENCRYPTION_AT_REST = '@aws-cdk/aws-efs:defaultEncryptionAtRest';
/**
* This map includes context keys and values for feature flags that enable
* capabilities "from the future", which we could not introduce as the default
Expand All @@ -159,6 +165,7 @@ export const FUTURE_FLAGS: { [key: string]: any } = {
[S3_GRANT_WRITE_WITHOUT_ACL]: true,
[ECS_REMOVE_DEFAULT_DESIRED_COUNT]: true,
[RDS_LOWERCASE_DB_IDENTIFIER]: true,
[EFS_DEFAULT_ENCRYPTION_AT_REST]: true,

// We will advertise this flag when the feature is complete
// [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: 'true',
Expand Down Expand Up @@ -187,6 +194,7 @@ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = {
[S3_GRANT_WRITE_WITHOUT_ACL]: false,
[ECS_REMOVE_DEFAULT_DESIRED_COUNT]: false,
[RDS_LOWERCASE_DB_IDENTIFIER]: false,
[EFS_DEFAULT_ENCRYPTION_AT_REST]: false,
};

export function futureFlagDefault(flag: string): boolean {
Expand Down

0 comments on commit 22f96ed

Please sign in to comment.