Golang example using DNS verification

I’m trying to find a working example of using the ACME protocol with DNS validation in Go. I’ve found loads of examples using HTTP but none with DNS. Does anyone have any working code or any good examples of it in action?

I’ve read the GoDoc for the package but it doesn’t really help.

3 Likes

Which package? The /x/crypto/acme one only supports ACME v1, which doesn't have wildcard support. Try github.com/eggsampler/acme or github.com/xenolf/lego for ACME v2 libraries.

But even with the v1 package, it's a very minor change to use the DNS challenge.

package main

import (
	"context"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"log"

	"golang.org/x/crypto/acme"
)

func main() {

	// All the usual account registration prelude
	accountKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)

	client := &acme.Client{
		Key:          accountKey,
		DirectoryURL: "https://acme-v01.api.letsencrypt.org/directory",
	}

	if _, err := client.Register(context.Background(), &acme.Account{},
		func(tos string) bool {
			log.Printf("Agreeing to ToS: %s", tos)
			return true
		}); err != nil {
		log.Fatal("Can't register an ACME account: ", err)
	}

	// Authorize a DNS name
	authz, err := client.Authorize(context.Background(), "example.org")
	if err != nil {
		log.Fatal("Can't authorize: ", err)
	}

	// Find the DNS challenge for this authorization
	var chal *acme.Challenge
	for _, c := range authz.Challenges {
		if c.Type == "dns-01" {
			chal = c
			break
		}
	}
	if chal == nil {
		log.Fatal("No DNS challenge was present")
	}

	// Determine the TXT record values for the DNS challenge
	txtLabel := "_acme-challenge." + authz.Identifier.Value
	txtValue, _ := client.DNS01ChallengeRecord(chal.Token)
	log.Printf("Creating record %s with value %s", txtLabel, txtValue)

	// Then the usual: accept the challenge, wait for the authorization ...
	if _, err := client.Accept(context.Background(), chal); err != nil {
		log.Fatal("Can't accept challenge: ", err)
	}

	if _, err := client.WaitAuthorization(context.Background(), authz.URI); err != nil {
		log.Fatal("Failed authorization: ", err)
	}

	// Submit certificate request if it suceeded ...
}
2 Likes

This is brilliant, thanks, it was the x/crypto library I was looking at.

I don’t need wildcards so is there any need to go to version 2? I’m only working on a fairly simple proof of concept that doesn’t need a long lifespan so I think I’ll probably be OK.

Not sure. There's no public plan to deprecate the v1 API, but using it for new integrations is "discouraged". I'd guess that it's going to be around for a few more years yet.

1 Like

If the project lasts beyond six months then it has taken off and will need a rewrite to make it more production ready anyway so I don’t need to worry about deprecation at the moment.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.