@@ -18,7 +18,6 @@ import {
1818 CfnKnowledgeBase ,
1919 CfnDataSource
2020} from "aws-cdk-lib/aws-bedrock"
21- import { LambdaFunction } from "../constructs/LambdaFunction"
2221import { PolicyStatement } from "aws-cdk-lib/aws-iam"
2322import * as cdk from "aws-cdk-lib"
2423import * as iam from "aws-cdk-lib/aws-iam"
@@ -28,15 +27,12 @@ import * as ssm from "aws-cdk-lib/aws-ssm"
2827import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"
2928import { nagSuppressions } from "../nagSuppressions"
3029import { Apis } from "../resources/Apis"
30+ import { Functions } from "../resources/Functions"
3131
32- const RAG_MODEL_ID = "anthropic.claude-3-sonnet-20240229-v1:0"
3332const EMBEDDING_MODEL = "amazon.titan-embed-text-v2:0"
34- const SLACK_SLASH_COMMAND = "/ask-eps"
3533const COLLECTION_NAME = "eps-assist-vector-db"
3634const VECTOR_INDEX_NAME = "eps-assist-os-index"
3735const BEDROCK_KB_NAME = "eps-assist-kb"
38- const BEDROCK_KB_DATA_SOURCE = "eps-assist-kb-ds"
39- const LAMBDA_MEMORY_SIZE = "265"
4036
4137export interface EpsAssistMeStackProps extends StackProps {
4238 readonly stackName : string
@@ -281,17 +277,51 @@ export class EpsAssistMeStack extends Stack {
281277 effect : iam . Effect . ALLOW
282278 } ) )
283279
284- // Define a lambda function to create an opensearch serverless index
285- const createIndexFunction = new LambdaFunction ( this , "CreateIndexFunction" , {
280+ const endpoint = `${ osCollection . attrId } .${ region } .aoss.amazonaws.com`
281+
282+ // Define a Bedrock knowledge base with type opensearch serverless and titan for embedding model
283+ const bedrockkb = new CfnKnowledgeBase ( this , "EpsKb" , {
284+ name : BEDROCK_KB_NAME ,
285+ description : "EPS Assist Knowledge Base" ,
286+ roleArn : bedrockExecutionRole . roleArn ,
287+ knowledgeBaseConfiguration : {
288+ type : "VECTOR" ,
289+ vectorKnowledgeBaseConfiguration : {
290+ embeddingModelArn : `arn:aws:bedrock:${ region } ::foundation-model/${ EMBEDDING_MODEL } `
291+ }
292+ } ,
293+ storageConfiguration : {
294+ type : "OPENSEARCH_SERVERLESS" ,
295+ opensearchServerlessConfiguration : {
296+ collectionArn : osCollection . attrArn ,
297+ fieldMapping : {
298+ vectorField : "bedrock-knowledge-base-default-vector" ,
299+ textField : "AMAZON_BEDROCK_TEXT_CHUNK" ,
300+ metadataField : "AMAZON_BEDROCK_METADATA"
301+ } ,
302+ vectorIndexName : VECTOR_INDEX_NAME
303+ }
304+ }
305+ } )
306+
307+ // Create Functions construct
308+ const functions = new Functions ( this , "Functions" , {
286309 stackName : props . stackName ,
287- functionName : `${ props . stackName } -CreateIndexFunction` ,
288- packageBasePath : "packages/createIndexFunction" ,
289- entryPoint : "app.py" ,
310+ version : props . version ,
311+ commitId : props . commitId ,
290312 logRetentionInDays,
291313 logLevel,
292- environmentVariables : { "INDEX_NAME" : osCollection . attrId } ,
293- additionalPolicies : [ ] ,
294- role : createIndexFunctionRole
314+ createIndexFunctionRole,
315+ slackBotTokenParameter,
316+ slackSigningSecretParameter,
317+ guardrailId : GUARD_RAIL_ID ,
318+ guardrailVersion : GUARD_RAIL_VERSION ,
319+ collectionId : osCollection . attrId ,
320+ knowledgeBaseId : bedrockkb . attrKnowledgeBaseId ,
321+ region,
322+ account,
323+ slackBotTokenSecret,
324+ slackBotSigningSecret
295325 } )
296326
297327 // Define OpenSearchServerless access policy to access the index and collection
@@ -307,23 +337,20 @@ export class EpsAssistMeStack extends Stack {
307337 // Add principal of bedrock execution role and lambda execution role
308338 Principal : [
309339 bedrockExecutionRole . roleArn ,
310- createIndexFunction . function . role ?. roleArn ,
340+ functions . functions . createIndex . function . role ?. roleArn ,
311341 `arn:aws:iam::${ account } :root`
312342 ]
313343 } ] )
314344 } )
315- //this.serverlessCollection = osCollection;
316345 osCollection . addDependency ( aossAccessPolicy )
317346
318- const endpoint = `${ osCollection . attrId } .${ region } .aoss.amazonaws.com`
319-
320347 const vectorIndex = new cr . AwsCustomResource ( this , "VectorIndex" , {
321348 installLatestAwsSdk : true ,
322349 onCreate : {
323350 service : "Lambda" ,
324351 action : "invoke" ,
325352 parameters : {
326- FunctionName : createIndexFunction . function . functionName ,
353+ FunctionName : functions . functions . createIndex . function . functionName ,
327354 InvocationType : "RequestResponse" ,
328355 Payload : JSON . stringify ( {
329356 RequestType : "Create" ,
@@ -338,7 +365,7 @@ export class EpsAssistMeStack extends Stack {
338365 service : "Lambda" ,
339366 action : "invoke" ,
340367 parameters : {
341- FunctionName : createIndexFunction . function . functionName ,
368+ FunctionName : functions . functions . createIndex . function . functionName ,
342369 InvocationType : "RequestResponse" ,
343370 Payload : JSON . stringify ( {
344371 RequestType : "Delete" ,
@@ -347,12 +374,11 @@ export class EpsAssistMeStack extends Stack {
347374 Endpoint : endpoint
348375 } )
349376 }
350- //physicalResourceId: cr.PhysicalResourceId.of('vectorIndexResource'),
351377 } ,
352378 policy : cr . AwsCustomResourcePolicy . fromStatements ( [
353379 new iam . PolicyStatement ( {
354380 actions : [ "lambda:InvokeFunction" ] ,
355- resources : [ createIndexFunction . function . functionArn ]
381+ resources : [ functions . functions . createIndex . function . functionArn ]
356382 } )
357383 ] ) ,
358384 timeout : cdk . Duration . seconds ( 60 )
@@ -361,33 +387,9 @@ export class EpsAssistMeStack extends Stack {
361387 // Ensure vectorIndex depends on collection
362388 vectorIndex . node . addDependency ( osCollection )
363389
364- // Define a Bedrock knowledge base with type opensearch serverless and titan for embedding model
365- const bedrockkb = new CfnKnowledgeBase ( this , "EpsKb" , {
366- name : BEDROCK_KB_NAME ,
367- description : "EPS Assist Knowledge Base" ,
368- roleArn : bedrockExecutionRole . roleArn ,
369- knowledgeBaseConfiguration : {
370- type : "VECTOR" ,
371- vectorKnowledgeBaseConfiguration : {
372- embeddingModelArn : `arn:aws:bedrock:${ region } ::foundation-model/${ EMBEDDING_MODEL } `
373- }
374- } ,
375- storageConfiguration : {
376- type : "OPENSEARCH_SERVERLESS" ,
377- opensearchServerlessConfiguration : {
378- collectionArn : osCollection . attrArn ,
379- fieldMapping : {
380- vectorField : "bedrock-knowledge-base-default-vector" ,
381- textField : "AMAZON_BEDROCK_TEXT_CHUNK" ,
382- metadataField : "AMAZON_BEDROCK_METADATA"
383- } ,
384- vectorIndexName : VECTOR_INDEX_NAME
385- }
386- }
387- } )
388390 // add a dependency for bedrock kb on the custom resource. Enables vector index to be created before KB
389391 bedrockkb . node . addDependency ( vectorIndex )
390- bedrockkb . node . addDependency ( createIndexFunction )
392+ bedrockkb . node . addDependency ( functions . functions . createIndex )
391393 bedrockkb . node . addDependency ( osCollection )
392394 bedrockkb . node . addDependency ( bedrockExecutionRole )
393395
@@ -403,84 +405,13 @@ export class EpsAssistMeStack extends Stack {
403405 }
404406 } )
405407
406- // Create an IAM policy to allow the lambda to invoke models in Amazon Bedrock
407- const lambdaBedrockModelPolicy = new PolicyStatement ( )
408- lambdaBedrockModelPolicy . addActions ( "bedrock:InvokeModel" )
409- lambdaBedrockModelPolicy . addResources ( `arn:aws:bedrock:${ region } ::foundation-model/${ RAG_MODEL_ID } ` )
410-
411- // Create an IAM policy to allow the lambda to call Retrieve and Retrieve and Generate on a Bedrock Knowledge Base
412- const lambdaBedrockKbPolicy = new PolicyStatement ( )
413- lambdaBedrockKbPolicy . addActions ( "bedrock:Retrieve" )
414- lambdaBedrockKbPolicy . addActions ( "bedrock:RetrieveAndGenerate" )
415- lambdaBedrockKbPolicy . addResources (
416- `arn:aws:bedrock:${ region } :${ account } :knowledge-base/${ bedrockkb . attrKnowledgeBaseId } `
417- )
418-
419- // Create an IAM policy to allow the lambda to call SSM
420- const lambdaSSMPolicy = new PolicyStatement ( )
421- lambdaSSMPolicy . addActions ( "ssm:GetParameter" )
422- //lambdaSSMPolicy.addActions("ssm:GetParameters");
423- // lambdaSSMPolicy.addResources("slackBotTokenParameter.parameterArn");
424- // lambdaSSMPolicy.addResources("slackBotSigningSecret.parameterArn");
425- lambdaSSMPolicy . addResources (
426- `arn:aws:ssm:${ region } :${ account } :parameter${ slackBotTokenParameter . parameterName } ` )
427- lambdaSSMPolicy . addResources (
428- `arn:aws:ssm:${ region } :${ account } :parameter${ slackSigningSecretParameter . parameterName } ` )
429-
430- //arn:aws:ssm:us-east-1:859498851685:parameter/slack/bot-token/parameter
431- //"arn:aws:ssm:us-east-2:123456789012:parameter/prod-*"
432- //(`arn:aws:bedrock:${region}:${account}:knowledge-base/${bedrockkb.attrKnowledgeBaseId}`);
433-
434- const lambdaReinvokePolicy = new PolicyStatement ( )
435- lambdaReinvokePolicy . addActions ( "lambda:InvokeFunction" )
436- lambdaReinvokePolicy . addResources ( `arn:aws:lambda:${ region } :${ account } :function:*` )
437-
438- const lambdaGRinvokePolicy = new PolicyStatement ( )
439- lambdaGRinvokePolicy . addActions ( "bedrock:ApplyGuardrail" )
440- lambdaGRinvokePolicy . addResources ( `arn:aws:bedrock:${ region } :${ account } :guardrail/*` )
441-
442- // Create the SlackBot (slash command) integration to Amazon Bedrock Knowledge base responses.
443- const slackBotLambda = new LambdaFunction ( this , "SlackBotLambda" , {
444- stackName : props . stackName ,
445- functionName : `${ props . stackName } -SlackBotFunction` ,
446- packageBasePath : "packages/slackBotFunction" ,
447- entryPoint : "app.py" ,
448- logRetentionInDays,
449- logLevel,
450- additionalPolicies : [ ] ,
451- environmentVariables : {
452- "RAG_MODEL_ID" : RAG_MODEL_ID ,
453- "SLACK_SLASH_COMMAND" : SLACK_SLASH_COMMAND ,
454- "KNOWLEDGEBASE_ID" : bedrockkb . attrKnowledgeBaseId ,
455- "BEDROCK_KB_DATA_SOURCE" : BEDROCK_KB_DATA_SOURCE ,
456- "LAMBDA_MEMORY_SIZE" : LAMBDA_MEMORY_SIZE ,
457- // "SLACK_BOT_TOKEN": SLACK_BOT_TOKEN,
458- // "SLACK_SIGNING_SECRET": SLACK_SIGNING_SECRET,
459- "SLACK_BOT_TOKEN_PARAMETER" : slackBotTokenParameter . parameterName ,
460- "SLACK_SIGNING_SECRET_PARAMETER" : slackSigningSecretParameter . parameterName ,
461- "GUARD_RAIL_ID" : GUARD_RAIL_ID ,
462- "GUARD_RAIL_VERSION" : GUARD_RAIL_VERSION
463- }
464- } )
465-
466- // Grant the Lambda function permission to read the secrets
467- slackBotTokenSecret . grantRead ( slackBotLambda . function )
468- slackBotSigningSecret . grantRead ( slackBotLambda . function )
469-
470- // Attach listed IAM policies to the Lambda functions Execution role
471- slackBotLambda . function . addToRolePolicy ( lambdaBedrockModelPolicy )
472- slackBotLambda . function . addToRolePolicy ( lambdaBedrockKbPolicy )
473- slackBotLambda . function . addToRolePolicy ( lambdaReinvokePolicy )
474- slackBotLambda . function . addToRolePolicy ( lambdaGRinvokePolicy )
475- slackBotLambda . function . addToRolePolicy ( lambdaSSMPolicy )
476-
477408 // Create Apis and pass the Lambda function
478409 const apis = new Apis ( this , "Apis" , {
479410 stackName : props . stackName ,
480411 logRetentionInDays,
481412 enableMutalTls : false ,
482413 functions : {
483- slackBot : slackBotLambda
414+ slackBot : functions . functions . slackBot
484415 }
485416 } )
486417
0 commit comments