forked from TrueCloudLab/lego
Move providers out of ACME package.
This commit is contained in:
parent
39eef1c2f6
commit
b412c67aa6
13 changed files with 93 additions and 49 deletions
|
@ -234,24 +234,6 @@ func findZoneByFqdn(fqdn, nameserver string) (string, error) {
|
||||||
return "", fmt.Errorf("NS %s did not return the expected SOA record in the authority section", nameserver)
|
return "", fmt.Errorf("NS %s did not return the expected SOA record in the authority section", nameserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
// toFqdn converts the name into a fqdn appending a trailing dot.
|
|
||||||
func toFqdn(name string) string {
|
|
||||||
n := len(name)
|
|
||||||
if n == 0 || name[n-1] == '.' {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
return name + "."
|
|
||||||
}
|
|
||||||
|
|
||||||
// unFqdn converts the fqdn into a name removing the trailing dot.
|
|
||||||
func unFqdn(name string) string {
|
|
||||||
n := len(name)
|
|
||||||
if n != 0 && name[n-1] == '.' {
|
|
||||||
return name[:n-1]
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearFqdnCache clears the cache of fqdn to zone mappings. Primarily used in testing.
|
// clearFqdnCache clears the cache of fqdn to zone mappings. Primarily used in testing.
|
||||||
func clearFqdnCache() {
|
func clearFqdnCache() {
|
||||||
fqdnToZone = map[string]string{}
|
fqdnToZone = map[string]string{}
|
||||||
|
|
|
@ -11,6 +11,11 @@ import (
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/xenolf/lego/acme"
|
"github.com/xenolf/lego/acme"
|
||||||
|
"github.com/xenolf/lego/providers/dns/cloudflare"
|
||||||
|
"github.com/xenolf/lego/providers/dns/digitalocean"
|
||||||
|
"github.com/xenolf/lego/providers/dns/dnsimple"
|
||||||
|
"github.com/xenolf/lego/providers/dns/rfc2136"
|
||||||
|
"github.com/xenolf/lego/providers/dns/route53"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkFolder(path string) error {
|
func checkFolder(path string) error {
|
||||||
|
@ -67,23 +72,23 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
|
||||||
var provider acme.ChallengeProvider
|
var provider acme.ChallengeProvider
|
||||||
switch c.GlobalString("dns") {
|
switch c.GlobalString("dns") {
|
||||||
case "cloudflare":
|
case "cloudflare":
|
||||||
provider, err = acme.NewDNSProviderCloudFlare("", "")
|
provider, err = cloudflare.NewDNSProviderCloudFlare("", "")
|
||||||
case "digitalocean":
|
case "digitalocean":
|
||||||
authToken := os.Getenv("DO_AUTH_TOKEN")
|
authToken := os.Getenv("DO_AUTH_TOKEN")
|
||||||
|
|
||||||
provider, err = acme.NewDNSProviderDigitalOcean(authToken)
|
provider, err = digitalocean.NewDNSProviderDigitalOcean(authToken)
|
||||||
case "dnsimple":
|
case "dnsimple":
|
||||||
provider, err = acme.NewDNSProviderDNSimple("", "")
|
provider, err = dnsimple.NewDNSProviderDNSimple("", "")
|
||||||
case "route53":
|
case "route53":
|
||||||
awsRegion := os.Getenv("AWS_REGION")
|
awsRegion := os.Getenv("AWS_REGION")
|
||||||
provider, err = acme.NewDNSProviderRoute53("", "", awsRegion)
|
provider, err = route53.NewDNSProviderRoute53("", "", awsRegion)
|
||||||
case "rfc2136":
|
case "rfc2136":
|
||||||
nameserver := os.Getenv("RFC2136_NAMESERVER")
|
nameserver := os.Getenv("RFC2136_NAMESERVER")
|
||||||
tsigAlgorithm := os.Getenv("RFC2136_TSIG_ALGORITHM")
|
tsigAlgorithm := os.Getenv("RFC2136_TSIG_ALGORITHM")
|
||||||
tsigKey := os.Getenv("RFC2136_TSIG_KEY")
|
tsigKey := os.Getenv("RFC2136_TSIG_KEY")
|
||||||
tsigSecret := os.Getenv("RFC2136_TSIG_SECRET")
|
tsigSecret := os.Getenv("RFC2136_TSIG_SECRET")
|
||||||
|
|
||||||
provider, err = acme.NewDNSProviderRFC2136(nameserver, tsigAlgorithm, tsigKey, tsigSecret)
|
provider, err = rfc2136.NewDNSProviderRFC2136(nameserver, tsigAlgorithm, tsigKey, tsigSecret)
|
||||||
case "manual":
|
case "manual":
|
||||||
provider, err = acme.NewDNSProviderManual()
|
provider, err = acme.NewDNSProviderManual()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package cloudflare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -9,6 +9,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xenolf/lego/acme"
|
||||||
|
"github.com/xenolf/lego/providers/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CloudFlareAPIURL represents the API endpoint to call.
|
// CloudFlareAPIURL represents the API endpoint to call.
|
||||||
|
@ -39,7 +42,7 @@ func NewDNSProviderCloudFlare(cloudflareEmail, cloudflareKey string) (*DNSProvid
|
||||||
|
|
||||||
// Present creates a TXT record to fulfil the dns-01 challenge
|
// Present creates a TXT record to fulfil the dns-01 challenge
|
||||||
func (c *DNSProviderCloudFlare) Present(domain, token, keyAuth string) error {
|
func (c *DNSProviderCloudFlare) Present(domain, token, keyAuth string) error {
|
||||||
fqdn, value, _ := DNS01Record(domain, keyAuth)
|
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||||
zoneID, err := c.getHostedZoneID(fqdn)
|
zoneID, err := c.getHostedZoneID(fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -47,7 +50,7 @@ func (c *DNSProviderCloudFlare) Present(domain, token, keyAuth string) error {
|
||||||
|
|
||||||
rec := cloudFlareRecord{
|
rec := cloudFlareRecord{
|
||||||
Type: "TXT",
|
Type: "TXT",
|
||||||
Name: unFqdn(fqdn),
|
Name: dns.UnFqdn(fqdn),
|
||||||
Content: value,
|
Content: value,
|
||||||
TTL: 120,
|
TTL: 120,
|
||||||
}
|
}
|
||||||
|
@ -67,7 +70,7 @@ func (c *DNSProviderCloudFlare) Present(domain, token, keyAuth string) error {
|
||||||
|
|
||||||
// CleanUp removes the TXT record matching the specified parameters
|
// CleanUp removes the TXT record matching the specified parameters
|
||||||
func (c *DNSProviderCloudFlare) CleanUp(domain, token, keyAuth string) error {
|
func (c *DNSProviderCloudFlare) CleanUp(domain, token, keyAuth string) error {
|
||||||
fqdn, _, _ := DNS01Record(domain, keyAuth)
|
fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
|
||||||
|
|
||||||
record, err := c.findTxtRecord(fqdn)
|
record, err := c.findTxtRecord(fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -102,7 +105,7 @@ func (c *DNSProviderCloudFlare) getHostedZoneID(fqdn string) (string, error) {
|
||||||
|
|
||||||
var hostedZone HostedZone
|
var hostedZone HostedZone
|
||||||
for _, zone := range zones {
|
for _, zone := range zones {
|
||||||
name := toFqdn(zone.Name)
|
name := dns.ToFqdn(zone.Name)
|
||||||
if strings.HasSuffix(fqdn, name) {
|
if strings.HasSuffix(fqdn, name) {
|
||||||
if len(zone.Name) > len(hostedZone.Name) {
|
if len(zone.Name) > len(hostedZone.Name) {
|
||||||
hostedZone = zone
|
hostedZone = zone
|
||||||
|
@ -134,7 +137,7 @@ func (c *DNSProviderCloudFlare) findTxtRecord(fqdn string) (*cloudFlareRecord, e
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rec := range records {
|
for _, rec := range records {
|
||||||
if rec.Name == unFqdn(fqdn) && rec.Type == "TXT" {
|
if rec.Name == dns.UnFqdn(fqdn) && rec.Type == "TXT" {
|
||||||
return &rec, nil
|
return &rec, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +166,7 @@ func (c *DNSProviderCloudFlare) makeRequest(method, uri string, body io.Reader)
|
||||||
|
|
||||||
req.Header.Set("X-Auth-Email", c.authEmail)
|
req.Header.Set("X-Auth-Email", c.authEmail)
|
||||||
req.Header.Set("X-Auth-Key", c.authKey)
|
req.Header.Set("X-Auth-Key", c.authKey)
|
||||||
req.Header.Set("User-Agent", userAgent())
|
//req.Header.Set("User-Agent", userAgent())
|
||||||
|
|
||||||
client := http.Client{Timeout: 30 * time.Second}
|
client := http.Client{Timeout: 30 * time.Second}
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package cloudflare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package digitalocean
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -6,6 +6,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/xenolf/lego/acme"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNSProviderDigitalOcean is an implementation of the DNSProvider interface
|
// DNSProviderDigitalOcean is an implementation of the DNSProvider interface
|
||||||
|
@ -45,7 +47,7 @@ func (d *DNSProviderDigitalOcean) Present(domain, token, keyAuth string) error {
|
||||||
} `json:"domain_record"`
|
} `json:"domain_record"`
|
||||||
}
|
}
|
||||||
|
|
||||||
fqdn, value, _ := DNS01Record(domain, keyAuth)
|
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||||
|
|
||||||
reqURL := fmt.Sprintf("%s/v2/domains/%s/records", digitalOceanBaseURL, domain)
|
reqURL := fmt.Sprintf("%s/v2/domains/%s/records", digitalOceanBaseURL, domain)
|
||||||
reqData := txtRecordRequest{RecordType: "TXT", Name: fqdn, Data: value}
|
reqData := txtRecordRequest{RecordType: "TXT", Name: fqdn, Data: value}
|
||||||
|
@ -88,7 +90,7 @@ func (d *DNSProviderDigitalOcean) Present(domain, token, keyAuth string) error {
|
||||||
|
|
||||||
// CleanUp removes the TXT record matching the specified parameters
|
// CleanUp removes the TXT record matching the specified parameters
|
||||||
func (d *DNSProviderDigitalOcean) CleanUp(domain, token, keyAuth string) error {
|
func (d *DNSProviderDigitalOcean) CleanUp(domain, token, keyAuth string) error {
|
||||||
fqdn, _, _ := DNS01Record(domain, keyAuth)
|
fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
|
||||||
|
|
||||||
// get the record's unique ID from when we created it
|
// get the record's unique ID from when we created it
|
||||||
d.recordIDsMu.Lock()
|
d.recordIDsMu.Lock()
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package digitalocean
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package dnsimple
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -6,6 +6,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/weppos/dnsimple-go/dnsimple"
|
"github.com/weppos/dnsimple-go/dnsimple"
|
||||||
|
"github.com/xenolf/lego/acme"
|
||||||
|
"github.com/xenolf/lego/providers/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNSProviderDNSimple is an implementation of the DNSProvider interface.
|
// DNSProviderDNSimple is an implementation of the DNSProvider interface.
|
||||||
|
@ -33,7 +35,7 @@ func NewDNSProviderDNSimple(dnsimpleEmail, dnsimpleAPIKey string) (*DNSProviderD
|
||||||
|
|
||||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||||
func (c *DNSProviderDNSimple) Present(domain, token, keyAuth string) error {
|
func (c *DNSProviderDNSimple) Present(domain, token, keyAuth string) error {
|
||||||
fqdn, value, ttl := DNS01Record(domain, keyAuth)
|
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
|
||||||
|
|
||||||
zoneID, zoneName, err := c.getHostedZone(domain)
|
zoneID, zoneName, err := c.getHostedZone(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -51,7 +53,7 @@ func (c *DNSProviderDNSimple) Present(domain, token, keyAuth string) error {
|
||||||
|
|
||||||
// CleanUp removes the TXT record matching the specified parameters.
|
// CleanUp removes the TXT record matching the specified parameters.
|
||||||
func (c *DNSProviderDNSimple) CleanUp(domain, token, keyAuth string) error {
|
func (c *DNSProviderDNSimple) CleanUp(domain, token, keyAuth string) error {
|
||||||
fqdn, _, _ := DNS01Record(domain, keyAuth)
|
fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
|
||||||
|
|
||||||
records, err := c.findTxtRecords(domain, fqdn)
|
records, err := c.findTxtRecords(domain, fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -122,7 +124,7 @@ func (c *DNSProviderDNSimple) newTxtRecord(zone, fqdn, value string, ttl int) *d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DNSProviderDNSimple) extractRecordName(fqdn, domain string) string {
|
func (c *DNSProviderDNSimple) extractRecordName(fqdn, domain string) string {
|
||||||
name := unFqdn(fqdn)
|
name := dns.UnFqdn(fqdn)
|
||||||
if idx := strings.Index(name, "."+domain); idx != -1 {
|
if idx := strings.Index(name, "."+domain); idx != -1 {
|
||||||
return name[:idx]
|
return name[:idx]
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package dnsimple
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package rfc2136
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
"github.com/xenolf/lego/acme"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNSProviderRFC2136 is an implementation of the ChallengeProvider interface that
|
// DNSProviderRFC2136 is an implementation of the ChallengeProvider interface that
|
||||||
|
@ -47,13 +48,13 @@ func NewDNSProviderRFC2136(nameserver, tsigAlgorithm, tsigKey, tsigSecret string
|
||||||
|
|
||||||
// Present creates a TXT record using the specified parameters
|
// Present creates a TXT record using the specified parameters
|
||||||
func (r *DNSProviderRFC2136) Present(domain, token, keyAuth string) error {
|
func (r *DNSProviderRFC2136) Present(domain, token, keyAuth string) error {
|
||||||
fqdn, value, ttl := DNS01Record(domain, keyAuth)
|
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
|
||||||
return r.changeRecord("INSERT", fqdn, value, ttl)
|
return r.changeRecord("INSERT", fqdn, value, ttl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanUp removes the TXT record matching the specified parameters
|
// CleanUp removes the TXT record matching the specified parameters
|
||||||
func (r *DNSProviderRFC2136) CleanUp(domain, token, keyAuth string) error {
|
func (r *DNSProviderRFC2136) CleanUp(domain, token, keyAuth string) error {
|
||||||
fqdn, value, ttl := DNS01Record(domain, keyAuth)
|
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
|
||||||
return r.changeRecord("REMOVE", fqdn, value, ttl)
|
return r.changeRecord("REMOVE", fqdn, value, ttl)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package rfc2136
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package route53
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -7,6 +7,8 @@ import (
|
||||||
|
|
||||||
"github.com/mitchellh/goamz/aws"
|
"github.com/mitchellh/goamz/aws"
|
||||||
"github.com/mitchellh/goamz/route53"
|
"github.com/mitchellh/goamz/route53"
|
||||||
|
"github.com/xenolf/lego/acme"
|
||||||
|
"github.com/xenolf/lego/providers/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNSProviderRoute53 is an implementation of the DNSProvider interface
|
// DNSProviderRoute53 is an implementation of the DNSProvider interface
|
||||||
|
@ -43,14 +45,14 @@ func NewDNSProviderRoute53(awsAccessKey, awsSecretKey, awsRegionName string) (*D
|
||||||
|
|
||||||
// Present creates a TXT record using the specified parameters
|
// Present creates a TXT record using the specified parameters
|
||||||
func (r *DNSProviderRoute53) Present(domain, token, keyAuth string) error {
|
func (r *DNSProviderRoute53) Present(domain, token, keyAuth string) error {
|
||||||
fqdn, value, ttl := DNS01Record(domain, keyAuth)
|
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
|
||||||
value = `"` + value + `"`
|
value = `"` + value + `"`
|
||||||
return r.changeRecord("UPSERT", fqdn, value, ttl)
|
return r.changeRecord("UPSERT", fqdn, value, ttl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanUp removes the TXT record matching the specified parameters
|
// CleanUp removes the TXT record matching the specified parameters
|
||||||
func (r *DNSProviderRoute53) CleanUp(domain, token, keyAuth string) error {
|
func (r *DNSProviderRoute53) CleanUp(domain, token, keyAuth string) error {
|
||||||
fqdn, value, ttl := DNS01Record(domain, keyAuth)
|
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
|
||||||
value = `"` + value + `"`
|
value = `"` + value + `"`
|
||||||
return r.changeRecord("DELETE", fqdn, value, ttl)
|
return r.changeRecord("DELETE", fqdn, value, ttl)
|
||||||
}
|
}
|
||||||
|
@ -69,7 +71,7 @@ func (r *DNSProviderRoute53) changeRecord(action, fqdn, value string, ttl int) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return waitFor(90, 5, func() (bool, error) {
|
return dns.WaitFor(90, 5, func() (bool, error) {
|
||||||
status, err := r.client.GetChange(resp.ChangeInfo.ID)
|
status, err := r.client.GetChange(resp.ChangeInfo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
|
@ -1,4 +1,4 @@
|
||||||
package acme
|
package route53
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
47
providers/dns/utils.go
Normal file
47
providers/dns/utils.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToFqdn converts the name into a fqdn appending a trailing dot.
|
||||||
|
func ToFqdn(name string) string {
|
||||||
|
n := len(name)
|
||||||
|
if n == 0 || name[n-1] == '.' {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return name + "."
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnFqdn converts the fqdn into a name removing the trailing dot.
|
||||||
|
func UnFqdn(name string) string {
|
||||||
|
n := len(name)
|
||||||
|
if n != 0 && name[n-1] == '.' {
|
||||||
|
return name[:n-1]
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitFor polls the given function 'f', once every 'interval' seconds, up to 'timeout' seconds.
|
||||||
|
func WaitFor(timeout, interval int, f func() (bool, error)) error {
|
||||||
|
var lastErr string
|
||||||
|
timeup := time.After(time.Duration(timeout) * time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timeup:
|
||||||
|
return fmt.Errorf("Time limit exceeded. Last error: %s", lastErr)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
stop, err := f()
|
||||||
|
if stop {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
lastErr = err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Duration(interval) * time.Second)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue