使用 lego 类库实现签发 [Let’s Encrypt] ACME v2 证书

by kingzcheung on September 22, 2019

因为 ACME v2 支持通配符证书,可以通过配置通配符证书统一管理所有的二级域名证书问题。golang web项目中,可以通过lego类库集成证书签发来实现https。

使用到的包:

github.com/xenolf/lego/acme // ACME签发

v2的签发地址是:https://acme-v02.api.letsencrypt.org/directory

代码实现:

首先,我们需要实现 acme.User 接口, acme.User 接口分别有三个方法:GetEmail,GetRegistration,GetPrivateKey

type Account struct {
    Email        string
    Registration *registration.Resource
    key          crypto.PrivateKey
}

func (a *Account) GetEmail() string {
    return a.Email
}
func (a Account) GetRegistration() *registration.Resource {
    return a.Registration
}
func (a *Account) GetPrivateKey() crypto.PrivateKey {
    return a.key
}

通过上面的实现创建一个账户,并且生成一个私钥:

account := Account{
        Email: "i@kingzcheung.com",
        key:   privateKey,
    }
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    if err != nil {
        log.Fatal(err)
    }
config := lego.NewConfig(&account)
config.Certificate.KeyType = certcrypto.RSA2048

还需要创建一个客户端与CA服务器进行通信:

client, err := lego.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }

证书的申请是否成功的关键在于CA服务器会让你去验证你是否有对域名的完整控制权,接下来我们需要进行“挑战”,Let’s Encrypt 的挑战有三种:DNS,HTTP,TLS。这里以DNS挑战为例子,DNS挑战的原理是CA给你一个字符串,让你为这个域名的一条值为这个字符串的TXT记录,之后CA会去验证,验证通过之后就会颁发证书。幸好,大多数DNS服务商都有相应的接口实现上面的要求,因此我们不必要自己手动添加,而lego也提供了很多DNS 供应商列表的实现,这里以阿里云 alidns为例子:

provider, err := dns.NewDNSChallengeProviderByName("alidns")
    if err != nil {
        log.Fatal(err)
    }
    err = client.Challenge.SetDNS01Provider(provider)
    if err != nil {
        log.Fatal(err)
    }

向客户端进行注册:

reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
    if err != nil {
        log.Fatal(err)
    }
    account.Registration = reg

提供需要签发的域名:

request := certificate.ObtainRequest{
        Domains: []string{"gobook.cc"},
        Bundle:  true,
    }

最后发起请求获取证书:

certificates, err := client.Certificate.Obtain(request)

解析certificates结果生成证书即可。