internal AuthlambdaStack(Construct scope, string id, AuthlambdaStackProps props = null) : base(scope, id, props) { functionsStack = props.functionsStack; Bucket websiteBucket = new Bucket(this, "websiteBucket", new BucketProps() { BlockPublicAccess = BlockPublicAccess.BLOCK_ALL, PublicReadAccess = false, //WebsiteIndexDocument = "index.html", RemovalPolicy = RemovalPolicy.DESTROY, Cors = new ICorsRule[] { new CorsRule() { AllowedHeaders = new string[] { "Authorization", "Content-Type", "Origin" }, AllowedMethods = new HttpMethods[] { HttpMethods.GET, HttpMethods.HEAD }, AllowedOrigins = new string[] { "*" } } } }); Bucket privateBucket = new Bucket(this, "privateBucket", new BucketProps() { BlockPublicAccess = BlockPublicAccess.BLOCK_ALL, PublicReadAccess = false, RemovalPolicy = RemovalPolicy.DESTROY, Cors = new ICorsRule[] { new CorsRule() { AllowedHeaders = new string[] { "Authorization", "Content-Type", "Origin" }, AllowedMethods = new HttpMethods[] { HttpMethods.GET, HttpMethods.HEAD }, AllowedOrigins = new string[] { "*" } } } }); // The S3 bucket deployment for the website var websiteDeployment = new BucketDeployment(this, "TestStaticWebsiteDeployment", new BucketDeploymentProps() { Sources = new [] { Source.Asset("./src/website") }, DestinationBucket = websiteBucket, RetainOnDelete = false }); var privateDeployment = new BucketDeployment(this, "TestPrivateDeployment", new BucketDeploymentProps() { Sources = new [] { Source.Asset("./src/private") }, DestinationBucket = privateBucket, RetainOnDelete = false }); var cloudfrontOAI = OriginAccessIdentity.FromOriginAccessIdentityName(this, "CloudfrontOAIName", cloudfrontOAIName); websiteBucket.GrantRead(cloudfrontOAI.GrantPrincipal); privateBucket.GrantRead(cloudfrontOAI.GrantPrincipal); var cachePolicy = new CachePolicy(this, "TestCachePolicy", new CachePolicyProps() { CachePolicyName = "TestCachePolicy", Comment = "Cache policy for Testing", DefaultTtl = Duration.Seconds(0), CookieBehavior = CacheCookieBehavior.All(), HeaderBehavior = CacheHeaderBehavior.AllowList( "Authorization", "Content-Type", "Origin" ), QueryStringBehavior = CacheQueryStringBehavior.All(), EnableAcceptEncodingBrotli = false, EnableAcceptEncodingGzip = false }); var websiteOrigin = new S3Origin(websiteBucket, new S3OriginProps() { OriginAccessIdentity = cloudfrontOAI }); var privateOrigin = new S3Origin(privateBucket, new S3OriginProps() { OriginAccessIdentity = cloudfrontOAI }); var dummyOrigin = new HttpOrigin("example.com", new HttpOriginProps() { ProtocolPolicy = OriginProtocolPolicy.HTTPS_ONLY }); // default behavior is for the privateOrigin var defaultPrivateBehavior = new BehaviorOptions { AllowedMethods = AllowedMethods.ALLOW_ALL, CachePolicy = cachePolicy, OriginRequestPolicy = OriginRequestPolicy.CORS_S3_ORIGIN, ViewerProtocolPolicy = ViewerProtocolPolicy.REDIRECT_TO_HTTPS, Origin = privateOrigin, EdgeLambdas = new IEdgeLambda[] { new EdgeLambda() { EventType = LambdaEdgeEventType.VIEWER_REQUEST, FunctionVersion = functionsStack.checkAuthHandler.CurrentVersion, }, new EdgeLambda() { EventType = LambdaEdgeEventType.ORIGIN_RESPONSE, FunctionVersion = functionsStack.httpHeadersHandler.CurrentVersion } } }; // this behavior is for dummy origin var parseAuthBehavior = new BehaviorOptions { AllowedMethods = AllowedMethods.ALLOW_GET_HEAD_OPTIONS, CachePolicy = cachePolicy, OriginRequestPolicy = OriginRequestPolicy.CORS_S3_ORIGIN, ViewerProtocolPolicy = ViewerProtocolPolicy.REDIRECT_TO_HTTPS, Origin = dummyOrigin, EdgeLambdas = new IEdgeLambda[] { new EdgeLambda() { EventType = LambdaEdgeEventType.VIEWER_REQUEST, FunctionVersion = functionsStack.parseAuthHandler.CurrentVersion, } } }; var refreshAuthBehavior = new BehaviorOptions { AllowedMethods = AllowedMethods.ALLOW_GET_HEAD_OPTIONS, CachePolicy = cachePolicy, OriginRequestPolicy = OriginRequestPolicy.CORS_S3_ORIGIN, ViewerProtocolPolicy = ViewerProtocolPolicy.REDIRECT_TO_HTTPS, Origin = dummyOrigin, EdgeLambdas = new IEdgeLambda[] { new EdgeLambda() { EventType = LambdaEdgeEventType.VIEWER_REQUEST, FunctionVersion = functionsStack.refreshAuthHandler.CurrentVersion, } } }; var signOutBehavior = new BehaviorOptions { AllowedMethods = AllowedMethods.ALLOW_GET_HEAD_OPTIONS, CachePolicy = cachePolicy, OriginRequestPolicy = OriginRequestPolicy.CORS_S3_ORIGIN, ViewerProtocolPolicy = ViewerProtocolPolicy.REDIRECT_TO_HTTPS, Origin = dummyOrigin, EdgeLambdas = new IEdgeLambda[] { new EdgeLambda() { EventType = LambdaEdgeEventType.VIEWER_REQUEST, FunctionVersion = functionsStack.signOutHandler.CurrentVersion, } } }; Distribution distribution = new Distribution(this, "TestCloudfrontDistribution", new DistributionProps() { Comment = "Test Website Distribution", DefaultRootObject = "index.html", PriceClass = PriceClass.PRICE_CLASS_ALL, GeoRestriction = GeoRestriction.Whitelist(new [] { "IN" }), DefaultBehavior = defaultPrivateBehavior, }); distribution.AddBehavior("/parseauth", dummyOrigin, parseAuthBehavior); distribution.AddBehavior("/refreshauth", dummyOrigin, refreshAuthBehavior); distribution.AddBehavior("/signout", dummyOrigin, signOutBehavior); var domainNameOutput = new CfnOutput(this, "TestWebsiteDistributionDomainName", new CfnOutputProps() { Value = distribution.DistributionDomainName }); }
public SpaStack(Construct scope, string id, SpaStackProps props) : base(scope, id, props) { //s3 bucket var bucket = new Bucket(this, $"{props.ServiceName}-bucket", new BucketProps { WebsiteIndexDocument = "index.html", Versioned = true, BucketName = props.ServiceName, RemovalPolicy = RemovalPolicy.DESTROY }); //cloudfront distribution var cloudFrontOai = new OriginAccessIdentity(this, $"{props.ServiceName}-oai", new OriginAccessIdentityProps { Comment = $"OAI for {props.ServiceName}." }); var cloudfrontDist = new CloudFrontWebDistribution(this, $"{props.ServiceName}-cfd", new CloudFrontWebDistributionProps { ViewerCertificate = ViewerCertificate.FromAcmCertificate( props.CloudFrontCert, new ViewerCertificateOptions { Aliases = new [] { $"{props.SubDomain}.{props.HostedZoneName}" }, SslMethod = SSLMethod.SNI }), OriginConfigs = new ISourceConfiguration[] { new SourceConfiguration { S3OriginSource = new S3OriginConfig { S3BucketSource = bucket, OriginAccessIdentity = cloudFrontOai }, Behaviors = new IBehavior[] { new Behavior { IsDefaultBehavior = true, } } } } }); var cnameRecord = new CnameRecord(this, $"{props.ServiceName}CloudFrontCname", new CnameRecordProps { Zone = HostedZone.FromHostedZoneAttributes(this, "HostedZone", new HostedZoneAttributes { ZoneName = props.HostedZoneName, HostedZoneId = props.HostedZoneId }), RecordName = props.SubDomain, DomainName = cloudfrontDist.DistributionDomainName }); var cloudfrontS3Access = new PolicyStatement(); cloudfrontS3Access.AddActions("s3:GetBucket*", "s3:GetObject*", "s3:List*"); cloudfrontS3Access.AddResources(bucket.BucketArn); cloudfrontS3Access.AddResources($"{bucket.BucketArn}/*"); cloudfrontS3Access.AddCanonicalUserPrincipal(cloudFrontOai.CloudFrontOriginAccessIdentityS3CanonicalUserId); bucket.AddToResourcePolicy(cloudfrontS3Access); //codebuild project var codeBuildProject = new Project(this, $"{props.ServiceName}-codeBuild-project", new ProjectProps { Vpc = props.Vpc, ProjectName = props.ServiceName, Environment = new BuildEnvironment { BuildImage = LinuxBuildImage.STANDARD_4_0, }, Source = Source.GitHub(props.GitHubSourceProps), BuildSpec = BuildSpec.FromSourceFilename(props.BuildSpecFile), EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable> { { "SPA_DIRECTORY", new BuildEnvironmentVariable { Value = props.SpaDirectory } }, { "S3_BUCKET", new BuildEnvironmentVariable { Value = bucket.BucketName } }, { "CLOUDFRONT_ID", new BuildEnvironmentVariable { Value = cloudfrontDist.DistributionId } }, { "API_URL", new BuildEnvironmentVariable { Value = props.ApiUrl } } } }); // iam policy to push your build to S3 codeBuildProject.AddToRolePolicy( new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Resources = new[] { bucket.BucketArn, $"{bucket.BucketArn}/*" }, Actions = new[] { "s3:GetBucket*", "s3:List*", "s3:GetObject*", "s3:DeleteObject", "s3:PutObject" } })); codeBuildProject.AddToRolePolicy( new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Resources = new [] { "*" }, Actions = new [] { "cloudfront:CreateInvalidation", "cloudfront:GetDistribution*", "cloudfront:GetInvalidation", "cloudfront:ListInvalidations", "cloudfront:ListDistributions" } })); //codepipeline? }