Skip to content

Commit 04c3a11

Browse files
authored
Updates to version v2.0.1
### Changed - With the release of [AWS-Solutions-Constructs v2.65.0](https://github.com/awslabs/aws-solutions-constructs/tree/main/source/patterns/%40aws-solutions-constructs/aws-apigatewayv2websocket-sqs), the AWS ApiGateway websocket integration with Amazon SQS Queue is available in the library. Hence the implementation has been updated to use this construct. ### Fixed - Issue [#131](#131) which caused an issue with rendering non-S3 source URLs from vector store for a RAG based use case. - Issue [#132](#132) where configured Guardrails for Amazon Bedrock to have no effect on a use case's text input validations and output responses. - Wizard validation failure for SageMaker model selection type, that allowed user to navigate ahead even when the page had failed validations. - An AWS WAF rule that blocked larger payloads for HTTP POST request to the `/deployments` endpoint. This restricted configuring large system prompts (over 8 KB) for use case cases. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
2 parents 06c740b + 621fe46 commit 04c3a11

File tree

95 files changed

+1949
-1371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+1949
-1371
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,8 @@ source/infrastructure/test/mock-lambda-func/java-lambda/checkstyle-result.xml
5353
dist/
5454
*.log
5555
bak.*
56+
*.bak
5657
*.ipynb*
5758
_bandit_temp.json
59+
RapidAi.code-workspace
60+
source/scripts/v2_migration/poetry.lock

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.0.1] - 2024-08-19
9+
10+
### Changed
11+
12+
- With the release of [AWS-Solutions-Constructs v2.65.0](https://github.com/awslabs/aws-solutions-constructs/tree/main/source/patterns/%40aws-solutions-constructs/aws-apigatewayv2websocket-sqs), the AWS ApiGateway websocket integration with Amazon SQS Queue is available in the library. Hence the
13+
implementation has been updated to use this construct.
14+
15+
### Fixed
16+
17+
- Issue [#131](https://github.com/aws-solutions/generative-ai-application-builder-on-aws/issues/131) which caused an issue with rendering non-S3 source URLs from vector store for a RAG based use case.
18+
- Issue [#132](https://github.com/aws-solutions/generative-ai-application-builder-on-aws/issues/132) where configured Guardrails for Amazon Bedrock to have no effect on a use case's text input validations and output responses.
19+
- Wizard validation failure for SageMaker model selection type, that allowed user to navigate ahead even when the page had failed validations.
20+
- An AWS WAF rule that blocked larger payloads for HTTP POST request to the `/deployments` endpoint. This restricted configuring large system prompts (over 8 KB) for use case cases.
21+
822
## [2.0.0] - 2024-08-08
923

1024
### Added

NOTICE.txt

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ aws-lambda-powertools==2.20.0 MIT
8181
aws-sdk-client-mock MIT
8282
aws-sdk-mock Apache-2.0
8383
aws-xray-sdk==2.12.0 Apache-2.0
84+
axios MIT
8485
black MIT
8586
boolean.py BSD-2-Clause
8687
bootstrap MIT

SECURITY.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Reporting Security Issues
2+
----------------------------------------------------------------------------------------------------------
3+
We take all security reports seriously. When we receive such reports, we will investigate and subsequently address any potential vulnerabilities as quickly as possible. If you discover a potential security issue in this project, please notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to [AWS Security](mailto:[email protected]). Please do not create a public GitHub issue in this project.

deployment/build-s3-dist.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ set -e
4040
# Check to see if input has been provided:
4141
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then
4242
echo "Please provide all required parameters for the build script"
43-
echo "For example: ./build-s3-dist.sh solutions trademarked-solution-name v2.0.0 template-bucket-name"
43+
echo "For example: ./build-s3-dist.sh solutions trademarked-solution-name v2.0.1 template-bucket-name"
4444
exit 1
4545
fi
4646

source/infrastructure/cdk.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"@custom-bundler/unit-test": false,
6464
"solution_id": "SO0276",
6565
"solution_name": "generative-ai-application-builder-on-aws",
66-
"solution_version": "v2.0.0",
66+
"solution_version": "v2.0.1",
6767
"app_registry_name": "GAAB",
6868
"application_type": "AWS-Solutions",
6969
"application_trademark_name": "Generative AI Application Builder on AWS",

source/infrastructure/lib/api/deployment-platform-rest-endpoint.ts

+111-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import * as lambda from 'aws-cdk-lib/aws-lambda';
1919

2020
import { ApiGatewayToLambda } from '@aws-solutions-constructs/aws-apigateway-lambda';
2121
import { WafwebaclToApiGateway } from '@aws-solutions-constructs/aws-wafwebacl-apigateway';
22-
import { DefaultWafRules } from '@aws-solutions-constructs/core';
22+
import { wrapManagedRuleSet } from '@aws-solutions-constructs/core';
2323
import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
2424
import { NagSuppressions } from 'cdk-nag';
2525
import { Construct } from 'constructs';
@@ -70,9 +70,15 @@ export class DeploymentPlatformRestEndpoint extends Construct {
7070
*/
7171
private readonly stack: cdk.Stack;
7272

73+
/**
74+
* Counter for the priority of custom WAF rules
75+
*/
76+
private rulePriorityCounter: number;
77+
7378
constructor(scope: Construct, id: string, props: DeploymentPlatformRestEndpointProps) {
7479
super(scope, id);
7580
this.stack = cdk.Stack.of(scope);
81+
this.rulePriorityCounter = CUSTOM_RULE_PRIORITY;
7682

7783
const lambdaRestApi = new ApiGatewayToLambda(this, 'EndPoint', {
7884
existingLambdaObj: props.useCaseManagementAPILambda,
@@ -108,7 +114,17 @@ export class DeploymentPlatformRestEndpoint extends Construct {
108114
webaclProps: {
109115
defaultAction: { allow: {} },
110116
scope: 'REGIONAL',
111-
rules: [...DefaultWafRules(), this.defineBlockRequestHeadersRule()],
117+
rules: [
118+
wrapManagedRuleSet('AWSManagedRulesBotControlRuleSet', 'AWS', 0),
119+
wrapManagedRuleSet('AWSManagedRulesKnownBadInputsRuleSet', 'AWS', 1),
120+
this.defineAWSManagedRulesCommonRuleSetWithBodyOverride(2),
121+
wrapManagedRuleSet('AWSManagedRulesAnonymousIpList', 'AWS', 3),
122+
wrapManagedRuleSet('AWSManagedRulesAmazonIpReputationList', 'AWS', 4),
123+
wrapManagedRuleSet('AWSManagedRulesAdminProtectionRuleSet', 'AWS', 5),
124+
wrapManagedRuleSet('AWSManagedRulesSQLiRuleSet', 'AWS', 6),
125+
this.defineBlockRequestHeadersRule(),
126+
this.defineBlockOversizedBodyNotInDeployRule()
127+
],
112128
customResponseBodies: {
113129
[HEADERS_NOT_ALLOWED_KEY]: this.createHeadersNotAllowedResponse()
114130
}
@@ -474,7 +490,7 @@ export class DeploymentPlatformRestEndpoint extends Construct {
474490
*/
475491
private defineBlockRequestHeadersRule(): CfnWebACL.RuleProperty {
476492
return {
477-
priority: CUSTOM_RULE_PRIORITY,
493+
priority: this.getCustomRulePriority(),
478494
name: 'Custom-BlockRequestHeaders',
479495
action: {
480496
block: {
@@ -515,4 +531,96 @@ export class DeploymentPlatformRestEndpoint extends Construct {
515531
contentType: 'TEXT_PLAIN'
516532
};
517533
}
534+
535+
/**
536+
* Define WAF rule which enforces the SizeRestrictions_Body rule from the core rule set for URIs not in the /deployments path
537+
* @returns WAF rule
538+
*/
539+
private defineBlockOversizedBodyNotInDeployRule(): CfnWebACL.RuleProperty {
540+
return {
541+
priority: this.getCustomRulePriority(),
542+
name: 'Custom-BlockOversizedBodyNotInDeploy',
543+
action: {
544+
block: {}
545+
},
546+
visibilityConfig: {
547+
cloudWatchMetricsEnabled: true,
548+
metricName: 'Custom-BlockOversizedBodyNotInDeploy',
549+
sampledRequestsEnabled: true
550+
},
551+
statement: {
552+
andStatement: {
553+
statements: [
554+
{
555+
labelMatchStatement: {
556+
scope: 'LABEL',
557+
key: 'awswaf:managed:aws:core-rule-set:SizeRestrictions_Body'
558+
}
559+
},
560+
{
561+
notStatement: {
562+
statement: {
563+
byteMatchStatement: {
564+
searchString: '/deployments',
565+
fieldToMatch: {
566+
uriPath: {}
567+
},
568+
textTransformations: [
569+
{
570+
priority: 0,
571+
type: 'NONE'
572+
}
573+
],
574+
positionalConstraint: 'ENDS_WITH'
575+
}
576+
}
577+
}
578+
}
579+
]
580+
}
581+
}
582+
};
583+
}
584+
585+
/**
586+
* Defines a WAF rule which enforces the AWSManagedRulesCommonRuleSet, with an override to only count the SizeRestrictions_BODY.
587+
* @param priority The priority of the rule
588+
* @returns The WAF rule
589+
*/
590+
private defineAWSManagedRulesCommonRuleSetWithBodyOverride(priority: number): CfnWebACL.RuleProperty {
591+
return {
592+
name: 'AWS-AWSManagedRulesCommonRuleSet',
593+
priority: priority,
594+
statement: {
595+
managedRuleGroupStatement: {
596+
vendorName: 'AWS',
597+
name: 'AWSManagedRulesCommonRuleSet',
598+
ruleActionOverrides: [
599+
{
600+
name: 'SizeRestrictions_BODY',
601+
actionToUse: {
602+
count: {}
603+
}
604+
}
605+
]
606+
}
607+
},
608+
overrideAction: {
609+
none: {}
610+
},
611+
visibilityConfig: {
612+
sampledRequestsEnabled: true,
613+
cloudWatchMetricsEnabled: true,
614+
metricName: 'AWS-AWSManagedRulesCommonRuleSet'
615+
}
616+
};
617+
}
618+
619+
/**
620+
* Gets a unique priority for a custom rule, incrementing an internal counter
621+
* @returns A unique priority for each custom rule
622+
*/
623+
private getCustomRulePriority(): number {
624+
return this.rulePriorityCounter++;
625+
}
518626
}

source/infrastructure/lib/api/websocket-endpoint.ts

+14-19
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,18 @@
1010
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES *
1111
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions *
1212
* and limitations under the License. *
13-
**********************************************************************************************************************/
13+
*********************************************************************************************************************/
1414

15+
import { ApiGatewayV2WebSocketToSqs } from '@aws-solutions-constructs/aws-apigatewayv2websocket-sqs';
1516
import { SqsToLambda } from '@aws-solutions-constructs/aws-sqs-lambda';
16-
import * as cdk from 'aws-cdk-lib';
1717
import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2';
1818
import { WebSocketApi, WebSocketStage } from 'aws-cdk-lib/aws-apigatewayv2';
1919
import { WebSocketLambdaAuthorizer } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
20-
import { WebSocketAwsIntegration, WebSocketLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
20+
import { WebSocketLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
2121
import * as iam from 'aws-cdk-lib/aws-iam';
2222
import * as lambda from 'aws-cdk-lib/aws-lambda';
2323
import { NagSuppressions } from 'cdk-nag';
2424
import { Construct } from 'constructs';
25-
import { ApiGatewayV2WebSocketToSqs } from '../framework/aws-apigwv2websocket-sqs';
2625
import { LOG_RETENTION_PERIOD } from '../utils/constants';
2726

2827
export interface WebSocketProps {
@@ -99,21 +98,10 @@ export class WebSocketEndpoint extends Construct {
9998
maxReceiveCount: 3,
10099
logGroupProps: {
101100
retention: LOG_RETENTION_PERIOD
102-
}
103-
});
104-
105-
apiGatewayV2WebSocketToSqs.webSocketApi.addRoute('sendMessage', {
106-
integration: new WebSocketAwsIntegration('DefaultIntegration', {
107-
integrationMethod: apigwv2.HttpMethod.POST,
108-
integrationUri: `arn:${cdk.Aws.PARTITION}:apigateway:${cdk.Aws.REGION}:sqs:path/${cdk.Aws.ACCOUNT_ID}/${apiGatewayV2WebSocketToSqs.sqsQueue.queueName}`,
109-
requestTemplates: { 'sendMessage': requestTemplate },
110-
templateSelectionExpression: 'sendMessage',
111-
passthroughBehavior: apigwv2.PassthroughBehavior.NEVER,
112-
credentialsRole: apiGatewayV2WebSocketToSqs.apiGatewayRole,
113-
requestParameters: {
114-
'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'"
115-
}
116-
})
101+
},
102+
createDefaultRoute: false,
103+
customRouteName: 'sendMessage',
104+
defaultRouteRequestTemplate: { 'sendMessage': requestTemplate }
117105
});
118106

119107
// the socket URL to post responses
@@ -159,5 +147,12 @@ export class WebSocketEndpoint extends Construct {
159147
}
160148
]
161149
);
150+
151+
NagSuppressions.addResourceSuppressions(this.websocketApiStage, [
152+
{
153+
id: 'AwsSolutions-APIG1',
154+
reason: 'Access logging configuration has been provided as per ApiGateway v2 requirements'
155+
}
156+
]);
162157
}
163158
}

source/infrastructure/lib/bedrock-chat-stack.ts

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export class BedrockChat extends UseCaseChat {
5555
customResourceLambdaArn: this.applicationSetup.customResourceLambda.functionArn,
5656
customResourceRoleArn: this.applicationSetup.customResourceLambda.role!.roleArn,
5757
iPamPoolId: this.iPamPoolId.valueAsString,
58+
accessLogBucket: this.applicationSetup.accessLoggingBucket,
5859
...this.baseStackProps
5960
});
6061
}

source/infrastructure/lib/deployment-platform-stack.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ export class DeploymentPlatformStack extends BaseStack {
152152
cloudFrontUrl: uiInfrastructureBuilder.getCloudFrontUrlWithCondition(),
153153
deployWebApp: this.deployWebApp.valueAsString,
154154
deployWebAppCondition: uiInfrastructureBuilder.deployWebAppCondition,
155+
accessLoggingBucket: this.applicationSetup.accessLoggingBucket,
155156
...this.baseStackProps
156157
});
157158

@@ -160,6 +161,7 @@ export class DeploymentPlatformStack extends BaseStack {
160161
modelInfoApiLambda: this.useCaseManagementSetup.useCaseManagement.modelInfoApiLambda,
161162
customResourceLambda: this.applicationSetup.customResourceLambda,
162163
customResourceRole: this.applicationSetup.customResourceRole,
164+
accessLoggingBucket: this.applicationSetup.accessLoggingBucket,
163165
...this.baseStackProps
164166
});
165167

@@ -196,7 +198,8 @@ export class DeploymentPlatformStack extends BaseStack {
196198
CustomResourceRoleArn: this.applicationSetup.customResourceLambda.role!.roleArn,
197199
CustomResourceLambdaArn: this.applicationSetup.customResourceLambda.functionArn,
198200
WebConfigKey: webConfigSsmKey,
199-
WebS3BucketArn: this.uiDistribution.websiteBucket.bucketArn
201+
WebS3BucketArn: this.uiDistribution.websiteBucket.bucketArn,
202+
AccessLoggingBucketArn: this.applicationSetup.accessLoggingBucket.bucketArn
200203
},
201204
description: `Custom resource that copies UI assets to S3 bucket - Version ${props.solutionVersion}`
202205
});
@@ -274,6 +277,7 @@ export class DeploymentPlatformStack extends BaseStack {
274277
customResourceLambdaArn: this.applicationSetup.customResourceLambda.functionArn,
275278
customResourceRoleArn: this.applicationSetup.customResourceLambda.role!.roleArn,
276279
iPamPoolId: this.iPamPoolId.valueAsString,
280+
accessLogBucket: this.applicationSetup.accessLoggingBucket,
277281
...this.baseStackProps
278282
});
279283
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env node
2+
/**********************************************************************************************************************
3+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. *
4+
* *
5+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance *
6+
* with the License. A copy of the License is located at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES *
11+
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions *
12+
* and limitations under the License. *
13+
*********************************************************************************************************************/
14+
15+
import * as cdk from 'aws-cdk-lib';
16+
import { Construct } from 'constructs';
17+
18+
/**
19+
* Stack properties for nested stack
20+
*/
21+
export abstract class BaseNestedStack extends cdk.NestedStack {
22+
/**
23+
* The custom resource lambda arn
24+
*/
25+
public customResourceLambdaArn: string;
26+
27+
/**
28+
* The custom resource lambda role arn
29+
*/
30+
public customResourceLambdaRoleArn: string;
31+
32+
/**
33+
* Access logging bucket to be associated with any S3 bucket creation
34+
*/
35+
public readonly accessLoggingBucket: string;
36+
37+
constructor(scope: Construct, id: string, props?: cdk.NestedStackProps) {
38+
super(scope, id, props);
39+
const stack = cdk.Stack.of(this);
40+
this.customResourceLambdaArn = new cdk.CfnParameter(stack, 'CustomResourceLambdaArn', {
41+
type: 'String',
42+
description: 'The custom resource lambda arn',
43+
allowedPattern:
44+
'^arn:(aws[a-zA-Z-]*)?:lambda:[a-z]{2}(-gov)?-[a-z]+-\\d{1}:\\d{12}:function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?$',
45+
constraintDescription: 'Please provide a valid lambda arn.'
46+
}).valueAsString;
47+
48+
this.customResourceLambdaRoleArn = new cdk.CfnParameter(stack, 'CustomResourceRoleArn', {
49+
type: 'String',
50+
description: 'The custom resource lambda role arn',
51+
allowedPattern: '^arn:(aws|aws-cn|aws-us-gov):iam::\\d{12}:role/[a-zA-Z_0-9+=,.@\\-_/]+$',
52+
constraintDescription: 'Please provide a valid lambda role arn.'
53+
}).valueAsString;
54+
55+
this.accessLoggingBucket = new cdk.CfnParameter(stack, 'AccessLoggingBucketArn', {
56+
type: 'String',
57+
allowedPattern: '^arn:(aws|aws-cn|aws-us-gov):s3:::\\S+$',
58+
description: 'Arn of the S3 bucket to use for access logging.'
59+
}).valueAsString;
60+
}
61+
}
62+
63+
export abstract class BaseUseCaseNestedStack extends BaseNestedStack {
64+
/**
65+
* Unique ID for this deployed use case within an application. Provided by the deployment platform if in use.
66+
*/
67+
public readonly useCaseUUID: string;
68+
69+
constructor(scope: Construct, id: string, props?: cdk.NestedStackProps) {
70+
super(scope, id, props);
71+
const stack = cdk.Stack.of(this);
72+
73+
this.useCaseUUID = new cdk.CfnParameter(stack, 'UseCaseUUID', {
74+
type: 'String',
75+
description:
76+
'UUID to identify this deployed use case within an application. Please provide an 8 character long UUID. If you are editing the stack, do not modify the value (retain the value used during creating the stack). A different UUID when editing the stack will result in new AWS resource created and deleting the old ones',
77+
allowedPattern: '^[0-9a-fA-F]{8}$',
78+
maxLength: 8,
79+
constraintDescription: 'Please provide an 8 character long UUID'
80+
}).valueAsString;
81+
}
82+
}

0 commit comments

Comments
 (0)