mirror of
https://gitee.com/samwaf/SamWaf.git
synced 2026-11-01 18:51:45 +08:00
Merge pull request #725 from Lvshujun0918/main
feat: skip dns local check
This commit is contained in:
@@ -39,6 +39,9 @@ func (w *WafSslOrderApi) AddApi(c *gin.Context) {
|
||||
var req request.WafSslorderaddReq
|
||||
err := c.ShouldBindJSON(&req)
|
||||
if err == nil {
|
||||
if req.ApplyMethod != "dns01" {
|
||||
req.SkipDNSVerify = 0
|
||||
}
|
||||
hostBean := wafHostService.GetDetailByCodeApi(req.HostCode)
|
||||
if hostBean.Id == "" {
|
||||
response.FailWithMessage("查找主机未找到", c)
|
||||
@@ -178,6 +181,9 @@ func (w *WafSslOrderApi) ModifyApi(c *gin.Context) {
|
||||
var req request.WafSslordereditReq
|
||||
err := c.ShouldBindJSON(&req)
|
||||
if err == nil {
|
||||
if req.ApplyMethod != "dns01" {
|
||||
req.SkipDNSVerify = 0
|
||||
}
|
||||
existingOrder := wafSslOrderService.GetDetailById(req.Id)
|
||||
if existingOrder.Id == "" {
|
||||
response.FailWithMessage("SSL订单不存在", c)
|
||||
|
||||
@@ -6,6 +6,7 @@ type WafSslorderaddReq struct {
|
||||
HostCode string `json:"host_code"` //网站唯一码(主要键)
|
||||
ApplyPlatform string `json:"apply_platform"` //申请平台
|
||||
ApplyMethod string `json:"apply_method"` //申请方式http,dns
|
||||
SkipDNSVerify int64 `json:"skip_dns_verify"` //dns01是否跳过本地DNS传播校验 0否 1是
|
||||
ApplyDns string `json:"apply_dns"` //申请dns服务商
|
||||
ApplyEmail string `json:"apply_email"` //申请邮箱
|
||||
ApplyDomain string `json:"apply_domain"` //申请域名
|
||||
@@ -16,6 +17,7 @@ type WafSslordereditReq struct {
|
||||
HostCode string `json:"host_code"` //网站唯一码(主要键)
|
||||
ApplyPlatform string `json:"apply_platform"` //申请平台
|
||||
ApplyMethod string `json:"apply_method"` //申请方式http01,dns
|
||||
SkipDNSVerify int64 `json:"skip_dns_verify"` //dns01是否跳过本地DNS传播校验 0否 1是
|
||||
ApplyDns string `json:"apply_dns"` //申请dns服务商
|
||||
ApplyEmail string `json:"apply_email"` //申请邮箱
|
||||
ApplyDomain string `json:"apply_domain"` //申请域名
|
||||
|
||||
@@ -13,6 +13,7 @@ type SslOrder struct {
|
||||
HostCode string `json:"host_code"` //网站唯一码(主要键)
|
||||
ApplyPlatform string `json:"apply_platform"` //申请平台
|
||||
ApplyMethod string `json:"apply_method"` //申请方式http01,dns
|
||||
SkipDNSVerify int64 `json:"skip_dns_verify"` //dns01是否跳过本地DNS传播校验 0否 1是
|
||||
ApplyDns string `json:"apply_dns"` //申请dns服务商
|
||||
ApplyEmail string `json:"apply_email"` //申请邮箱
|
||||
ApplyKey string `json:"apply_key"` //申请私钥
|
||||
|
||||
@@ -26,6 +26,7 @@ func (receiver *WafSSLOrderService) AddApi(req request.WafSslorderaddReq) (model
|
||||
HostCode: req.HostCode,
|
||||
ApplyPlatform: req.ApplyPlatform,
|
||||
ApplyMethod: req.ApplyMethod,
|
||||
SkipDNSVerify: req.SkipDNSVerify,
|
||||
ApplyDns: req.ApplyDns,
|
||||
ApplyDomain: req.ApplyDomain,
|
||||
ApplyEmail: req.ApplyEmail,
|
||||
@@ -43,6 +44,7 @@ func (receiver *WafSSLOrderService) ModifyApi(req request.WafSslordereditReq) er
|
||||
"HostCode": req.HostCode,
|
||||
"ApplyPlatform": req.ApplyPlatform,
|
||||
"ApplyMethod": req.ApplyMethod,
|
||||
"SkipDNSVerify": req.SkipDNSVerify,
|
||||
"ApplyDns": req.ApplyDns,
|
||||
"ApplyDomain": req.ApplyDomain,
|
||||
"ApplyEmail": req.ApplyEmail,
|
||||
@@ -108,6 +110,7 @@ func (receiver *WafSSLOrderService) ModifyById(sslOrder model.SslOrder) error {
|
||||
"HostCode": sslOrder.HostCode,
|
||||
"ApplyPlatform": sslOrder.ApplyPlatform,
|
||||
"ApplyMethod": sslOrder.ApplyMethod,
|
||||
"SkipDNSVerify": sslOrder.SkipDNSVerify,
|
||||
"ApplyDns": sslOrder.ApplyDns,
|
||||
"ApplyDomain": sslOrder.ApplyDomain,
|
||||
"ApplyEmail": sslOrder.ApplyEmail,
|
||||
@@ -145,6 +148,7 @@ func (receiver *WafSSLOrderService) RenewAdd(orderId string) (model.SslOrder, er
|
||||
HostCode: order.HostCode,
|
||||
ApplyPlatform: order.ApplyPlatform,
|
||||
ApplyMethod: order.ApplyMethod,
|
||||
SkipDNSVerify: order.SkipDNSVerify,
|
||||
ApplyDns: order.ApplyDns,
|
||||
ApplyDomain: order.ApplyDomain,
|
||||
ApplyEmail: order.ApplyEmail,
|
||||
|
||||
+52
-16
@@ -1,6 +1,7 @@
|
||||
package ssl
|
||||
|
||||
import (
|
||||
"SamWaf/common/zlog"
|
||||
"SamWaf/model"
|
||||
"SamWaf/utils"
|
||||
"crypto"
|
||||
@@ -14,10 +15,12 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/providers/dns/alidns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/baiducloud"
|
||||
@@ -91,23 +94,25 @@ func RegistrationSSL(order model.SslOrder, savePath string, caServerAddress stri
|
||||
// because we aren't running as root and can't bind a listener to port 80 and 443
|
||||
// (used later when we attempt to pass challenges). Keep in mind that you still
|
||||
// need to proxy challenge traffic to port 5002 and 5001.
|
||||
if order.ApplyMethod == "http01" {
|
||||
switch order.ApplyMethod {
|
||||
case "http01":
|
||||
provider, err := webroot.NewHTTPProvider(savePath)
|
||||
if err != nil {
|
||||
return order, err
|
||||
}
|
||||
err = client.Challenge.SetHTTP01Provider(provider)
|
||||
} else if order.ApplyMethod == "dns01" {
|
||||
case "dns01":
|
||||
dnsProvider, err := GetDnsProvider(order.ApplyDns)
|
||||
if err != nil {
|
||||
zlog.Error(fmt.Sprintf("Failed to initialize DNS provider `%s`: %v", order.ApplyDns, err))
|
||||
return order, err
|
||||
}
|
||||
err = client.Challenge.SetDNS01Provider(dnsProvider)
|
||||
err = setDNS01ProviderWithRetry(client, dnsProvider, order.SkipDNSVerify)
|
||||
if err != nil {
|
||||
zlog.Error(fmt.Sprintf("Failed to set DNS-01 provider: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return order, err
|
||||
}
|
||||
// New users will need to register
|
||||
var reg *registration.Resource
|
||||
if applyPlatform == "zerossl" {
|
||||
@@ -185,7 +190,6 @@ func RegistrationSSL(order model.SslOrder, savePath string, caServerAddress stri
|
||||
}
|
||||
// Each certificate comes back with the cert bytes, the bytes of the client's
|
||||
// private key, and a certificate URL. SAVE THESE TO DISK.
|
||||
fmt.Printf("%#v\n", certificates)
|
||||
|
||||
order.ResultPrivateKey = certificates.PrivateKey
|
||||
order.ResultCertificate = certificates.Certificate
|
||||
@@ -268,13 +272,13 @@ func ReNewSSL(order model.SslOrder, savePath string, caServerAddress string, app
|
||||
} else if order.ApplyMethod == "dns01" {
|
||||
dnsProvider, err := GetDnsProvider(order.ApplyDns)
|
||||
if err != nil {
|
||||
zlog.Error(fmt.Sprintf("Failed to initialize DNS provider `%s`: %v", order.ApplyDns, err))
|
||||
return order, err
|
||||
}
|
||||
err = client.Challenge.SetDNS01Provider(dnsProvider)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return order, err
|
||||
err = setDNS01ProviderWithRetry(client, dnsProvider, order.SkipDNSVerify)
|
||||
if err != nil {
|
||||
zlog.Error(fmt.Sprintf("Failed to set DNS-01 provider: %v", err))
|
||||
}
|
||||
}
|
||||
// New users will need to register
|
||||
var reg *registration.Resource
|
||||
@@ -363,7 +367,6 @@ func ReNewSSL(order model.SslOrder, savePath string, caServerAddress string, app
|
||||
|
||||
// Each certificate comes back with the cert bytes, the bytes of the client's
|
||||
// private key, and a certificate URL. SAVE THESE TO DISK.
|
||||
fmt.Printf("%#v\n", certificates)
|
||||
|
||||
order.ResultPrivateKey = certificates.PrivateKey
|
||||
order.ResultCertificate = certificates.Certificate
|
||||
@@ -429,15 +432,48 @@ func GetDnsProvider(dnsName string) (challenge.Provider, error) {
|
||||
case "huaweicloud":
|
||||
return huaweicloud.NewDNSProvider()
|
||||
case "tencentcloud":
|
||||
|
||||
return tencentcloud.NewDNSProvider()
|
||||
case "cloudflare":
|
||||
|
||||
return cloudflare.NewDNSProvider()
|
||||
case "baiducloud":
|
||||
|
||||
return baiducloud.NewDNSProvider()
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized DNS provider: %s", dnsName)
|
||||
}
|
||||
}
|
||||
|
||||
func setDNS01ProviderWithRetry(client *lego.Client, dnsProvider challenge.Provider, skipDNSVerify int64) error {
|
||||
// 默认重试10次,每次间隔30秒
|
||||
dnsPrecheckRetry := 10
|
||||
dnsPrecheckRetryInterval := 30 * time.Second
|
||||
|
||||
// DNS 传播等待时间:300秒(3分钟)
|
||||
propagationTimeout := 180 * time.Second
|
||||
|
||||
if skipDNSVerify == 1 {
|
||||
// 跳过本地DNS传播校验:固定等待后直接通知CA进行验证
|
||||
return client.Challenge.SetDNS01Provider(dnsProvider, dns01.PropagationWait(propagationTimeout, true))
|
||||
}
|
||||
|
||||
// 默认执行本地DNS传播校验,并增加重试机制
|
||||
return client.Challenge.SetDNS01Provider(dnsProvider,
|
||||
dns01.WrapPreCheck(func(domain, fqdn, value string, check dns01.PreCheckFunc) (bool, error) {
|
||||
var lastErr error
|
||||
for i := 1; i <= dnsPrecheckRetry; i++ {
|
||||
ok, err := check(fqdn, value)
|
||||
if ok && err == nil {
|
||||
return true, nil
|
||||
}
|
||||
lastErr = err
|
||||
if i < dnsPrecheckRetry {
|
||||
time.Sleep(dnsPrecheckRetryInterval)
|
||||
}
|
||||
}
|
||||
|
||||
if lastErr != nil {
|
||||
return false, lastErr
|
||||
}
|
||||
return false, fmt.Errorf("dns propagation precheck failed after %d retries", dnsPrecheckRetry)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -718,6 +718,42 @@ func RunCoreDBMigrations(db *gorm.DB) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
// 迁移20: 为 ssl_orders 表添加 skip_dns_verify 字段(DNS校验跳过开关)
|
||||
{
|
||||
ID: "202603250001_add_ssl_orders_skip_dns_verify",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
zlog.Info("迁移 202603250001: 为 ssl_orders 表添加 skip_dns_verify 字段")
|
||||
|
||||
// 检查字段是否已存在
|
||||
if tx.Migrator().HasColumn(&model.SslOrder{}, "skip_dns_verify") {
|
||||
zlog.Info("skip_dns_verify 字段已存在,执行默认值回填")
|
||||
if err := tx.Exec("UPDATE ssl_orders SET skip_dns_verify = 0 WHERE skip_dns_verify IS NULL").Error; err != nil {
|
||||
zlog.Warn("回填 skip_dns_verify 默认值失败", "error", err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加字段
|
||||
if err := tx.Migrator().AddColumn(&model.SslOrder{}, "skip_dns_verify"); err != nil {
|
||||
return fmt.Errorf("添加 skip_dns_verify 字段失败: %w", err)
|
||||
}
|
||||
|
||||
// 为历史数据回填默认值 0(不跳过DNS校验)
|
||||
if err := tx.Exec("UPDATE ssl_orders SET skip_dns_verify = 0 WHERE skip_dns_verify IS NULL").Error; err != nil {
|
||||
zlog.Warn("设置 skip_dns_verify 默认值失败", "error", err.Error())
|
||||
}
|
||||
|
||||
zlog.Info("skip_dns_verify 字段添加成功")
|
||||
return nil
|
||||
},
|
||||
Rollback: func(tx *gorm.DB) error {
|
||||
zlog.Info("回滚 202603250001: 删除 ssl_orders 表的 skip_dns_verify 字段")
|
||||
if tx.Migrator().HasColumn(&model.SslOrder{}, "skip_dns_verify") {
|
||||
return tx.Migrator().DropColumn(&model.SslOrder{}, "skip_dns_verify")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// 执行迁移
|
||||
|
||||
@@ -31,6 +31,7 @@ func (waf *WafEngine) ApplySSLOrder(chanType int, bean model.SslOrder) {
|
||||
//加载环境变量
|
||||
privateGroupName := bean.PrivateGroupName
|
||||
privateGroupBelongCloud := bean.ApplyDns
|
||||
zlog.Debug(fmt.Sprintf("Loading DNS provider env info - Group: `%s`, Cloud: `%s` for domain: %s", privateGroupName, privateGroupBelongCloud, bean.ApplyDomain))
|
||||
//查询环境变量信息
|
||||
wafssl.LoadDnsProviderEnvInfo(privateGroupName, privateGroupBelongCloud)
|
||||
}
|
||||
|
||||
+39
-12
@@ -11,19 +11,46 @@ import (
|
||||
|
||||
// LoadDnsProviderEnvInfo 初始化dns所需要的参数信息
|
||||
func LoadDnsProviderEnvInfo(groupName string, belongCloud string) {
|
||||
privateInfos, _, err := waf_service.WafPrivateInfoServiceApp.GetListByGroupAndBelongCloudPureApi(groupName, belongCloud)
|
||||
if err == nil {
|
||||
for _, info := range privateInfos {
|
||||
err := os.Setenv(info.PrivateKey, info.PrivateValue)
|
||||
if err != nil {
|
||||
return
|
||||
} else {
|
||||
zlog.Info(fmt.Sprintf("Cloud `%s` Group `%s` ENV `%s` LOADED", belongCloud, groupName, info.PrivateKey))
|
||||
}
|
||||
}
|
||||
// 清除旧的 DNS provider 相关环境变量,防止污染
|
||||
dnsEnvKeys := []string{
|
||||
// Tencent Cloud
|
||||
"TENCENTCLOUD_SECRET_ID", "TENCENTCLOUD_SECRET_KEY", "TENCENTCLOUD_REGION",
|
||||
// Alibaba Cloud
|
||||
"ALICLOUD_ACCESS_KEY", "ALICLOUD_SECRET_KEY", "ALICLOUD_REGION_ID",
|
||||
// Huawei Cloud
|
||||
"HUAWEICLOUD_DOMAIN_NAME", "HUAWEICLOUD_ACCESS_KEY_ID", "HUAWEICLOUD_ACCESS_KEY_SECRET", "HUAWEICLOUD_REGION",
|
||||
// Cloudflare
|
||||
"CLOUDFLARE_API_TOKEN", "CLOUDFLARE_API_KEY", "CLOUDFLARE_ACCOUNT_ID",
|
||||
// Baidu Cloud
|
||||
"BAIDUCLOUD_ACCESS_KEY", "BAIDUCLOUD_SECRET_ACCESS_KEY", "BAIDUCLOUD_REGION",
|
||||
}
|
||||
for _, key := range dnsEnvKeys {
|
||||
os.Unsetenv(key)
|
||||
}
|
||||
|
||||
privateInfos, _, err := waf_service.WafPrivateInfoServiceApp.GetListByGroupAndBelongCloudPureApi(groupName, belongCloud)
|
||||
if err != nil {
|
||||
zlog.Error(fmt.Sprintf("Failed to load DNS provider env info for cloud `%s` group `%s`: %v", belongCloud, groupName, err))
|
||||
return
|
||||
}
|
||||
if len(privateInfos) == 0 {
|
||||
zlog.Warn(fmt.Sprintf("No DNS credentials found in DB for cloud `%s` group `%s` - DNS provider will have no auth", belongCloud, groupName))
|
||||
return
|
||||
}
|
||||
|
||||
for _, info := range privateInfos {
|
||||
err := os.Setenv(info.PrivateKey, info.PrivateValue)
|
||||
if err != nil {
|
||||
zlog.Error(fmt.Sprintf("Failed to set env var `%s`: %v", info.PrivateKey, err))
|
||||
return
|
||||
}
|
||||
zlog.Info(fmt.Sprintf("Cloud `%s` Group `%s` ENV `%s` LOADED", belongCloud, groupName, info.PrivateKey))
|
||||
}
|
||||
|
||||
zlog.Info(fmt.Sprintf("Successfully loaded %d credentials for cloud `%s` group `%s`", len(privateInfos), belongCloud, groupName))
|
||||
|
||||
if global.GWAF_RELEASE == "false" {
|
||||
fmt.Println("当前环境变量:")
|
||||
zlog.Debug("Current DNS-related environment variables:")
|
||||
for _, env := range os.Environ() {
|
||||
parts := strings.SplitN(env, "=", 2)
|
||||
key := parts[0]
|
||||
@@ -31,7 +58,7 @@ func LoadDnsProviderEnvInfo(groupName string, belongCloud string) {
|
||||
if len(parts) > 1 {
|
||||
value = parts[1]
|
||||
}
|
||||
fmt.Printf("%s = %s\n", key, value)
|
||||
zlog.Debug(fmt.Sprintf("%s = %s", key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user