diff --git a/README.md b/README.md index ffdb8260..fa9c4c1f 100644 --- a/README.md +++ b/README.md @@ -45,25 +45,25 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns). | | | | | |---------------------------------------------------------------------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------| -| [Alibaba Cloud DNS](https://go-acme.github.io/lego/dns/alidns/) | [Amazon Lightsail](https://go-acme.github.io/lego/dns/lightsail/) | [Amazon Route 53](https://go-acme.github.io/lego/dns/route53/) | [ArvanCloud](https://go-acme.github.io/lego/dns/arvancloud/) | -| [Aurora DNS](https://go-acme.github.io/lego/dns/auroradns/) | [Autodns](https://go-acme.github.io/lego/dns/autodns/) | [Azure](https://go-acme.github.io/lego/dns/azure/) | [Bindman](https://go-acme.github.io/lego/dns/bindman/) | -| [Bluecat](https://go-acme.github.io/lego/dns/bluecat/) | [Checkdomain](https://go-acme.github.io/lego/dns/checkdomain/) | [CloudDNS](https://go-acme.github.io/lego/dns/clouddns/) | [Cloudflare](https://go-acme.github.io/lego/dns/cloudflare/) | -| [ClouDNS](https://go-acme.github.io/lego/dns/cloudns/) | [CloudXNS](https://go-acme.github.io/lego/dns/cloudxns/) | [ConoHa](https://go-acme.github.io/lego/dns/conoha/) | [Constellix](https://go-acme.github.io/lego/dns/constellix/) | -| [deSEC.io](https://go-acme.github.io/lego/dns/desec/) | [Designate DNSaaS for Openstack](https://go-acme.github.io/lego/dns/designate/) | [Digital Ocean](https://go-acme.github.io/lego/dns/digitalocean/) | [DNS Made Easy](https://go-acme.github.io/lego/dns/dnsmadeeasy/) | -| [DNSimple](https://go-acme.github.io/lego/dns/dnsimple/) | [DNSPod](https://go-acme.github.io/lego/dns/dnspod/) | [Domain Offensive (do.de)](https://go-acme.github.io/lego/dns/dode/) | [DreamHost](https://go-acme.github.io/lego/dns/dreamhost/) | -| [Duck DNS](https://go-acme.github.io/lego/dns/duckdns/) | [Dyn](https://go-acme.github.io/lego/dns/dyn/) | [Dynu](https://go-acme.github.io/lego/dns/dynu/) | [EasyDNS](https://go-acme.github.io/lego/dns/easydns/) | -| [Exoscale](https://go-acme.github.io/lego/dns/exoscale/) | [External program](https://go-acme.github.io/lego/dns/exec/) | [FastDNS](https://go-acme.github.io/lego/dns/fastdns/) | [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/) | -| [Gandi](https://go-acme.github.io/lego/dns/gandi/) | [Glesys](https://go-acme.github.io/lego/dns/glesys/) | [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/) | [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/) | -| [Hetzner](https://go-acme.github.io/lego/dns/hetzner/) | [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/) | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) | -| [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | [Linode (deprecated)](https://go-acme.github.io/lego/dns/linode/) | -| [Linode (v4)](https://go-acme.github.io/lego/dns/linodev4/) | [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) | [Manual](https://go-acme.github.io/lego/dns/manual/) | -| [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) | [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) | -| [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | -| [NS1](https://go-acme.github.io/lego/dns/ns1/) | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | [OVH](https://go-acme.github.io/lego/dns/ovh/) | -| [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | [reg.ru](https://go-acme.github.io/lego/dns/regru/) | [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | -| [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) | [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) | [Selectel](https://go-acme.github.io/lego/dns/selectel/) | -| [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | -| [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [Yandex](https://go-acme.github.io/lego/dns/yandex/) | -| [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | | | +| [Akamai EdgeDNS](https://go-acme.github.io/lego/dns/edgedns/) | [Alibaba Cloud DNS](https://go-acme.github.io/lego/dns/alidns/) | [Amazon Lightsail](https://go-acme.github.io/lego/dns/lightsail/) | [Amazon Route 53](https://go-acme.github.io/lego/dns/route53/) | +| [ArvanCloud](https://go-acme.github.io/lego/dns/arvancloud/) | [Aurora DNS](https://go-acme.github.io/lego/dns/auroradns/) | [Autodns](https://go-acme.github.io/lego/dns/autodns/) | [Azure](https://go-acme.github.io/lego/dns/azure/) | +| [Bindman](https://go-acme.github.io/lego/dns/bindman/) | [Bluecat](https://go-acme.github.io/lego/dns/bluecat/) | [Checkdomain](https://go-acme.github.io/lego/dns/checkdomain/) | [CloudDNS](https://go-acme.github.io/lego/dns/clouddns/) | +| [Cloudflare](https://go-acme.github.io/lego/dns/cloudflare/) | [ClouDNS](https://go-acme.github.io/lego/dns/cloudns/) | [CloudXNS](https://go-acme.github.io/lego/dns/cloudxns/) | [ConoHa](https://go-acme.github.io/lego/dns/conoha/) | +| [Constellix](https://go-acme.github.io/lego/dns/constellix/) | [deSEC.io](https://go-acme.github.io/lego/dns/desec/) | [Designate DNSaaS for Openstack](https://go-acme.github.io/lego/dns/designate/) | [Digital Ocean](https://go-acme.github.io/lego/dns/digitalocean/) | +| [DNS Made Easy](https://go-acme.github.io/lego/dns/dnsmadeeasy/) | [DNSimple](https://go-acme.github.io/lego/dns/dnsimple/) | [DNSPod](https://go-acme.github.io/lego/dns/dnspod/) | [Domain Offensive (do.de)](https://go-acme.github.io/lego/dns/dode/) | +| [DreamHost](https://go-acme.github.io/lego/dns/dreamhost/) | [Duck DNS](https://go-acme.github.io/lego/dns/duckdns/) | [Dyn](https://go-acme.github.io/lego/dns/dyn/) | [Dynu](https://go-acme.github.io/lego/dns/dynu/) | +| [EasyDNS](https://go-acme.github.io/lego/dns/easydns/) | [Exoscale](https://go-acme.github.io/lego/dns/exoscale/) | [External program](https://go-acme.github.io/lego/dns/exec/) | [FastDNS (Deprecated)](https://go-acme.github.io/lego/dns/fastdns/) | +| [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/) | [Gandi](https://go-acme.github.io/lego/dns/gandi/) | [Glesys](https://go-acme.github.io/lego/dns/glesys/) | [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/) | +| [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/) | [Hetzner](https://go-acme.github.io/lego/dns/hetzner/) | [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/) | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | +| [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) | [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | +| [Linode (deprecated)](https://go-acme.github.io/lego/dns/linode/) | [Linode (v4)](https://go-acme.github.io/lego/dns/linodev4/) | [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) | +| [Manual](https://go-acme.github.io/lego/dns/manual/) | [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) | +| [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) | +| [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | [NS1](https://go-acme.github.io/lego/dns/ns1/) | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | +| [OVH](https://go-acme.github.io/lego/dns/ovh/) | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | [reg.ru](https://go-acme.github.io/lego/dns/regru/) | +| [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) | [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) | +| [Selectel](https://go-acme.github.io/lego/dns/selectel/) | [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) | +| [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) | +| [Yandex](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | | diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go index 7008b20d..70cbcefb 100644 --- a/cmd/zz_gen_cmd_dnshelp.go +++ b/cmd/zz_gen_cmd_dnshelp.go @@ -41,6 +41,7 @@ func allDNSCodes() string { "dyn", "dynu", "easydns", + "edgedns", "exec", "exoscale", "fastdns", @@ -681,6 +682,28 @@ func displayDNSHelp(name string) error { ew.writeln() ew.writeln(`More information: https://go-acme.github.io/lego/dns/easydns`) + case "edgedns": + // generated from: providers/dns/edgedns/edgedns.toml + ew.writeln(`Configuration for Akamai EdgeDNS.`) + ew.writeln(`Code: 'edgedns'`) + ew.writeln(`Since: 'v3.9.0'`) + ew.writeln() + + ew.writeln(`Credentials:`) + ew.writeln(` - "AKAMAI_ACCESS_TOKEN": Access token`) + ew.writeln(` - "AKAMAI_CLIENT_SECRET": Client secret`) + ew.writeln(` - "AKAMAI_CLIENT_TOKEN": Client token`) + ew.writeln(` - "AKAMAI_HOST": API host`) + ew.writeln() + + ew.writeln(`Additional Configuration:`) + ew.writeln(` - "AKAMAI_POLLING_INTERVAL": Time between DNS propagation check. Default: 15 seconds`) + ew.writeln(` - "AKAMAI_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation. Default: 3 minutes`) + ew.writeln(` - "AKAMAI_TTL": The TTL of the TXT record used for the DNS challenge`) + + ew.writeln() + ew.writeln(`More information: https://go-acme.github.io/lego/dns/edgedns`) + case "exec": // generated from: providers/dns/exec/exec.toml ew.writeln(`Configuration for External program.`) @@ -715,7 +738,7 @@ func displayDNSHelp(name string) error { case "fastdns": // generated from: providers/dns/fastdns/fastdns.toml - ew.writeln(`Configuration for FastDNS.`) + ew.writeln(`Configuration for FastDNS (Deprecated).`) ew.writeln(`Code: 'fastdns'`) ew.writeln(`Since: 'v0.5.0'`) ew.writeln() diff --git a/docs/content/dns/zz_gen_edgedns.md b/docs/content/dns/zz_gen_edgedns.md new file mode 100644 index 00000000..b349f7ba --- /dev/null +++ b/docs/content/dns/zz_gen_edgedns.md @@ -0,0 +1,68 @@ +--- +title: "Akamai EdgeDNS" +date: 2019-03-03T16:39:46+01:00 +draft: false +slug: edgedns +--- + + + + + +Since: v3.9.0 +Akamai edgedns supercedes fastdns; implementing a DNS provider for solving the DNS-01 challenge using Akamai EdgeDNS + + + + + +- Code: `edgedns` + +Here is an example bash command using the Akamai EdgeDNS provider: + +```bash +AKAMAI_CLIENT_SECRET=abcdefghijklmnopqrstuvwxyz1234567890ABCDEFG= \ +AKAMAI_CLIENT_TOKEN=akab-mnbvcxzlkjhgfdsapoiuytrewq1234567 \ +AKAMAI_HOST=akab-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.luna.akamaiapis.net \ +AKAMAI_ACCESS_TOKEN=akab-1234567890qwerty-asdfghjklzxcvtnu \ +lego --domains="example.zone" --email="testuser@mail.me" --dns="edgedns" -a run +``` + + + + +## Credentials + +| Environment Variable Name | Description | +|-----------------------|-------------| +| `AKAMAI_ACCESS_TOKEN` | Access token | +| `AKAMAI_CLIENT_SECRET` | Client secret | +| `AKAMAI_CLIENT_TOKEN` | Client token | +| `AKAMAI_HOST` | API host | + +The environment variable names can be suffixed by `_FILE` to reference a file instead of a value. +More information [here](/lego/dns/#configuration-and-credentials). + + +## Additional Configuration + +| Environment Variable Name | Description | +|--------------------------------|-------------| +| `AKAMAI_POLLING_INTERVAL` | Time between DNS propagation check. Default: 15 seconds | +| `AKAMAI_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation. Default: 3 minutes | +| `AKAMAI_TTL` | The TTL of the TXT record used for the DNS challenge | + +The environment variable names can be suffixed by `_FILE` to reference a file instead of a value. +More information [here](/lego/dns/#configuration-and-credentials). + + + + +## More information + +- [API documentation](https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html) +- [Go client](https://github.com/akamai/AkamaiOPEN-edgegrid-golang) + + + + diff --git a/docs/content/dns/zz_gen_fastdns.md b/docs/content/dns/zz_gen_fastdns.md index e0ed1739..f622f3cc 100644 --- a/docs/content/dns/zz_gen_fastdns.md +++ b/docs/content/dns/zz_gen_fastdns.md @@ -1,5 +1,5 @@ --- -title: "FastDNS" +title: "FastDNS (Deprecated)" date: 2019-03-03T16:39:46+01:00 draft: false slug: fastdns @@ -11,7 +11,7 @@ slug: fastdns Since: v0.5.0 -Configuration for [FastDNS](https://www.akamai.com/us/en/products/security/fast-dns.jsp). +Configuration for [FastDNS (Deprecated)](https://www.akamai.com/us/en/products/security/fast-dns.jsp). diff --git a/go.mod b/go.mod index 68ca08ed..c0b47c7e 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/Azure/go-autorest/autorest/validation v0.1.0 // indirect github.com/BurntSushi/toml v0.3.1 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 - github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.8 + github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.17 github.com/aliyun/alibaba-cloud-sdk-go v1.61.112 github.com/aws/aws-sdk-go v1.30.20 github.com/cenkalti/backoff/v4 v4.0.0 diff --git a/go.sum b/go.sum index 1a2686bd..d6d2e04b 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.8 h1:6rJvj+NXjjauunLeS7uGy891F1cuAwsWKa9iGzTjz1s= -github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.8/go.mod h1:aVvklgKsPENRkl29bNwrHISa1F+YLGTHArMxZMBqWM8= +github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.17 h1:0k+AIGfLheq1YMcrHLJsjx6r/Y9eee4cELW/gFlLUEU= +github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.17/go.mod h1:L+HB2uBoDgi3+r1pJEJcbGwyyHhd2QXaGsKLbDwtm8Q= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/aliyun/alibaba-cloud-sdk-go v1.61.112 h1:E273ePcLllLIBGg5BHr3T0Fp1BJTvUyh5Y57ziSy81w= @@ -270,6 +270,8 @@ github.com/oracle/oci-go-sdk v7.0.0+incompatible h1:oj5ESjXwwkFRdhZSnPlShvLWYdt/ github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 h1:37VE5TYj2m/FLA9SNr4z0+A0JefvTmR60Zwf8XSEV7c= github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -391,6 +393,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/providers/dns/dns_providers.go b/providers/dns/dns_providers.go index 4185ac86..29739053 100644 --- a/providers/dns/dns_providers.go +++ b/providers/dns/dns_providers.go @@ -32,6 +32,7 @@ import ( "github.com/go-acme/lego/v3/providers/dns/dyn" "github.com/go-acme/lego/v3/providers/dns/dynu" "github.com/go-acme/lego/v3/providers/dns/easydns" + "github.com/go-acme/lego/v3/providers/dns/edgedns" "github.com/go-acme/lego/v3/providers/dns/exec" "github.com/go-acme/lego/v3/providers/dns/exoscale" "github.com/go-acme/lego/v3/providers/dns/fastdns" @@ -139,6 +140,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) { return dyn.NewDNSProvider() case "dynu": return dynu.NewDNSProvider() + case "edgedns": + return edgedns.NewDNSProvider() case "fastdns": return fastdns.NewDNSProvider() case "easydns": diff --git a/providers/dns/edgedns/edgedns.go b/providers/dns/edgedns/edgedns.go new file mode 100644 index 00000000..c87d3a5d --- /dev/null +++ b/providers/dns/edgedns/edgedns.go @@ -0,0 +1,226 @@ +// Package edgedns replaces fastdns, implementing a DNS provider for solving the DNS-01 challenge using Akamai EdgeDNS. +package edgedns + +import ( + "errors" + "fmt" + "strings" + "time" + + configdns "github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v2" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" + "github.com/go-acme/lego/v3/challenge/dns01" + "github.com/go-acme/lego/v3/log" + "github.com/go-acme/lego/v3/platform/config/env" +) + +// Environment variables names. +const ( + envNamespace = "AKAMAI_" + + EnvHost = envNamespace + "HOST" + EnvClientToken = envNamespace + "CLIENT_TOKEN" + EnvClientSecret = envNamespace + "CLIENT_SECRET" + EnvAccessToken = envNamespace + "ACCESS_TOKEN" + + EnvTTL = envNamespace + "TTL" + EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" + EnvPollingInterval = envNamespace + "POLLING_INTERVAL" + + DefaultPropagationTimeout = 3 * time.Minute + DefaultPollInterval = 15 * time.Second +) + +// Config is used to configure the creation of the DNSProvider. +type Config struct { + edgegrid.Config + PropagationTimeout time.Duration + PollingInterval time.Duration + TTL int +} + +// NewDefaultConfig returns a default configuration for the DNSProvider. +func NewDefaultConfig() *Config { + return &Config{ + TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL), + PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, DefaultPropagationTimeout), + PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, DefaultPollInterval), + Config: edgegrid.Config{ + MaxBody: 131072, + }, + } +} + +// DNSProvider implements the challenge.Provider interface. +type DNSProvider struct { + config *Config +} + +// NewDNSProvider uses the supplied environment variables to return a DNSProvider instance: +// AKAMAI_HOST, AKAMAI_CLIENT_TOKEN, AKAMAI_CLIENT_SECRET, AKAMAI_ACCESS_TOKEN. +func NewDNSProvider() (*DNSProvider, error) { + values, err := env.Get(EnvHost, EnvClientToken, EnvClientSecret, EnvAccessToken) + if err != nil { + return nil, fmt.Errorf("edgedns: %w", err) + } + + config := NewDefaultConfig() + config.Config.Host = values[EnvHost] + config.Config.ClientToken = values[EnvClientToken] + config.Config.ClientSecret = values[EnvClientSecret] + config.Config.AccessToken = values[EnvAccessToken] + + return NewDNSProviderConfig(config) +} + +// NewDNSProviderConfig return a DNSProvider instance configured for EdgeDNS. +func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { + if config == nil { + return nil, errors.New("edgedns: the configuration of the DNS provider is nil") + } + + if config.ClientToken == "" || config.ClientSecret == "" || config.AccessToken == "" || config.Host == "" { + return nil, errors.New("edgedns: credentials are missing") + } + + return &DNSProvider{config: config}, nil +} + +// Timeout returns the timeout and interval to use when checking for DNS propagation. +// Adjusting here to cope with spikes in propagation times. +func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { + return d.config.PropagationTimeout, d.config.PollingInterval +} + +// Present creates a TXT record to fulfill the dns-01 challenge. +func (d *DNSProvider) Present(domain, token, keyAuth string) error { + fqdn, value := dns01.GetRecord(domain, keyAuth) + + zone, err := findZone(domain) + if err != nil { + return fmt.Errorf("edgedns: %w", err) + } + + record, err := configdns.GetRecord(zone, fqdn, "TXT") + if err != nil && !isNotFound(err) { + return fmt.Errorf("edgedns: %w", err) + } + + if err == nil && record == nil { + return fmt.Errorf("edgedns: unknown error") + } + + if record != nil { + log.Infof("TXT record already exists. Updating target") + + if containsValue(record.Target, value) { + // have a record and have entry already + return nil + } + + record.Target = append(record.Target, `"`+value+`"`) + record.TTL = d.config.TTL + + err = record.Update(zone) + if err != nil { + return fmt.Errorf("edgedns: %w", err) + } + } + + record = &configdns.RecordBody{ + Name: fqdn, + RecordType: "TXT", + TTL: d.config.TTL, + Target: []string{`"` + value + `"`}, + } + + err = record.Save(zone) + if err != nil { + return fmt.Errorf("edgedns: %w", err) + } + + return nil +} + +// CleanUp removes the record matching the specified parameters. +func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { + fqdn, value := dns01.GetRecord(domain, keyAuth) + + zone, err := findZone(domain) + if err != nil { + return fmt.Errorf("edgedns: %w", err) + } + + existingRec, err := configdns.GetRecord(zone, fqdn, "TXT") + if err != nil { + if isNotFound(err) { + return nil + } + return fmt.Errorf("edgedns: %w", err) + } + + if existingRec == nil { + return fmt.Errorf("edgedns: unknown failure") + } + + if len(existingRec.Target) == 0 { + return fmt.Errorf("edgedns: TXT record is invalid") + } + + if !containsValue(existingRec.Target, value) { + return nil + } + + var newRData []string + for _, val := range existingRec.Target { + val = strings.Trim(val, `"`) + if val == value { + continue + } + newRData = append(newRData, val) + } + + if len(newRData) > 0 { + existingRec.Target = newRData + + err = existingRec.Update(zone) + if err != nil { + return fmt.Errorf("edgedns: %w", err) + } + } + + err = existingRec.Delete(zone) + if err != nil { + return fmt.Errorf("edgedns: %w", err) + } + + return nil +} + +func findZone(domain string) (string, error) { + zone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain)) + if err != nil { + return "", err + } + + return dns01.UnFqdn(zone), nil +} + +func containsValue(values []string, value string) bool { + for _, val := range values { + if strings.Trim(val, `"`) == value { + return true + } + } + + return false +} + +func isNotFound(err error) bool { + if err == nil { + return false + } + + e, ok := err.(configdns.ConfigDNSError) + return ok && e.NotFound() +} diff --git a/providers/dns/edgedns/edgedns.toml b/providers/dns/edgedns/edgedns.toml new file mode 100644 index 00000000..59b281f7 --- /dev/null +++ b/providers/dns/edgedns/edgedns.toml @@ -0,0 +1,32 @@ +Name = "Akamai EdgeDNS" +Description = ''' +Akamai edgedns supercedes fastdns; implementing a DNS provider for solving the DNS-01 challenge using Akamai EdgeDNS +''' +URL = "https://www.akamai.com/us/en/products/security/edge-dns.jsp" +Code = "edgedns" +Since = "v3.9.0" + +Example = ''' +AKAMAI_CLIENT_SECRET=abcdefghijklmnopqrstuvwxyz1234567890ABCDEFG= \ +AKAMAI_CLIENT_TOKEN=akab-mnbvcxzlkjhgfdsapoiuytrewq1234567 \ +AKAMAI_HOST=akab-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.luna.akamaiapis.net \ +AKAMAI_ACCESS_TOKEN=akab-1234567890qwerty-asdfghjklzxcvtnu \ +lego --domains="example.zone" --email="testuser@mail.me" --dns="edgedns" -a run +''' + +[Configuration] + [Configuration.Credentials] + AKAMAI_HOST = "API host" + AKAMAI_CLIENT_TOKEN = "Client token" + AKAMAI_CLIENT_SECRET = "Client secret" + AKAMAI_ACCESS_TOKEN = "Access token" + [Configuration.Additional] + AKAMAI_POLLING_INTERVAL = "Time between DNS propagation check. Default: 15 seconds" + AKAMAI_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation. Default: 3 minutes" + AKAMAI_TTL = "The TTL of the TXT record used for the DNS challenge" + +[Links] + API = "https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html" + GoClient = "https://github.com/akamai/AkamaiOPEN-edgegrid-golang" + + diff --git a/providers/dns/edgedns/edgedns_test.go b/providers/dns/edgedns/edgedns_test.go new file mode 100644 index 00000000..51d7dfcb --- /dev/null +++ b/providers/dns/edgedns/edgedns_test.go @@ -0,0 +1,243 @@ +package edgedns + +import ( + "testing" + "time" + + "github.com/go-acme/lego/v3/platform/tester" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const envDomain = envNamespace + "TEST_DOMAIN" + +var envTest = tester.NewEnvTest( + EnvHost, + EnvClientToken, + EnvClientSecret, + EnvAccessToken). + WithDomain(envDomain) + +func TestNewDNSProvider(t *testing.T) { + testCases := []struct { + desc string + envVars map[string]string + expected string + }{ + { + desc: "success", + envVars: map[string]string{ + EnvHost: "A", + EnvClientToken: "B", + EnvClientSecret: "C", + EnvAccessToken: "D", + }, + }, + { + desc: "missing credentials", + envVars: map[string]string{ + EnvHost: "", + EnvClientToken: "", + EnvClientSecret: "", + EnvAccessToken: "", + }, + expected: "edgedns: some credentials information are missing: AKAMAI_HOST,AKAMAI_CLIENT_TOKEN,AKAMAI_CLIENT_SECRET,AKAMAI_ACCESS_TOKEN", + }, + { + desc: "missing host", + envVars: map[string]string{ + EnvHost: "", + EnvClientToken: "B", + EnvClientSecret: "C", + EnvAccessToken: "D", + }, + expected: "edgedns: some credentials information are missing: AKAMAI_HOST", + }, + { + desc: "missing client token", + envVars: map[string]string{ + EnvHost: "A", + EnvClientToken: "", + EnvClientSecret: "C", + EnvAccessToken: "D", + }, + expected: "edgedns: some credentials information are missing: AKAMAI_CLIENT_TOKEN", + }, + { + desc: "missing client secret", + envVars: map[string]string{ + EnvHost: "A", + EnvClientToken: "B", + EnvClientSecret: "", + EnvAccessToken: "D", + }, + expected: "edgedns: some credentials information are missing: AKAMAI_CLIENT_SECRET", + }, + { + desc: "missing access token", + envVars: map[string]string{ + EnvHost: "A", + EnvClientToken: "B", + EnvClientSecret: "C", + EnvAccessToken: "", + }, + expected: "edgedns: some credentials information are missing: AKAMAI_ACCESS_TOKEN", + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + defer envTest.RestoreEnv() + envTest.ClearEnv() + + envTest.Apply(test.envVars) + + p, err := NewDNSProvider() + + if len(test.expected) == 0 { + require.NoError(t, err) + require.NotNil(t, p) + require.NotNil(t, p.config) + } else { + require.EqualError(t, err, test.expected) + } + }) + } +} + +func TestNewDNSProviderConfig(t *testing.T) { + testCases := []struct { + desc string + host string + clientToken string + clientSecret string + accessToken string + expected string + }{ + { + desc: "success", + host: "A", + clientToken: "B", + clientSecret: "C", + accessToken: "D", + }, + { + desc: "missing credentials", + expected: "edgedns: credentials are missing", + }, + { + desc: "missing host", + host: "", + clientToken: "B", + clientSecret: "C", + accessToken: "D", + expected: "edgedns: credentials are missing", + }, + { + desc: "missing client token", + host: "A", + clientToken: "", + clientSecret: "C", + accessToken: "D", + expected: "edgedns: credentials are missing", + }, + { + desc: "missing client secret", + host: "A", + clientToken: "B", + clientSecret: "", + accessToken: "B", + expected: "edgedns: credentials are missing", + }, + { + desc: "missing access token", + host: "A", + clientToken: "B", + clientSecret: "C", + accessToken: "", + expected: "edgedns: credentials are missing", + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + config := NewDefaultConfig() + config.ClientToken = test.clientToken + config.ClientSecret = test.clientSecret + config.Host = test.host + config.AccessToken = test.accessToken + + p, err := NewDNSProviderConfig(config) + + if len(test.expected) == 0 { + require.NoError(t, err) + require.NotNil(t, p) + require.NotNil(t, p.config) + } else { + require.EqualError(t, err, test.expected) + } + }) + } +} + +func TestDNSProvider_findZone(t *testing.T) { + testCases := []struct { + desc string + domain string + expected string + }{ + { + desc: "Extract root record name", + domain: "bar.com", + expected: "bar.com", + }, + { + desc: "Extract sub record name", + domain: "foo.bar.com", + expected: "bar.com", + }, + } + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + zone, err := findZone(test.domain) + require.NoError(t, err) + assert.Equal(t, test.expected, zone) + }) + } +} + +func TestLivePresent(t *testing.T) { + if !envTest.IsLiveTest() { + t.Skip("skipping live test") + } + + envTest.RestoreEnv() + provider, err := NewDNSProvider() + require.NoError(t, err) + + err = provider.Present(envTest.GetDomain(), "", "123d==") + require.NoError(t, err) + + // Present Twice to handle create / update + err = provider.Present(envTest.GetDomain(), "", "123d==") + require.NoError(t, err) +} + +func TestLiveCleanUp(t *testing.T) { + if !envTest.IsLiveTest() { + t.Skip("skipping live test") + } + + envTest.RestoreEnv() + provider, err := NewDNSProvider() + require.NoError(t, err) + + time.Sleep(1 * time.Second) + + err = provider.CleanUp(envTest.GetDomain(), "", "123d==") + require.NoError(t, err) +} diff --git a/providers/dns/fastdns/fastdns.toml b/providers/dns/fastdns/fastdns.toml index 5dbae3ba..010897d7 100644 --- a/providers/dns/fastdns/fastdns.toml +++ b/providers/dns/fastdns/fastdns.toml @@ -1,4 +1,4 @@ -Name = "FastDNS" +Name = "FastDNS (Deprecated)" Description = '''''' URL = "https://www.akamai.com/us/en/products/security/fast-dns.jsp" Code = "fastdns"