DEV Community

Sam
Sam

Posted on

Request ACM certificate with DNS validation in Go

I've been dealing with AWS SDK a lot in building https://github.com/dotenx/dotenx, and I've found it challenging quite often, particularly because of poor documentation.

One of the issues I had to resolve was requesting a TLS certificate from AWS ACM and validating it with DNS validation.

If you're in a similar situation, you can use this snippet.

func requestCertificate(domainName, hostedZoneId string) (string, error) { cfg := &aws.Config{ Region: aws.String(config.Region), } svc := acm.New(session.New(), cfg) input := &acm.RequestCertificateInput{ DomainName: aws.String(domainName), IdempotencyToken: aws.String(strings.Replace(domainName, ".", "", -1)), ValidationMethod: aws.String("DNS"), SubjectAlternativeNames: []*string{ aws.String("*." + domainName), }, DomainValidationOptions: []*acm.DomainValidationOption{ { DomainName: aws.String(domainName), ValidationDomain: aws.String(domainName), }, }, } result, err := svc.RequestCertificate(input) if err != nil { return "", err } time.Sleep(time.Second * 10) // This MUST be long enough, o.w. the validation options won't be available dcIn := &acm.DescribeCertificateInput{ CertificateArn: result.CertificateArn, } c, err := svc.DescribeCertificate(dcIn) if err != nil { return "", err } if c.Certificate.DomainValidationOptions == nil { errMsg := "DomainValidationOptions does not exists" logrus.Error(errMsg) return "", errors.New(errMsg) } fmt.Println("DomainValidationOptions: ", c.Certificate.DomainValidationOptions) // ---> Log at the bottom for _, dvo := range c.Certificate.DomainValidationOptions { vRecordName := dvo.ResourceRecord.Name // -----> this is nil and causes panic vRecordValue := dvo.ResourceRecord.Value createRoute53Record(*vRecordName, *vRecordValue, hostedZoneId) } return *result.CertificateArn, nil } func createRoute53Record(domain, value, hostedZoneId string) error { cfg := &aws.Config{ Region: aws.String(config.Region), } if config.Configs.App.RunLocally { creds := credentials.NewStaticCredentials(config.Configs.Secrets.AwsAccessKeyId, config.Configs.Secrets.AwsSecretAccessKey, "") cfg = aws.NewConfig().WithRegion(config.Configs.Upload.S3Region).WithCredentials(creds) } svc := route53.New(session.New(), cfg) resourceRecordSet := &route53.ResourceRecordSet{ Name: aws.String(domain + "."), Type: aws.String("CNAME"), ResourceRecords: []*route53.ResourceRecord{ { Value: aws.String(value), }, }, TTL: aws.Int64(300), } upsert := []*route53.Change{{ Action: aws.String("UPSERT"), ResourceRecordSet: resourceRecordSet, }} // Put it into a pretty envelope with a stamp for route53#zoneId and change ticket params := route53.ChangeResourceRecordSetsInput{ ChangeBatch: &route53.ChangeBatch{ Changes: upsert, }, HostedZoneId: aws.String(hostedZoneId), } // Post it _, err := svc.ChangeResourceRecordSets(&params) if err != nil { logrus.Error(err.Error()) } return err } 
Enter fullscreen mode Exit fullscreen mode

You can find the code here:

https://gist.github.com/mkamrani/edf0134801076352e8c502ff28801e46

Top comments (0)