使用go-acme/lego自动签发证书

本文章介绍如何使用 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 客户端

安装

  1. 如果有golang开发环境可以使用以下命令安装lego
shell 复制代码
go install github.com/go-acme/lego/v4/cmd/lego@latest
  1. 如果没有golang开发环境可前往 github.com/go-acme/leg... 下载最新cli客户端

签发证书

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

http服务器验证

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

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

shell 复制代码
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验证。

这边以腾讯云为例:

执行以下命令:

ini 复制代码
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服务器验证部分,二选一即可。

go 复制代码
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)
	}
}
相关推荐
石牌桥网管12 小时前
OpenSSL 生成根证书、中间证书和网站证书
网络协议·https·openssl
earthzhang20211 天前
《深入浅出HTTPS》读书笔记(5):随机数
网络协议·http·https
xiaoxiongip6661 天前
HTTP 和 HTTPS
网络·爬虫·网络协议·tcp/ip·http·https·ip
CXDNW1 天前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
‍。。。1 天前
使用Rust实现http/https正向代理
http·https·rust
田三番2 天前
使用 vscode 简单配置 ESP32 连接 Wi-Fi 每日定时发送 HTTP 和 HTTPS 请求
单片机·物联网·http·https·嵌入式·esp32·sntp
圈圈的熊3 天前
HTTP 和 HTTPS 的区别
前端·网络协议·http·https
小黄编程快乐屋4 天前
HTTP和HTTPS的区别
网络协议·http·https
GDDGHS_4 天前
HTTP和HTTPS 的作用和应用场景 (python 爬虫简单入门)
爬虫·python·网络协议·http·https
伍嘉源5 天前
HTTP与HTTPS的区别
网络协议·http·https