1
0
mirror of https://github.com/go-acme/lego.git synced 2025-11-28 00:38:24 +02:00

edgeone: add zones mapping (#2728)

This commit is contained in:
Ludovic Fernandez
2025-11-25 19:29:47 +01:00
committed by GitHub
parent aea6afe2d6
commit 56cb356ef2
7 changed files with 61 additions and 20 deletions

View File

@@ -1342,6 +1342,7 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(` - "EDGEONE_REGION": Region`) ew.writeln(` - "EDGEONE_REGION": Region`)
ew.writeln(` - "EDGEONE_SESSION_TOKEN": Access Key token`) ew.writeln(` - "EDGEONE_SESSION_TOKEN": Access Key token`)
ew.writeln(` - "EDGEONE_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`) ew.writeln(` - "EDGEONE_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
ew.writeln(` - "EDGEONE_ZONES_MAPPING": Mapping between DNS zones and site IDs. (ex: 'example.org:id1,example.com:id2')`)
ew.writeln() ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/edgeone`) ew.writeln(`More information: https://go-acme.github.io/lego/dns/edgeone`)

View File

@@ -55,6 +55,7 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| `EDGEONE_REGION` | Region | | `EDGEONE_REGION` | Region |
| `EDGEONE_SESSION_TOKEN` | Access Key token | | `EDGEONE_SESSION_TOKEN` | Access Key token |
| `EDGEONE_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) | | `EDGEONE_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
| `EDGEONE_ZONES_MAPPING` | Mapping between DNS zones and site IDs. (ex: 'example.org:id1,example.com:id2') |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value. The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}). More information [here]({{% ref "dns#configuration-and-credentials" %}}).

View File

@@ -165,7 +165,7 @@ func (d *DNSProvider) getHostedZone(domain string) (string, string, error) {
} }
if hostedZone.ID == "" || hostedZone.ID == "0" { if hostedZone.ID == "" || hostedZone.ID == "0" {
return "", "", fmt.Errorf("zone %s not found in dnspod for domain %s", authZone, domain) return "", "", fmt.Errorf("zone %s not found for domain %s", authZone, domain)
} }
return hostedZone.ID.String(), hostedZone.Name, nil return hostedZone.ID.String(), hostedZone.Name, nil

View File

@@ -26,6 +26,7 @@ const (
EnvSecretKey = envNamespace + "SECRET_KEY" EnvSecretKey = envNamespace + "SECRET_KEY"
EnvRegion = envNamespace + "REGION" EnvRegion = envNamespace + "REGION"
EnvSessionToken = envNamespace + "SESSION_TOKEN" EnvSessionToken = envNamespace + "SESSION_TOKEN"
EnvZonesMapping = envNamespace + "ZONES_MAPPING"
EnvTTL = envNamespace + "TTL" EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@@ -40,6 +41,8 @@ type Config struct {
Region string Region string
SessionToken string SessionToken string
ZonesMapping map[string]string
PropagationTimeout time.Duration PropagationTimeout time.Duration
PollingInterval time.Duration PollingInterval time.Duration
TTL int TTL int
@@ -78,6 +81,14 @@ func NewDNSProvider() (*DNSProvider, error) {
config.Region = env.GetOrDefaultString(EnvRegion, "") config.Region = env.GetOrDefaultString(EnvRegion, "")
config.SessionToken = env.GetOrDefaultString(EnvSessionToken, "") config.SessionToken = env.GetOrDefaultString(EnvSessionToken, "")
mapping := env.GetOrDefaultString(EnvZonesMapping, "")
if mapping != "" {
config.ZonesMapping, err = env.ParsePairs(mapping)
if err != nil {
return nil, fmt.Errorf("edgeone: zones mapping: %w", err)
}
}
return NewDNSProviderConfig(config) return NewDNSProviderConfig(config)
} }
@@ -121,7 +132,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
ctx := context.Background() ctx := context.Background()
zone, err := d.getHostedZone(ctx, info.EffectiveFQDN) zoneID, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("edgeone: failed to get hosted zone: %w", err) return fmt.Errorf("edgeone: failed to get hosted zone: %w", err)
} }
@@ -133,7 +144,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
request := teo.NewCreateDnsRecordRequest() request := teo.NewCreateDnsRecordRequest()
request.Name = ptr.Pointer(punnyCoded) request.Name = ptr.Pointer(punnyCoded)
request.ZoneId = zone.ZoneId request.ZoneId = zoneID
request.Type = ptr.Pointer("TXT") request.Type = ptr.Pointer("TXT")
request.Content = ptr.Pointer(info.Value) request.Content = ptr.Pointer(info.Value)
request.TTL = ptr.Pointer(int64(d.config.TTL)) request.TTL = ptr.Pointer(int64(d.config.TTL))
@@ -156,7 +167,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
ctx := context.Background() ctx := context.Background()
zone, err := d.getHostedZone(ctx, info.EffectiveFQDN) zoneID, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
if err != nil { if err != nil {
return fmt.Errorf("edgeone: failed to get hosted zone: %w", err) return fmt.Errorf("edgeone: failed to get hosted zone: %w", err)
} }
@@ -171,7 +182,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
} }
request := teo.NewDeleteDnsRecordsRequest() request := teo.NewDeleteDnsRecordsRequest()
request.ZoneId = zone.ZoneId request.ZoneId = zoneID
request.RecordIds = []*string{recordID} request.RecordIds = []*string{recordID}
_, err = teo.DeleteDnsRecordsWithContext(ctx, d.client, request) _, err = teo.DeleteDnsRecordsWithContext(ctx, d.client, request)

View File

@@ -17,6 +17,7 @@ lego --email you@example.com --dns edgeone -d '*.example.com' -d example.com run
[Configuration.Additional] [Configuration.Additional]
EDGEONE_SESSION_TOKEN = "Access Key token" EDGEONE_SESSION_TOKEN = "Access Key token"
EDGEONE_REGION = "Region" EDGEONE_REGION = "Region"
EDGEONE_ZONES_MAPPING = "Mapping between DNS zones and site IDs. (ex: 'example.org:id1,example.com:id2')"
EDGEONE_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 30)" EDGEONE_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 30)"
EDGEONE_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 1200)" EDGEONE_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 1200)"
EDGEONE_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)" EDGEONE_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"

View File

@@ -9,8 +9,11 @@ import (
const envDomain = envNamespace + "DOMAIN" const envDomain = envNamespace + "DOMAIN"
var envTest = tester.NewEnvTest(EnvSecretID, EnvSecretKey). var envTest = tester.NewEnvTest(
WithDomain(envDomain) EnvSecretID,
EnvSecretKey,
EnvZonesMapping,
).WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) { func TestNewDNSProvider(t *testing.T) {
testCases := []struct { testCases := []struct {
@@ -25,6 +28,14 @@ func TestNewDNSProvider(t *testing.T) {
EnvSecretKey: "456", EnvSecretKey: "456",
}, },
}, },
{
desc: "success with zones mapping",
envVars: map[string]string{
EnvSecretID: "123",
EnvSecretKey: "456",
EnvZonesMapping: "example.org:id1,example.com:id2",
},
},
{ {
desc: "missing credentials", desc: "missing credentials",
envVars: map[string]string{ envVars: map[string]string{
@@ -49,6 +60,15 @@ func TestNewDNSProvider(t *testing.T) {
}, },
expected: "edgeone: some credentials information are missing: EDGEONE_SECRET_KEY", expected: "edgeone: some credentials information are missing: EDGEONE_SECRET_KEY",
}, },
{
desc: "invalid mapping",
envVars: map[string]string{
EnvSecretID: "123",
EnvSecretKey: "456",
EnvZonesMapping: "example.org:id1,example.com",
},
expected: "edgeone: zones mapping: incorrect pair: example.com",
},
} }
for _, test := range testCases { for _, test := range testCases {

View File

@@ -9,10 +9,22 @@ import (
teo "github.com/go-acme/tencentedgdeone/v20220901" teo "github.com/go-acme/tencentedgdeone/v20220901"
) )
func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (*teo.Zone, error) { func (d *DNSProvider) getHostedZoneID(ctx context.Context, domain string) (*string, error) {
authZone, err := dns01.FindZoneByFqdn(domain)
if err != nil {
return nil, fmt.Errorf("could not find zone: %w", err)
}
if d.config.ZonesMapping != nil {
zoneID, ok := d.config.ZonesMapping[authZone]
if ok {
return ptr.Pointer(zoneID), nil
}
}
request := teo.NewDescribeZonesRequest() request := teo.NewDescribeZonesRequest()
var domains []*teo.Zone var zones []*teo.Zone
for { for {
response, err := teo.DescribeZonesWithContext(ctx, d.client, request) response, err := teo.DescribeZonesWithContext(ctx, d.client, request)
@@ -20,23 +32,18 @@ func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (*teo.Zo
return nil, fmt.Errorf("API call failed: %w", err) return nil, fmt.Errorf("API call failed: %w", err)
} }
domains = append(domains, response.Response.Zones...) zones = append(zones, response.Response.Zones...)
if int64(len(domains)) >= ptr.Deref(response.Response.TotalCount) { if int64(len(zones)) >= ptr.Deref(response.Response.TotalCount) {
break break
} }
request.Offset = ptr.Pointer(int64(len(domains))) request.Offset = ptr.Pointer(int64(len(zones)))
}
authZone, err := dns01.FindZoneByFqdn(domain)
if err != nil {
return nil, fmt.Errorf("could not find zone: %w", err)
} }
var hostedZone *teo.Zone var hostedZone *teo.Zone
for _, zone := range domains { for _, zone := range zones {
unfqdn := dns01.UnFqdn(authZone) unfqdn := dns01.UnFqdn(authZone)
if ptr.Deref(zone.ZoneName) == unfqdn { if ptr.Deref(zone.ZoneName) == unfqdn {
hostedZone = zone hostedZone = zone
@@ -44,8 +51,8 @@ func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (*teo.Zo
} }
if hostedZone == nil { if hostedZone == nil {
return nil, fmt.Errorf("zone %s not found in dnspod for domain %s", authZone, domain) return nil, fmt.Errorf("zone %s not found for domain %s", authZone, domain)
} }
return hostedZone, nil return hostedZone.ZoneId, nil
} }