diff --git a/templates/codebuild-deploy.yaml b/templates/codebuild-deploy.yaml index fd2bc44b..7097d793 100644 --- a/templates/codebuild-deploy.yaml +++ b/templates/codebuild-deploy.yaml @@ -545,6 +545,16 @@ Parameters: Default: '' Description: > If enabling upload, the name of the S3 bucket where uploaded documents should be stored + + VpcSubnetId: + Type: String + Default: '' + Description: ID of a VPC subnet where all Lambda functions will run, only used if you need Lambda to run in a VPC + + VpcSecurityGroupId: + Type: String + Default: '' + Description: ID of a security group where all Lambda functions will run, only used if you need Lambda to run in a VPC Conditions: NeedsParentOrigin: !Equals [!Ref ParentOrigin, ''] @@ -554,6 +564,7 @@ Conditions: ShouldNotSpecifyWafAcl: !Equals [!Ref WebAppWafAclArn, ''] EnableStreaming: !Equals [!Ref AllowStreamingResponses, true] EnableUpload: !Equals [!Ref ShouldEnableUpload, true] + NeedsVpc: !And [ !Not [ !Equals [!Ref VpcSubnetId, ''] ], !Not [ !Equals [!Ref VpcSecurityGroupId, ''] ] ] Resources: # Bucket where S3 access logs are stored @@ -769,6 +780,8 @@ Resources: InitiateChatLambdaCodeObject: !Ref InitiateChatLambdaCodeObject ConnectContactFlowId: !Ref ConnectContactFlowId ConnectInstanceId: !Ref ConnectInstanceId + VpcSubnetId: !Ref VpcSubnetId + VpcSecurityGroupId: !Ref VpcSecurityGroupId ParentOrigin: !If - UseDefaultCloudfrontUrl @@ -786,6 +799,8 @@ Resources: SourceBucket: !Ref SourceBucket StreamingLambdaCodeObject: !Ref StreamingLambdaCodeObject TableName: !Join ["-", [!Ref "AWS::StackName", "streaming"]] + VpcSubnetId: !Ref VpcSubnetId + VpcSecurityGroupId: !Ref VpcSecurityGroupId ParentOrigin: !If - UseDefaultCloudfrontUrl @@ -1032,8 +1047,17 @@ Resources: # Lambda function for custom resource CodeBuildStarterLambda: - Type: AWS::Lambda::Function + Type: AWS::Lambda::Function Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" Code: S3Bucket: !Ref SourceBucket S3Key: !Ref CustomResourceCodeObject @@ -1128,6 +1152,12 @@ Resources: Type: AWS::IAM::Role Properties: Path: / + ManagedPolicyArns: + !If + - NeedsVpc + - + - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + - !Ref "AWS::NoValue" AssumeRolePolicyDocument: Version: 2012-10-17 Statement: @@ -1184,14 +1214,24 @@ Resources: Condition: ShouldCleanupBuckets Properties: ServiceToken: !GetAtt S3CleanupLambda.Arn + ServiceTimeout: 60 Buckets: - !Ref WebAppBucket # Lambda function for custom resource S3CleanupLambda: Type: AWS::Lambda::Function - Condition: ShouldCleanupBuckets + Condition: ShouldCleanupBuckets Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" Code: S3Bucket: !Ref SourceBucket S3Key: !Ref CustomResourceCodeObject @@ -1207,6 +1247,12 @@ Resources: Condition: ShouldCleanupBuckets Properties: Path: / + ManagedPolicyArns: + !If + - NeedsVpc + - + - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + - !Ref "AWS::NoValue" AssumeRolePolicyDocument: Version: 2012-10-17 Statement: diff --git a/templates/cognitouserpoolconfig.yaml b/templates/cognitouserpoolconfig.yaml index b21bf0e7..0fb7f27a 100644 --- a/templates/cognitouserpoolconfig.yaml +++ b/templates/cognitouserpoolconfig.yaml @@ -35,6 +35,19 @@ Parameters: Type: Number Description: > This is a required parameter. + + VpcSubnetId: + Type: String + Default: '' + Description: ID of a VPC subnet where all Lambda functions will run, only used if you need Lambda to run in a VPC + + VpcSecurityGroupId: + Type: String + Default: '' + Description: ID of a security group where all Lambda functions will run, only used if you need Lambda to run in a VPC + +Conditions: + NeedsVpc: !And [ !Not [ !Equals [!Ref VpcSubnetId, ''] ], !Not [ !Equals [!Ref VpcSecurityGroupId, ''] ] ] Resources: @@ -44,8 +57,17 @@ Resources: ServiceToken: !GetAtt CognitoUserPoolDomainFunction.Arn CognitoUserPoolDomainFunction: - Type: AWS::Lambda::Function + Type: AWS::Lambda::Function Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" Handler: index.handler Role: !GetAtt CognitoUserPoolDomainExecutionRole.Arn Runtime: python3.10 @@ -146,6 +168,12 @@ Resources: Type: AWS::IAM::Role Properties: Path: / + ManagedPolicyArns: + !If + - NeedsVpc + - + - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + - !Ref "AWS::NoValue" AssumeRolePolicyDocument: Version: 2012-10-17 Statement: @@ -224,8 +252,17 @@ Resources: Timestamp: !Ref Timestamp CognitoUserPoolUpdatesFunction: - Type: AWS::Lambda::Function + Type: AWS::Lambda::Function Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" Handler: index.handler Role: !GetAtt CognitoUserPoolDomainExecutionRole.Arn Runtime: python3.10 @@ -316,6 +353,12 @@ Resources: Type: AWS::IAM::Role Properties: Path: / + ManagedPolicyArns: + !If + - NeedsVpc + - + - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + - !Ref "AWS::NoValue" AssumeRolePolicyDocument: Version: 2012-10-17 Statement: @@ -364,8 +407,17 @@ Resources: Properties: ServiceToken: !GetAtt CleanStackNameFunction.Arn CleanStackNameFunction: - Type: AWS::Lambda::Function + Type: AWS::Lambda::Function Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" Handler: index.handler Role: !GetAtt CleanStackNameExecutionRole.Arn Runtime: python3.10 diff --git a/templates/lexbot.yaml b/templates/lexbot.yaml index db93792e..23b9dd0b 100644 --- a/templates/lexbot.yaml +++ b/templates/lexbot.yaml @@ -51,10 +51,21 @@ Parameters: Type: String Default: aws-bigdata-blog + VpcSubnetId: + Type: String + Default: '' + Description: ID of a VPC subnet where all Lambda functions will run, only used if you need Lambda to run in a VPC + + VpcSecurityGroupId: + Type: String + Default: '' + Description: ID of a security group where all Lambda functions will run, only used if you need Lambda to run in a VPC + Conditions: EnableQBusiness: !Not [!Equals [!Ref AmazonQAppId, '']] ExampleBot: !Equals [!Ref AmazonQAppId, ''] DeleteBot: !Equals [!Ref ShouldDeleteBot, true] + NeedsVpc: !And [ !Not [ !Equals [!Ref VpcSubnetId, ''] ], !Not [ !Equals [!Ref VpcSecurityGroupId, ''] ] ] Resources: ExampleBotRuntimeRole: @@ -367,7 +378,13 @@ Resources: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + !If + - NeedsVpc + - + - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + - + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyDocument: Version: 2012-10-17 @@ -436,8 +453,17 @@ Resources: QnaBusinessLambdaFulfillmentFunction: Type: AWS::Lambda::Function - Condition: EnableQBusiness + Condition: EnableQBusiness Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" FunctionName: !Join ["-", [!Ref ParentStackName, "Fulfillment-Lambda"]] Handler: index.lambda_handler Role: !GetAtt 'LambdaFunctionRole.Arn' diff --git a/templates/master.yaml b/templates/master.yaml index 870b8745..4fb1d58f 100644 --- a/templates/master.yaml +++ b/templates/master.yaml @@ -589,6 +589,17 @@ Parameters: This process is not automated because in many use cases Identity Center will not be in the same account as the bot. Manual set-up instructions can be found here: https://github.com/aws-samples/aws-lex-web-ui/blob/master/README-qbusiness.md + VpcSubnetId: + Type: String + Default: '' + Description: ID of a VPC subnet where all Lambda functions will run, only used if you need Lambda to run in a VPC + + VpcSecurityGroupId: + Type: String + Default: '' + Description: ID of a security group where all Lambda functions will run, only used if you need Lambda to run in a VPC + + Rules: ValidateEitherV1orV2: RuleCondition: !Not @@ -697,6 +708,11 @@ Metadata: - BotChatBubble - CustomerChatBubble - MinimizedButtonColor + - Label: + default: Lambda VPC Support + Parameters: + - VpcSubnetId + - VpcSecurityGroupId - Label: default: Q Business Parameters Parameters: @@ -706,6 +722,7 @@ Metadata: Conditions: IsLexV2: !Not [ !Equals [!Ref LexV2BotId, ''] ] NeedsBot: !And [ !Equals [!Ref BotName, ''], !Equals [!Ref LexV2BotId, ''] ] + NeedsVpc: !And [ !Not [ !Equals [!Ref VpcSubnetId, ''] ], !Not [ !Equals [!Ref VpcSecurityGroupId, ''] ] ] NeedsCognito: !Equals [!Ref CognitoIdentityPoolId, ''] NeedsParentOrigin: !Equals [!Ref WebAppParentOrigin, ''] ShouldForceCognitoLogin: !Equals [!Ref ForceCognitoLogin, true] @@ -726,6 +743,8 @@ Resources: QBusinessLambdaCodeObject: !Sub "${BootstrapPrefix}/qbusiness-lambda-v0.21.5.zip" AmazonQAppId: !Ref AmazonQAppId IDCApplicationARN: !Ref IDCApplicationARN + VpcSubnetId: !Ref VpcSubnetId + VpcSecurityGroupId: !Ref VpcSecurityGroupId CognitoIdentityPool: Type: AWS::CloudFormation::Stack @@ -860,7 +879,9 @@ Resources: AllowStreamingResponses: !Ref AllowStreamingResponses ShouldEnableUpload: !Ref ShouldEnableUpload UploadBucket: !Ref UploadBucket - Timestamp: 1723566731 + VpcSubnetId: !Ref VpcSubnetId + VpcSecurityGroupId: !Ref VpcSecurityGroupId + Timestamp: 1726069319 CognitoIdentityPoolConfig: Type: AWS::CloudFormation::Stack @@ -874,14 +895,25 @@ Resources: CodeBuildProjectName: !GetAtt CodeBuildDeploy.Outputs.CodeBuildProject CognitoUserPool: !GetAtt CognitoIdentityPool.Outputs.CognitoUserPoolId CognitoUserPoolClient: !GetAtt CognitoIdentityPool.Outputs.CognitoUserPoolClientId - Timestamp: 1723566731 + VpcSubnetId: !Ref VpcSubnetId + VpcSecurityGroupId: !Ref VpcSecurityGroupId + Timestamp: 1726069319 ########################################################################## # Lambda that will validate if user has put in an invalid CSS color/Hex string and fail deployment ########################################################################## CSSValidationLambda: - Type: AWS::Lambda::Function + Type: AWS::Lambda::Function Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" Description: 'Lambda invoke wrapper for Custom CFN actions' Code: ZipFile: !Sub | @@ -928,6 +960,12 @@ Resources: Type: AWS::IAM::Role Properties: Path: / + ManagedPolicyArns: + !If + - NeedsVpc + - + - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + - !Ref "AWS::NoValue" AssumeRolePolicyDocument: Version: 2012-10-17 Statement: @@ -957,6 +995,7 @@ Resources: Version: "1.0" Properties: ServiceToken: !GetAtt CSSValidationLambda.Arn + ServiceTimeout: 60 MessageTextColor: !Ref MessageTextColor ChatBackgroundColor: !Ref ChatBackgroundColor ToolbarColor: !Ref ToolbarColor diff --git a/templates/restapi.yaml b/templates/restapi.yaml index 8d76a50f..6419cefd 100644 --- a/templates/restapi.yaml +++ b/templates/restapi.yaml @@ -36,12 +36,34 @@ Parameters: Description: > Parent Origin for CORS allow-origin + VpcSubnetId: + Type: String + Default: '' + Description: ID of a VPC subnet where all Lambda functions will run, only used if you need Lambda to run in a VPC + + VpcSecurityGroupId: + Type: String + Default: '' + Description: ID of a security group where all Lambda functions will run, only used if you need Lambda to run in a VPC + +Conditions: + NeedsVpc: !And [ !Not [ !Equals [!Ref VpcSubnetId, ''] ], !Not [ !Equals [!Ref VpcSecurityGroupId, ''] ] ] + Resources: #### Lambda ##### InitiateChatLambda: - Type: "AWS::Lambda::Function" + Type: "AWS::Lambda::Function" Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" Description: AWS Lambda Function to initiate the chat with the end user Handler: "index.handler" Role: !GetAtt InitiateChatLambdaExecutionRole.Arn @@ -60,6 +82,12 @@ Resources: InitiateChatLambdaExecutionRole: Type: "AWS::IAM::Role" Properties: + ManagedPolicyArns: + !If + - NeedsVpc + - + - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + - !Ref "AWS::NoValue" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: diff --git a/templates/streaming-support.yaml b/templates/streaming-support.yaml index 7786743f..5cb72b88 100644 --- a/templates/streaming-support.yaml +++ b/templates/streaming-support.yaml @@ -31,13 +31,35 @@ Parameters: Description: > Parent Origin for CORS allow-origin + VpcSubnetId: + Type: String + Default: '' + Description: ID of a VPC subnet where all Lambda functions will run, only used if you need Lambda to run in a VPC + + VpcSecurityGroupId: + Type: String + Default: '' + Description: ID of a security group where all Lambda functions will run, only used if you need Lambda to run in a VPC + +Conditions: + NeedsVpc: !And [ !Not [ !Equals [!Ref VpcSubnetId, ''] ], !Not [ !Equals [!Ref VpcSecurityGroupId, ''] ] ] + Resources: #### Lambda ##### StreamingLambda: - Type: "AWS::Lambda::Function" + Type: "AWS::Lambda::Function" Properties: + VpcConfig: + !If + - NeedsVpc + - + SecurityGroupIds: + - !Ref VpcSecurityGroupId + SubnetIds: + - !Ref VpcSubnetId + - !Ref "AWS::NoValue" Description: AWS Lambda Function to initiate web socket connection for streaming Handler: "index.handler" Role: !GetAtt StreamingLambdaExecutionRole.Arn @@ -54,6 +76,12 @@ Resources: StreamingLambdaExecutionRole: Type: "AWS::IAM::Role" Properties: + ManagedPolicyArns: + !If + - NeedsVpc + - + - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + - !Ref "AWS::NoValue" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: