Skip to content

Commit

Permalink
gov2: create example code for cloudfront (#5156)
Browse files Browse the repository at this point in the history
  • Loading branch information
tae2089 authored and ford-at-aws committed Dec 15, 2023
1 parent a3a996b commit c5f809d
Show file tree
Hide file tree
Showing 4 changed files with 348 additions and 0 deletions.
194 changes: 194 additions & 0 deletions gov2/cloudfront/CreateDistribution/CreateDistribution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// snippet-start:[cloudfront.go-v2.CreateDistribution]

package main

import (
"context"
"errors"
"flag"
"fmt"
"log"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/cloudfront"
cloudfrontTypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
"github.com/aws/aws-sdk-go-v2/service/s3"
)

// CFDistributionAPI defines the interface for the CreateDistribution function.
// We use this interface to test the function using a mocked service.
type CFDistributionAPI interface {
CreateDistribution(bucketName, certificateSSLArn, domain string) (*cloudfront.CreateDistributionOutput, error)
createoriginAccessIdentity(domainName string) (string, error)
}

type CFDistributionAPIImpl struct {
s3Client *s3.Client
cloudfrontClient *cloudfront.Client
}

func createCFDistribution(s3client *s3.Client, cloudfront *cloudfront.Client) CFDistributionAPI {
return &CFDistributionAPIImpl{
s3Client: s3client,
cloudfrontClient: cloudfront,
}
}

func (c *CFDistributionAPIImpl) CreateDistribution(bucketName, certificateSSLArn, domain string) (*cloudfront.CreateDistributionOutput, error) {
locationOutput, err := c.s3Client.GetBucketLocation(context.Background(), &s3.GetBucketLocationInput{Bucket: aws.String(bucketName)})

if err != nil {
return nil, err
}
originDomain := bucketName + ".s3." + string(locationOutput.LocationConstraint) + ".amazonaws.com"

if err != nil {
return nil, err
}

originAccessIdentityID, err := c.createoriginAccessIdentity(domain)
if err != nil {
return nil, err
}

cloudfrontResponse, err := c.cloudfrontClient.CreateDistribution(context.TODO(), &cloudfront.CreateDistributionInput{
DistributionConfig: &cloudfrontTypes.DistributionConfig{
Enabled: aws.Bool(true),
CallerReference: &originDomain,
Comment: &originDomain,
IsIPV6Enabled: aws.Bool(false),
PriceClass: cloudfrontTypes.PriceClassPriceClass100,
HttpVersion: cloudfrontTypes.HttpVersionHttp11,
DefaultRootObject: aws.String("index.html"),
Aliases: &cloudfrontTypes.Aliases{
Quantity: aws.Int32(1),
Items: []string{domain},
},
ViewerCertificate: &cloudfrontTypes.ViewerCertificate{
ACMCertificateArn: aws.String(certificateSSLArn),
SSLSupportMethod: cloudfrontTypes.SSLSupportMethodSniOnly,
},
CustomErrorResponses: &cloudfrontTypes.CustomErrorResponses{
Quantity: aws.Int32(1),
Items: []cloudfrontTypes.CustomErrorResponse{
{
ErrorCode: aws.Int32(403),
ResponseCode: aws.String("200"),
ErrorCachingMinTTL: aws.Int64(10),
ResponsePagePath: aws.String("/index.html"),
},
},
},
Origins: &cloudfrontTypes.Origins{
Quantity: aws.Int32(1),
Items: []cloudfrontTypes.Origin{
{
DomainName: aws.String(originDomain),
Id: aws.String(originDomain),
S3OriginConfig: &cloudfrontTypes.S3OriginConfig{
OriginAccessIdentity: aws.String("origin-access-identity/cloudfront/" + originAccessIdentityID),
},
},
},
},
CacheBehaviors: nil,
DefaultCacheBehavior: &cloudfrontTypes.DefaultCacheBehavior{
TargetOriginId: aws.String(originDomain),
Compress: aws.Bool(true),
ViewerProtocolPolicy: cloudfrontTypes.ViewerProtocolPolicyRedirectToHttps,
AllowedMethods: &cloudfrontTypes.AllowedMethods{
Quantity: aws.Int32(2),
Items: []cloudfrontTypes.Method{
cloudfrontTypes.MethodGet,
cloudfrontTypes.MethodHead,
},
},
},
},
})

if err != nil {
return nil, err
}

return cloudfrontResponse, nil
}

func (c *CFDistributionAPIImpl) createoriginAccessIdentity(domainName string) (string, error) {
ctx := context.Background()
oai, err := c.cloudfrontClient.CreateCloudFrontOriginAccessIdentity(ctx, &cloudfront.CreateCloudFrontOriginAccessIdentityInput{
CloudFrontOriginAccessIdentityConfig: &cloudfrontTypes.CloudFrontOriginAccessIdentityConfig{
CallerReference: aws.String(domainName),
Comment: aws.String(domainName),
},
})
if err != nil {
return "", err
}
return *oai.CloudFrontOriginAccessIdentity.Id, nil
}

var (
// bucketName is the name of the S3 bucket to create a CloudFront distribution for.
bucketName = ""
// certificateSSLArn is the ARN value of the certificate issued by the AWS Certificate Manager (ACM).
// When testing, please check and copy and paste the ARN of the pre-issued certificate.
// If you don't know how to create a TLS/SSL certificate using ACM, follow the link below.
// https://docs.aws.amazon.com/acm/latest/userguide/acm-overview.html
certificateSSLArn = ""
// domain refers to the domain that will be used in conjunction with CloudFront and Amazon Route 53.
// For testing, please enter a domain that is registered in Route 53 and will be used in conjunction with CloudFront.
domain = ""
)

// main uses the AWS SDK for Go V2 to create an Amazon CloudFront distribution.
// This example uses the default settings specified in your shared credentials
// and config files.
func main() {

flag.StringVar(&bucketName, "bucket", "", "<EXAMPLE-BUCKET-NAME>")
flag.StringVar(&certificateSSLArn, "cert", "", "<AWS CERTIFICATE MANGER ARN>")
flag.StringVar(&domain, "domain", "", "<YOUR DOMAIN>")
flag.Parse()
if bucketName == "" {
log.Println(errors.New("please setup bucket name"))
return
}

if certificateSSLArn == "" {
log.Println(errors.New("please setup certificate ARN"))
return
}

if domain == "" {
log.Println(errors.New("please setup your domain"))
return
}

sdkConfig, err := config.LoadDefaultConfig(context.TODO())

if err != nil {
fmt.Println("Couldn't load default configuration. Have you set up your AWS account?")
fmt.Println(err)
return
}

s3Client := s3.NewFromConfig(sdkConfig)
cloudfrontClient := cloudfront.NewFromConfig(sdkConfig)

cfDistribution := createCFDistribution(s3Client, cloudfrontClient)

result, err := cfDistribution.CreateDistribution(bucketName, certificateSSLArn, domain)
if err != nil {
fmt.Println("Couldn't create distribution. Please check error message and try again.")
fmt.Println(err)
return
}
fmt.Println(result.Distribution.ARN)
}

// snippet-end:[cloudfront.go-v2.CreateDistribution]
81 changes: 81 additions & 0 deletions gov2/cloudfront/CreateDistribution/CreateDistribution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
"context"
"errors"
"testing"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/cloudfront"
"github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
"github.com/aws/aws-sdk-go-v2/service/s3"
)

type MockCFDistributionAPI struct {
s3Client *s3.Client
cloudfrontClient *cloudfront.Client
}

func (m *MockCFDistributionAPI) CreateDistribution(bucketName, certificateSSLArn, domain string) (*cloudfront.CreateDistributionOutput, error) {
if bucketName == "" || certificateSSLArn == "" || domain == "" {
return nil, errors.New("bucket name, certificate SSL ARN, and domain are required")
}
return &cloudfront.CreateDistributionOutput{
Distribution: &types.Distribution{
ARN: aws.String("arn:aws:cloudfront::1234567890:distribution/AAAAAAAAAAAA"),
DomainName: aws.String(domain),
DistributionConfig: &types.DistributionConfig{
ViewerCertificate: &types.ViewerCertificate{
ACMCertificateArn: aws.String(certificateSSLArn),
},
},
},
}, nil
}

func (m *MockCFDistributionAPI) createoriginAccessIdentity(domainName string) (string, error) {
return domainName, nil
}

func createMockCFDistribution(s3client *s3.Client, cloudfront *cloudfront.Client) CFDistributionAPI {
return &MockCFDistributionAPI{
s3Client: s3client,
cloudfrontClient: cloudfront,
}
}

func TestCreateDistribution(t *testing.T) {
thisTime := time.Now()
nowString := thisTime.Format("2006-01-02 15:04:05 Monday")
t.Log("Starting integration test at " + nowString)

sdkConfig, err := config.LoadDefaultConfig(context.TODO())

if err != nil {
t.Log("Got an error ...:")
t.Log(err)
return
}

s3Client := s3.NewFromConfig(sdkConfig)
cloudfrontClient := cloudfront.NewFromConfig(sdkConfig)

mockCFDistribution := createMockCFDistribution(s3Client, cloudfrontClient)

bucketName := "example-com"
certificateSSLArn := "arn:aws:acm:ap-northeast-2:123456789000:certificate/000000000-0000-0000-0000-000000000000"
domain := "example.com"

result, err := mockCFDistribution.CreateDistribution(bucketName, certificateSSLArn, domain)

if err != nil {
t.Error(err)
return
}

t.Log("Created Distribution with ARN: " + *result.Distribution.ARN + " for name: " + *result.Distribution.DomainName)
}
26 changes: 26 additions & 0 deletions gov2/cloudfront/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module example.aws/go-v2/examples/cloudfront

go 1.18

require (
github.com/aws/aws-sdk-go-v2 v1.17.4 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.12 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.12 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19 // indirect
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.24.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
)
47 changes: 47 additions & 0 deletions gov2/cloudfront/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
github.com/aws/aws-sdk-go-v2 v1.17.4 h1:wyC6p9Yfq6V2y98wfDsj6OnNQa4w2BLGCLIxzNhwOGY=
github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
github.com/aws/aws-sdk-go-v2/config v1.18.12 h1:fKs/I4wccmfrNRO9rdrbMO1NgLxct6H9rNMiPdBxHWw=
github.com/aws/aws-sdk-go-v2/config v1.18.12/go.mod h1:J36fOhj1LQBr+O4hJCiT8FwVvieeoSGOtPuvhKlsNu8=
github.com/aws/aws-sdk-go-v2/credentials v1.13.12 h1:Cb+HhuEnV19zHRaYYVglwvdHGMJWbdsyP4oHhw04xws=
github.com/aws/aws-sdk-go-v2/credentials v1.13.12/go.mod h1:37HG2MBroXK3jXfxVGtbM2J48ra2+Ltu+tmwr/jO0KA=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 h1:3aMfcTmoXtTZnaT86QlVaYh+BRMbvrrmZwIQ5jWqCZQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22/go.mod h1:YGSIJyQ6D6FjKMQh16hVFSIUD54L4F7zTGePqYMYYJU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 h1:r+XwaCLpIvCKjBIYy/HVZujQS9tsz5ohHG3ZIe0wKoE=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 h1:7AwGYXDdqRQYsluvKFmWoqpcOQJ4bH634SkYf3FNj/A=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 h1:J4xhFd6zHhdF9jPP0FQJ6WknzBboGMBNjKOv4iTuw4A=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19 h1:FGvpyTg2LKEmMrLlpjOgkoNp9XF5CGeyAyo33LdqZW8=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19/go.mod h1:8W88sW3PjamQpKFUQvHWWKay6ARsNvZnzU7+a4apubw=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.24.1 h1:+JyTKAmvtszyz+LH0ag+Jm1BdcjfyXK3O2KJKSHIXtM=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.24.1/go.mod h1:SJRh4g8v7lNgjBVlSalPRp7Vfi2PU0LZN0PNEPjm9qk=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 h1:c5+bNdV8E4fIPteWx4HZSkqI07oY9exbfQ7JH7Yx4PI=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23/go.mod h1:1jcUfF+FAOEwtIcNiHPaV4TSoZqkUIPzrohmD7fb95c=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 h1:LjFQf8hFuMO22HkV5VWGLBvmCLBCLPivUAmpdpnp4Vs=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22 h1:ISLJ2BKXe4zzyZ7mp5ewKECiw0U7KpLgS3S6OxY9Cm0=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22/go.mod h1:QFVbqK54XArazLvn2wvWMRBi/jGrWii46qbr5DyPGjc=
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2 h1:5EQWIFO+Hc8E2hFcXQJ1vm6ufl/PMt/6RVRDZRju2vM=
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2/go.mod h1:SXDHd6fI2RhqB7vmAzyYQCTQnpZrIprVJvYxpzW3JAM=
github.com/aws/aws-sdk-go-v2/service/sso v1.12.1 h1:lQKN/LNa3qqu2cDOQZybP7oL4nMGGiFqob0jZJaR8/4=
github.com/aws/aws-sdk-go-v2/service/sso v1.12.1/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 h1:0bLhH6DRAqox+g0LatcjGKjjhU6Eudyys6HB6DJVPj8=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1/go.mod h1:O1YSOg3aekZibh2SngvCRRG+cRHKKlYgxf/JBF/Kr/k=
github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 h1:s49mSnsBZEXjfGBkRfmK+nPqzT7Lt3+t2SmAKNyHblw=
github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiOVVG8uVjGI6HaZ8WBHdgDgU=
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

0 comments on commit c5f809d

Please sign in to comment.