Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > go自动签发证书

详解如何使用go-acme/lego实现自动签发证书

作者:AlpsMonaco

这篇文章主要为大家详细介绍了如何使用 go-acme/lego 的客户端或库完成证书的自动签发,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

相关背景知识

Let's Encrypt

Let's Encrypt是一个于2015年三季度推出的数字证书认证机构,旨在以自动化流程消除手动创建和安装证书的复杂流程,并推广使万维网服务器的加密连接无所不在,为安全网站提供免费的传输层安全性协议证书。

ACME

ACME,即自动自动证书管理环境(Automatic Certificate Management Environment),是一种协议,用于自动颁发和更新证书,无需人工干预。

互联网安全研究小组 (ISRG) 最初为自己的证书服务设计了ACME协议。证书颁发机构Let’s Encrypt通过ACME协议免费提供DV证书。如今,各种其他的CA、PKI供应商和浏览器都支持ACME协议,支持不同类型的证书。

go-acme/lego

一个用go语言写的acme客户端和go语言库。下文简称为 lego

使用 lego 客户端

安装

如果有golang开发环境可以使用以下命令安装lego

go install github.com/go-acme/lego/v4/cmd/lego@latest

如果没有golang开发环境可前往 github.com/go-acme/lego/releases 下载最新cli客户端

签发证书

签发证书需要验证域名的所有权,acme协议提供了两种方法来验证你的域名所有权,分别是http服务器验证和dns验证。

http服务器验证

使用该方法验证需要有一台服务器,该服务器要有公网ip。同时还需要拥有服务器的root权限,才能监听80和443端口。

假设需要部署证书的域名为 example.com ,我们需要先配置 example.com 指向该服务器的公网ip,然后在服务器上执行

lego --email="you@example.com" --domains="example.com" --http run

该命令启动一个http服务器,监听80/443端口。

随后Let's Encrypt会根据域名(example.com)访问服务器的80/443端口,验证域名的所有权。这个过程是自动化的,只需要等待即可。

验证通过后会下发证书到 ./.lego/certificates 里,证书的有效期为3个月。

dns验证

lego强大的地方便是集成了几乎所有常用的云厂商,如CloudFlare、阿里云和腾讯云等的服务API。只需要设置API_KEY和API_SECRET便可以自动帮你完成DNS验证。

这边以腾讯云为例:

执行以下命令:

TENCENTCLOUD_SECRET_ID=abcdefghijklmnopqrstuvwx \ 
TENCENTCLOUD_SECRET_KEY=your-secret-key \ 
lego --email you@example.com --dns tencentcloud --domains my.example.org run

该命令会调用腾讯云的后台API,为example.com填写DNS验证信息;Let's Encrypt验证通过之后,下发证书到./.lego/certificates,同时也会自动帮你删除该DNS验证信息。

使用lego库

我们也可以使用lego库来生成证书,或者做一些自动化证书生成然后部署的二次开发。lego库同样也支持http服务器验证和dns验证,下面给出完整可用代码。

50-62行为腾讯云dns验证部分,64-73为http服务器验证部分,二选一即可。

package main

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"fmt"
	"github.com/go-acme/lego/v4/certcrypto"
	"github.com/go-acme/lego/v4/certificate"
	"github.com/go-acme/lego/v4/lego"
	"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
	"github.com/go-acme/lego/v4/registration"
	"log"
	"os"
)

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

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

func main() {
	privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Fatal(err)
	}
	myUser := MyUser{
		Email: "you@example.com",
		key:   privateKey,
	}
	config := lego.NewConfig(&myUser)
	config.Certificate.KeyType = certcrypto.RSA2048
	client, err := lego.NewClient(config)
	if err != nil {
		log.Fatal(err)
	}
        
   // 使用dns验证的方式,这边以腾讯云为例子。
	cfg := tencentcloud.NewDefaultConfig()
	cfg.SecretID = "abcdefghijklmnopqrstuvwx"
	cfg.SecretKey = "your-secret-key"
	p, err := tencentcloud.NewDNSProviderConfig(cfg)
	if err != nil {
		log.Fatal(err)
	}
	err = client.Challenge.SetDNS01Provider(p)
	if err != nil {
		log.Fatal(err)
	}
   // ---------使用dns-腾讯云验证的方式结束-----------
   
   // 使用http服务器验证的方式,注释上面dns验证的代码部分,取消下面http验证的代码注释部分
	// err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "80"))
	// if err != nil {
	// 	log.Fatal(err)
	// }
	// err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", "443"))
	// if err != nil {
	// 	log.Fatal(err)
	// }
   //-----------使用http服务器验证的方式结束-----------
   
	reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
	if err != nil {
		log.Fatal(err)
	}
	myUser.Registration = reg
	request := certificate.ObtainRequest{
		Domains: []string{"sd.pigudaxiang.cn"},
		Bundle:  true,
	}
	certificates, err := client.Certificate.Obtain(request)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%#v\n", certificates)
	err = os.WriteFile("PrivateKey", certificates.PrivateKey, os.ModePerm)
	if err != nil {
		log.Print(err)
	}
	err = os.WriteFile("Certificate", certificates.Certificate, os.ModePerm)
	if err != nil {
		log.Print(err)
	}
	err = os.WriteFile("IssuerCertificate", certificates.IssuerCertificate, os.ModePerm)
	if err != nil {
		log.Print(err)
	}
	err = os.WriteFile("CSR", certificates.CSR, os.ModePerm)
	if err != nil {
		log.Print(err)
	}
}

到此这篇关于详解如何使用go-acme/lego实现自动签发证书的文章就介绍到这了,更多相关go自动签发证书内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文