Untitled
unknown
plain_text
9 days ago
37 kB
1
Indexable
Never
import { SqsToLambda } from "@aws-solutions-constructs/aws-sqs-lambda"; import * as cdk from "aws-cdk-lib"; import { RestApi, DomainName, Resource, Cors, LambdaIntegration, CognitoUserPoolsAuthorizer, BasePathMapping, AuthorizationType, } from "aws-cdk-lib/aws-apigateway"; import { HttpMethod } from "aws-cdk-lib/aws-apigatewayv2"; import * as acm from "aws-cdk-lib/aws-certificatemanager"; import * as cloudtrail from "aws-cdk-lib/aws-cloudtrail"; import * as ec2 from "aws-cdk-lib/aws-ec2"; import * as events from "aws-cdk-lib/aws-events"; import * as targets from "aws-cdk-lib/aws-events-targets"; import * as iam from "aws-cdk-lib/aws-iam"; import * as kms from 'aws-cdk-lib/aws-kms'; import * as lambda from "aws-cdk-lib/aws-lambda"; import * as logs from "aws-cdk-lib/aws-logs"; import * as route53 from "aws-cdk-lib/aws-route53"; import * as route53Targets from "aws-cdk-lib/aws-route53-targets"; import * as s3 from "aws-cdk-lib/aws-s3"; import { HttpMethods } from "aws-cdk-lib/aws-s3"; import * as sqs from "aws-cdk-lib/aws-sqs"; import * as waf from "aws-cdk-lib/aws-wafv2"; import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId, } from "aws-cdk-lib/custom-resources"; import { Construct } from "constructs/lib/construct"; import { camelCase, capitalize } from "lodash"; import { LAMBDA_FUNCTION_TIMEOUT_DURATION } from "@lambdas/shared/monitoring/lambda"; import { DRAFTS_FOLDER } from "@lambdas/shared/services/dto/S3"; import { EnvironmentConfig } from "./config"; import { KepcoLambda } from "./construct"; import { AuthStack } from "./nested-stacks/auth-stack"; import { DatabaseStack } from "./nested-stacks/database-stack"; export interface KepcoStackProps extends cdk.StackProps { stage: string; dbConfig: EnvironmentConfig["dbConfig"]; domainConfig: EnvironmentConfig["domainConfig"]; config: Pick<EnvironmentConfig, "application">; mailConfig: EnvironmentConfig["mailConfig"]; apiGateway: EnvironmentConfig["apiGateway"]; } export interface LambdaVpcConfig { vpc: cdk.aws_ec2.IVpc; vpcSubnets: cdk.aws_ec2.SubnetSelection; securityGroups: ec2.SecurityGroup[]; } export class KepcoStack extends cdk.Stack { region: string; account: string; stage: string; lambdaVpcConfig: LambdaVpcConfig; config: Pick<EnvironmentConfig, "application">; domainConstruct: DomainName; adminDomainConstruct: DomainName; apiDomain: string; dbConfig: { databaseName: string; loginCredentialArn: string; host: string; }; bucket: s3.Bucket; authorizer: CognitoUserPoolsAuthorizer; restApiResource: Resource; authStack: AuthStack; // s3ServerLoggingBucket: s3.Bucket; privateBucket: s3.Bucket; publicBucket: s3.Bucket; mailConfig: { apiKeyArn: string; apiKeyEncryptionKeyArn: string; domain: string; username: string; }; logGroup: logs.LogGroup; constructor(scope: Construct, id: string, props: KepcoStackProps) { super(scope, id, props); this.region = cdk.Stack.of(this).region; this.account = cdk.Stack.of(this).account; // this.s3ServerLoggingBucket = this.createS3ServerLoggingBucket(); this.privateBucket = this.createPrivateMoactBucket(); this.publicBucket = this.createPublicMoactBucket(); this.stage = props.stage; this.config = props.config; this.mailConfig = props.mailConfig; const vpc = this.createVpc(`MoactVpc${capitalize(camelCase(this.stage))}`); const lambdaSecurityGroup = new ec2.SecurityGroup( this, "LambdaSecurityGroup", { vpc, description: "Security group for lambda", allowAllOutbound: true, } ); this.lambdaVpcConfig = { vpc, vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, }, securityGroups: [lambdaSecurityGroup], }; const acmCert = acm.Certificate.fromCertificateArn( this, "moact-api-cert", props.domainConfig.acmArn ); const hostedZone = route53.HostedZone.fromLookup( this, `MoactApiHostedZoneId${capitalize(camelCase(this.stage))}`, { domainName: props.domainConfig.apiDomain.slice( props.domainConfig.apiDomain.indexOf(".") + 1 ), } ); const database = new DatabaseStack(this, "DatabaseStack", { vpcConfig: this.lambdaVpcConfig, stage: this.stage, databaseConfig: props.dbConfig, acmCert: acmCert, domainConfig: props.domainConfig, hostedZone, }); new cdk.CfnOutput(this, "dbProxyUrl", { value: database.dbProxy.endpoint, }); this.dbConfig = { ...props.dbConfig, host: database.dbProxy.endpoint, loginCredentialArn: database.cluster.secret!.secretArn, }; this.domainConstruct = new DomainName( this, `MoactApiDomain${capitalize(camelCase(this.stage))}`, { domainName: props.domainConfig.apiDomain, certificate: acmCert, } ); const apiGatewayRecordTarget = route53.RecordTarget.fromAlias( new route53Targets.ApiGatewayDomain(this.domainConstruct) ); new route53.ARecord( this, `MoactApiAliasRecord${capitalize(camelCase(this.stage))}`, { target: apiGatewayRecordTarget, zone: hostedZone, recordName: props.domainConfig.apiDomain.slice( 0, props.domainConfig.apiDomain.indexOf(".") ), } ); const restApi = new RestApi( this, `MoactRestAPI${capitalize(camelCase(this.stage))}`, { description: "Rest API for moact", defaultCorsPreflightOptions: { allowHeaders: ["Content-Type", "Authorization"], allowMethods: Cors.ALL_METHODS, allowOrigins: [props.apiGateway.cors.origin], allowCredentials: true, exposeHeaders: [ "Referrer-Policy", "Cache-control", "Content-Security-Policy", "X-Content-Type-Options", "Content-Disposition" ], }, deploy: true, deployOptions: { stageName: this.stage, tracingEnabled: true, }, } ); this.configApiGatewayWaf(restApi); //config prefix for all of endpoint /api/v1 this.restApiResource = restApi.root.addResource("api").addResource("v1"); //create path mapping betweene domain name and api new BasePathMapping( this, `BaseMapping${capitalize(camelCase(this.stage))}`, { domainName: this.domainConstruct, restApi: restApi, } ); new cdk.CfnOutput(this, "DatabaseSecretArn", { value: this.dbConfig.loginCredentialArn, }); this.authStack = new AuthStack(this, "AuthStack", { stage: this.stage, vpcConfig: this.lambdaVpcConfig, mailConfig: this.mailConfig, }); // Instantiate authorizer from cognito user pool this.authorizer = new CognitoUserPoolsAuthorizer( this, `MoactAuthorizer${capitalize(camelCase(this.stage))}`, { cognitoUserPools: [this.authStack.userPool], } ); new cdk.CfnOutput(this, "httpApiUrl", { value: this.domainConstruct.domainName, }); new cdk.CfnOutput(this, "userPoolClientId", { value: this.authStack.userPoolClient.userPoolClientId, }); new cdk.CfnOutput(this, "vpcId", { value: this.lambdaVpcConfig.vpc.vpcId, }); const encryptionKey = new kms.Key(this, 'queueEncryptionKey', { enableKeyRotation: true, }); const saveCollectionDLQ = new sqs.Queue( this, "saveCollectionDeadLetterQueue", { receiveMessageWaitTime: cdk.Duration.seconds(20), fifo: true, contentBasedDeduplication: true, encryptionMasterKey: encryptionKey, } ); const saveCollectionQueue = new sqs.Queue(this, "saveCollectionQueue", { retentionPeriod: cdk.Duration.days(14), enforceSSL: true, receiveMessageWaitTime: cdk.Duration.seconds(20), visibilityTimeout: cdk.Duration.seconds( 6 * LAMBDA_FUNCTION_TIMEOUT_DURATION.saveCollectionHandler ), fifo: true, contentBasedDeduplication: true, deadLetterQueue: { queue: saveCollectionDLQ, maxReceiveCount: 1, }, encryptionMasterKey: encryptionKey, }); const saveNormTransactionDLQ = new sqs.Queue( this, "saveNormTransactionDeadLetterQueue", { receiveMessageWaitTime: cdk.Duration.seconds(20), fifo: true, contentBasedDeduplication: true, encryptionMasterKey: encryptionKey, } ); const saveNormTransactionQueue = new sqs.Queue( this, "saveNormTransactionQueue", { retentionPeriod: cdk.Duration.days(14), enforceSSL: true, receiveMessageWaitTime: cdk.Duration.seconds(20), visibilityTimeout: cdk.Duration.seconds( 6 * LAMBDA_FUNCTION_TIMEOUT_DURATION.saveNormTransactionHandler ), fifo: true, contentBasedDeduplication: true, deadLetterQueue: { queue: saveNormTransactionDLQ, maxReceiveCount: 1, }, encryptionMasterKey: encryptionKey, } ); const sharpLayer = new lambda.LayerVersion(this, "sharpLayer", { layerVersionName: "sharpLayer", code: lambda.Code.fromAsset("./assets/sharp.zip"), compatibleRuntimes: [lambda.Runtime.NODEJS_18_X], compatibleArchitectures: [lambda.Architecture.X86_64], }); this.logGroup = new logs.LogGroup( this, `MoactLogGroup${capitalize(camelCase(this.stage))}`, { removalPolicy: cdk.RemovalPolicy.DESTROY, retention: logs.RetentionDays.INFINITE, } ); this.createTrailForObjectLevelEventLogs([ { bucket: this.privateBucket, }, { bucket: this.publicBucket, } ]) this.getUserProfileHandler(); this.updateUserHandler(sharpLayer); this.getUserBalanceHandler(); this.listActiveMissionHandler(); this.getUserPortfolioHandler(); this.getMissionHandler(); this.createDeleteUserHandler(); this.getListUserMissionHandler(); this.createUserMissionHandler(sharpLayer); this.getListContentHandler(); this.getContentDetailHandler(); this.normDistributionBatchHandler(); this.getListCollectionHandler(); this.getCollectionHandler(); this.getListNormTransactionHandler(); this.createSaveCollectionHandler(saveCollectionQueue); this.createSaveCollectionConsumer(saveCollectionQueue); this.createSaveNormTransactionHandler(saveNormTransactionQueue); this.createSaveNormTransactionConsumer(saveNormTransactionQueue); this.getPresignedUrlHandler(); this.createS3FoldersHandler(); this.getListSystemSettingHandler(); this.airdropBatchHandler(); } // private createS3ServerLoggingBucket() { // return new s3.Bucket( // this, // `MoactS3ServerLoggingBucket${capitalize(camelCase(this.stage))}`, // { // removalPolicy: cdk.RemovalPolicy.RETAIN, // enforceSSL: true, // versioned: true, // blockPublicAccess: new cdk.aws_s3.BlockPublicAccess({ // blockPublicAcls: true, // ignorePublicAcls: true, // blockPublicPolicy: true, // restrictPublicBuckets: true, // }), // } // ); // } private createPrivateMoactBucket() { return new s3.Bucket( this, `MoactPrivateBucket${capitalize(camelCase(this.stage))}`, { removalPolicy: cdk.RemovalPolicy.RETAIN, enforceSSL: true, versioned: true, blockPublicAccess: new cdk.aws_s3.BlockPublicAccess({ blockPublicAcls: true, ignorePublicAcls: true, blockPublicPolicy: true, restrictPublicBuckets: true, }), lifecycleRules: [ { id: "autoDeleteNonResizeImageLifecycle", enabled: true, expiration: cdk.Duration.days(1), noncurrentVersionExpiration: cdk.Duration.days(1), prefix: DRAFTS_FOLDER, }, ], cors: [ { allowedHeaders: ["*"], allowedMethods: [ HttpMethods.GET, HttpMethods.HEAD, HttpMethods.PUT, HttpMethods.POST, HttpMethods.DELETE, ], allowedOrigins: ["*"], exposedHeaders: [""], maxAge: 3000, }, ], } ); } private createPublicMoactBucket() { const bucket = new s3.Bucket( this, `MoactPublicBucket${capitalize(camelCase(this.stage))}`, { removalPolicy: cdk.RemovalPolicy.RETAIN, enforceSSL: false, publicReadAccess: true, websiteIndexDocument: "index.html", versioned: true, blockPublicAccess: new cdk.aws_s3.BlockPublicAccess({ blockPublicAcls: false, ignorePublicAcls: false, blockPublicPolicy: false, restrictPublicBuckets: false, }), } ); bucket.addToResourcePolicy(new iam.PolicyStatement({ effect: iam.Effect.DENY, principals: [new iam.ArnPrincipal("*")], actions: ["*"], resources: [bucket.arnForObjects("*")], conditions: { 'Bool': { 'aws:SecureTransport': 'false', }, }, })); return bucket; } private createS3FoldersHandler() { const handler = new KepcoLambda(this, "CreateS3FoldersHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/init-s3-empty-folder"), environment: { REGION: this.region, S3_BUCKET_NAME: this.publicBucket.bucketName, }, logGroup: this.logGroup, }, }).getLambda(); this.publicBucket.grantPut(handler); const lambdaTrigger = new AwsCustomResource( this, "CreateS3PublicFolderTrigger", { policy: AwsCustomResourcePolicy.fromStatements([ new iam.PolicyStatement({ actions: ["lambda:InvokeFunction"], effect: iam.Effect.ALLOW, resources: [handler.functionArn], }), ]), timeout: cdk.Duration.minutes(1), installLatestAwsSdk: true, onCreate: { service: "Lambda", action: "invoke", parameters: { FunctionName: handler.functionName, InvocationType: "Event", }, physicalResourceId: PhysicalResourceId.of( "JobSenderTriggerPhysicalId" ), }, } ); lambdaTrigger.node.addDependency(handler, this.publicBucket); } private createTrailForObjectLevelEventLogs(s3Selector: cloudtrail.S3EventSelector[]) { const trail = new cloudtrail.Trail(this, "MoactObjectLevelEventTrail"); trail.addS3EventSelector(s3Selector, { readWriteType: cloudtrail.ReadWriteType.WRITE_ONLY, includeManagementEvents: false, }) return trail; } private getUserProfileHandler() { const handler = new KepcoLambda(this, "GetUserProfileHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/user-profile"), environment: { REGION: this.region, S3_BUCKET_NAME: this.privateBucket.bucketName, S3_PRIVATE_URL_EXPIRES: this.config.application.privateUrlExpires.toString(), }, logGroup: this.logGroup, }, }).getLambda(); this.privateBucket.grantRead(handler); this.restApiResource .resourceForPath("users") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private updateUserHandler(layer: cdk.aws_lambda.LayerVersion) { const handler = new KepcoLambda(this, "UpdateUserHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, layers: [layer], memorySize: 1024, code: lambda.Code.fromAsset("./dist/lambdas/update-user"), timeout: cdk.Duration.seconds( LAMBDA_FUNCTION_TIMEOUT_DURATION.updateUserHandler ), environment: { S3_BUCKET_NAME: this.privateBucket.bucketName, }, logGroup: this.logGroup, }, }).getLambda(); this.privateBucket.grantDelete(handler); this.privateBucket.grantPut(handler); this.privateBucket.grantRead(handler); this.restApiResource .resourceForPath("users") .addMethod(HttpMethod.POST, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getUserBalanceHandler() { const handler = new KepcoLambda(this, "GetUserBalanceHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/get-user-balance"), logGroup: this.logGroup, }, }).getLambda(); this.restApiResource .resourceForPath("users/balance") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private listActiveMissionHandler() { const handler = new KepcoLambda(this, "ListActiveMissionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, memorySize: 1024, code: lambda.Code.fromAsset("./dist/lambdas/list-active-mission"), logGroup: this.logGroup, environment: { S3_PUBLIC_DOMAIN_NAME: this.publicBucket.bucketDomainName, }, }, }).getLambda(); this.restApiResource .resourceForPath("missions") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getMissionHandler() { const handler = new KepcoLambda(this, "GetMissionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/get-mission"), environment: { S3_PUBLIC_DOMAIN_NAME: this.publicBucket.bucketDomainName, S3_BUCKET_NAME: this.privateBucket.bucketName, S3_PRIVATE_URL_EXPIRES: this.config.application.privateUrlExpires.toString(), }, logGroup: this.logGroup, }, }).getLambda(); this.privateBucket.grantRead(handler); this.restApiResource .resourceForPath("missions/{missionId}") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getUserPortfolioHandler() { const handler = new KepcoLambda(this, "GetUserPortfolioHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/get-portfolio"), logGroup: this.logGroup, }, }).getLambda(); this.restApiResource .resourceForPath("users/portfolio") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getListUserMissionHandler() { const handler = new KepcoLambda(this, "GetListUserMissionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/list-user-mission"), logGroup: this.logGroup, environment: { S3_PUBLIC_DOMAIN_NAME: this.publicBucket.bucketDomainName, S3_BUCKET_NAME: this.privateBucket.bucketName, S3_PRIVATE_URL_EXPIRES: this.config.application.privateUrlExpires.toString(), }, }, }).getLambda(); this.privateBucket.grantRead(handler); this.restApiResource .resourceForPath("user-missions") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getListNormTransactionHandler() { const handler = new KepcoLambda(this, "GetListNormTransactionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/list-norm-transaction"), logGroup: this.logGroup, }, }).getLambda(); this.restApiResource .resourceForPath("norm-transactions") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getListContentHandler() { const handler = new KepcoLambda(this, "GetListContentHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/list-content"), logGroup: this.logGroup, environment: { S3_PUBLIC_DOMAIN_NAME: this.publicBucket.bucketDomainName, }, }, }).getLambda(); this.restApiResource .resourceForPath("contents") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private createSaveCollectionHandler(queue: sqs.Queue) { const handler = new KepcoLambda(this, "SaveCollectionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/save-collection"), environment: { QUEUE_URL: queue.queueUrl, }, logGroup: this.logGroup, }, }).getLambda(); queue.grantSendMessages(handler); this.restApiResource .resourceForPath("collections") .addMethod(HttpMethod.POST, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getListCollectionHandler() { const handler = new KepcoLambda(this, "GetListCollectionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/list-collection"), logGroup: this.logGroup, environment: { S3_PUBLIC_DOMAIN_NAME: this.publicBucket.bucketDomainName, }, }, }).getLambda(); this.restApiResource .resourceForPath("collections") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getCollectionHandler() { const handler = new KepcoLambda(this, "GetCollectionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/get-collection"), logGroup: this.logGroup, environment: { S3_PUBLIC_DOMAIN_NAME: this.publicBucket.bucketDomainName, }, }, }).getLambda(); this.restApiResource .resourceForPath("collections/{collectionId}") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private normDistributionBatchHandler() { const handler = new KepcoLambda(this, "NormDistributionBatchHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, timeout: cdk.Duration.seconds( LAMBDA_FUNCTION_TIMEOUT_DURATION.normDistributionBatchHandler ), code: lambda.Code.fromAsset("./dist/lambdas/norm-distribution-batch"), logGroup: this.logGroup, }, }).getLambda(); new events.Rule(this, "NormDistributionBatchExecuteRule", { targets: [new targets.LambdaFunction(handler)], schedule: events.Schedule.expression( this.config.application.normDistributionBatchExecuteTimeRule ), }); } private createUserMissionHandler(layer: cdk.aws_lambda.LayerVersion) { const handler = new KepcoLambda(this, "CreateUserMissionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, memorySize: 1024, code: lambda.Code.fromAsset("./dist/lambdas/create-user-mission"), timeout: cdk.Duration.seconds( LAMBDA_FUNCTION_TIMEOUT_DURATION.createUserMissionHandler ), layers: [layer], environment: { S3_BUCKET_NAME: this.privateBucket.bucketName, S3_PRIVATE_URL_EXPIRES: this.config.application.privateUrlExpires.toString(), }, logGroup: this.logGroup, }, }).getLambda(); this.privateBucket.grantRead(handler); this.privateBucket.grantPut(handler); this.privateBucket.grantDelete(handler); this.restApiResource .resourceForPath("user-missions") .addMethod(HttpMethod.POST, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private createVpc(name: string) { return new ec2.Vpc(this, name, { ipAddresses: ec2.IpAddresses.cidr("10.0.0.0/16"), natGateways: 1, subnetConfiguration: [ { cidrMask: 22, name: "ingress", subnetType: ec2.SubnetType.PUBLIC, }, { cidrMask: 22, name: "application", subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, }, { cidrMask: 22, name: "rds", subnetType: ec2.SubnetType.PRIVATE_ISOLATED, }, ], }); } private createDeleteUserHandler() { const handler = new KepcoLambda(this, "DeleteUserHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/delete-user"), environment: { USER_POOL_ID: this.authStack.userPool.userPoolId, }, logGroup: this.logGroup, }, }).getLambda(); handler.addToRolePolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ["cognito-idp:AdminDeleteUser"], resources: [ `arn:aws:cognito-idp:${this.region}:${this.account}:userpool/*`, ], }) ); this.restApiResource .resourceForPath("users") .addMethod(HttpMethod.DELETE, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getContentDetailHandler() { const handler = new KepcoLambda(this, "GetContentDetailHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/get-content"), logGroup: this.logGroup, environment: { S3_PUBLIC_DOMAIN_NAME: this.publicBucket.bucketDomainName, }, }, }).getLambda(); this.restApiResource .resourceForPath("contents/{contentId}") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private createSaveCollectionConsumer(queue: sqs.Queue) { const handler = new KepcoLambda(this, "saveCollectionConsumer", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { code: lambda.Code.fromAsset("./dist/lambdas/save-collection-consumer"), timeout: cdk.Duration.seconds( LAMBDA_FUNCTION_TIMEOUT_DURATION.saveCollectionHandler ), environment: { SALE_WALLET_ADDRESS: this.config.application.saleWalletAddress, }, ...this.lambdaVpcConfig, logGroup: this.logGroup, }, }).getLambda(); new SqsToLambda(this, "SqsToSaveCollectionConsumer", { existingLambdaObj: handler, existingQueueObj: queue, sqsEventSourceProps: { maxConcurrency: 50, reportBatchItemFailures: true, batchSize: 1, }, }); } private createSaveNormTransactionHandler(queue: sqs.Queue) { const handler = new KepcoLambda(this, "SaveNormTransactionHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/save-norm-transaction"), environment: { QUEUE_URL: queue.queueUrl, }, logGroup: this.logGroup, }, }).getLambda(); queue.grantSendMessages(handler); this.restApiResource .resourceForPath("norm-transactions") .addMethod(HttpMethod.POST, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private createSaveNormTransactionConsumer(queue: sqs.Queue) { const handler = new KepcoLambda(this, "saveNormTransactionConsumer", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { code: lambda.Code.fromAsset( "./dist/lambdas/save-norm-transaction-consumer" ), timeout: cdk.Duration.seconds( LAMBDA_FUNCTION_TIMEOUT_DURATION.saveNormTransactionHandler ), ...this.lambdaVpcConfig, logGroup: this.logGroup, }, }).getLambda(); new SqsToLambda(this, "SqsToSaveNormTransactionConsumer", { existingLambdaObj: handler, existingQueueObj: queue, sqsEventSourceProps: { maxConcurrency: 50, reportBatchItemFailures: true, batchSize: 1, }, }); } private getPresignedUrlHandler() { const handler = new KepcoLambda(this, "PresignedUrlHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/get-presigned-url"), environment: { UPLOAD_PRESIGN_EXPR: this.config.application.presingedUrlExpires.toString(), S3_BUCKET_NAME: this.privateBucket.bucketName, }, logGroup: this.logGroup, }, }).getLambda(); this.privateBucket.grantReadWrite(handler); this.restApiResource .resourceForPath("presigned-url") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private getListSystemSettingHandler() { const handler = new KepcoLambda(this, "GetListSystemSettingHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, code: lambda.Code.fromAsset("./dist/lambdas/list-system-setting"), logGroup: this.logGroup, }, }).getLambda(); this.restApiResource .resourceForPath("system-settings") .addMethod(HttpMethod.GET, new LambdaIntegration(handler), { authorizer: this.authorizer, authorizationType: AuthorizationType.COGNITO, }); } private airdropBatchHandler() { const handler = new KepcoLambda(this, "AirdropBatchHandler", { account: this.account, stage: this.stage, region: this.region, lambdaProps: { ...this.lambdaVpcConfig, timeout: cdk.Duration.seconds( LAMBDA_FUNCTION_TIMEOUT_DURATION.airdropBatchHandler ), code: lambda.Code.fromAsset("./dist/lambdas/airdrop-batch"), logGroup: this.logGroup, }, }).getLambda(); new events.Rule(this, "AirdropBatchExecuteRule", { targets: [new targets.LambdaFunction(handler)], schedule: events.Schedule.expression( this.config.application.airdropBatchExecuteTimeRule ), }); } private configApiGatewayWaf(restApiGateway: RestApi) { const webACL = new waf.CfnWebACL( this, `MoactACL2${capitalize(camelCase(this.stage))}`, { defaultAction: { allow: {}, }, scope: "REGIONAL", visibilityConfig: { cloudWatchMetricsEnabled: true, metricName: "waf", sampledRequestsEnabled: false, }, rules: [ { name: "AWS-AWSManagedRulesCommonRuleSet", priority: 0, statement: { managedRuleGroupStatement: { vendorName: "AWS", name: "AWSManagedRulesCommonRuleSet", }, }, overrideAction: { none: {}, }, visibilityConfig: { sampledRequestsEnabled: true, cloudWatchMetricsEnabled: true, metricName: "AWS-AWSManagedRulesCommonRuleSet", }, }, { name: "AWS-AWSManagedRulesAdminProtectionRuleSet", priority: 1, statement: { managedRuleGroupStatement: { vendorName: "AWS", name: "AWSManagedRulesAdminProtectionRuleSet", }, }, overrideAction: { none: {}, }, visibilityConfig: { sampledRequestsEnabled: true, cloudWatchMetricsEnabled: true, metricName: "AWS-AWSManagedRulesAdminProtectionRuleSet", }, }, { name: "AWS-AWSManagedRulesKnownBadInputsRuleSet", priority: 2, statement: { managedRuleGroupStatement: { vendorName: "AWS", name: "AWSManagedRulesKnownBadInputsRuleSet", }, }, overrideAction: { none: {}, }, visibilityConfig: { sampledRequestsEnabled: true, cloudWatchMetricsEnabled: true, metricName: "AWS-AWSManagedRulesKnownBadInputsRuleSet", }, }, ], } ); new waf.CfnWebACLAssociation(this, "WebACLAssociation", { webAclArn: webACL.attrArn, resourceArn: `arn:aws:apigateway:${cdk.Stack.of(this).region }::/restapis/${restApiGateway.restApiId}/stages/${restApiGateway.deploymentStage.stageName }`, }); } }
Leave a Comment