github.com/mweagle/Sparta@v1.15.0/decorator/distribution.go (about) 1 package decorator 2 3 import ( 4 "fmt" 5 6 "github.com/aws/aws-sdk-go/aws/session" 7 sparta "github.com/mweagle/Sparta" 8 gocf "github.com/mweagle/go-cloudformation" 9 "github.com/pkg/errors" 10 "github.com/sirupsen/logrus" 11 ) 12 13 // CloudFrontSiteDistributionDecorator returns a CloudFrontSiteDecorator with 14 // the default VIP certificate. 15 // NOTE: The default VIP certificate is expensive. Consider using SNI to 16 // reduce costs. See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-viewercertificate.html#cfn-cloudfront-distribution-viewercertificate-sslsupportmethod 17 // for more information. 18 func CloudFrontSiteDistributionDecorator(s3Site *sparta.S3Site, 19 subdomain string, 20 domainName string, 21 acmCertificateARN gocf.Stringable) sparta.ServiceDecoratorHookHandler { 22 23 var cert *gocf.CloudFrontDistributionViewerCertificate 24 if acmCertificateARN != nil { 25 cert = &gocf.CloudFrontDistributionViewerCertificate{ 26 AcmCertificateArn: acmCertificateARN.String(), 27 SslSupportMethod: gocf.String("vip"), 28 } 29 } 30 return CloudFrontSiteDistributionDecoratorWithCert(s3Site, 31 subdomain, 32 domainName, 33 cert) 34 } 35 36 // CloudFrontSiteDistributionDecoratorWithCert returns a ServiceDecoratorHookHandler 37 // function that provisions a CloudFront distribution whose origin 38 // is the supplied S3Site bucket. The supplied viewer certificate 39 // allows customization of the CloudFront Distribution SSL options. 40 // See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-viewercertificate.html 41 // for more information. 42 func CloudFrontSiteDistributionDecoratorWithCert(s3Site *sparta.S3Site, 43 subdomain string, 44 domainName string, 45 cert *gocf.CloudFrontDistributionViewerCertificate) sparta.ServiceDecoratorHookHandler { 46 47 // Setup the CF distro 48 distroDecorator := func(context map[string]interface{}, 49 serviceName string, 50 template *gocf.Template, 51 S3Bucket string, 52 S3Key string, 53 buildID string, 54 awsSession *session.Session, 55 noop bool, 56 logger *logrus.Logger) error { 57 58 // Computed name 59 bucketName := domainName 60 if subdomain != "" { 61 bucketName = fmt.Sprintf("%s.%s", subdomain, domainName) 62 } 63 64 // If there isn't a domain name, then it's an issue... 65 if s3Site.BucketName == nil { 66 return errors.Errorf("CloudFrontDistribution requires an s3Site.BucketName value in the form of a DNS entry") 67 } 68 if s3Site.BucketName.Literal != "" && s3Site.BucketName.Literal != bucketName { 69 return errors.Errorf("Mismatch between S3Site.BucketName Literal (%s) and CloudFront DNS entry (%s)", 70 s3Site.BucketName.Literal, 71 bucketName) 72 } 73 74 dnsRecordResourceName := sparta.CloudFormationResourceName("DNSRecord", 75 "DNSRecord") 76 cloudFrontDistroResourceName := sparta.CloudFormationResourceName("CloudFrontDistro", 77 "CloudFrontDistro") 78 79 // Use the HostedZoneName to create the record 80 hostedZoneName := fmt.Sprintf("%s.", domainName) 81 dnsRecordResource := &gocf.Route53RecordSet{ 82 // // Zone for the mweagle.io 83 HostedZoneName: gocf.String(hostedZoneName), 84 Name: gocf.String(bucketName), 85 Type: gocf.String("A"), 86 AliasTarget: &gocf.Route53RecordSetAliasTarget{ 87 // This HostedZoneID value is required... 88 HostedZoneID: gocf.String("Z2FDTNDATAQYW2"), 89 DNSName: gocf.GetAtt(cloudFrontDistroResourceName, "DomainName"), 90 }, 91 } 92 template.AddResource(dnsRecordResourceName, dnsRecordResource) 93 // IndexDocument 94 indexDocument := gocf.String("index.html") 95 if s3Site.WebsiteConfiguration != nil && 96 s3Site.WebsiteConfiguration.IndexDocument != nil && 97 s3Site.WebsiteConfiguration.IndexDocument.Suffix != nil { 98 indexDocument = gocf.String(*s3Site.WebsiteConfiguration.IndexDocument.Suffix) 99 } 100 // Add the distro... 101 distroConfig := &gocf.CloudFrontDistributionDistributionConfig{ 102 Aliases: gocf.StringList(s3Site.BucketName), 103 DefaultRootObject: indexDocument, 104 Origins: &gocf.CloudFrontDistributionOriginList{ 105 gocf.CloudFrontDistributionOrigin{ 106 DomainName: gocf.GetAtt(s3Site.CloudFormationS3ResourceName(), "DomainName"), 107 ID: gocf.String("S3Origin"), 108 S3OriginConfig: &gocf.CloudFrontDistributionS3OriginConfig{}, 109 }, 110 }, 111 Enabled: gocf.Bool(true), 112 DefaultCacheBehavior: &gocf.CloudFrontDistributionDefaultCacheBehavior{ 113 ForwardedValues: &gocf.CloudFrontDistributionForwardedValues{ 114 QueryString: gocf.Bool(false), 115 }, 116 TargetOriginID: gocf.String("S3Origin"), 117 ViewerProtocolPolicy: gocf.String("allow-all"), 118 }, 119 } 120 // Update the cert... 121 distroConfig.ViewerCertificate = cert 122 123 cloudfrontDistro := &gocf.CloudFrontDistribution{ 124 DistributionConfig: distroConfig, 125 } 126 template.AddResource(cloudFrontDistroResourceName, cloudfrontDistro) 127 128 // Log the created record 129 template.Outputs["CloudFrontDistribution"] = &gocf.Output{ 130 Description: "CloudFront Distribution Route53 entry", 131 Value: s3Site.BucketName, 132 } 133 return nil 134 } 135 return sparta.ServiceDecoratorHookFunc(distroDecorator) 136 }