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  }