diff --git a/codebuild_specs/e2e_workflow.yml b/codebuild_specs/e2e_workflow.yml index cca6c53b8e..25a82f00bf 100644 --- a/codebuild_specs/e2e_workflow.yml +++ b/codebuild_specs/e2e_workflow.yml @@ -4,7 +4,7 @@ env: shell: bash compute-type: BUILD_GENERAL1_MEDIUM variables: - JSII_DEPRECATED: 'quiet' + JSII_DEPRECATED: quiet batch: fast-fail: false build-graph: diff --git a/packages/amplify-data-construct/.jsii b/packages/amplify-data-construct/.jsii index 424689b3ac..44216a7c75 100644 --- a/packages/amplify-data-construct/.jsii +++ b/packages/amplify-data-construct/.jsii @@ -295,6 +295,19 @@ } } }, + "aws-cdk-lib.aws_aiops": { + "targets": { + "dotnet": { + "package": "Amazon.CDK.AWS.AIOps" + }, + "java": { + "package": "software.amazon.awscdk.services.aiops" + }, + "python": { + "module": "aws_cdk.aws_aiops" + } + } + }, "aws-cdk-lib.aws_amazonmq": { "targets": { "dotnet": { @@ -542,6 +555,19 @@ } } }, + "aws-cdk-lib.aws_arcregionswitch": { + "targets": { + "dotnet": { + "package": "Amazon.CDK.AWS.ARCRegionSwitch" + }, + "java": { + "package": "software.amazon.awscdk.services.arcregionswitch" + }, + "python": { + "module": "aws_cdk.aws_arcregionswitch" + } + } + }, "aws-cdk-lib.aws_arczonalshift": { "targets": { "dotnet": { @@ -1687,6 +1713,19 @@ } } }, + "aws-cdk-lib.aws_evs": { + "targets": { + "dotnet": { + "package": "Amazon.CDK.AWS.EVS" + }, + "java": { + "package": "software.amazon.awscdk.services.evs" + }, + "python": { + "module": "aws_cdk.aws_evs" + } + } + }, "aws-cdk-lib.aws_finspace": { "targets": { "dotnet": { @@ -2623,6 +2662,19 @@ } } }, + "aws-cdk-lib.aws_mpa": { + "targets": { + "dotnet": { + "package": "Amazon.CDK.AWS.MPA" + }, + "java": { + "package": "software.amazon.awscdk.services.mpa" + }, + "python": { + "module": "aws_cdk.aws_mpa" + } + } + }, "aws-cdk-lib.aws_msk": { "targets": { "dotnet": { @@ -2753,6 +2805,32 @@ } } }, + "aws-cdk-lib.aws_observabilityadmin": { + "targets": { + "dotnet": { + "package": "Amazon.CDK.AWS.ObservabilityAdmin" + }, + "java": { + "package": "software.amazon.awscdk.services.observabilityadmin" + }, + "python": { + "module": "aws_cdk.aws_observabilityadmin" + } + } + }, + "aws-cdk-lib.aws_odb": { + "targets": { + "dotnet": { + "package": "Amazon.CDK.AWS.ODB" + }, + "java": { + "package": "software.amazon.awscdk.services.odb" + }, + "python": { + "module": "aws_cdk.aws_odb" + } + } + }, "aws-cdk-lib.aws_omics": { "targets": { "dotnet": { @@ -3897,6 +3975,19 @@ } } }, + "aws-cdk-lib.aws_workspacesinstances": { + "targets": { + "dotnet": { + "package": "Amazon.CDK.AWS.WorkspacesInstances" + }, + "java": { + "package": "software.amazon.awscdk.services.workspacesinstances" + }, + "python": { + "module": "aws_cdk.aws_workspacesinstances" + } + } + }, "aws-cdk-lib.aws_workspacesthinclient": { "targets": { "dotnet": { @@ -4135,5 +4226,5 @@ }, "types": {}, "version": "1.16.3", - "fingerprint": "fzGBCKNwHwuPMXWS1xoNXBM2atwR4IUBCU8MceERXbE=" + "fingerprint": "HTOsJxkNU8L6RCYxGgyH9u3mGcqEGwe0olj0Gkklq+g=" } \ No newline at end of file diff --git a/packages/amplify-graphql-api-construct/API.md b/packages/amplify-graphql-api-construct/API.md index 70582e7e0e..f0320a1fe8 100644 --- a/packages/amplify-graphql-api-construct/API.md +++ b/packages/amplify-graphql-api-construct/API.md @@ -344,6 +344,7 @@ export interface PartialTranslationBehavior { readonly allowDestructiveGraphqlSchemaUpdates?: boolean; readonly disableResolverDeduping?: boolean; readonly enableAutoIndexQueryNames?: boolean; + readonly enableSearchEncryptionAtRest?: boolean; readonly enableSearchNodeToNodeEncryption?: boolean; readonly enableTransformerCfnOutputs?: boolean; readonly populateOwnerFieldForStaticGroupAuth?: boolean; @@ -478,7 +479,7 @@ export interface TranslationBehavior { readonly allowDestructiveGraphqlSchemaUpdates: boolean; readonly disableResolverDeduping: boolean; readonly enableAutoIndexQueryNames: boolean; - // (undocumented) + readonly enableSearchEncryptionAtRest: boolean; readonly enableSearchNodeToNodeEncryption: boolean; readonly enableTransformerCfnOutputs: boolean; readonly populateOwnerFieldForStaticGroupAuth: boolean; diff --git a/packages/amplify-graphql-api-construct/src/internal/default-parameters.ts b/packages/amplify-graphql-api-construct/src/internal/default-parameters.ts index 5b3b780219..5dbab6f8dc 100644 --- a/packages/amplify-graphql-api-construct/src/internal/default-parameters.ts +++ b/packages/amplify-graphql-api-construct/src/internal/default-parameters.ts @@ -17,6 +17,7 @@ export const defaultTranslationBehavior: TranslationBehavior = { enableAutoIndexQueryNames: true, respectPrimaryKeyAttributesOnConnectionField: true, enableSearchNodeToNodeEncryption: false, + enableSearchEncryptionAtRest: false, enableTransformerCfnOutputs: false, allowDestructiveGraphqlSchemaUpdates: false, replaceTableUponGsiUpdate: false, diff --git a/packages/amplify-graphql-api-construct/src/types.ts b/packages/amplify-graphql-api-construct/src/types.ts index c14e344199..c1b6a6e429 100644 --- a/packages/amplify-graphql-api-construct/src/types.ts +++ b/packages/amplify-graphql-api-construct/src/types.ts @@ -353,7 +353,7 @@ export type ConflictResolutionStrategy = * @deprecated use DataStoreConfiguration instead. */ /* c8 ignore start */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type export interface ConflictResolution extends DataStoreConfiguration {} /* c8 ignore stop */ @@ -548,8 +548,20 @@ export interface TranslationBehavior { */ readonly respectPrimaryKeyAttributesOnConnectionField: boolean; + /** + * Whether Node to Node encryption is enabled on the ElasticSearch cluster + * + * @default false + */ readonly enableSearchNodeToNodeEncryption: boolean; + /** + * Whether server-side encryption is enabled on the ElasticSearch cluster + * + * @default false + */ + readonly enableSearchEncryptionAtRest: boolean; + /** * When enabled, internal cfn outputs which existed in Amplify-generated apps will continue to be emitted. * @default false @@ -583,7 +595,11 @@ export interface TranslationBehavior { /* c8 ignore stop */ /** - * A utility interface equivalent to Partial. + * A utility interface equivalent to Partial, plus + * some additional private fields. + * + * It's not a mapped type because this file is compiled using jsii which + * doesn't support that. */ /* c8 ignore start */ export interface PartialTranslationBehavior { @@ -652,14 +668,19 @@ export interface PartialTranslationBehavior { readonly respectPrimaryKeyAttributesOnConnectionField?: boolean; /** - * If enabled, set nodeToNodeEncryption on the searchable domain (if one exists). Not recommended for use, prefer - * to use `Object.values(resources.additionalResources['AWS::Elasticsearch::Domain']).forEach((domain: CfnDomain) => { - * domain.NodeToNodeEncryptionOptions = { Enabled: True }; - * }); + * Whether Node to Node encryption is enabled on the ElasticSearch cluster + * * @default false */ readonly enableSearchNodeToNodeEncryption?: boolean; + /** + * Whether server-side encryption is enabled on the ElasticSearch cluster + * + * @default false + */ + readonly enableSearchEncryptionAtRest?: boolean; + /** * When enabled, internal cfn outputs which existed in Amplify-generated apps will continue to be emitted. * @default false @@ -683,13 +704,12 @@ export interface PartialTranslationBehavior { /** * This behavior will only come into effect when both "allowDestructiveGraphqlSchemaUpdates" and this value are set to true * - * When enabled, any global secondary index update operation will replace the table instead of iterative deployment, which will WIPE ALL - * EXISTING DATA but cost much less time for deployment This will only affect DynamoDB tables with provision strategy "AMPLIFY_TABLE". + * When enabled, any GSI update operation will replace the table instead of iterative deployment, which will WIPE ALL EXISTING DATA but + * cost much less time for deployment This will only affect DynamoDB tables with provision strategy "AMPLIFY_TABLE". * @default false * @experimental */ readonly replaceTableUponGsiUpdate?: boolean; - /** * When enabled, sandbox deployment will be faster by skipping the creation of the Hotswap friendly resources. * diff --git a/packages/amplify-graphql-searchable-transformer/src/__tests__/amplify-graphql-searchable-transformer.test.ts b/packages/amplify-graphql-searchable-transformer/src/__tests__/amplify-graphql-searchable-transformer.test.ts index e78feed434..8f10f3250f 100644 --- a/packages/amplify-graphql-searchable-transformer/src/__tests__/amplify-graphql-searchable-transformer.test.ts +++ b/packages/amplify-graphql-searchable-transformer/src/__tests__/amplify-graphql-searchable-transformer.test.ts @@ -447,6 +447,23 @@ describe('nodeToNodeEncryption transformParameter', () => { }, }); }); + + it('synthesizes w/ serverSideEncryption enabled if specified', () => { + const out = testTransform({ + schema, + transformers: [new ModelTransformer(), new SearchableModelTransformer()], + transformParameters: { + enableSearchEncryptionAtRest: true, + }, + }); + expect(out).toBeDefined(); + const searchableStack = out.stacks.SearchableStack; + Template.fromJSON(searchableStack).hasResourceProperties('AWS::Elasticsearch::Domain', { + EncryptionAtRestOptions: { + Enabled: true, + }, + }); + }); }); describe('auth', () => { diff --git a/packages/amplify-graphql-searchable-transformer/src/cdk/create-searchable-domain.ts b/packages/amplify-graphql-searchable-transformer/src/cdk/create-searchable-domain.ts index 7dd28b9ff6..6c99bb5b57 100644 --- a/packages/amplify-graphql-searchable-transformer/src/cdk/create-searchable-domain.ts +++ b/packages/amplify-graphql-searchable-transformer/src/cdk/create-searchable-domain.ts @@ -12,11 +12,15 @@ export const createSearchableDomain = ( parameterMap: Map, apiId: string, nodeToNodeEncryption: boolean, + encryptionAtRest: boolean, ): Domain => { const { OpenSearchEBSVolumeGB, OpenSearchInstanceType, OpenSearchInstanceCount } = ResourceConstants.PARAMETERS; const { OpenSearchDomainLogicalID } = ResourceConstants.RESOURCES; const { HasEnvironmentParameter } = ResourceConstants.CONDITIONS; + // Encryption at rest is not supported with t2.small.elasticsearch instances + // https://docs.aws.amazon.com/opensearch-service/latest/developerguide/supported-instance-types.html + const domain = new Domain(stack, OpenSearchDomainLogicalID, { version: { version: '7.10' } as ElasticsearchVersion, enforceHttps: true, @@ -26,6 +30,9 @@ export const createSearchableDomain = ( volumeSize: parameterMap.get(OpenSearchEBSVolumeGB)?.valueAsNumber, }, nodeToNodeEncryption, + encryptionAtRest: { + enabled: encryptionAtRest, + }, zoneAwareness: { enabled: false, }, diff --git a/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts b/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts index 470ca840f5..b025046c47 100644 --- a/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts +++ b/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts @@ -311,6 +311,7 @@ export class SearchableModelTransformer extends TransformerPluginBase { parameterMap, context.api.apiId, context.transformParameters.enableSearchNodeToNodeEncryption, + context.transformParameters.enableSearchEncryptionAtRest, ); const openSearchRole = createSearchableDomainRole(context, stack, parameterMap); diff --git a/packages/amplify-graphql-transformer-core/src/transformer-context/transform-parameters.ts b/packages/amplify-graphql-transformer-core/src/transformer-context/transform-parameters.ts index f40c7ee1fb..fbe353dd06 100644 --- a/packages/amplify-graphql-transformer-core/src/transformer-context/transform-parameters.ts +++ b/packages/amplify-graphql-transformer-core/src/transformer-context/transform-parameters.ts @@ -27,4 +27,5 @@ export const defaultTransformParameters: TransformParameters = { // Search Params enableSearchNodeToNodeEncryption: false, + enableSearchEncryptionAtRest: false, }; diff --git a/packages/amplify-graphql-transformer-interfaces/API.md b/packages/amplify-graphql-transformer-interfaces/API.md index ba15479165..e5efd0f4c3 100644 --- a/packages/amplify-graphql-transformer-interfaces/API.md +++ b/packages/amplify-graphql-transformer-interfaces/API.md @@ -965,6 +965,7 @@ export type TransformParameters = { enableAutoIndexQueryNames: boolean; respectPrimaryKeyAttributesOnConnectionField: boolean; enableSearchNodeToNodeEncryption: boolean; + enableSearchEncryptionAtRest: boolean; }; // @public (undocumented) diff --git a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transform-parameters.ts b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transform-parameters.ts index 6f82377918..2dcc783aa8 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transform-parameters.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transform-parameters.ts @@ -31,4 +31,5 @@ export type TransformParameters = { // Search Params enableSearchNodeToNodeEncryption: boolean; + enableSearchEncryptionAtRest: boolean; }; diff --git a/packages/amplify-graphql-transformer-test-utils/src/test-transform.ts b/packages/amplify-graphql-transformer-test-utils/src/test-transform.ts index 06483ff73b..3aca8a2cd0 100644 --- a/packages/amplify-graphql-transformer-test-utils/src/test-transform.ts +++ b/packages/amplify-graphql-transformer-test-utils/src/test-transform.ts @@ -36,9 +36,12 @@ export type TestTransformParameters = RDSLayerMappingProvider & /** * Defaults for transform parameters in tests, if they're not set explicitly. + * + * Will be applied to e2e tests, so also affect actually deployed infrastructure. */ const DEFAULT_TEST_TRANSFORM_PARAMETERS: Partial = { enableSearchNodeToNodeEncryption: true, + enableSearchEncryptionAtRest: true, }; /** diff --git a/packages/amplify-graphql-transformer/src/__tests__/graphql-transformer.test.ts b/packages/amplify-graphql-transformer/src/__tests__/graphql-transformer.test.ts index 7f147383a4..4e1f77eee7 100644 --- a/packages/amplify-graphql-transformer/src/__tests__/graphql-transformer.test.ts +++ b/packages/amplify-graphql-transformer/src/__tests__/graphql-transformer.test.ts @@ -39,6 +39,9 @@ describe('constructTransformerChain', () => { }); }); +/** + * Default transform config for the unit tests in this file + */ const defaultTransformConfig: TransformConfig = { transformersFactoryArgs: {}, transformParameters: { @@ -53,6 +56,7 @@ const defaultTransformConfig: TransformConfig = { enableAutoIndexQueryNames: false, respectPrimaryKeyAttributesOnConnectionField: false, enableSearchNodeToNodeEncryption: false, + enableSearchEncryptionAtRest: true, enableTransformerCfnOutputs: true, allowDestructiveGraphqlSchemaUpdates: false, replaceTableUponGsiUpdate: false, diff --git a/packages/graphql-transformers-e2e-tests/src/CloudFormationClient.ts b/packages/graphql-transformers-e2e-tests/src/CloudFormationClient.ts index 2390ee31b2..7c1c73e550 100644 --- a/packages/graphql-transformers-e2e-tests/src/CloudFormationClient.ts +++ b/packages/graphql-transformers-e2e-tests/src/CloudFormationClient.ts @@ -96,8 +96,8 @@ export class CloudFormationClient { */ async waitForStack( name: string, - success: StackStatus[] = ['CREATE_COMPLETE', 'ROLLBACK_COMPLETE', 'DELETE_COMPLETE', 'UPDATE_COMPLETE', 'UPDATE_ROLLBACK_COMPLETE'], - failure: StackStatus[] = ['CREATE_FAILED', 'ROLLBACK_FAILED', 'DELETE_FAILED', 'UPDATE_ROLLBACK_FAILED'], + success: StackStatus[] = ['CREATE_COMPLETE', 'DELETE_COMPLETE', 'UPDATE_COMPLETE', 'UPDATE_ROLLBACK_COMPLETE'], + failure: StackStatus[] = ['CREATE_FAILED', 'ROLLBACK_COMPLETE', 'ROLLBACK_FAILED', 'DELETE_FAILED', 'UPDATE_ROLLBACK_FAILED'], poll: StackStatus[] = [ 'CREATE_IN_PROGRESS', 'ROLLBACK_IN_PROGRESS', diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableModelTransformerV2.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableModelTransformerV2.e2e.test.ts index 31ac56416c..a145b63c12 100644 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableModelTransformerV2.e2e.test.ts +++ b/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableModelTransformerV2.e2e.test.ts @@ -100,7 +100,11 @@ beforeAll(async () => { cf, STACK_NAME, out, - {}, + { + // Cheapest instance type that supports encryption at rest, and is available in + // most regions (m4 is not everywhere) + [ResourceConstants.PARAMETERS.OpenSearchInstanceType]: 'm5.large.elasticsearch', + }, LOCAL_FS_BUILD_DIR, BUCKET_NAME, S3_ROOT_DIR_KEY, diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthV2.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthV2.e2e.test.ts index c942fc3f45..22fd02f13a 100644 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthV2.e2e.test.ts +++ b/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthV2.e2e.test.ts @@ -214,7 +214,14 @@ beforeAll(async () => { cf, STACK_NAME, out, - { AuthCognitoUserPoolId: USER_POOL_ID, authRoleName: authRole.RoleName, unauthRoleName: unauthRole.RoleName }, + { + [ResourceConstants.PARAMETERS.AuthCognitoUserPoolId]: USER_POOL_ID, + [ResourceConstants.PARAMETERS.AuthRoleName]: authRole.RoleName ?? '', + [ResourceConstants.PARAMETERS.UnauthRoleName]: unauthRole.RoleName ?? '', + // Cheapest instance type that supports encryption at rest, and is available in + // most regions (m4 is not everywhere) + [ResourceConstants.PARAMETERS.OpenSearchInstanceType]: 'm5.large.elasticsearch', + }, LOCAL_FS_BUILD_DIR, BUCKET_NAME, S3_ROOT_DIR_KEY, diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts index 0010f5c205..12c2684ad8 100644 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts +++ b/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts @@ -213,7 +213,14 @@ beforeAll(async () => { cf, STACK_NAME, out, - { AuthCognitoUserPoolId: USER_POOL_ID, authRoleName: authRole.RoleName, unauthRoleName: unauthRole.RoleName }, + { + [ResourceConstants.PARAMETERS.AuthCognitoUserPoolId]: USER_POOL_ID, + [ResourceConstants.PARAMETERS.AuthRoleName]: authRole.RoleName ?? '', + [ResourceConstants.PARAMETERS.UnauthRoleName]: unauthRole.RoleName ?? '', + // Cheapest instance type that supports encryption at rest, and is available in + // most regions (m4 is not everywhere) + [ResourceConstants.PARAMETERS.OpenSearchInstanceType]: 'm5.large.elasticsearch', + }, LOCAL_FS_BUILD_DIR, BUCKET_NAME, S3_ROOT_DIR_KEY, diff --git a/packages/graphql-transformers-e2e-tests/src/deployNestedStacks.ts b/packages/graphql-transformers-e2e-tests/src/deployNestedStacks.ts index d9b664e9da..9ec4b280c6 100644 --- a/packages/graphql-transformers-e2e-tests/src/deployNestedStacks.ts +++ b/packages/graphql-transformers-e2e-tests/src/deployNestedStacks.ts @@ -129,7 +129,7 @@ export async function deploy( cf: CloudFormationClient, stackName: string, deploymentResources: DeploymentResources, - params: any, + params: Record, buildPath: string, bucketName: string, rootKey: string, @@ -145,6 +145,7 @@ export async function deploy( } catch (e) { console.error(`Error cleaning up build directory: ${e}`); } + try { addAPIKeys(deploymentResources);