packages/constructs/L3/ai/gaia-l3-construct/lib/gaia-l3-construct.ts (188 lines of code) (raw):

/*! * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ import { MdaaRoleRef } from '@aws-mdaa/iam-role-helper'; import { MdaaL3Construct, MdaaL3ConstructProps } from '@aws-mdaa/l3-construct'; import { FilterOrPolicy, SubscriptionFilter } from 'aws-cdk-lib/aws-sns'; import { SqsSubscription } from 'aws-cdk-lib/aws-sns-subscriptions'; import { Construct } from 'constructs'; import { Authentication } from './authentication'; import { ChatBotApi } from './chatbot-api'; import { LangChainInterface } from './model-interfaces/langchain'; import { Models } from './models'; import { RagEngines } from './rag-engines'; import { Shared } from './shared'; import { Direction, ModelInterface, SystemConfig } from './shared/types'; import { Stack } from 'aws-cdk-lib'; import { MdaaNagSuppressions } from '@aws-mdaa/construct'; //NOSONAR import { MdaaKmsKey, DECRYPT_ACTIONS, ENCRYPT_ACTIONS } from '@aws-mdaa/kms-constructs'; import { Effect, PolicyStatement, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; export interface GAIAProps extends SystemConfig { /** * List of admin roles which will be provided access to team resources (like KMS/Bucket) */ readonly dataAdminRoles: MdaaRoleRef[]; } export interface GAIAL3ConstructProps extends MdaaL3ConstructProps { readonly gaia: GAIAProps; } //This stack creates all the resources required for a Gen AI Factory Application export class GAIAL3Construct extends MdaaL3Construct { protected readonly props: GAIAL3ConstructProps; constructor(scope: Construct, id: string, props: GAIAL3ConstructProps) { super(scope, id, props); this.props = props; const stackEncryptionKey = new MdaaKmsKey(this, 'StackEncryptionKey', { naming: props.naming, createParams: true, createOutputs: false, }); const cloudwatchStatement = new PolicyStatement({ sid: 'CloudWatchLogsEncryption', effect: Effect.ALLOW, actions: [...DECRYPT_ACTIONS, ...ENCRYPT_ACTIONS], principals: [new ServicePrincipal(`logs.${this.region}.amazonaws.com`)], resources: ['*'], //Limit access to use this key only for log groups within this account conditions: { ArnEquals: { 'kms:EncryptionContext:aws:logs:arn': `arn:${this.partition}:logs:${this.region}:${this.account}:log-group:*`, }, }, }); stackEncryptionKey.addToResourcePolicy(cloudwatchStatement); const shared = new Shared(this, 'Shared', { config: props.gaia, encryptionKey: stackEncryptionKey, ...props, }); const authentication = new Authentication(this, 'Authentication', { config: props.gaia, naming: props.naming, }); const models = new Models(this, 'Models', { ...props, encryptionKey: stackEncryptionKey, config: props.gaia, shared, }); let ragEngines: RagEngines | undefined = undefined; if (props.gaia.rag) { ragEngines = new RagEngines(this, 'RagEngines', { ...props, shared, encryptionKey: stackEncryptionKey, config: props.gaia, }); } const chatBotApi = new ChatBotApi(this, 'ChatBotApi', { ...props, shared, encryptionKey: stackEncryptionKey, config: props.gaia, ragEngines: ragEngines, userPool: authentication.userPool, userPoolClient: authentication.userPoolClient, modelsParameter: models.modelsParameter, models: models.models, }); // Langchain Interface Construct // This is the model interface recieving messages from the websocket interface via the message topic // and interacting with the model via LangChain library const langchainModels = models.models.filter(model => model.modelInterface === ModelInterface.LANG_CHAIN); // check if any deployed model requires langchain interface or if bedrock is enabled from config if (langchainModels.length > 0 || props.gaia.bedrock?.enabled) { const langchainInterface = new LangChainInterface(this, 'LangchainInterface', { ...props, shared, encryptionKey: stackEncryptionKey, config: props.gaia, ragEngines, messagesTopic: chatBotApi.messagesTopic, sessionsTable: chatBotApi.sessionsTable, byUserIdIndex: chatBotApi.byUserIdIndex, }); // Route all incoming messages targeted to langchain to the langchain model interface queue chatBotApi.messagesTopic.addSubscription( new SqsSubscription(langchainInterface.ingestionQueue, { filterPolicyWithMessageBody: { direction: FilterOrPolicy.filter( SubscriptionFilter.stringFilter({ allowlist: [Direction.IN], }), ), modelInterface: FilterOrPolicy.filter( SubscriptionFilter.stringFilter({ allowlist: [ModelInterface.LANG_CHAIN], }), ), }, }), ); for (const model of models.models) { if (model.modelInterface === ModelInterface.LANG_CHAIN) { langchainInterface.addSageMakerEndpoint(model); } } } MdaaNagSuppressions.addCodeResourceSuppressions( this, [{ id: 'AwsSolutions-L1', reason: 'GAIA designed for Python 3.11.' }], true, ); // BucketDeployment uses a Custom Resource Lambda to copy assets // from CDK Deployment bucket to destination bucket. Stack.of(this).node.children.forEach(child => { if ( child.node.id.includes('Custom::CDKBucketDeployment') || child.node.id.includes('BucketNotificationsHandler') || child.node.id.includes('DatabaseSetupFunction') || child.node.id.includes('LogRetention') ) { console.log(child.node.id); MdaaNagSuppressions.addCodeResourceSuppressions( child, [ { id: 'AwsSolutions-L1', reason: 'Function is used only as custom resource during CDK deployment.' }, { id: 'NIST.800.53.R5-LambdaConcurrency', reason: 'Function is used only as custom resource during CDK deployment.', }, { id: 'NIST.800.53.R5-LambdaInsideVPC', reason: 'Function is used only as custom resource during CDK deployment and interacts only with S3.', }, { id: 'NIST.800.53.R5-LambdaDLQ', reason: 'Function is used only as custom resource during CDK deployment. Errors will be handled by CloudFormation.', }, { id: 'HIPAA.Security-LambdaConcurrency', reason: 'Function is used only as custom resource during CDK deployment.', }, { id: 'PCI.DSS.321-LambdaConcurrency', reason: 'Function is used only as custom resource during CDK deployment.', }, { id: 'HIPAA.Security-LambdaInsideVPC', reason: 'Function is used only as custom resource during CDK deployment and interacts only with S3.', }, { id: 'PCI.DSS.321-LambdaInsideVPC', reason: 'Function is used only as custom resource during CDK deployment and interacts only with S3.', }, { id: 'HIPAA.Security-LambdaDLQ', reason: 'Function is used only as custom resource during CDK deployment. Errors will be handled by CloudFormation.', }, { id: 'PCI.DSS.321-LambdaDLQ', reason: 'Function is used only as custom resource during CDK deployment. Errors will be handled by CloudFormation.', }, { id: 'AwsSolutions-IAM4', reason: 'Function is used only as custom resource during CDK deployment.' }, { id: 'AwsSolutions-IAM5', reason: 'Function is used only as custom resource during CDK deployment.' }, { id: 'HIPAA.Security-IAMNoInlinePolicy', reason: 'Policy managed by CDK and only used during deployment.', }, { id: 'PCI.DSS.321-IAMNoInlinePolicy', reason: 'Policy managed by CDK and only used during deployment.' }, { id: 'NIST.800.53.R5-IAMNoInlinePolicy', reason: 'Policy managed by CDK and only used during deployment.', }, ], true, ); } }); } }