使用Lego申请签发证书
前言
本文不是Lego
使用教程。
由于SSL证书一年也就申请给几次,所以一般我都是手动去配置申请,上次介绍了Certbot
提供acme
模块用法,本文将介绍lego
这个ACME
客户端所提供的的库的用法。基本上重新造了个轮子,没有去用内部具体的接口。
实现
package main
import (
"crypto"
"crypto/x509"
"encoding/pem"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/registration"
"io/ioutil"
"time"
)
// 参见: https://pkg.go.dev/github.com/go-acme/lego/[email protected]/registration#User
type AcmeUser struct {
Email string
Registration *registration.Resource
key crypto.PrivateKey
}
func (u *AcmeUser) GetEmail() string {
return u.Email
}
func (u *AcmeUser) GetRegistration() *registration.Resource {
return u.Registration
}
func (u *AcmeUser) GetPrivateKey() crypto.PrivateKey {
return u.key
}
// 实现 Provider 接口
// 参见: https://pkg.go.dev/github.com/go-acme/lego/v4/[email protected]#Provider
// lego本身提供一些DNS服务商的接口,但我一般都是手动申请
type plainDnsProvider struct{}
func (p *plainDnsProvider) Present(domain, token, keyAuth string) error {
log.Infof("domain: _acme-challenge.%s token: %s", domain, token)
return nil
}
func (p *plainDnsProvider) CleanUp(domain, token, keyAuth string) error {
return nil
}
func main() {
// 本地ACME测试用
// httpClient := &http.Client{
// Transport: &http.Transport{
// TLSClientConfig: &tls.Config{InsecureSkipVerify: true
// },
// }}
key, err := ioutil.ReadFile("account_private.key")
if err != nil {
panic(err)
}
block, _ := pem.Decode(key)
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
panic(err)
}
// 加载账户信息
user := AcmeUser{
Email: "[email protected]",
key: priKey,
}
config := lego.NewConfig(&user)
// Pebble 默认地址
// config.CADirURL = "https://127.0.0.1:14000/dir"
// config.CADirURL = "https://api.buypass.com/acme/directory"
config.CADirURL = "https://acme-v02.api.letsencrypt.org/directory"
config.UserAgent = "acm_go/0.0.1"
// 秘钥类型
config.Certificate.KeyType = certcrypto.RSA2048
// 本地测试用
// config.HTTPClient = httpClient
// 新建客户端
client, err := lego.NewClient(config)
if err != nil {
panic(err)
}
// 账户注册
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
// 使用秘钥查找账户
// reg, err := client.Registration.ResolveAccountByKey()
if err != nil {
panic(err)
}
user.Registration = reg
// 生成证书请求
request := certificate.ObtainRequest{
Domains: []string{"yajyusenpai.coat.co.jp"},
// 证书链
Bundle: true,
}
dnsProvider := plainDnsProvider{}
// dns.NewDNSChallengeProviderByName(provider_name)
// dnspodConfig := dnspod.Config{config...}
// dnspodProvider := dnspod.NewDNSProviderConfig(&dnspodConfig)
// 以DNS方式验证
err = client.Challenge.SetDNS01Provider(&dnsProvider, dns01.AddDNSTimeout(6*time.Minute))
if err != nil {
panic(err)
}
// 自动轮询
certificates, err := client.Certificate.Obtain(request)
if err != nil {
panic(err)
}
// 导出
_ = ioutil.WriteFile("certificate.crt", certificates.Certificate, 0755)
_ = ioutil.WriteFile("certificate_private.key", certificates.PrivateKey, 0755)
}