From f16d2e668b442abc7d8d3ad0759dc440ca589806 Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Sat, 27 Apr 2024 07:16:53 +0000 Subject: [PATCH 1/9] =?UTF-8?q?constructs=E3=83=95=E3=82=A9=E3=83=AB?= =?UTF-8?q?=E3=83=80=E3=81=AE=E5=90=84=E3=82=B3=E3=83=B3=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=83=A9=E3=82=AF=E3=82=BF=E3=81=AE=E3=83=95=E3=82=A1=E3=82=A4?= =?UTF-8?q?=E3=83=AB=E3=82=92=E4=BD=9C=E6=88=90=E3=81=97=E3=81=BE=E3=81=97?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/constructs/api.ts | 0 src/backend/lib/constructs/auth.ts | 0 src/backend/lib/constructs/web.ts | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/backend/lib/constructs/api.ts create mode 100644 src/backend/lib/constructs/auth.ts create mode 100644 src/backend/lib/constructs/web.ts diff --git a/src/backend/lib/constructs/api.ts b/src/backend/lib/constructs/api.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/backend/lib/constructs/auth.ts b/src/backend/lib/constructs/auth.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/backend/lib/constructs/web.ts b/src/backend/lib/constructs/web.ts new file mode 100644 index 00000000..e69de29b From 81cbbc6d61f6cfd8ca5bc869f9258091fc6efcf7 Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Sat, 27 Apr 2024 07:27:44 +0000 Subject: [PATCH 2/9] =?UTF-8?q?=E5=90=84=E3=82=B3=E3=83=B3=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=83=A9=E3=82=AF=E3=82=BF=E3=81=AE=E4=B8=AD=E8=BA=AB?= =?UTF-8?q?=E3=82=92=E5=AE=9A=E7=BE=A9=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F?= =?UTF-8?q?(=E3=81=9F=E3=81=A0=E3=81=97api.ts=E3=81=AF=E9=81=A9=E5=BD=93)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/constructs/api.ts | 23 ++++++++++++ src/backend/lib/constructs/auth.ts | 50 ++++++++++++++++++++++++++ src/backend/lib/constructs/web.ts | 57 ++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) diff --git a/src/backend/lib/constructs/api.ts b/src/backend/lib/constructs/api.ts index e69de29b..a7d19e39 100644 --- a/src/backend/lib/constructs/api.ts +++ b/src/backend/lib/constructs/api.ts @@ -0,0 +1,23 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; + +export class ApiStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const backendLambda = new lambda.Function(this, 'BackendLambda', { + runtime: lambda.Runtime.NODEJS_14_X, + code: lambda.Code.fromAsset('path/to/lambda/code'), + handler: 'index.handler', + }); + + const api = new apigateway.RestApi(this, 'ApiGateway', { + restApiName: 'ServiceAPI', + }); + + const lambdaIntegration = new apigateway.LambdaIntegration(backendLambda); + api.root.addMethod('GET', lambdaIntegration); + } +} diff --git a/src/backend/lib/constructs/auth.ts b/src/backend/lib/constructs/auth.ts index e69de29b..9f54fe93 100644 --- a/src/backend/lib/constructs/auth.ts +++ b/src/backend/lib/constructs/auth.ts @@ -0,0 +1,50 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as cognito from 'aws-cdk-lib/aws-cognito'; + +export class AuthStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const userPool = new cognito.UserPool(this, 'UserPool', { + userPoolName: 'app-user-pool', + selfSignUpEnabled: true, + autoVerify: { email: true }, + userVerification: { + emailSubject: 'Verify your email for our app!', + emailBody: 'Thanks for signing up! Your verification code is {####}', + emailStyle: cognito.VerificationEmailStyle.CODE, + }, + signInAliases: { email: true }, + passwordPolicy: { + minLength: 8, + requireLowercase: true, + requireUppercase: true, + requireDigits: true, + requireSymbols: true, + }, + mfa: cognito.Mfa.OPTIONAL, + mfaSecondFactor: { + sms: true, + otp: true, + }, + }); + + new cognito.UserPoolClient(this, 'UserPoolClient', { + userPool, + generateSecret: false, + }); + + const identityPool = new cognito.CfnIdentityPool(this, 'IdentityPool', { + allowUnauthenticatedIdentities: false, + cognitoIdentityProviders: [{ + clientId: userPool.userPoolClientId, + providerName: userPool.userPoolProviderName, + }], + }); + + userPool.addDomain('UserPoolDomain', { + cognitoDomain: { domainPrefix: 'unique-prefix-123' }, + }); + } +} diff --git a/src/backend/lib/constructs/web.ts b/src/backend/lib/constructs/web.ts index e69de29b..03f48b09 100644 --- a/src/backend/lib/constructs/web.ts +++ b/src/backend/lib/constructs/web.ts @@ -0,0 +1,57 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as cloudfrontOrigins from 'aws-cdk-lib/aws-cloudfront-origins'; + +export class WebHostingStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const logBucket = new s3.Bucket(this, 'LogBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + enforceSSL: true, + serverAccessLogsPrefix: 'log/', + }); + + const websiteBucket = new s3.Bucket(this, 'WebsiteBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + enforceSSL: true, + serverAccessLogsBucket: logBucket, + serverAccessLogsPrefix: 'WebHostingBucketLog/', + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + websiteIndexDocument: 'index.html', + cors: [{ + allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.HEAD], + allowedOrigins: ['*'], + allowedHeaders: ['*'], + }], + }); + + const distribution = new cloudfront.Distribution(this, 'WebDistribution', { + defaultBehavior: { + origin: new cloudfrontOrigins.S3Origin(websiteBucket, { + originAccessIdentity: new cloudfront.OriginAccessIdentity(this, 'OAI') + }), + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + }, + defaultRootObject: 'index.html', + }); + + // Bucket policy to allow CloudFront access + const policyStatement = new iam.PolicyStatement({ + actions: ['s3:GetObject'], + effect: iam.Effect.ALLOW, + principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')], + resources: [`${websiteBucket.bucketArn}/*`], + conditions: { + StringEquals: { + "AWS:SourceArn": distribution.distributionArn, + }, + }, + }); + + websiteBucket.addToResourcePolicy(policyStatement); + } +} From 61ee552ba878d63a77230a2a5d5024f41984ae74 Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Sat, 27 Apr 2024 08:24:20 +0000 Subject: [PATCH 3/9] =?UTF-8?q?=E3=82=B3=E3=83=B3=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=83=A9=E3=82=AF=E3=82=BF=E5=86=85=E3=81=AE=E5=A4=89=E6=95=B0?= =?UTF-8?q?=E5=90=8D=E7=AD=89=E3=82=92=E4=BF=AE=E6=AD=A3=E3=81=97=E3=81=BE?= =?UTF-8?q?=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/constructs/auth.ts | 14 +++++++++++--- src/backend/lib/constructs/web.ts | 23 +++++++++++------------ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/backend/lib/constructs/auth.ts b/src/backend/lib/constructs/auth.ts index 9f54fe93..be4a704a 100644 --- a/src/backend/lib/constructs/auth.ts +++ b/src/backend/lib/constructs/auth.ts @@ -30,15 +30,23 @@ export class AuthStack extends cdk.Stack { }, }); - new cognito.UserPoolClient(this, 'UserPoolClient', { + const userPoolClient = new cognito.UserPoolClient(this, "DiaryUserPoolClient", { userPool, - generateSecret: false, + userPoolClientName: "diary-userpool-client", + authFlows: { + adminUserPassword: true, + custom: true, + userSrp: true, + }, + supportedIdentityProviders: [ + cognito.UserPoolClientIdentityProvider.COGNITO, + ], }); const identityPool = new cognito.CfnIdentityPool(this, 'IdentityPool', { allowUnauthenticatedIdentities: false, cognitoIdentityProviders: [{ - clientId: userPool.userPoolClientId, + clientId: userPoolClient.userPoolClientId, providerName: userPool.userPoolProviderName, }], }); diff --git a/src/backend/lib/constructs/web.ts b/src/backend/lib/constructs/web.ts index 03f48b09..a05b1ab4 100644 --- a/src/backend/lib/constructs/web.ts +++ b/src/backend/lib/constructs/web.ts @@ -39,19 +39,18 @@ export class WebHostingStack extends cdk.Stack { defaultRootObject: 'index.html', }); - // Bucket policy to allow CloudFront access - const policyStatement = new iam.PolicyStatement({ - actions: ['s3:GetObject'], - effect: iam.Effect.ALLOW, - principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')], - resources: [`${websiteBucket.bucketArn}/*`], - conditions: { - StringEquals: { - "AWS:SourceArn": distribution.distributionArn, + const websiteBucketPolicyStatement = new cdk.aws_iam.PolicyStatement({ + actions: ["s3:GetObject"], + effect: cdk.aws_iam.Effect.ALLOW, + principals: [new cdk.aws_iam.ServicePrincipal("cloudfront.amazonaws.com")], + resources: [`${websiteBucket.bucketArn}/*`], + conditions: { + StringEquals: { + "AWS:SourceArn": `arn:aws:cloudfront::${this.account}:distribution/${distribution.distributionId}`, + }, }, - }, - }); + }); - websiteBucket.addToResourcePolicy(policyStatement); + websiteBucket.addToResourcePolicy(websiteBucketPolicyStatement); } } From 967fa87d5fde0f2347767b2609df461d8c4659e6 Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Sat, 27 Apr 2024 08:37:51 +0000 Subject: [PATCH 4/9] =?UTF-8?q?backend=20stack=E3=81=AB=E5=90=84=E3=82=B3?= =?UTF-8?q?=E3=83=B3=E3=82=B9=E3=83=88=E3=83=A9=E3=82=AF=E3=82=BF=E3=82=92?= =?UTF-8?q?import=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/backend-stack.ts | 3 +++ src/backend/lib/constructs/auth.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backend/lib/backend-stack.ts b/src/backend/lib/backend-stack.ts index 5af675ca..ddc3e4c4 100644 --- a/src/backend/lib/backend-stack.ts +++ b/src/backend/lib/backend-stack.ts @@ -3,6 +3,9 @@ import { Construct } from "constructs"; import * as s3 from "aws-cdk-lib/aws-s3"; import * as cognito from "aws-cdk-lib/aws-cognito"; import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; +import { ApiStack } from './constructs/api'; +import { AuthStack } from './constructs/auth'; +import { WebHostingStack } from './constructs/web'; interface BackendStackProps extends cdk.StackProps { } diff --git a/src/backend/lib/constructs/auth.ts b/src/backend/lib/constructs/auth.ts index be4a704a..b4fca22c 100644 --- a/src/backend/lib/constructs/auth.ts +++ b/src/backend/lib/constructs/auth.ts @@ -52,7 +52,7 @@ export class AuthStack extends cdk.Stack { }); userPool.addDomain('UserPoolDomain', { - cognitoDomain: { domainPrefix: 'unique-prefix-123' }, + cognitoDomain: { domainPrefix: 'dairy-851725642854' }, }); } } From e91ec4fd053759f2099acdc49e6d6f5fea52c875 Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Sat, 27 Apr 2024 08:46:18 +0000 Subject: [PATCH 5/9] =?UTF-8?q?web.ts=E3=81=AE=E5=86=85=E5=AE=B9=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/constructs/web.ts | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/backend/lib/constructs/web.ts b/src/backend/lib/constructs/web.ts index a05b1ab4..89a74ba9 100644 --- a/src/backend/lib/constructs/web.ts +++ b/src/backend/lib/constructs/web.ts @@ -29,14 +29,27 @@ export class WebHostingStack extends cdk.Stack { }], }); - const distribution = new cloudfront.Distribution(this, 'WebDistribution', { + const cfnOriginAccessControl = new cdk.aws_cloudfront.CfnOriginAccessControl( + this, + "OriginAccessControl", + { + originAccessControlConfig: { + name: "OriginAccessControlForAppBucket", + originAccessControlOriginType: "s3", + signingBehavior: "always", + signingProtocol: "sigv4", + description: "S3 Access Control", + }, + } + ); + + const distribution =new cdk.aws_cloudfront.Distribution(this, 'distro', { defaultBehavior: { - origin: new cloudfrontOrigins.S3Origin(websiteBucket, { - originAccessIdentity: new cloudfront.OriginAccessIdentity(this, 'OAI') - }), - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + origin: new cdk.aws_cloudfront_origins.S3Origin(websiteBucket), + viewerProtocolPolicy: cdk.aws_cloudfront.ViewerProtocolPolicy.HTTPS_ONLY }, - defaultRootObject: 'index.html', + defaultRootObject: "index.html", + geoRestriction: cdk.aws_cloudfront.GeoRestriction.allowlist('US', 'JP'), }); const websiteBucketPolicyStatement = new cdk.aws_iam.PolicyStatement({ @@ -52,5 +65,11 @@ export class WebHostingStack extends cdk.Stack { }); websiteBucket.addToResourcePolicy(websiteBucketPolicyStatement); + + const cfnDistribution = distribution.node.defaultChild as cdk.aws_cloudfront.CfnDistribution + cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.OriginAccessControlId', cfnOriginAccessControl.getAtt('Id')) + cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.DomainName', websiteBucket.bucketRegionalDomainName) + cfnDistribution.addOverride('Properties.DistributionConfig.Origins.0.S3OriginConfig.OriginAccessIdentity', "") + cfnDistribution.addPropertyDeletionOverride('DistributionConfig.Origins.0.CustomOriginConfig') } } From 8d1238445c943bb5e1303bfbe620e04e74b6c6d6 Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Mon, 29 Apr 2024 08:18:33 +0000 Subject: [PATCH 6/9] =?UTF-8?q?main=E3=81=AE=E3=82=B9=E3=82=BF=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=81=AEWeb=E3=83=9B=E3=82=B9=E3=83=86=E3=82=A3?= =?UTF-8?q?=E3=83=B3=E3=82=B0=E9=83=A8=E5=88=86=E3=82=92=E3=82=B3=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=83=88=E3=82=A2=E3=82=A6=E3=83=88=E3=81=97=E3=81=A6?= =?UTF-8?q?,Web=E3=82=B9=E3=82=BF=E3=83=83=E3=82=AF=E3=81=A8=E3=81=97?= =?UTF-8?q?=E3=81=A6=E3=82=A4=E3=83=B3=E3=82=B9=E3=82=BF=E3=83=B3=E3=82=B9?= =?UTF-8?q?=E5=8C=96=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/backend-stack.ts | 132 ++++++++++++++++--------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/src/backend/lib/backend-stack.ts b/src/backend/lib/backend-stack.ts index ddc3e4c4..e456b0dc 100644 --- a/src/backend/lib/backend-stack.ts +++ b/src/backend/lib/backend-stack.ts @@ -13,11 +13,13 @@ export class BackendStack extends cdk.Stack { constructor(scope: Construct, id: string, props: BackendStackProps) { super(scope, id, props); - const logBucket = new s3.Bucket(this, `LogBucket`, { - removalPolicy: cdk.RemovalPolicy.DESTROY, - enforceSSL: true, - serverAccessLogsPrefix: "log/", - }); + // const logBucket = new s3.Bucket(this, `LogBucket`, { + // removalPolicy: cdk.RemovalPolicy.DESTROY, + // enforceSSL: true, + // serverAccessLogsPrefix: "log/", + // }); + // ウェブホスティングスタックのインスタンス化 + new WebHostingStack(this, 'WebHostingStack'); new dynamodb.Table(this, `DiaryContentsTable`, { partitionKey: { @@ -113,69 +115,69 @@ export class BackendStack extends cdk.Stack { }); // Hosting S3 & CloudFront - const websiteBucket = new s3.Bucket(this, 'diary-hosting-bucket', { - removalPolicy: cdk.RemovalPolicy.DESTROY, - enforceSSL: true, - serverAccessLogsBucket: logBucket, - serverAccessLogsPrefix: "DiaryHostingBucketLog/", - blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, - websiteIndexDocument: 'index.html', - cors: [ - { - allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.HEAD], - allowedOrigins: ["*"], - allowedHeaders: ["*"], - }, - ], - }); - - const cfnOriginAccessControl = new cdk.aws_cloudfront.CfnOriginAccessControl( - this, - "OriginAccessControl", - { - originAccessControlConfig: { - name: "OriginAccessControlForAppBucket", - originAccessControlOriginType: "s3", - signingBehavior: "always", - signingProtocol: "sigv4", - description: "S3 Access Control", - }, - } - ); - - - const distribution =new cdk.aws_cloudfront.Distribution(this, 'distro', { - defaultBehavior: { - origin: new cdk.aws_cloudfront_origins.S3Origin(websiteBucket), - viewerProtocolPolicy: cdk.aws_cloudfront.ViewerProtocolPolicy.HTTPS_ONLY - }, - defaultRootObject: "index.html", - // enableLogging: true, // Optional, this is implied if logBucket is specified - // logBucket: logBucket, - // logFilePrefix: 'distribution/', - // logIncludesCookies: true, - geoRestriction: cdk.aws_cloudfront.GeoRestriction.allowlist('US', 'JP'), - }); + // const websiteBucket = new s3.Bucket(this, 'diary-hosting-bucket', { + // removalPolicy: cdk.RemovalPolicy.DESTROY, + // enforceSSL: true, + // serverAccessLogsBucket: logBucket, + // serverAccessLogsPrefix: "DiaryHostingBucketLog/", + // blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + // websiteIndexDocument: 'index.html', + // cors: [ + // { + // allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.HEAD], + // allowedOrigins: ["*"], + // allowedHeaders: ["*"], + // }, + // ], + // }); + + // const cfnOriginAccessControl = new cdk.aws_cloudfront.CfnOriginAccessControl( + // this, + // "OriginAccessControl", + // { + // originAccessControlConfig: { + // name: "OriginAccessControlForAppBucket", + // originAccessControlOriginType: "s3", + // signingBehavior: "always", + // signingProtocol: "sigv4", + // description: "S3 Access Control", + // }, + // } + // ); + + + // const distribution =new cdk.aws_cloudfront.Distribution(this, 'distro', { + // defaultBehavior: { + // origin: new cdk.aws_cloudfront_origins.S3Origin(websiteBucket), + // viewerProtocolPolicy: cdk.aws_cloudfront.ViewerProtocolPolicy.HTTPS_ONLY + // }, + // defaultRootObject: "index.html", + // // enableLogging: true, // Optional, this is implied if logBucket is specified + // // logBucket: logBucket, + // // logFilePrefix: 'distribution/', + // // logIncludesCookies: true, + // geoRestriction: cdk.aws_cloudfront.GeoRestriction.allowlist('US', 'JP'), + // }); - const websiteBucketPolicyStatement = new cdk.aws_iam.PolicyStatement({ - actions: ["s3:GetObject"], - effect: cdk.aws_iam.Effect.ALLOW, - principals: [new cdk.aws_iam.ServicePrincipal("cloudfront.amazonaws.com")], - resources: [`${websiteBucket.bucketArn}/*`], - conditions: { - StringEquals: { - "AWS:SourceArn": `arn:aws:cloudfront::${this.account}:distribution/${distribution.distributionId}`, - }, - }, - }); + // const websiteBucketPolicyStatement = new cdk.aws_iam.PolicyStatement({ + // actions: ["s3:GetObject"], + // effect: cdk.aws_iam.Effect.ALLOW, + // principals: [new cdk.aws_iam.ServicePrincipal("cloudfront.amazonaws.com")], + // resources: [`${websiteBucket.bucketArn}/*`], + // conditions: { + // StringEquals: { + // "AWS:SourceArn": `arn:aws:cloudfront::${this.account}:distribution/${distribution.distributionId}`, + // }, + // }, + // }); - websiteBucket.addToResourcePolicy(websiteBucketPolicyStatement); + // websiteBucket.addToResourcePolicy(websiteBucketPolicyStatement); - const cfnDistribution = distribution.node.defaultChild as cdk.aws_cloudfront.CfnDistribution - cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.OriginAccessControlId', cfnOriginAccessControl.getAtt('Id')) - cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.DomainName', websiteBucket.bucketRegionalDomainName) - cfnDistribution.addOverride('Properties.DistributionConfig.Origins.0.S3OriginConfig.OriginAccessIdentity', "") - cfnDistribution.addPropertyDeletionOverride('DistributionConfig.Origins.0.CustomOriginConfig') + // const cfnDistribution = distribution.node.defaultChild as cdk.aws_cloudfront.CfnDistribution + // cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.OriginAccessControlId', cfnOriginAccessControl.getAtt('Id')) + // cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.DomainName', websiteBucket.bucketRegionalDomainName) + // cfnDistribution.addOverride('Properties.DistributionConfig.Origins.0.S3OriginConfig.OriginAccessIdentity', "") + // cfnDistribution.addPropertyDeletionOverride('DistributionConfig.Origins.0.CustomOriginConfig') // new cdk.aws_s3_deployment.BucketDeployment(this, 'WebsiteDeploy', { // sources: [ From 6e2db98cf227c356c3b3ff1954677afdbe2837ce Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Mon, 29 Apr 2024 13:51:01 +0000 Subject: [PATCH 7/9] =?UTF-8?q?web.ts=E3=81=ABnagsuppression=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/backend-stack.ts | 23 ++++------------------- src/backend/lib/constructs/web.ts | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/backend/lib/backend-stack.ts b/src/backend/lib/backend-stack.ts index e456b0dc..8674a194 100644 --- a/src/backend/lib/backend-stack.ts +++ b/src/backend/lib/backend-stack.ts @@ -12,14 +12,14 @@ interface BackendStackProps extends cdk.StackProps { } export class BackendStack extends cdk.Stack { constructor(scope: Construct, id: string, props: BackendStackProps) { super(scope, id, props); - + // ウェブホスティングスタックのインスタンス化 + new WebHostingStack(this, 'WebHostingStack'); + // const logBucket = new s3.Bucket(this, `LogBucket`, { // removalPolicy: cdk.RemovalPolicy.DESTROY, // enforceSSL: true, // serverAccessLogsPrefix: "log/", // }); - // ウェブホスティングスタックのインスタンス化 - new WebHostingStack(this, 'WebHostingStack'); new dynamodb.Table(this, `DiaryContentsTable`, { partitionKey: { @@ -179,21 +179,6 @@ export class BackendStack extends cdk.Stack { // cfnDistribution.addOverride('Properties.DistributionConfig.Origins.0.S3OriginConfig.OriginAccessIdentity', "") // cfnDistribution.addPropertyDeletionOverride('DistributionConfig.Origins.0.CustomOriginConfig') - // new cdk.aws_s3_deployment.BucketDeployment(this, 'WebsiteDeploy', { - // sources: [ - // cdk.aws_s3_deployment.Source.data( - // '/index.html', - // '

Hello World

' - // ), - // // cdk.aws_s3_deployment.Source.data( - // // '/error.html', - // // '

Error!!!!!!!!!!!!!

' - // // ), - // ], - // destinationBucket: websiteBucket, - // distribution: distribution, - // distributionPaths: ['/*'], - // accessControl: s3.BucketAccessControl.PUBLIC_READ_WRITE - // }); + } } \ No newline at end of file diff --git a/src/backend/lib/constructs/web.ts b/src/backend/lib/constructs/web.ts index 89a74ba9..dcb68799 100644 --- a/src/backend/lib/constructs/web.ts +++ b/src/backend/lib/constructs/web.ts @@ -4,6 +4,7 @@ import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as cloudfrontOrigins from 'aws-cdk-lib/aws-cloudfront-origins'; +import { AwsSolutionsChecks, NagSuppressions } from 'cdk-nag'; export class WebHostingStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { @@ -71,5 +72,28 @@ export class WebHostingStack extends cdk.Stack { cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.DomainName', websiteBucket.bucketRegionalDomainName) cfnDistribution.addOverride('Properties.DistributionConfig.Origins.0.S3OriginConfig.OriginAccessIdentity', "") cfnDistribution.addPropertyDeletionOverride('DistributionConfig.Origins.0.CustomOriginConfig') + + NagSuppressions.addStackSuppressions(this, [ + { + id: 'AwsSolutions-CFR2', + reason: '暫定的にオフにしているが、本番環境では必要に応じてWAFの導入も行う。', + }, + { + id: 'AwsSolutions-CFR4', + reason: 'カスタムドメインが必要になるので暫定的にオフにします', + }, + { + id: 'AwsSolutions-CFR5', + reason: 'カスタムドメインが必要になるので暫定的にオフにします', + }, + { + id: 'AwsSolutions-CFR3', + reason: 'CloudFrontのロギングをオフにします。S3のパブリックアクセスをオフにしなければオンに出来無さそうでした', + }, + { + id: 'AwsSolutions-S5', + reason: 'OAIの強制をオフにします。OACを使うので', + }, + ]) } } From ca5db9e75180490e582c0b1291ffc5a2104b2c93 Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Wed, 1 May 2024 00:12:04 +0000 Subject: [PATCH 8/9] =?UTF-8?q?backend-stack.ts=E3=81=AE=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=E3=81=97auth.tsni=E7=B5=84=E3=81=BF?= =?UTF-8?q?=E8=BE=BC=E3=81=BF=E3=81=BE=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/backend-stack.ts | 234 ++++++++++------------------- src/backend/lib/constructs/api.ts | 33 ++-- src/backend/lib/constructs/auth.ts | 17 +++ 3 files changed, 123 insertions(+), 161 deletions(-) diff --git a/src/backend/lib/backend-stack.ts b/src/backend/lib/backend-stack.ts index 8674a194..2778aab3 100644 --- a/src/backend/lib/backend-stack.ts +++ b/src/backend/lib/backend-stack.ts @@ -14,170 +14,102 @@ export class BackendStack extends cdk.Stack { super(scope, id, props); // ウェブホスティングスタックのインスタンス化 new WebHostingStack(this, 'WebHostingStack'); + + // 認証機能スタックのインスタンス化 + new AuthStack(this, 'AuthStack'); - // const logBucket = new s3.Bucket(this, `LogBucket`, { + // new dynamodb.Table(this, `DiaryContentsTable`, { + // partitionKey: { + // name: "user_id", + // type: dynamodb.AttributeType.STRING, + // }, + // sortKey: { + // name: "date", + // type: dynamodb.AttributeType.STRING, + // }, // removalPolicy: cdk.RemovalPolicy.DESTROY, - // enforceSSL: true, - // serverAccessLogsPrefix: "log/", + // pointInTimeRecovery: true, // }); - new dynamodb.Table(this, `DiaryContentsTable`, { - partitionKey: { - name: "user_id", - type: dynamodb.AttributeType.STRING, - }, - sortKey: { - name: "date", - type: dynamodb.AttributeType.STRING, - }, - removalPolicy: cdk.RemovalPolicy.DESTROY, - pointInTimeRecovery: true, - }); - - const userPool = new cognito.UserPool(this, `DiaryUserPool`, { - userPoolName: `diary-user-pool`, - signInAliases: { - email: true, - }, - selfSignUpEnabled: true, - autoVerify: { - email: true, - }, - userVerification: { - emailSubject: 'メールアドレスを認証してください。', - emailBody: 'ご登録ありがとうございます。 あなたの認証コードは {####} です。', - emailStyle: cognito.VerificationEmailStyle.CODE, - }, - standardAttributes: { - familyName: { - mutable: false, - required: true, - }, - givenName: { - mutable: false, - required: true, - }, - address: { - mutable: true, - required: false, - }, - gender: { - mutable: true, - required: true, - }, - email: { - mutable: false, - required: true, - }, - }, - passwordPolicy: { - minLength: 8, - requireLowercase: true, - requireUppercase: true, - requireDigits: true, - requireSymbols: true, - }, - accountRecovery: cognito.AccountRecovery.EMAIL_ONLY, - mfa: cognito.Mfa.REQUIRED, - mfaSecondFactor: { - sms: true, - otp: true, - }, - removalPolicy: cdk.RemovalPolicy.DESTROY, - }); - - const userPoolClient = new cognito.UserPoolClient(this, "DiaryUserPoolClient", { - userPool, - userPoolClientName: "diary-userpool-client", - authFlows: { - adminUserPassword: true, - custom: true, - userSrp: true, - }, - supportedIdentityProviders: [ - cognito.UserPoolClientIdentityProvider.COGNITO, - ], - }); - - // Cognito Identity Pool - const identityPool = new cognito.CfnIdentityPool(this, "IdentityPool", { - allowUnauthenticatedIdentities: false, // Don't allow unathenticated users - cognitoIdentityProviders: [ - { - clientId: userPoolClient.userPoolClientId, - providerName: userPool.userPoolProviderName, - }, - ], - }); - - userPool.addDomain('UserPoolDomain', { - cognitoDomain: { domainPrefix: 'dairy-851725642854' }, - }); - - // Hosting S3 & CloudFront - // const websiteBucket = new s3.Bucket(this, 'diary-hosting-bucket', { - // removalPolicy: cdk.RemovalPolicy.DESTROY, - // enforceSSL: true, - // serverAccessLogsBucket: logBucket, - // serverAccessLogsPrefix: "DiaryHostingBucketLog/", - // blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, - // websiteIndexDocument: 'index.html', - // cors: [ - // { - // allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.HEAD], - // allowedOrigins: ["*"], - // allowedHeaders: ["*"], + // const userPool = new cognito.UserPool(this, `DiaryUserPool`, { + // userPoolName: `diary-user-pool`, + // signInAliases: { + // email: true, + // }, + // selfSignUpEnabled: true, + // autoVerify: { + // email: true, + // }, + // userVerification: { + // emailSubject: 'メールアドレスを認証してください。', + // emailBody: 'ご登録ありがとうございます。 あなたの認証コードは {####} です。', + // emailStyle: cognito.VerificationEmailStyle.CODE, + // }, + // standardAttributes: { + // familyName: { + // mutable: false, + // required: true, // }, - // ], - // }); - - // const cfnOriginAccessControl = new cdk.aws_cloudfront.CfnOriginAccessControl( - // this, - // "OriginAccessControl", - // { - // originAccessControlConfig: { - // name: "OriginAccessControlForAppBucket", - // originAccessControlOriginType: "s3", - // signingBehavior: "always", - // signingProtocol: "sigv4", - // description: "S3 Access Control", + // givenName: { + // mutable: false, + // required: true, // }, - // } - // ); - - - // const distribution =new cdk.aws_cloudfront.Distribution(this, 'distro', { - // defaultBehavior: { - // origin: new cdk.aws_cloudfront_origins.S3Origin(websiteBucket), - // viewerProtocolPolicy: cdk.aws_cloudfront.ViewerProtocolPolicy.HTTPS_ONLY + // address: { + // mutable: true, + // required: false, + // }, + // gender: { + // mutable: true, + // required: true, + // }, + // email: { + // mutable: false, + // required: true, + // }, + // }, + // passwordPolicy: { + // minLength: 8, + // requireLowercase: true, + // requireUppercase: true, + // requireDigits: true, + // requireSymbols: true, + // }, + // accountRecovery: cognito.AccountRecovery.EMAIL_ONLY, + // mfa: cognito.Mfa.REQUIRED, + // mfaSecondFactor: { + // sms: true, + // otp: true, // }, - // defaultRootObject: "index.html", - // // enableLogging: true, // Optional, this is implied if logBucket is specified - // // logBucket: logBucket, - // // logFilePrefix: 'distribution/', - // // logIncludesCookies: true, - // geoRestriction: cdk.aws_cloudfront.GeoRestriction.allowlist('US', 'JP'), + // removalPolicy: cdk.RemovalPolicy.DESTROY, // }); - // const websiteBucketPolicyStatement = new cdk.aws_iam.PolicyStatement({ - // actions: ["s3:GetObject"], - // effect: cdk.aws_iam.Effect.ALLOW, - // principals: [new cdk.aws_iam.ServicePrincipal("cloudfront.amazonaws.com")], - // resources: [`${websiteBucket.bucketArn}/*`], - // conditions: { - // StringEquals: { - // "AWS:SourceArn": `arn:aws:cloudfront::${this.account}:distribution/${distribution.distributionId}`, - // }, + // const userPoolClient = new cognito.UserPoolClient(this, "DiaryUserPoolClient", { + // userPool, + // userPoolClientName: "diary-userpool-client", + // authFlows: { + // adminUserPassword: true, + // custom: true, + // userSrp: true, // }, + // supportedIdentityProviders: [ + // cognito.UserPoolClientIdentityProvider.COGNITO, + // ], // }); - // websiteBucket.addToResourcePolicy(websiteBucketPolicyStatement); + // // Cognito Identity Pool + // const identityPool = new cognito.CfnIdentityPool(this, "IdentityPool", { + // allowUnauthenticatedIdentities: false, // Don't allow unathenticated users + // cognitoIdentityProviders: [ + // { + // clientId: userPoolClient.userPoolClientId, + // providerName: userPool.userPoolProviderName, + // }, + // ], + // }); - // const cfnDistribution = distribution.node.defaultChild as cdk.aws_cloudfront.CfnDistribution - // cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.OriginAccessControlId', cfnOriginAccessControl.getAtt('Id')) - // cfnDistribution.addPropertyOverride('DistributionConfig.Origins.0.DomainName', websiteBucket.bucketRegionalDomainName) - // cfnDistribution.addOverride('Properties.DistributionConfig.Origins.0.S3OriginConfig.OriginAccessIdentity', "") - // cfnDistribution.addPropertyDeletionOverride('DistributionConfig.Origins.0.CustomOriginConfig') + // userPool.addDomain('UserPoolDomain', { + // cognitoDomain: { domainPrefix: 'dairy-851725642854' }, + // }); } diff --git a/src/backend/lib/constructs/api.ts b/src/backend/lib/constructs/api.ts index a7d19e39..1f6c0b6d 100644 --- a/src/backend/lib/constructs/api.ts +++ b/src/backend/lib/constructs/api.ts @@ -2,22 +2,35 @@ import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; export class ApiStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); - const backendLambda = new lambda.Function(this, 'BackendLambda', { - runtime: lambda.Runtime.NODEJS_14_X, - code: lambda.Code.fromAsset('path/to/lambda/code'), - handler: 'index.handler', - }); + // const backendLambda = new lambda.Function(this, 'BackendLambda', { + // runtime: lambda.Runtime.NODEJS_14_X, + // code: lambda.Code.fromAsset('path/to/lambda/code'), + // handler: 'index.handler', + // }); - const api = new apigateway.RestApi(this, 'ApiGateway', { - restApiName: 'ServiceAPI', - }); + // const api = new apigateway.RestApi(this, 'ApiGateway', { + // restApiName: 'ServiceAPI', + // }); - const lambdaIntegration = new apigateway.LambdaIntegration(backendLambda); - api.root.addMethod('GET', lambdaIntegration); + // const lambdaIntegration = new apigateway.LambdaIntegration(backendLambda); + // api.root.addMethod('GET', lambdaIntegration); + new dynamodb.Table(this, `DiaryContentsTable`, { + partitionKey: { + name: "user_id", + type: dynamodb.AttributeType.STRING, + }, + sortKey: { + name: "date", + type: dynamodb.AttributeType.STRING, + }, + removalPolicy: cdk.RemovalPolicy.DESTROY, + pointInTimeRecovery: true, + }); } } diff --git a/src/backend/lib/constructs/auth.ts b/src/backend/lib/constructs/auth.ts index b4fca22c..1a11eeb9 100644 --- a/src/backend/lib/constructs/auth.ts +++ b/src/backend/lib/constructs/auth.ts @@ -1,6 +1,7 @@ import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as cognito from 'aws-cdk-lib/aws-cognito'; +import { AwsSolutionsChecks, NagSuppressions } from 'cdk-nag'; export class AuthStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { @@ -54,5 +55,21 @@ export class AuthStack extends cdk.Stack { userPool.addDomain('UserPoolDomain', { cognitoDomain: { domainPrefix: 'dairy-851725642854' }, }); + + NagSuppressions.addStackSuppressions(this, [ + { + id: 'AwsSolutions-COG2', + reason: '一般ユーザにMFAはいらないと判断した.', + }, + { + id: 'AwsSolutions-COG3', + reason: 'このプロジェクトではAdvancedSecurityModeをENFORCEDに設定する必要はないと判断した。', + }, + { + id: 'AwsSolutions-IAM5', + reason: '暫定的にオフにしているが、本番環境では適切なIAMポリシーを設定すること。', + }, + + ]) } } From fd9d62bf7516beec55c35c89ce4f768f346034c2 Mon Sep 17 00:00:00 2001 From: Namiki Asuka Date: Wed, 1 May 2024 01:31:08 +0000 Subject: [PATCH 9/9] =?UTF-8?q?backend-stack.ts=E3=81=AE=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=E3=81=97api.ts=E3=82=92i=E7=B5=84?= =?UTF-8?q?=E3=81=BF=E8=BE=BC=E3=81=BF=E3=81=BE=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/lib/backend-stack.ts | 82 ++------------------------------ 1 file changed, 3 insertions(+), 79 deletions(-) diff --git a/src/backend/lib/backend-stack.ts b/src/backend/lib/backend-stack.ts index 2778aab3..6fb54f6c 100644 --- a/src/backend/lib/backend-stack.ts +++ b/src/backend/lib/backend-stack.ts @@ -17,6 +17,9 @@ export class BackendStack extends cdk.Stack { // 認証機能スタックのインスタンス化 new AuthStack(this, 'AuthStack'); + + // 認証機能スタックのインスタンス化 + new ApiStack(this, 'ApiStack'); // new dynamodb.Table(this, `DiaryContentsTable`, { // partitionKey: { @@ -31,85 +34,6 @@ export class BackendStack extends cdk.Stack { // pointInTimeRecovery: true, // }); - // const userPool = new cognito.UserPool(this, `DiaryUserPool`, { - // userPoolName: `diary-user-pool`, - // signInAliases: { - // email: true, - // }, - // selfSignUpEnabled: true, - // autoVerify: { - // email: true, - // }, - // userVerification: { - // emailSubject: 'メールアドレスを認証してください。', - // emailBody: 'ご登録ありがとうございます。 あなたの認証コードは {####} です。', - // emailStyle: cognito.VerificationEmailStyle.CODE, - // }, - // standardAttributes: { - // familyName: { - // mutable: false, - // required: true, - // }, - // givenName: { - // mutable: false, - // required: true, - // }, - // address: { - // mutable: true, - // required: false, - // }, - // gender: { - // mutable: true, - // required: true, - // }, - // email: { - // mutable: false, - // required: true, - // }, - // }, - // passwordPolicy: { - // minLength: 8, - // requireLowercase: true, - // requireUppercase: true, - // requireDigits: true, - // requireSymbols: true, - // }, - // accountRecovery: cognito.AccountRecovery.EMAIL_ONLY, - // mfa: cognito.Mfa.REQUIRED, - // mfaSecondFactor: { - // sms: true, - // otp: true, - // }, - // removalPolicy: cdk.RemovalPolicy.DESTROY, - // }); - - // const userPoolClient = new cognito.UserPoolClient(this, "DiaryUserPoolClient", { - // userPool, - // userPoolClientName: "diary-userpool-client", - // authFlows: { - // adminUserPassword: true, - // custom: true, - // userSrp: true, - // }, - // supportedIdentityProviders: [ - // cognito.UserPoolClientIdentityProvider.COGNITO, - // ], - // }); - - // // Cognito Identity Pool - // const identityPool = new cognito.CfnIdentityPool(this, "IdentityPool", { - // allowUnauthenticatedIdentities: false, // Don't allow unathenticated users - // cognitoIdentityProviders: [ - // { - // clientId: userPoolClient.userPoolClientId, - // providerName: userPool.userPoolProviderName, - // }, - // ], - // }); - - // userPool.addDomain('UserPoolDomain', { - // cognitoDomain: { domainPrefix: 'dairy-851725642854' }, - // }); }