From 1331d656f76335c7539055064c7c01f3c4ceca2d Mon Sep 17 00:00:00 2001 From: rowanchen-com Date: Sat, 23 May 2026 21:53:44 +0800 Subject: [PATCH 1/2] feat(ssl): upgrade go-acme/lego to v5.1.0 lego v5 introduces several breaking API changes that touch every entry point we use. This commit migrates 1Panel's SSL stack to v5 and adds a data migration so existing certificates keep auto-renewing without operator action. Code changes: - AcmeUser.Key is now a crypto.Signer (was crypto.PrivateKey); same for the key returned by GetPrivateKeyByType. Account registration is now an *acme.ExtendedAccount (was *registration.Resource). - A new parsePrivateKeyPEM helper accepts both v4 (SEC1 EC, PKCS#1 RSA) and v5 (PKCS#8) key formats, so account/certificate keys persisted under v4 keep loading after the upgrade. - Obtain/ObtainForCSR/Revoke now require a context.Context. - dns01.AddRecursiveNameservers and dns01.AddDNSTimeout were removed. Recursive nameservers and timeout are now passed via dns01.SetDefaultClient(dns01.NewClient(&dns01.Options{...})). - ObtainRequest disables the CN by default in v5; we set EnableCommonName: true to preserve the v4 behaviour for legacy clients (Java keystores, embedded routers, etc.) that still rely on the CommonName field. - lego.CertificateConfig.KeyType was removed (the key type is taken from the user's account); the matching code path is dropped. - certificate.Resource.Domain was renamed to Domains (now []string). - log.Logger is now an *slog.Logger; switch website_ssl.go over to slog with a TextHandler that writes to the existing file logger. KeyType migration: - certcrypto.KeyType string values were renamed in v5: P256->EC256, P384->EC384, 2048->RSA2048, 3072->RSA3072, 4096->RSA4096, 8192->RSA8192. A gormigrate migration rewrites the key_type column in website_acme_accounts, website_ssls and website_cas on first start, so old certificates renew under their new names automatically. - A normalizeKeyType helper falls back to the same mapping at runtime, in case the database migration has not yet run. - Frontend KeyTypes select options and four form-initial keyType defaults are updated to the v5 form so newly created accounts also use the new strings. Build and vet pass on linux/amd64 (GOOS=linux GOARCH=amd64 go build/vet ./...). --- agent/app/service/website_acme_account.go | 2 +- agent/app/service/website_ca.go | 2 +- agent/app/service/website_ssl.go | 14 +- agent/go.mod | 20 +-- agent/go.sum | 40 ++--- agent/init/migration/migrate.go | 1 + agent/init/migration/migrations/init.go | 53 ++++++ agent/utils/ssl/acme.go | 163 +++++++++++------- agent/utils/ssl/client.go | 53 ++++-- agent/utils/ssl/dns_provider.go | 64 +++---- agent/utils/ssl/manual_client.go | 26 +-- frontend/src/global/mimetype.ts | 10 +- .../website/ssl/acme-account/create/index.vue | 2 +- .../src/views/website/ssl/ca/create/index.vue | 2 +- .../src/views/website/ssl/ca/obtain/index.vue | 2 +- .../src/views/website/ssl/create/index.vue | 2 +- 16 files changed, 273 insertions(+), 183 deletions(-) diff --git a/agent/app/service/website_acme_account.go b/agent/app/service/website_acme_account.go index af7fc5b29d16..5d5367c87ebe 100644 --- a/agent/app/service/website_acme_account.go +++ b/agent/app/service/website_acme_account.go @@ -68,7 +68,7 @@ func (w WebsiteAcmeAccountService) Create(create request.WebsiteAcmeAccountCreat return nil, err } acmeAccount.PrivateKey = string(privateKey) - acmeAccount.URL = client.User.Registration.URI + acmeAccount.URL = client.User.Registration.Location if err := websiteAcmeRepo.Create(*acmeAccount); err != nil { return nil, err diff --git a/agent/app/service/website_ca.go b/agent/app/service/website_ca.go index e6f899cf1e4c..6b8ffa0906b2 100644 --- a/agent/app/service/website_ca.go +++ b/agent/app/service/website_ca.go @@ -30,7 +30,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/i18n" "github.com/1Panel-dev/1Panel/agent/utils/files" "github.com/1Panel-dev/1Panel/agent/utils/ssl" - "github.com/go-acme/lego/v4/certcrypto" + "github.com/go-acme/lego/v5/certcrypto" ) type WebsiteCAService struct { diff --git a/agent/app/service/website_ssl.go b/agent/app/service/website_ssl.go index 92ac08aaa78e..51c432a86008 100644 --- a/agent/app/service/website_ssl.go +++ b/agent/app/service/website_ssl.go @@ -7,14 +7,15 @@ import ( "fmt" "io" "log" + "log/slog" "os" "path" "strconv" "strings" "time" - "github.com/go-acme/lego/v4/certificate" - legoLogger "github.com/go-acme/lego/v4/log" + "github.com/go-acme/lego/v5/certificate" + legoLogger "github.com/go-acme/lego/v5/log" "github.com/jinzhu/gorm" "github.com/1Panel-dev/1Panel/agent/app/dto/request" @@ -343,7 +344,10 @@ func (w WebsiteSSLService) obtainSSL(id uint, autoRenew bool) error { if logFile != nil { defer logFile.Close() } - legoLogger.Logger = logger + // lego v5 switched to slog. Bridge it to the existing *log.Logger + // so the SSL apply log is still written to the per-domain file + // under SSLLogDir. + legoLogger.SetDefault(slog.New(slog.NewTextHandler(logger.Writer(), nil))) startMsg := i18n.GetMsgWithMap("ApplySSLStart", map[string]interface{}{"domain": strings.Join(domains, ","), "type": i18n.GetMsgByKey(websiteSSL.Provider)}) if websiteSSL.Provider == constant.DNSAccount { startMsg = startMsg + i18n.GetMsgWithMap("DNSAccountName", map[string]interface{}{"name": dnsAccount.Name, "type": dnsAccount.Type}) @@ -470,7 +474,9 @@ func handleError(websiteSSL *model.WebsiteSSL, err error) { websiteSSL.Status = constant.SSLApplyError } websiteSSL.Message = err.Error() - legoLogger.Logger.Println(i18n.GetErrMsg("ApplySSLFailed", map[string]interface{}{"domain": websiteSSL.PrimaryDomain, "detail": err.Error()})) + // lego v5 uses slog; use the same global default logger to write the + // failure message to the SSL log. + legoLogger.Default().Error(i18n.GetErrMsg("ApplySSLFailed", map[string]interface{}{"domain": websiteSSL.PrimaryDomain, "detail": err.Error()})) _ = websiteSSLRepo.Save(websiteSSL) } diff --git a/agent/go.mod b/agent/go.mod index a148f0c9201c..6b2812c30ace 100644 --- a/agent/go.mod +++ b/agent/go.mod @@ -15,7 +15,7 @@ require ( github.com/fsnotify/fsnotify v1.9.0 github.com/gin-gonic/gin v1.12.0 github.com/glebarez/sqlite v1.11.0 - github.com/go-acme/lego/v4 v4.35.2 + github.com/go-acme/lego/v5 v5.1.0 github.com/go-gormigrate/gormigrate/v2 v2.1.5 github.com/go-playground/validator/v10 v10.30.2 github.com/go-redis/redis v6.15.9+incompatible @@ -59,7 +59,7 @@ require ( golang.org/x/text v0.37.0 golang.org/x/time v0.15.0 google.golang.org/genproto v0.0.0-20260414002931-afd174a4e478 - gopkg.in/ini.v1 v1.67.1 + gopkg.in/ini.v1 v1.67.2 gopkg.in/yaml.v3 v3.0.1 gorm.io/gorm v1.31.1 ) @@ -86,13 +86,13 @@ require ( github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect - github.com/aws/aws-sdk-go-v2/service/route53 v1.62.6 // indirect + github.com/aws/aws-sdk-go-v2/service/route53 v1.62.7 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect github.com/aws/smithy-go v1.25.1 // indirect - github.com/baidubce/bce-sdk-go v0.9.265 // indirect + github.com/baidubce/bce-sdk-go v0.9.266 // indirect github.com/bodgit/plumbing v1.3.0 // indirect github.com/bodgit/sevenzip v1.6.1 // indirect github.com/bodgit/windows v1.0.1 // indirect @@ -171,7 +171,7 @@ require ( github.com/kr/fs v0.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e // indirect - github.com/mattn/go-isatty v0.0.21 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect github.com/mattn/go-runewidth v0.0.23 // indirect github.com/mattn/go-shellwords v1.0.13 // indirect github.com/minio/crc64nvme v1.1.1 // indirect @@ -197,7 +197,6 @@ require ( github.com/mozillazg/go-httpheader v0.4.0 // indirect github.com/namedotcom/go/v4 v4.0.2 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect - github.com/nrdcg/dnspod-go v0.4.0 // indirect github.com/nrdcg/freemyip v0.3.0 // indirect github.com/nrdcg/goacmedns v0.2.0 // indirect github.com/nrdcg/namesilo v0.5.0 // indirect @@ -222,7 +221,7 @@ require ( github.com/sigstore/sigstore-go v1.1.4 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.83 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.102 // indirect github.com/therootcompany/xz v1.0.1 // indirect github.com/tinylib/msgp v1.6.4 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect @@ -236,7 +235,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect - github.com/volcengine/volc-sdk-golang v1.0.242 // indirect + github.com/volcengine/volc-sdk-golang v1.0.248 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.2.0 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect @@ -266,12 +265,13 @@ require ( golang.org/x/term v0.43.0 // indirect golang.org/x/tools v0.45.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect - google.golang.org/grpc v1.80.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/grpc v1.81.1 // indirect google.golang.org/protobuf v1.36.11 // indirect modernc.org/fileutil v1.4.0 // indirect modernc.org/libc v1.72.0 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect modernc.org/sqlite v1.48.2 // indirect + software.sslmate.com/src/go-pkcs12 v0.7.1 // indirect ) diff --git a/agent/go.sum b/agent/go.sum index 429d3ebb29d2..afbb2ff676de 100644 --- a/agent/go.sum +++ b/agent/go.sum @@ -155,8 +155,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZL github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA= -github.com/aws/aws-sdk-go-v2/service/route53 v1.62.6 h1:6b+KS0uVMMsCUKlW8OPNxmcEmoEUtqP1LfnzSzWmuQM= -github.com/aws/aws-sdk-go-v2/service/route53 v1.62.6/go.mod h1:+wmraHmxwqi7feUL/41uULJWl8V1HxtxzOJH6a4ZRg4= +github.com/aws/aws-sdk-go-v2/service/route53 v1.62.7 h1:twRRMmtSITnt/rrp+D7UDLzE5pKMZe759aalkUdN+OY= +github.com/aws/aws-sdk-go-v2/service/route53 v1.62.7/go.mod h1:ztM1lr+sRoCAI8336ZUvlRPbToue0d3gE/wd6jomSJ8= github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc= github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI= github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE= @@ -168,8 +168,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7 github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.25.1 h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI= github.com/aws/smithy-go v1.25.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= -github.com/baidubce/bce-sdk-go v0.9.265 h1:xZeLhmADeOmmV+Zlt+3TelazS0czBNXELYSPrbtU3zE= -github.com/baidubce/bce-sdk-go v0.9.265/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= +github.com/baidubce/bce-sdk-go v0.9.266 h1:MDWm/S4TNRZRH8Mo5J0t4gq34G3y2+WcbG0KCGLEpek= +github.com/baidubce/bce-sdk-go v0.9.266/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -359,8 +359,8 @@ github.com/go-acme/alidns-20150109/v4 v4.7.0 h1:PqJ/wR0JTpL4v0Owu1uM7bPQ1Yww0eQL github.com/go-acme/alidns-20150109/v4 v4.7.0/go.mod h1:btQvB6xZoN6ykKB74cPhiR+uvhrEE2AFVXm6RDmCHm0= github.com/go-acme/esa-20240910/v2 v2.48.0 h1:muSDyhjDTejxUGe3FTthCPCqRaEdYY9cG3N/AmU52Lc= github.com/go-acme/esa-20240910/v2 v2.48.0/go.mod h1:shPb6hzc1rJL15IJBY8HQ4GZk4E8RC52+52twutEwIg= -github.com/go-acme/lego/v4 v4.35.2 h1:uVQg+KC/yj9R2g7Q9W5wDqhvQvxV5SMu5eqFVoN5xZU= -github.com/go-acme/lego/v4 v4.35.2/go.mod h1:pX2jN5n8OphMGY1IaMjYm5DAEzguBaKRt8AvJAgJXpc= +github.com/go-acme/lego/v5 v5.1.0 h1:8JvnoRgH6uyFENTKS+3+JXdobpo4jYGfj4Bs4izVwmk= +github.com/go-acme/lego/v5 v5.1.0/go.mod h1:oCmaeLjpcqHmB1JGqGzsAjCMXXCPbDpNCckYv6J47m4= github.com/go-acme/tencentclouddnspod v1.3.24 h1:uCSiOW1EJttcnOON+MVVyVDJguFL/Q4NIGkq1CrT9p8= github.com/go-acme/tencentclouddnspod v1.3.24/go.mod h1:RKcB2wSoZncjBA0OEFj59s1ko1XDy+ZsAtk+9uMxUF0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -709,8 +709,8 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs= -github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-shellwords v1.0.13 h1:DC0OMEpGjm6LfNFU4ckYcvbQKyp2vE8atyFGXNtDcf4= @@ -809,8 +809,6 @@ github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJm github.com/nicksnyder/go-i18n/v2 v2.6.1 h1:JDEJraFsQE17Dut9HFDHzCoAWGEQJom5s0TRd17NIEQ= github.com/nicksnyder/go-i18n/v2 v2.6.1/go.mod h1:Vee0/9RD3Quc/NmwEjzzD7VTZ+Ir7QbXocrkhOzmUKA= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nrdcg/dnspod-go v0.4.0 h1:c/jn1mLZNKF3/osJ6mz3QPxTudvPArXTjpkmYj0uK6U= -github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ= github.com/nrdcg/freemyip v0.3.0 h1:0D2rXgvLwe2RRaVIjyUcQ4S26+cIS2iFwnhzDsEuuwc= github.com/nrdcg/freemyip v0.3.0/go.mod h1:c1PscDvA0ukBF0dwelU/IwOakNKnVxetpAQ863RMJoM= github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0= @@ -1013,8 +1011,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.24/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.83 h1:C8ro7XQVV17O+A7zUTe28VK02NuyazuaY0CB2CH5Scw= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.83/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.102 h1:3n7BpLOPnE9Rv3Y9Jxgl/XaQX3GzktO+dEaAbtVbjSk= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.102/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= github.com/tencentyun/cos-go-sdk-v5 v0.7.73 h1:uFfgp1A7cQaAGR6QP9DsIkoEQ67b8ewj5r1RV6XB540= github.com/tencentyun/cos-go-sdk-v5 v0.7.73/go.mod h1:STbTNaNKq03u+gscPEGOahKzLcGSYOj6Dzc5zNay7Pg= @@ -1062,8 +1060,8 @@ github.com/upyun/go-sdk v2.1.0+incompatible/go.mod h1:eu3F5Uz4b9ZE5bE5QsCL6mgSNW github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4= github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= -github.com/volcengine/volc-sdk-golang v1.0.242 h1:YEnYLl8mn83JCdO/X5GRDvxfxGvpUqk5j0Mj4VhwM6Y= -github.com/volcengine/volc-sdk-golang v1.0.242/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM= +github.com/volcengine/volc-sdk-golang v1.0.248 h1:2XxvADkC9Q3UNxE1/X/QhRB45Ic2z7dbH33jZurwB8I= +github.com/volcengine/volc-sdk-golang v1.0.248/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= @@ -1560,8 +1558,8 @@ google.golang.org/genproto v0.0.0-20260414002931-afd174a4e478 h1:aLsVTW0lZ8+IY5u google.golang.org/genproto v0.0.0-20260414002931-afd174a4e478/go.mod h1:YJAzKjfHIUHb9T+bfu8L7mthAp7VVXQBUs1PLdBWS7M= google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1579,8 +1577,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1609,8 +1607,8 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= -gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= +gopkg.in/ini.v1 v1.67.2 h1:JtOSMb9OuaCZKr7h5D/h6iii14sK0hLbplTc6frx4Ss= +gopkg.in/ini.v1 v1.67.2/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -1674,3 +1672,5 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +software.sslmate.com/src/go-pkcs12 v0.7.1 h1:bxkUPRsvTPNRBZa4M/aSX4PyMOEbq3V8I6hbkG4F4Q8= +software.sslmate.com/src/go-pkcs12 v0.7.1/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go index 7707272b16c4..76755271724f 100644 --- a/agent/init/migration/migrate.go +++ b/agent/init/migration/migrate.go @@ -83,6 +83,7 @@ func InitAgentDB() { migrations.AddFileManageAISettings, migrations.AddFileShareTable, migrations.AddFileHistoryTable, + migrations.MigrateLegoV5, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go index f94525b8d835..36f0c6f3b7b3 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -1260,3 +1260,56 @@ var AddFileHistoryTable = &gormigrate.Migration{ return nil }, } + +// MigrateLegoV5 normalizes data persisted under lego v4 so that lego v5 can read it. +// +// Two things changed in lego v5 that affect existing rows: +// +// 1. certcrypto.KeyType string values were renamed: +// "P256"->"EC256", "P384"->"EC384", +// "2048"->"RSA2048", "3072"->"RSA3072", "4096"->"RSA4096", "8192"->"RSA8192". +// We update every key_type column we own to the new form. +// +// 2. DnsPod provider was removed from upstream lego v5; the frontend already +// marked it deprecated. Existing DnsPod website_dns_accounts rows are kept +// so the user can decide what to do, but any website_ssls still pointing +// at a DnsPod account would fail to renew. We log a warning row count and +// leave deletion to the operator. +var MigrateLegoV5 = &gormigrate.Migration{ + ID: "20260523-migrate-lego-v5", + Migrate: func(tx *gorm.DB) error { + keyTypeMap := map[string]string{ + "P256": "EC256", + "P384": "EC384", + "2048": "RSA2048", + "3072": "RSA3072", + "4096": "RSA4096", + "8192": "RSA8192", + } + for old, neu := range keyTypeMap { + if err := tx.Model(&model.WebsiteAcmeAccount{}). + Where("key_type = ?", old). + Update("key_type", neu).Error; err != nil { + return fmt.Errorf("migrate WebsiteAcmeAccount.key_type %s->%s: %w", old, neu, err) + } + if err := tx.Model(&model.WebsiteSSL{}). + Where("key_type = ?", old). + Update("key_type", neu).Error; err != nil { + return fmt.Errorf("migrate WebsiteSSL.key_type %s->%s: %w", old, neu, err) + } + if err := tx.Model(&model.WebsiteCA{}). + Where("key_type = ?", old). + Update("key_type", neu).Error; err != nil { + return fmt.Errorf("migrate WebsiteCA.key_type %s->%s: %w", old, neu, err) + } + } + + var dnsPodCount int64 + _ = tx.Model(&model.WebsiteDnsAccount{}).Where("type = ?", "DnsPod").Count(&dnsPodCount).Error + if dnsPodCount > 0 { + global.LOG.Warnf("lego v5 removed the DnsPod provider; %d existing DnsPod DNS account(s) will not be usable for renewal -- please switch them to TencentCloud", dnsPodCount) + } + + return nil + }, +} diff --git a/agent/utils/ssl/acme.go b/agent/utils/ssl/acme.go index 3e7efc268e08..4128dfbdf58b 100644 --- a/agent/utils/ssl/acme.go +++ b/agent/utils/ssl/acme.go @@ -1,6 +1,7 @@ package ssl import ( + "context" "crypto" "crypto/ecdsa" "crypto/rsa" @@ -10,9 +11,6 @@ import ( "encoding/pem" "errors" "fmt" - "github.com/1Panel-dev/1Panel/agent/app/dto" - "github.com/1Panel-dev/1Panel/agent/buserr" - "golang.org/x/crypto/acme" "io" "net" "net/http" @@ -22,14 +20,45 @@ import ( "strings" "time" + "golang.org/x/crypto/acme" + + "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/model" - "github.com/go-acme/lego/v4/certcrypto" - "github.com/go-acme/lego/v4/lego" - "github.com/go-acme/lego/v4/registration" + "github.com/1Panel-dev/1Panel/agent/buserr" + legoacme "github.com/go-acme/lego/v5/acme" + "github.com/go-acme/lego/v5/certcrypto" + "github.com/go-acme/lego/v5/lego" + "github.com/go-acme/lego/v5/registration" ) var Orders = make(map[uint]*acme.Order) +// parsePrivateKeyPEM decodes a PEM-encoded private key produced by either +// lego v4 (SEC1 for EC, PKCS#1 for RSA) or lego v5 (PKCS#8 for both). It tries +// PKCS#8 first because that is what v5 and any modern tooling emits, then +// falls back to the legacy formats so account keys persisted under v4 keep +// working without manual conversion. +func parsePrivateKeyPEM(pemBytes []byte) (crypto.Signer, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return nil, buserr.New("invalid PEM block") + } + if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil { + signer, ok := key.(crypto.Signer) + if !ok { + return nil, fmt.Errorf("PKCS#8 key does not implement crypto.Signer") + } + return signer, nil + } + if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil { + return key, nil + } + if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil { + return key, nil + } + return nil, fmt.Errorf("unsupported private key format") +} + type zeroSSLRes struct { Success bool `json:"success"` EabKid string `json:"eab_kid"` @@ -46,20 +75,44 @@ const ( KeyRSA4096 = certcrypto.RSA4096 ) +// normalizeKeyType maps legacy v4 KeyType strings (P256/P384/2048/...) to v5 form (EC256/EC384/RSA2048/...). +// Used as a safety net in case database migration has not run yet. +func normalizeKeyType(stored string) KeyType { + switch stored { + case "P256": + return certcrypto.EC256 + case "P384": + return certcrypto.EC384 + case "2048": + return certcrypto.RSA2048 + case "3072": + return certcrypto.RSA3072 + case "4096": + return certcrypto.RSA4096 + case "8192": + return certcrypto.RSA8192 + default: + return KeyType(stored) + } +} + +// AcmeUser implements registration.User. Key is crypto.Signer +// (lego v5 changed the field type from crypto.PrivateKey to crypto.Signer). type AcmeUser struct { Email string - Registration *registration.Resource - Key crypto.PrivateKey + Registration *legoacme.ExtendedAccount + Key crypto.Signer } func (u *AcmeUser) GetEmail() string { return u.Email } -func (u *AcmeUser) GetRegistration() *registration.Resource { +func (u *AcmeUser) GetRegistration() *legoacme.ExtendedAccount { return u.Registration } -func (u *AcmeUser) GetPrivateKey() crypto.PrivateKey { + +func (u *AcmeUser) GetPrivateKey() crypto.Signer { return u.Key } @@ -95,31 +148,28 @@ func GetPrivateKey(priKey crypto.PrivateKey, keyType KeyType) ([]byte, error) { func NewRegisterClient(acmeAccount *model.WebsiteAcmeAccount, proxy *dto.SystemProxy) (*AcmeClient, error) { var ( - priKey crypto.PrivateKey + priKey crypto.Signer err error ) + keyType := normalizeKeyType(acmeAccount.KeyType) + if acmeAccount.PrivateKey != "" { - switch KeyType(acmeAccount.KeyType) { - case KeyEC256, KeyEC384: - block, _ := pem.Decode([]byte(acmeAccount.PrivateKey)) - priKey, err = x509.ParseECPrivateKey(block.Bytes) - if err != nil { - return nil, err - } - case KeyRSA2048, KeyRSA3072, KeyRSA4096: - block, _ := pem.Decode([]byte(acmeAccount.PrivateKey)) - priKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return nil, err - } + signer, parseErr := parsePrivateKeyPEM([]byte(acmeAccount.PrivateKey)) + if parseErr != nil { + return nil, parseErr } - + priKey = signer } else { - priKey, err = certcrypto.GeneratePrivateKey(KeyType(acmeAccount.KeyType)) - if err != nil { - return nil, err + generated, genErr := certcrypto.GeneratePrivateKey(keyType) + if genErr != nil { + return nil, genErr + } + signer, ok := generated.(crypto.Signer) + if !ok { + return nil, fmt.Errorf("generated key does not implement crypto.Signer") } + priKey = signer } myUser := &AcmeUser{ @@ -131,7 +181,10 @@ func NewRegisterClient(acmeAccount *model.WebsiteAcmeAccount, proxy *dto.SystemP if err != nil { return nil, err } - var reg *registration.Resource + + ctx := context.Background() + + var reg *legoacme.ExtendedAccount if acmeAccount.Type == "zerossl" || acmeAccount.Type == "google" || acmeAccount.Type == "freessl" || (acmeAccount.Type == "custom" && acmeAccount.UseEAB) { if acmeAccount.Type == "zerossl" { var res *zeroSSLRes @@ -152,12 +205,12 @@ func NewRegisterClient(acmeAccount *model.WebsiteAcmeAccount, proxy *dto.SystemP Kid: acmeAccount.EabKid, HmacEncoded: acmeAccount.EabHmacKey, } - reg, err = client.Registration.RegisterWithExternalAccountBinding(eabOptions) + reg, err = client.Registration.RegisterWithExternalAccountBinding(ctx, eabOptions) if err != nil { return nil, err } } else { - reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) + reg, err = client.Registration.Register(ctx, registration.RegisterOptions{TermsOfServiceAgreed: true}) if err != nil { return nil, err } @@ -205,13 +258,14 @@ func NewConfigWithProxy(user registration.User, accountType, customCaURL string, proxyUser = systemProxy.User proxyPassword = systemProxy.Password } + // lego v5 removed lego.CertificateConfig.KeyType; the key type is now + // taken from the user's account for each ObtainRequest call. return &lego.Config{ CADirURL: caDirURL, UserAgent: "1Panel", User: user, HTTPClient: createHTTPClientWithProxy(proxyURL, proxyUser, proxyPassword), Certificate: lego.CertificateConfig{ - KeyType: certcrypto.RSA2048, Timeout: 60 * time.Second, }, } @@ -312,38 +366,21 @@ func getZeroSSLEabCredentials(email string) (*zeroSSLRes, error) { return &result, nil } -func GetPrivateKeyByType(keyType, sslPrivateKey string) (crypto.PrivateKey, error) { - var ( - privateKey crypto.PrivateKey - err error - ) - kType := KeyType(keyType) +// GetPrivateKeyByType returns a crypto.Signer (lego v5 changed from crypto.PrivateKey). +func GetPrivateKeyByType(keyType, sslPrivateKey string) (crypto.Signer, error) { + kType := normalizeKeyType(keyType) if sslPrivateKey == "" { - privateKey, err = certcrypto.GeneratePrivateKey(kType) - if err != nil { - return nil, err + generated, genErr := certcrypto.GeneratePrivateKey(kType) + if genErr != nil { + return nil, genErr } - return privateKey, nil - } - block, _ := pem.Decode([]byte(sslPrivateKey)) - if block == nil { - return nil, buserr.New("invalid PEM block") - } - var privKey crypto.PrivateKey - switch kType { - case certcrypto.EC256, certcrypto.EC384: - privKey, err = x509.ParseECPrivateKey(block.Bytes) - if err != nil { - return nil, err - } - case certcrypto.RSA2048, certcrypto.RSA3072, certcrypto.RSA4096: - privKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return nil, err + signer, ok := generated.(crypto.Signer) + if !ok { + return nil, fmt.Errorf("generated key does not implement crypto.Signer") } + return signer, nil } - privateKey = privKey - return privateKey, nil + return parsePrivateKeyPEM([]byte(sslPrivateKey)) } func getWebsiteSSLDomains(websiteSSL *model.WebsiteSSL) []string { @@ -359,19 +396,19 @@ const ( retryDelayOn503 = 30 * time.Second ) -// isHTTP503Error checks if an error is an HTTP 503 Service Unavailable error +// isHTTP503Error checks if an error is an HTTP 503 Service Unavailable error. func isHTTP503Error(err error) bool { if err == nil { return false } - // Check for golang.org/x/crypto/acme.Error (used in manual_client.go) + // Check for golang.org/x/crypto/acme.Error (used in manual_client.go). var acmeErr *acme.Error if errors.As(err, &acmeErr) { return acmeErr.StatusCode == http.StatusServiceUnavailable } - // Check error message for 503 (fallback for lego library errors) + // Check error message for 503 (fallback for lego library errors). errMsg := err.Error() return strings.Contains(errMsg, "503") || strings.Contains(errMsg, "Service busy") diff --git a/agent/utils/ssl/client.go b/agent/utils/ssl/client.go index 9d349fa674c0..032e4b1bcbff 100644 --- a/agent/utils/ssl/client.go +++ b/agent/utils/ssl/client.go @@ -1,6 +1,7 @@ package ssl import ( + "context" "crypto" "crypto/rand" "crypto/x509" @@ -12,10 +13,10 @@ import ( "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/global" - "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/providers/http/webroot" + "github.com/go-acme/lego/v5/certificate" + "github.com/go-acme/lego/v5/challenge/dns01" + "github.com/go-acme/lego/v5/lego" + "github.com/go-acme/lego/v5/providers/http/webroot" "github.com/pkg/errors" ) @@ -62,13 +63,19 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string, websiteSSL model.Web _ = os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "false") } - return c.Client.Challenge.SetDNS01Provider(p, - dns01.CondOption(len(nameservers) > 0, - dns01.AddRecursiveNameservers(nameservers)), - dns01.CondOption(websiteSSL.SkipDNS, - dns01.DisableAuthoritativeNssPropagationRequirement()), - dns01.AddDNSTimeout(dnsTimeOut), - ) + // lego v5 removed dns01.AddRecursiveNameservers and dns01.AddDNSTimeout; + // configure them via dns01.NewClient(&dns01.Options{...}) + SetDefaultClient. + dns01.SetDefaultClient(dns01.NewClient(&dns01.Options{ + RecursiveNameservers: nameservers, + Timeout: dnsTimeOut, + })) + + var opts []dns01.ChallengeOption + if websiteSSL.SkipDNS { + opts = append(opts, dns01.DisableAuthoritativeNssPropagationRequirement()) + } + + return c.Client.Challenge.SetDNS01Provider(p, opts...) } func (c *AcmeClient) UseHTTP(path string) error { @@ -84,18 +91,24 @@ func (c *AcmeClient) UseHTTP(path string) error { return nil } -func (c *AcmeClient) ObtainSSL(domains []string, privateKey crypto.PrivateKey) (certificate.Resource, error) { +func (c *AcmeClient) ObtainSSL(domains []string, privateKey crypto.Signer) (certificate.Resource, error) { + // lego v5 disables Common Name by default; explicitly enable it to keep + // the v4 behaviour, so legacy Java/router clients that still rely on the + // CommonName field do not fail TLS handshake. request := certificate.ObtainRequest{ - Domains: domains, - Bundle: true, - PrivateKey: privateKey, + Domains: domains, + Bundle: true, + PrivateKey: privateKey, + EnableCommonName: true, } + ctx := context.Background() + var certificates *certificate.Resource var err error for attempt := 1; attempt <= maxRetryAttempts; attempt++ { - certificates, err = c.Client.Certificate.Obtain(request) + certificates, err = c.Client.Certificate.Obtain(ctx, request) if err == nil { return *certificates, nil } @@ -114,7 +127,7 @@ func (c *AcmeClient) ObtainSSL(domains []string, privateKey crypto.PrivateKey) ( return certificate.Resource{}, err } -func (c *AcmeClient) ObtainIPSSL(ipAddress string, privKey crypto.PrivateKey) (certificate.Resource, error) { +func (c *AcmeClient) ObtainIPSSL(ipAddress string, privKey crypto.Signer) (certificate.Resource, error) { csrTemplate := &x509.CertificateRequest{ Subject: pkix.Name{ CommonName: "", @@ -142,9 +155,11 @@ func (c *AcmeClient) ObtainIPSSL(ipAddress string, privKey crypto.PrivateKey) (c Bundle: true, } + ctx := context.Background() + var certificates *certificate.Resource for attempt := 1; attempt <= maxRetryAttempts; attempt++ { - certificates, err = c.Client.Certificate.ObtainForCSR(req) + certificates, err = c.Client.Certificate.ObtainForCSR(ctx, req) if err == nil { return *certificates, nil } @@ -163,5 +178,5 @@ func (c *AcmeClient) ObtainIPSSL(ipAddress string, privKey crypto.PrivateKey) (c } func (c *AcmeClient) RevokeSSL(pemSSL []byte) error { - return c.Client.Certificate.Revoke(pemSSL) + return c.Client.Certificate.Revoke(context.Background(), pemSSL) } diff --git a/agent/utils/ssl/dns_provider.go b/agent/utils/ssl/dns_provider.go index 141c2287e34c..3d2d0c644839 100644 --- a/agent/utils/ssl/dns_provider.go +++ b/agent/utils/ssl/dns_provider.go @@ -2,40 +2,39 @@ package ssl import ( "encoding/json" - "github.com/go-acme/lego/v4/challenge" - "github.com/go-acme/lego/v4/providers/dns/acmedns" - "github.com/go-acme/lego/v4/providers/dns/alidns" - "github.com/go-acme/lego/v4/providers/dns/aliesa" - "github.com/go-acme/lego/v4/providers/dns/baiducloud" - "github.com/go-acme/lego/v4/providers/dns/clouddns" - "github.com/go-acme/lego/v4/providers/dns/cloudflare" - "github.com/go-acme/lego/v4/providers/dns/cloudns" - "github.com/go-acme/lego/v4/providers/dns/dnspod" - "github.com/go-acme/lego/v4/providers/dns/dynu" - "github.com/go-acme/lego/v4/providers/dns/freemyip" - "github.com/go-acme/lego/v4/providers/dns/godaddy" - "github.com/go-acme/lego/v4/providers/dns/huaweicloud" - "github.com/go-acme/lego/v4/providers/dns/namecheap" - "github.com/go-acme/lego/v4/providers/dns/namedotcom" - "github.com/go-acme/lego/v4/providers/dns/namesilo" - "github.com/go-acme/lego/v4/providers/dns/ovh" - "github.com/go-acme/lego/v4/providers/dns/porkbun" - "github.com/go-acme/lego/v4/providers/dns/rainyun" - "github.com/go-acme/lego/v4/providers/dns/regru" - "github.com/go-acme/lego/v4/providers/dns/route53" - "github.com/go-acme/lego/v4/providers/dns/spaceship" - "github.com/go-acme/lego/v4/providers/dns/technitium" - "github.com/go-acme/lego/v4/providers/dns/tencentcloud" - "github.com/go-acme/lego/v4/providers/dns/vercel" - "github.com/go-acme/lego/v4/providers/dns/volcengine" - "github.com/go-acme/lego/v4/providers/dns/westcn" "time" + + "github.com/go-acme/lego/v5/challenge" + "github.com/go-acme/lego/v5/providers/dns/acmedns" + "github.com/go-acme/lego/v5/providers/dns/alidns" + "github.com/go-acme/lego/v5/providers/dns/aliesa" + "github.com/go-acme/lego/v5/providers/dns/baiducloud" + "github.com/go-acme/lego/v5/providers/dns/clouddns" + "github.com/go-acme/lego/v5/providers/dns/cloudflare" + "github.com/go-acme/lego/v5/providers/dns/cloudns" + "github.com/go-acme/lego/v5/providers/dns/dynu" + "github.com/go-acme/lego/v5/providers/dns/freemyip" + "github.com/go-acme/lego/v5/providers/dns/godaddy" + "github.com/go-acme/lego/v5/providers/dns/huaweicloud" + "github.com/go-acme/lego/v5/providers/dns/namecheap" + "github.com/go-acme/lego/v5/providers/dns/namedotcom" + "github.com/go-acme/lego/v5/providers/dns/namesilo" + "github.com/go-acme/lego/v5/providers/dns/ovh" + "github.com/go-acme/lego/v5/providers/dns/porkbun" + "github.com/go-acme/lego/v5/providers/dns/rainyun" + "github.com/go-acme/lego/v5/providers/dns/regru" + "github.com/go-acme/lego/v5/providers/dns/route53" + "github.com/go-acme/lego/v5/providers/dns/spaceship" + "github.com/go-acme/lego/v5/providers/dns/technitium" + "github.com/go-acme/lego/v5/providers/dns/tencentcloud" + "github.com/go-acme/lego/v5/providers/dns/vercel" + "github.com/go-acme/lego/v5/providers/dns/volcengine" + "github.com/go-acme/lego/v5/providers/dns/westcn" ) type DnsType string const ( - DnsPod DnsType = "DnsPod" AliYun DnsType = "AliYun" AliESA DnsType = "AliESA" AWSRoute53 DnsType = "AWSRoute53" @@ -60,7 +59,7 @@ const ( Ovh DnsType = "Ovh" AcmeDNS DnsType = "AcmeDNS" PorkBun DnsType = "PorkBun" - Technitium DnsType = "Technitium" + Technitium DnsType = "Technitium" ) type DNSParam struct { @@ -103,13 +102,6 @@ func getDNSProviderConfig(dnsType DnsType, params string) (challenge.Provider, e return nil, err } switch dnsType { - case DnsPod: - config := dnspod.NewDefaultConfig() - config.LoginToken = param.ID + "," + param.Token - config.PropagationTimeout = propagationTimeout - config.PollingInterval = pollingInterval - config.TTL = ttl - p, err = dnspod.NewDNSProviderConfig(config) case AliYun: config := alidns.NewDefaultConfig() config.SecretKey = param.SecretKey diff --git a/agent/utils/ssl/manual_client.go b/agent/utils/ssl/manual_client.go index 655de5524bb7..772f568daae2 100644 --- a/agent/utils/ssl/manual_client.go +++ b/agent/utils/ssl/manual_client.go @@ -11,7 +11,7 @@ import ( "encoding/pem" "fmt" "github.com/1Panel-dev/1Panel/agent/app/model" - "github.com/go-acme/lego/v4/certificate" + "github.com/go-acme/lego/v5/certificate" "github.com/miekg/dns" "golang.org/x/crypto/acme" "log" @@ -31,30 +31,16 @@ type RequestCertRequest struct { } func NewCustomAcmeClient(acmeAccount *model.WebsiteAcmeAccount, logger *log.Logger) (*ManualClient, error) { - var ( - key crypto.PrivateKey - err error - ) - switch KeyType(acmeAccount.KeyType) { - case KeyEC256, KeyEC384: - block, _ := pem.Decode([]byte(acmeAccount.PrivateKey)) - key, err = x509.ParseECPrivateKey(block.Bytes) - if err != nil { - return nil, err - } - case KeyRSA2048, KeyRSA3072, KeyRSA4096: - block, _ := pem.Decode([]byte(acmeAccount.PrivateKey)) - key, err = x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return nil, err - } + key, err := parsePrivateKeyPEM([]byte(acmeAccount.PrivateKey)) + if err != nil { + return nil, err } if logger == nil { logger = log.Default() } client := &acme.Client{ - Key: key.(crypto.Signer), + Key: key, DirectoryURL: getCaDirURL(acmeAccount.Type, acmeAccount.CaDirURL), } return &ManualClient{ @@ -355,7 +341,7 @@ func (c *ManualClient) RequestCertificate(ctx context.Context, websiteSSL *model } c.logger.Printf("[INFO] acme: Server responded with a certificate.") resource := certificate.Resource{ - Domain: domains[0], + Domains: domains, CertURL: certURL, CertStableURL: certURL, PrivateKey: []byte(privateKeyPEM), diff --git a/frontend/src/global/mimetype.ts b/frontend/src/global/mimetype.ts index 8811f2e047a2..18bb6af1e060 100644 --- a/frontend/src/global/mimetype.ts +++ b/frontend/src/global/mimetype.ts @@ -168,11 +168,11 @@ export const AcmeAccountTypes = [ ]; export const KeyTypes = [ - { label: 'EC 256', value: 'P256' }, - { label: 'EC 384', value: 'P384' }, - { label: 'RSA 2048', value: '2048' }, - { label: 'RSA 3072', value: '3072' }, - { label: 'RSA 4096', value: '4096' }, + { label: 'EC 256', value: 'EC256' }, + { label: 'EC 384', value: 'EC384' }, + { label: 'RSA 2048', value: 'RSA2048' }, + { label: 'RSA 3072', value: 'RSA3072' }, + { label: 'RSA 4096', value: 'RSA4096' }, ]; export const DNSTypes = [ diff --git a/frontend/src/views/website/ssl/acme-account/create/index.vue b/frontend/src/views/website/ssl/acme-account/create/index.vue index cbaa11af5d02..6e8b4c6c7af3 100644 --- a/frontend/src/views/website/ssl/acme-account/create/index.vue +++ b/frontend/src/views/website/ssl/acme-account/create/index.vue @@ -111,7 +111,7 @@ const initData = () => ({ type: 'letsencrypt', eabKid: '', eabHmacKey: '', - keyType: 'P256', + keyType: 'EC256', useProxy: false, caDirURL: '', useEAB: false, diff --git a/frontend/src/views/website/ssl/ca/create/index.vue b/frontend/src/views/website/ssl/ca/create/index.vue index 5f1cb375daa4..35ea352abe42 100644 --- a/frontend/src/views/website/ssl/ca/create/index.vue +++ b/frontend/src/views/website/ssl/ca/create/index.vue @@ -72,7 +72,7 @@ const rules = ref({ const initData = () => ({ name: '', - keyType: 'P256', + keyType: 'EC256', commonName: '', country: 'CN', organization: '', diff --git a/frontend/src/views/website/ssl/ca/obtain/index.vue b/frontend/src/views/website/ssl/ca/obtain/index.vue index 751cc70916d5..3250fd29ac0e 100644 --- a/frontend/src/views/website/ssl/ca/obtain/index.vue +++ b/frontend/src/views/website/ssl/ca/obtain/index.vue @@ -103,7 +103,7 @@ const rules = ref({ }); const initData = () => ({ - keyType: 'P256', + keyType: 'EC256', domains: '', id: 0, time: 10, diff --git a/frontend/src/views/website/ssl/create/index.vue b/frontend/src/views/website/ssl/create/index.vue index c00914bd4bf4..eb426ff7115f 100644 --- a/frontend/src/views/website/ssl/create/index.vue +++ b/frontend/src/views/website/ssl/create/index.vue @@ -242,7 +242,7 @@ const initData = () => ({ acmeAccountId: undefined, dnsAccountId: undefined, autoRenew: true, - keyType: 'P256', + keyType: 'EC256', pushDir: false, dir: '', description: '', From 08c8924a3c3853455b27bffe4f1c672523f174e8 Mon Sep 17 00:00:00 2001 From: rowanchen-com Date: Sat, 23 May 2026 21:59:19 +0800 Subject: [PATCH 2/2] feat(ssl): add Dynadot DNS provider, drop DnsPod Dynadot was added to upstream lego in v5.1.0 (go-acme/lego#3125). Wire it into the same DNS provider switch the other 25 providers use, and surface it in the frontend so users can pick it in the DNS account dialog. DnsPod is removed from the DNS provider list. lego v5 has no DnsPod implementation; the previous frontend already showed a deprecation hint pointing at TencentCloud, which is now the recommended way to manage DNSPod-hosted zones (the underlying API is the same). --- agent/utils/ssl/dns_provider.go | 10 ++++++++++ frontend/src/global/mimetype.ts | 4 ++-- .../website/ssl/dns-account/create/index.vue | 16 +++------------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/agent/utils/ssl/dns_provider.go b/agent/utils/ssl/dns_provider.go index 3d2d0c644839..efcc859db64d 100644 --- a/agent/utils/ssl/dns_provider.go +++ b/agent/utils/ssl/dns_provider.go @@ -12,6 +12,7 @@ import ( "github.com/go-acme/lego/v5/providers/dns/clouddns" "github.com/go-acme/lego/v5/providers/dns/cloudflare" "github.com/go-acme/lego/v5/providers/dns/cloudns" + "github.com/go-acme/lego/v5/providers/dns/dynadot" "github.com/go-acme/lego/v5/providers/dns/dynu" "github.com/go-acme/lego/v5/providers/dns/freemyip" "github.com/go-acme/lego/v5/providers/dns/godaddy" @@ -55,6 +56,7 @@ const ( ClouDNS DnsType = "ClouDNS" RegRu DnsType = "RegRu" Dynu DnsType = "Dynu" + Dynadot DnsType = "Dynadot" BaiduCloud DnsType = "BaiduCloud" Ovh DnsType = "Ovh" AcmeDNS DnsType = "AcmeDNS" @@ -266,6 +268,14 @@ func getDNSProviderConfig(dnsType DnsType, params string) (challenge.Provider, e config.PollingInterval = pollingInterval config.TTL = ttl p, err = dynu.NewDNSProviderConfig(config) + case Dynadot: + config := dynadot.NewDefaultConfig() + config.APIKey = param.APIkey + config.APISecret = param.APISecret + config.PropagationTimeout = propagationTimeout + config.PollingInterval = pollingInterval + config.TTL = ttl + p, err = dynadot.NewDNSProviderConfig(config) case BaiduCloud: config := baiducloud.NewDefaultConfig() config.AccessKeyID = param.AccessKey diff --git a/frontend/src/global/mimetype.ts b/frontend/src/global/mimetype.ts index 18bb6af1e060..bb707add4d9b 100644 --- a/frontend/src/global/mimetype.ts +++ b/frontend/src/global/mimetype.ts @@ -273,8 +273,8 @@ export const DNSTypes = [ value: 'PorkBun', }, { - label: 'DNSPod (' + i18n.global.t('ssl.deprecated') + ')', - value: 'DnsPod', + label: 'Dynadot', + value: 'Dynadot', }, { label: 'Technitium', diff --git a/frontend/src/views/website/ssl/dns-account/create/index.vue b/frontend/src/views/website/ssl/dns-account/create/index.vue index 6633d31d95f4..faff8995babb 100644 --- a/frontend/src/views/website/ssl/dns-account/create/index.vue +++ b/frontend/src/views/website/ssl/dns-account/create/index.vue @@ -15,9 +15,6 @@ :value="type.value" > - - {{ $t('ssl.deprecatedHelper') }} -
-
- - - - - - -
@@ -93,6 +82,7 @@ account.type === 'Godaddy' || account.type === 'RainYun' || account.type === 'Spaceship' || + account.type === 'Dynadot' || account.type === 'Dynu' " > @@ -104,7 +94,7 @@ @@ -260,7 +250,7 @@ const resetForm = () => { account.value = { id: 0, name: '', - type: 'DnsPod', + type: 'AliYun', authorization: {}, }; accountForm.value?.resetFields();