Skip to content

Commit

Permalink
Updates to version v2.0.1
Browse files Browse the repository at this point in the history
### 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.
  • Loading branch information
tabdunabi authored Aug 19, 2024
2 parents 96b64f0 + bb070cb commit 621fe46
Show file tree
Hide file tree
Showing 95 changed files with 1,949 additions and 1,371 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,8 @@ source/infrastructure/test/mock-lambda-func/java-lambda/checkstyle-result.xml
dist/
*.log
bak.*
*.bak
*.ipynb*
_bandit_temp.json
RapidAi.code-workspace
source/scripts/v2_migration/poetry.lock
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.1] - 2024-08-19

### 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](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.
- 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.
- 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.

## [2.0.0] - 2024-08-08

### Added
Expand Down
1 change: 1 addition & 0 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ aws-lambda-powertools==2.20.0 MIT
aws-sdk-client-mock MIT
aws-sdk-mock Apache-2.0
aws-xray-sdk==2.12.0 Apache-2.0
axios MIT
black MIT
boolean.py BSD-2-Clause
bootstrap MIT
Expand Down
3 changes: 3 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Reporting Security Issues
----------------------------------------------------------------------------------------------------------
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.
2 changes: 1 addition & 1 deletion deployment/build-s3-dist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ set -e
# Check to see if input has been provided:
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then
echo "Please provide all required parameters for the build script"
echo "For example: ./build-s3-dist.sh solutions trademarked-solution-name v2.0.0 template-bucket-name"
echo "For example: ./build-s3-dist.sh solutions trademarked-solution-name v2.0.1 template-bucket-name"
exit 1
fi

Expand Down
2 changes: 1 addition & 1 deletion source/infrastructure/cdk.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"@custom-bundler/unit-test": false,
"solution_id": "SO0276",
"solution_name": "generative-ai-application-builder-on-aws",
"solution_version": "v2.0.0",
"solution_version": "v2.0.1",
"app_registry_name": "GAAB",
"application_type": "AWS-Solutions",
"application_trademark_name": "Generative AI Application Builder on AWS",
Expand Down
114 changes: 111 additions & 3 deletions source/infrastructure/lib/api/deployment-platform-rest-endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as lambda from 'aws-cdk-lib/aws-lambda';

import { ApiGatewayToLambda } from '@aws-solutions-constructs/aws-apigateway-lambda';
import { WafwebaclToApiGateway } from '@aws-solutions-constructs/aws-wafwebacl-apigateway';
import { DefaultWafRules } from '@aws-solutions-constructs/core';
import { wrapManagedRuleSet } from '@aws-solutions-constructs/core';
import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
Expand Down Expand Up @@ -70,9 +70,15 @@ export class DeploymentPlatformRestEndpoint extends Construct {
*/
private readonly stack: cdk.Stack;

/**
* Counter for the priority of custom WAF rules
*/
private rulePriorityCounter: number;

constructor(scope: Construct, id: string, props: DeploymentPlatformRestEndpointProps) {
super(scope, id);
this.stack = cdk.Stack.of(scope);
this.rulePriorityCounter = CUSTOM_RULE_PRIORITY;

const lambdaRestApi = new ApiGatewayToLambda(this, 'EndPoint', {
existingLambdaObj: props.useCaseManagementAPILambda,
Expand Down Expand Up @@ -108,7 +114,17 @@ export class DeploymentPlatformRestEndpoint extends Construct {
webaclProps: {
defaultAction: { allow: {} },
scope: 'REGIONAL',
rules: [...DefaultWafRules(), this.defineBlockRequestHeadersRule()],
rules: [
wrapManagedRuleSet('AWSManagedRulesBotControlRuleSet', 'AWS', 0),
wrapManagedRuleSet('AWSManagedRulesKnownBadInputsRuleSet', 'AWS', 1),
this.defineAWSManagedRulesCommonRuleSetWithBodyOverride(2),
wrapManagedRuleSet('AWSManagedRulesAnonymousIpList', 'AWS', 3),
wrapManagedRuleSet('AWSManagedRulesAmazonIpReputationList', 'AWS', 4),
wrapManagedRuleSet('AWSManagedRulesAdminProtectionRuleSet', 'AWS', 5),
wrapManagedRuleSet('AWSManagedRulesSQLiRuleSet', 'AWS', 6),
this.defineBlockRequestHeadersRule(),
this.defineBlockOversizedBodyNotInDeployRule()
],
customResponseBodies: {
[HEADERS_NOT_ALLOWED_KEY]: this.createHeadersNotAllowedResponse()
}
Expand Down Expand Up @@ -474,7 +490,7 @@ export class DeploymentPlatformRestEndpoint extends Construct {
*/
private defineBlockRequestHeadersRule(): CfnWebACL.RuleProperty {
return {
priority: CUSTOM_RULE_PRIORITY,
priority: this.getCustomRulePriority(),
name: 'Custom-BlockRequestHeaders',
action: {
block: {
Expand Down Expand Up @@ -515,4 +531,96 @@ export class DeploymentPlatformRestEndpoint extends Construct {
contentType: 'TEXT_PLAIN'
};
}

/**
* Define WAF rule which enforces the SizeRestrictions_Body rule from the core rule set for URIs not in the /deployments path
* @returns WAF rule
*/
private defineBlockOversizedBodyNotInDeployRule(): CfnWebACL.RuleProperty {
return {
priority: this.getCustomRulePriority(),
name: 'Custom-BlockOversizedBodyNotInDeploy',
action: {
block: {}
},
visibilityConfig: {
cloudWatchMetricsEnabled: true,
metricName: 'Custom-BlockOversizedBodyNotInDeploy',
sampledRequestsEnabled: true
},
statement: {
andStatement: {
statements: [
{
labelMatchStatement: {
scope: 'LABEL',
key: 'awswaf:managed:aws:core-rule-set:SizeRestrictions_Body'
}
},
{
notStatement: {
statement: {
byteMatchStatement: {
searchString: '/deployments',
fieldToMatch: {
uriPath: {}
},
textTransformations: [
{
priority: 0,
type: 'NONE'
}
],
positionalConstraint: 'ENDS_WITH'
}
}
}
}
]
}
}
};
}

/**
* Defines a WAF rule which enforces the AWSManagedRulesCommonRuleSet, with an override to only count the SizeRestrictions_BODY.
* @param priority The priority of the rule
* @returns The WAF rule
*/
private defineAWSManagedRulesCommonRuleSetWithBodyOverride(priority: number): CfnWebACL.RuleProperty {
return {
name: 'AWS-AWSManagedRulesCommonRuleSet',
priority: priority,
statement: {
managedRuleGroupStatement: {
vendorName: 'AWS',
name: 'AWSManagedRulesCommonRuleSet',
ruleActionOverrides: [
{
name: 'SizeRestrictions_BODY',
actionToUse: {
count: {}
}
}
]
}
},
overrideAction: {
none: {}
},
visibilityConfig: {
sampledRequestsEnabled: true,
cloudWatchMetricsEnabled: true,
metricName: 'AWS-AWSManagedRulesCommonRuleSet'
}
};
}

/**
* Gets a unique priority for a custom rule, incrementing an internal counter
* @returns A unique priority for each custom rule
*/
private getCustomRulePriority(): number {
return this.rulePriorityCounter++;
}
}
33 changes: 14 additions & 19 deletions source/infrastructure/lib/api/websocket-endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,18 @@
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES *
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions *
* and limitations under the License. *
**********************************************************************************************************************/
*********************************************************************************************************************/

import { ApiGatewayV2WebSocketToSqs } from '@aws-solutions-constructs/aws-apigatewayv2websocket-sqs';
import { SqsToLambda } from '@aws-solutions-constructs/aws-sqs-lambda';
import * as cdk from 'aws-cdk-lib';
import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2';
import { WebSocketApi, WebSocketStage } from 'aws-cdk-lib/aws-apigatewayv2';
import { WebSocketLambdaAuthorizer } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
import { WebSocketAwsIntegration, WebSocketLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
import { WebSocketLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { ApiGatewayV2WebSocketToSqs } from '../framework/aws-apigwv2websocket-sqs';
import { LOG_RETENTION_PERIOD } from '../utils/constants';

export interface WebSocketProps {
Expand Down Expand Up @@ -99,21 +98,10 @@ export class WebSocketEndpoint extends Construct {
maxReceiveCount: 3,
logGroupProps: {
retention: LOG_RETENTION_PERIOD
}
});

apiGatewayV2WebSocketToSqs.webSocketApi.addRoute('sendMessage', {
integration: new WebSocketAwsIntegration('DefaultIntegration', {
integrationMethod: apigwv2.HttpMethod.POST,
integrationUri: `arn:${cdk.Aws.PARTITION}:apigateway:${cdk.Aws.REGION}:sqs:path/${cdk.Aws.ACCOUNT_ID}/${apiGatewayV2WebSocketToSqs.sqsQueue.queueName}`,
requestTemplates: { 'sendMessage': requestTemplate },
templateSelectionExpression: 'sendMessage',
passthroughBehavior: apigwv2.PassthroughBehavior.NEVER,
credentialsRole: apiGatewayV2WebSocketToSqs.apiGatewayRole,
requestParameters: {
'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'"
}
})
},
createDefaultRoute: false,
customRouteName: 'sendMessage',
defaultRouteRequestTemplate: { 'sendMessage': requestTemplate }
});

// the socket URL to post responses
Expand Down Expand Up @@ -159,5 +147,12 @@ export class WebSocketEndpoint extends Construct {
}
]
);

NagSuppressions.addResourceSuppressions(this.websocketApiStage, [
{
id: 'AwsSolutions-APIG1',
reason: 'Access logging configuration has been provided as per ApiGateway v2 requirements'
}
]);
}
}
1 change: 1 addition & 0 deletions source/infrastructure/lib/bedrock-chat-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export class BedrockChat extends UseCaseChat {
customResourceLambdaArn: this.applicationSetup.customResourceLambda.functionArn,
customResourceRoleArn: this.applicationSetup.customResourceLambda.role!.roleArn,
iPamPoolId: this.iPamPoolId.valueAsString,
accessLogBucket: this.applicationSetup.accessLoggingBucket,
...this.baseStackProps
});
}
Expand Down
6 changes: 5 additions & 1 deletion source/infrastructure/lib/deployment-platform-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export class DeploymentPlatformStack extends BaseStack {
cloudFrontUrl: uiInfrastructureBuilder.getCloudFrontUrlWithCondition(),
deployWebApp: this.deployWebApp.valueAsString,
deployWebAppCondition: uiInfrastructureBuilder.deployWebAppCondition,
accessLoggingBucket: this.applicationSetup.accessLoggingBucket,
...this.baseStackProps
});

Expand All @@ -160,6 +161,7 @@ export class DeploymentPlatformStack extends BaseStack {
modelInfoApiLambda: this.useCaseManagementSetup.useCaseManagement.modelInfoApiLambda,
customResourceLambda: this.applicationSetup.customResourceLambda,
customResourceRole: this.applicationSetup.customResourceRole,
accessLoggingBucket: this.applicationSetup.accessLoggingBucket,
...this.baseStackProps
});

Expand Down Expand Up @@ -196,7 +198,8 @@ export class DeploymentPlatformStack extends BaseStack {
CustomResourceRoleArn: this.applicationSetup.customResourceLambda.role!.roleArn,
CustomResourceLambdaArn: this.applicationSetup.customResourceLambda.functionArn,
WebConfigKey: webConfigSsmKey,
WebS3BucketArn: this.uiDistribution.websiteBucket.bucketArn
WebS3BucketArn: this.uiDistribution.websiteBucket.bucketArn,
AccessLoggingBucketArn: this.applicationSetup.accessLoggingBucket.bucketArn
},
description: `Custom resource that copies UI assets to S3 bucket - Version ${props.solutionVersion}`
});
Expand Down Expand Up @@ -274,6 +277,7 @@ export class DeploymentPlatformStack extends BaseStack {
customResourceLambdaArn: this.applicationSetup.customResourceLambda.functionArn,
customResourceRoleArn: this.applicationSetup.customResourceLambda.role!.roleArn,
iPamPoolId: this.iPamPoolId.valueAsString,
accessLogBucket: this.applicationSetup.accessLoggingBucket,
...this.baseStackProps
});
}
Expand Down
82 changes: 82 additions & 0 deletions source/infrastructure/lib/framework/base-nested-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env node
/**********************************************************************************************************************
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. *
* *
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance *
* with the License. A copy of the License is located at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES *
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions *
* and limitations under the License. *
*********************************************************************************************************************/

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';

/**
* Stack properties for nested stack
*/
export abstract class BaseNestedStack extends cdk.NestedStack {
/**
* The custom resource lambda arn
*/
public customResourceLambdaArn: string;

/**
* The custom resource lambda role arn
*/
public customResourceLambdaRoleArn: string;

/**
* Access logging bucket to be associated with any S3 bucket creation
*/
public readonly accessLoggingBucket: string;

constructor(scope: Construct, id: string, props?: cdk.NestedStackProps) {
super(scope, id, props);
const stack = cdk.Stack.of(this);
this.customResourceLambdaArn = new cdk.CfnParameter(stack, 'CustomResourceLambdaArn', {
type: 'String',
description: 'The custom resource lambda arn',
allowedPattern:
'^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-_]+))?$',
constraintDescription: 'Please provide a valid lambda arn.'
}).valueAsString;

this.customResourceLambdaRoleArn = new cdk.CfnParameter(stack, 'CustomResourceRoleArn', {
type: 'String',
description: 'The custom resource lambda role arn',
allowedPattern: '^arn:(aws|aws-cn|aws-us-gov):iam::\\d{12}:role/[a-zA-Z_0-9+=,.@\\-_/]+$',
constraintDescription: 'Please provide a valid lambda role arn.'
}).valueAsString;

this.accessLoggingBucket = new cdk.CfnParameter(stack, 'AccessLoggingBucketArn', {
type: 'String',
allowedPattern: '^arn:(aws|aws-cn|aws-us-gov):s3:::\\S+$',
description: 'Arn of the S3 bucket to use for access logging.'
}).valueAsString;
}
}

export abstract class BaseUseCaseNestedStack extends BaseNestedStack {
/**
* Unique ID for this deployed use case within an application. Provided by the deployment platform if in use.
*/
public readonly useCaseUUID: string;

constructor(scope: Construct, id: string, props?: cdk.NestedStackProps) {
super(scope, id, props);
const stack = cdk.Stack.of(this);

this.useCaseUUID = new cdk.CfnParameter(stack, 'UseCaseUUID', {
type: 'String',
description:
'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',
allowedPattern: '^[0-9a-fA-F]{8}$',
maxLength: 8,
constraintDescription: 'Please provide an 8 character long UUID'
}).valueAsString;
}
}
Loading

0 comments on commit 621fe46

Please sign in to comment.