Merge pull request #157 from beevik/dns-credential-handling
Make DNS provider credential-handling more consistent.
This commit is contained in:
commit
4d8e4d3ec1
18 changed files with 214 additions and 160 deletions
|
@ -14,12 +14,12 @@ import (
|
|||
"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/dyn"
|
||||
"github.com/xenolf/lego/providers/dns/gandi"
|
||||
"github.com/xenolf/lego/providers/dns/googlecloud"
|
||||
"github.com/xenolf/lego/providers/dns/namecheap"
|
||||
"github.com/xenolf/lego/providers/dns/rfc2136"
|
||||
"github.com/xenolf/lego/providers/dns/route53"
|
||||
"github.com/xenolf/lego/providers/dns/dyn"
|
||||
"github.com/xenolf/lego/providers/http/webroot"
|
||||
)
|
||||
|
||||
|
@ -89,38 +89,25 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
|
|||
var provider acme.ChallengeProvider
|
||||
switch c.GlobalString("dns") {
|
||||
case "cloudflare":
|
||||
provider, err = cloudflare.NewDNSProvider("", "")
|
||||
provider, err = cloudflare.NewDNSProvider()
|
||||
case "digitalocean":
|
||||
authToken := os.Getenv("DO_AUTH_TOKEN")
|
||||
|
||||
provider, err = digitalocean.NewDNSProvider(authToken)
|
||||
provider, err = digitalocean.NewDNSProvider()
|
||||
case "dnsimple":
|
||||
provider, err = dnsimple.NewDNSProvider("", "")
|
||||
case "gandi":
|
||||
apiKey := os.Getenv("GANDI_API_KEY")
|
||||
provider, err = gandi.NewDNSProvider(apiKey)
|
||||
case "gcloud":
|
||||
provider, err = googlecloud.NewDNSProvider("")
|
||||
case "namecheap":
|
||||
provider, err = namecheap.NewDNSProvider("", "")
|
||||
case "route53":
|
||||
awsRegion := os.Getenv("AWS_REGION")
|
||||
provider, err = route53.NewDNSProvider("", "", awsRegion)
|
||||
case "rfc2136":
|
||||
nameserver := os.Getenv("RFC2136_NAMESERVER")
|
||||
tsigAlgorithm := os.Getenv("RFC2136_TSIG_ALGORITHM")
|
||||
tsigKey := os.Getenv("RFC2136_TSIG_KEY")
|
||||
tsigSecret := os.Getenv("RFC2136_TSIG_SECRET")
|
||||
|
||||
provider, err = rfc2136.NewDNSProvider(nameserver, tsigAlgorithm, tsigKey, tsigSecret)
|
||||
provider, err = dnsimple.NewDNSProvider()
|
||||
case "dyn":
|
||||
dynCustomerName := os.Getenv("DYN_CUSTOMER_NAME")
|
||||
dynUserName := os.Getenv("DYN_USER_NAME")
|
||||
dynPassword := os.Getenv("DYN_PASSWORD")
|
||||
|
||||
provider, err = dyn.NewDNSProvider(dynCustomerName, dynUserName, dynPassword)
|
||||
provider, err = dyn.NewDNSProvider()
|
||||
case "gandi":
|
||||
provider, err = gandi.NewDNSProvider()
|
||||
case "gcloud":
|
||||
provider, err = googlecloud.NewDNSProvider()
|
||||
case "manual":
|
||||
provider, err = acme.NewDNSProviderManual()
|
||||
case "namecheap":
|
||||
provider, err = namecheap.NewDNSProvider()
|
||||
case "route53":
|
||||
provider, err = route53.NewDNSProvider()
|
||||
case "rfc2136":
|
||||
provider, err = rfc2136.NewDNSProvider()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Package cloudflare implements a DNS provider for solving the DNS-01 challenge using cloudflare DNS.
|
||||
// Package cloudflare implements a DNS provider for solving the DNS-01
|
||||
// challenge using cloudflare DNS.
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
|
@ -24,19 +25,25 @@ type DNSProvider struct {
|
|||
authKey string
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance with a configured cloudflare client.
|
||||
// Credentials can either be passed as arguments or through CLOUDFLARE_EMAIL and CLOUDFLARE_API_KEY env vars.
|
||||
func NewDNSProvider(cloudflareEmail, cloudflareKey string) (*DNSProvider, error) {
|
||||
if cloudflareEmail == "" || cloudflareKey == "" {
|
||||
cloudflareEmail, cloudflareKey = cloudflareEnvAuth()
|
||||
if cloudflareEmail == "" || cloudflareKey == "" {
|
||||
return nil, fmt.Errorf("CloudFlare credentials missing")
|
||||
}
|
||||
// NewDNSProvider returns a DNSProvider instance configured for cloudflare.
|
||||
// Credentials must be passed in the environment variables: CLOUDFLARE_EMAIL
|
||||
// and CLOUDFLARE_API_KEY.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
email := os.Getenv("CLOUDFLARE_EMAIL")
|
||||
key := os.Getenv("CLOUDFLARE_API_KEY")
|
||||
return NewDNSProviderCredentials(email, key)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for cloudflare.
|
||||
func NewDNSProviderCredentials(email, key string) (*DNSProvider, error) {
|
||||
if email == "" || key == "" {
|
||||
return nil, fmt.Errorf("CloudFlare credentials missing")
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
authEmail: cloudflareEmail,
|
||||
authKey: cloudflareKey,
|
||||
authEmail: email,
|
||||
authKey: key,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -192,15 +199,6 @@ func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawM
|
|||
return r.Result, nil
|
||||
}
|
||||
|
||||
func cloudflareEnvAuth() (email, apiKey string) {
|
||||
email = os.Getenv("CLOUDFLARE_EMAIL")
|
||||
apiKey = os.Getenv("CLOUDFLARE_API_KEY")
|
||||
if len(email) == 0 || len(apiKey) == 0 {
|
||||
return "", ""
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// cloudFlareRecord represents a CloudFlare DNS record
|
||||
type cloudFlareRecord struct {
|
||||
Name string `json:"name"`
|
||||
|
|
|
@ -32,7 +32,7 @@ func restoreCloudFlareEnv() {
|
|||
func TestNewDNSProviderValid(t *testing.T) {
|
||||
os.Setenv("CLOUDFLARE_EMAIL", "")
|
||||
os.Setenv("CLOUDFLARE_API_KEY", "")
|
||||
_, err := NewDNSProvider("123", "123")
|
||||
_, err := NewDNSProviderCredentials("123", "123")
|
||||
assert.NoError(t, err)
|
||||
restoreCloudFlareEnv()
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func TestNewDNSProviderValid(t *testing.T) {
|
|||
func TestNewDNSProviderValidEnv(t *testing.T) {
|
||||
os.Setenv("CLOUDFLARE_EMAIL", "test@example.com")
|
||||
os.Setenv("CLOUDFLARE_API_KEY", "123")
|
||||
_, err := NewDNSProvider("", "")
|
||||
_, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
restoreCloudFlareEnv()
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
|
|||
func TestNewDNSProviderMissingCredErr(t *testing.T) {
|
||||
os.Setenv("CLOUDFLARE_EMAIL", "")
|
||||
os.Setenv("CLOUDFLARE_API_KEY", "")
|
||||
_, err := NewDNSProvider("", "")
|
||||
_, err := NewDNSProvider()
|
||||
assert.EqualError(t, err, "CloudFlare credentials missing")
|
||||
restoreCloudFlareEnv()
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func TestCloudFlarePresent(t *testing.T) {
|
|||
t.Skip("skipping live test")
|
||||
}
|
||||
|
||||
provider, err := NewDNSProvider(cflareEmail, cflareAPIKey)
|
||||
provider, err := NewDNSProviderCredentials(cflareEmail, cflareAPIKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = provider.Present(cflareDomain, "", "123d==")
|
||||
|
@ -72,7 +72,7 @@ func TestCloudFlareCleanUp(t *testing.T) {
|
|||
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
provider, err := NewDNSProvider(cflareEmail, cflareAPIKey)
|
||||
provider, err := NewDNSProviderCredentials(cflareEmail, cflareAPIKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = provider.CleanUp(cflareDomain, "", "123d==")
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Package digitalocean implements a DNS provider for solving the DNS-01 challenge using digitalocean DNS.
|
||||
// Package digitalocean implements a DNS provider for solving the DNS-01
|
||||
// challenge using digitalocean DNS.
|
||||
package digitalocean
|
||||
|
||||
import (
|
||||
|
@ -6,6 +7,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -20,10 +22,20 @@ type DNSProvider struct {
|
|||
recordIDsMu sync.Mutex
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a new DNSProvider instance.
|
||||
// apiAuthToken is the personal access token created in the DigitalOcean account
|
||||
// control panel, and it will be sent in bearer authorization headers.
|
||||
func NewDNSProvider(apiAuthToken string) (*DNSProvider, error) {
|
||||
// NewDNSProvider returns a DNSProvider instance configured for Digital
|
||||
// Ocean. Credentials must be passed in the environment variable:
|
||||
// DO_AUTH_TOKEN.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
apiAuthToken := os.Getenv("DO_AUTH_TOKEN")
|
||||
return NewDNSProviderCredentials(apiAuthToken)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for Digital Ocean.
|
||||
func NewDNSProviderCredentials(apiAuthToken string) (*DNSProvider, error) {
|
||||
if apiAuthToken == "" {
|
||||
return nil, fmt.Errorf("DigitalOcean credentials missing")
|
||||
}
|
||||
return &DNSProvider{
|
||||
apiAuthToken: apiAuthToken,
|
||||
recordIDs: make(map[string]int),
|
||||
|
|
|
@ -53,7 +53,7 @@ func TestDigitalOceanPresent(t *testing.T) {
|
|||
defer mock.Close()
|
||||
digitalOceanBaseURL = mock.URL
|
||||
|
||||
doprov, err := NewDNSProvider(fakeDigitalOceanAuth)
|
||||
doprov, err := NewDNSProviderCredentials(fakeDigitalOceanAuth)
|
||||
if doprov == nil {
|
||||
t.Fatal("Expected non-nil DigitalOcean provider, but was nil")
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ func TestDigitalOceanCleanUp(t *testing.T) {
|
|||
defer mock.Close()
|
||||
digitalOceanBaseURL = mock.URL
|
||||
|
||||
doprov, err := NewDNSProvider(fakeDigitalOceanAuth)
|
||||
doprov, err := NewDNSProviderCredentials(fakeDigitalOceanAuth)
|
||||
if doprov == nil {
|
||||
t.Fatal("Expected non-nil DigitalOcean provider, but was nil")
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Package dnsimple implements a DNS provider for solving the DNS-01 challenge using dnsimple DNS.
|
||||
// Package dnsimple implements a DNS provider for solving the DNS-01 challenge
|
||||
// using dnsimple DNS.
|
||||
package dnsimple
|
||||
|
||||
import (
|
||||
|
@ -15,22 +16,25 @@ type DNSProvider struct {
|
|||
client *dnsimple.Client
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance with a configured dnsimple client.
|
||||
// Authentication is either done using the passed credentials or - when empty - using the environment
|
||||
// variables DNSIMPLE_EMAIL and DNSIMPLE_API_KEY.
|
||||
func NewDNSProvider(dnsimpleEmail, dnsimpleAPIKey string) (*DNSProvider, error) {
|
||||
if dnsimpleEmail == "" || dnsimpleAPIKey == "" {
|
||||
dnsimpleEmail, dnsimpleAPIKey = dnsimpleEnvAuth()
|
||||
if dnsimpleEmail == "" || dnsimpleAPIKey == "" {
|
||||
return nil, fmt.Errorf("DNSimple credentials missing")
|
||||
}
|
||||
// NewDNSProvider returns a DNSProvider instance configured for dnsimple.
|
||||
// Credentials must be passed in the environment variables: DNSIMPLE_EMAIL
|
||||
// and DNSIMPLE_API_KEY.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
email := os.Getenv("DNSIMPLE_EMAIL")
|
||||
key := os.Getenv("DNSIMPLE_API_KEY")
|
||||
return NewDNSProviderCredentials(email, key)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for dnsimple.
|
||||
func NewDNSProviderCredentials(email, key string) (*DNSProvider, error) {
|
||||
if email == "" || key == "" {
|
||||
return nil, fmt.Errorf("DNSimple credentials missing")
|
||||
}
|
||||
|
||||
c := &DNSProvider{
|
||||
client: dnsimple.NewClient(dnsimpleAPIKey, dnsimpleEmail),
|
||||
}
|
||||
|
||||
return c, nil
|
||||
return &DNSProvider{
|
||||
client: dnsimple.NewClient(key, email),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfil the dns-01 challenge.
|
||||
|
@ -130,12 +134,3 @@ func (c *DNSProvider) extractRecordName(fqdn, domain string) string {
|
|||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func dnsimpleEnvAuth() (email, apiKey string) {
|
||||
email = os.Getenv("DNSIMPLE_EMAIL")
|
||||
apiKey = os.Getenv("DNSIMPLE_API_KEY")
|
||||
if len(email) == 0 || len(apiKey) == 0 {
|
||||
return "", ""
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ func restoreDNSimpleEnv() {
|
|||
func TestNewDNSProviderValid(t *testing.T) {
|
||||
os.Setenv("DNSIMPLE_EMAIL", "")
|
||||
os.Setenv("DNSIMPLE_API_KEY", "")
|
||||
_, err := NewDNSProvider("example@example.com", "123")
|
||||
_, err := NewDNSProviderCredentials("example@example.com", "123")
|
||||
assert.NoError(t, err)
|
||||
restoreDNSimpleEnv()
|
||||
}
|
||||
func TestNewDNSProviderValidEnv(t *testing.T) {
|
||||
os.Setenv("DNSIMPLE_EMAIL", "example@example.com")
|
||||
os.Setenv("DNSIMPLE_API_KEY", "123")
|
||||
_, err := NewDNSProvider("", "")
|
||||
_, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
restoreDNSimpleEnv()
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
|
|||
func TestNewDNSProviderMissingCredErr(t *testing.T) {
|
||||
os.Setenv("DNSIMPLE_EMAIL", "")
|
||||
os.Setenv("DNSIMPLE_API_KEY", "")
|
||||
_, err := NewDNSProvider("", "")
|
||||
_, err := NewDNSProvider()
|
||||
assert.EqualError(t, err, "DNSimple credentials missing")
|
||||
restoreDNSimpleEnv()
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func TestLiveDNSimplePresent(t *testing.T) {
|
|||
t.Skip("skipping live test")
|
||||
}
|
||||
|
||||
provider, err := NewDNSProvider(dnsimpleEmail, dnsimpleAPIKey)
|
||||
provider, err := NewDNSProviderCredentials(dnsimpleEmail, dnsimpleAPIKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = provider.Present(dnsimpleDomain, "", "123d==")
|
||||
|
@ -71,7 +71,7 @@ func TestLiveDNSimpleCleanUp(t *testing.T) {
|
|||
|
||||
time.Sleep(time.Second * 1)
|
||||
|
||||
provider, err := NewDNSProvider(dnsimpleEmail, dnsimpleAPIKey)
|
||||
provider, err := NewDNSProviderCredentials(dnsimpleEmail, dnsimpleAPIKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = provider.CleanUp(dnsimpleDomain, "", "123d==")
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Package dyn implements a DNS provider for solving the DNS-01 challenge using Dyn Managed DNS.
|
||||
// Package dyn implements a DNS provider for solving the DNS-01 challenge
|
||||
// using Dyn Managed DNS.
|
||||
package dyn
|
||||
|
||||
import (
|
||||
|
@ -6,6 +7,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -37,10 +39,23 @@ type DNSProvider struct {
|
|||
token string
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a new DNSProvider instance. customerName is
|
||||
// the customer name of the Dyn account. userName is the user name. password is
|
||||
// the password.
|
||||
func NewDNSProvider(customerName, userName, password string) (*DNSProvider, error) {
|
||||
// NewDNSProvider returns a DNSProvider instance configured for Dyn DNS.
|
||||
// Credentials must be passed in the environment variables: DYN_CUSTOMER_NAME,
|
||||
// DYN_USER_NAME and DYN_PASSWORD.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
customerName := os.Getenv("DYN_CUSTOMER_NAME")
|
||||
userName := os.Getenv("DYN_USER_NAME")
|
||||
password := os.Getenv("DYN_PASSWORD")
|
||||
return NewDNSProviderCredentials(customerName, userName, password)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for Dyn DNS.
|
||||
func NewDNSProviderCredentials(customerName, userName, password string) (*DNSProvider, error) {
|
||||
if customerName == "" || userName == "" || password == "" {
|
||||
return nil, fmt.Errorf("DynDNS credentials missing")
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
customerName: customerName,
|
||||
userName: userName,
|
||||
|
|
|
@ -31,7 +31,7 @@ func TestLiveDynPresent(t *testing.T) {
|
|||
t.Skip("skipping live test")
|
||||
}
|
||||
|
||||
provider, err := NewDNSProvider(dynCustomerName, dynUserName, dynPassword)
|
||||
provider, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = provider.Present(dynDomain, "", "123d==")
|
||||
|
@ -45,7 +45,7 @@ func TestLiveDynCleanUp(t *testing.T) {
|
|||
|
||||
time.Sleep(time.Second * 1)
|
||||
|
||||
provider, err := NewDNSProvider(dynCustomerName, dynUserName, dynPassword)
|
||||
provider, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = provider.CleanUp(dynDomain, "", "123d==")
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -35,9 +36,16 @@ type DNSProvider struct {
|
|||
inProgressMu sync.Mutex
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a new DNSProvider instance. apiKey is the
|
||||
// API access key obtained from the Gandi account control panel.
|
||||
func NewDNSProvider(apiKey string) (*DNSProvider, error) {
|
||||
// NewDNSProvider returns a DNSProvider instance configured for Gandi.
|
||||
// Credentials must be passed in the environment variable: GANDI_API_KEY.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
apiKey := os.Getenv("GANDI_API_KEY")
|
||||
return NewDNSProviderCredentials(apiKey)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for Gandi.
|
||||
func NewDNSProviderCredentials(apiKey string) (*DNSProvider, error) {
|
||||
if apiKey == "" {
|
||||
return nil, fmt.Errorf("No Gandi API Key given")
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package gandi_test
|
||||
package gandi
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
@ -8,8 +8,6 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/xenolf/lego/providers/dns/gandi"
|
||||
)
|
||||
|
||||
// TestDNSProvider runs Present and CleanUp against a fake Gandi RPC
|
||||
|
@ -17,7 +15,7 @@ import (
|
|||
func TestDNSProvider(t *testing.T) {
|
||||
fakeAPIKey := "123412341234123412341234"
|
||||
fakeKeyAuth := "XXXX"
|
||||
provider, err := gandi.NewDNSProvider(fakeAPIKey)
|
||||
provider, err := NewDNSProviderCredentials(fakeAPIKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -47,11 +45,11 @@ func TestDNSProvider(t *testing.T) {
|
|||
}))
|
||||
defer fakeServer.Close()
|
||||
// override gandi endpoint to point to fake server
|
||||
savedEndpoint := gandi.Endpoint
|
||||
savedEndpoint := Endpoint
|
||||
defer func() {
|
||||
gandi.Endpoint = savedEndpoint
|
||||
Endpoint = savedEndpoint
|
||||
}()
|
||||
gandi.Endpoint = fakeServer.URL + "/"
|
||||
Endpoint = fakeServer.URL + "/"
|
||||
// run Present
|
||||
err = provider.Present("abc.def.example.com", "", fakeKeyAuth)
|
||||
if err != nil {
|
||||
|
|
|
@ -22,12 +22,16 @@ type DNSProvider struct {
|
|||
client *dns.Service
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance with a configured gcloud client.
|
||||
// Authentication is done using the local account credentials managed by the gcloud utility.
|
||||
func NewDNSProvider(project string) (*DNSProvider, error) {
|
||||
if project == "" {
|
||||
project = gcloudEnvAuth()
|
||||
}
|
||||
// NewDNSProvider returns a DNSProvider instance configured for Google Cloud
|
||||
// DNS. Credentials must be passed in the environment variable: GCE_PROJECT.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
project := os.Getenv("GCE_PROJECT")
|
||||
return NewDNSProviderCredentials(project)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for Google Cloud DNS.
|
||||
func NewDNSProviderCredentials(project string) (*DNSProvider, error) {
|
||||
if project == "" {
|
||||
return nil, fmt.Errorf("Google Cloud project name missing")
|
||||
}
|
||||
|
@ -149,7 +153,3 @@ func (c *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSe
|
|||
|
||||
return found, nil
|
||||
}
|
||||
|
||||
func gcloudEnvAuth() (gcloud string) {
|
||||
return os.Getenv("GCE_PROJECT")
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ func TestNewDNSProviderValid(t *testing.T) {
|
|||
t.Skip("skipping live test (requires credentials)")
|
||||
}
|
||||
os.Setenv("GCE_PROJECT", "")
|
||||
_, err := NewDNSProvider("my-project")
|
||||
_, err := NewDNSProviderCredentials("my-project")
|
||||
assert.NoError(t, err)
|
||||
restoreGCloudEnv()
|
||||
}
|
||||
|
@ -46,14 +46,14 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
|
|||
t.Skip("skipping live test (requires credentials)")
|
||||
}
|
||||
os.Setenv("GCE_PROJECT", "my-project")
|
||||
_, err := NewDNSProvider("")
|
||||
_, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
restoreGCloudEnv()
|
||||
}
|
||||
|
||||
func TestNewDNSProviderMissingCredErr(t *testing.T) {
|
||||
os.Setenv("GCE_PROJECT", "")
|
||||
_, err := NewDNSProvider("")
|
||||
_, err := NewDNSProvider()
|
||||
assert.EqualError(t, err, "Google Cloud project name missing")
|
||||
restoreGCloudEnv()
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ func TestLiveGoogleCloudPresent(t *testing.T) {
|
|||
t.Skip("skipping live test")
|
||||
}
|
||||
|
||||
provider, err := NewDNSProvider(gcloudProject)
|
||||
provider, err := NewDNSProviderCredentials(gcloudProject)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = provider.Present(gcloudDomain, "", "123d==")
|
||||
|
@ -77,7 +77,7 @@ func TestLiveGoogleCloudCleanUp(t *testing.T) {
|
|||
|
||||
time.Sleep(time.Second * 1)
|
||||
|
||||
provider, err := NewDNSProvider(gcloudProject)
|
||||
provider, err := NewDNSProviderCredentials(gcloudProject)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = provider.CleanUp(gcloudDomain, "", "123d==")
|
||||
|
|
|
@ -44,15 +44,20 @@ type DNSProvider struct {
|
|||
clientIP string
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a new DNSProvider instance. apiUser is the namecheap
|
||||
// API user's account name, and apiKey is the account's API access key.
|
||||
func NewDNSProvider(apiUser, apiKey string) (*DNSProvider, error) {
|
||||
// NewDNSProvider returns a DNSProvider instance configured for namecheap.
|
||||
// Credentials must be passed in the environment variables: NAMECHEAP_API_USER
|
||||
// and NAMECHEAP_API_KEY.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
apiUser := os.Getenv("NAMECHEAP_API_USER")
|
||||
apiKey := os.Getenv("NAMECHEAP_API_KEY")
|
||||
return NewDNSProviderCredentials(apiUser, apiKey)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for namecheap.
|
||||
func NewDNSProviderCredentials(apiUser, apiKey string) (*DNSProvider, error) {
|
||||
if apiUser == "" || apiKey == "" {
|
||||
apiUser = os.Getenv("NAMECHEAP_API_USER")
|
||||
apiKey = os.Getenv("NAMECHEAP_API_KEY")
|
||||
if apiUser == "" || apiKey == "" {
|
||||
return nil, fmt.Errorf("Namecheap credentials missing")
|
||||
}
|
||||
return nil, fmt.Errorf("Namecheap credentials missing")
|
||||
}
|
||||
|
||||
clientIP, err := getClientIP()
|
||||
|
@ -68,8 +73,9 @@ func NewDNSProvider(apiUser, apiKey string) (*DNSProvider, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Timeout : Namecheap can sometimes take a long time to complete an update, so wait
|
||||
// up to 60 minutes for the update to propagate.
|
||||
// Timeout returns the timeout and interval to use when checking for DNS
|
||||
// propagation. Namecheap can sometimes take a long time to complete an
|
||||
// update, so wait up to 60 minutes for the update to propagate.
|
||||
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return 60 * time.Minute, 15 * time.Second
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// Package rfc2136 implements a DNS provider for solving the DNS-01 challenge using the rfc2136 dynamic update.
|
||||
// Package rfc2136 implements a DNS provider for solving the DNS-01 challenge
|
||||
// using the rfc2136 dynamic update.
|
||||
package rfc2136
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -20,10 +22,29 @@ type DNSProvider struct {
|
|||
tsigSecret string
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a new DNSProvider instance.
|
||||
// To disable TSIG authentication 'tsigAlgorithm, 'tsigKey' and 'tsigSecret' must be set to the empty string.
|
||||
// 'nameserver' must be a network address in the the form "host" or "host:port".
|
||||
func NewDNSProvider(nameserver, tsigAlgorithm, tsigKey, tsigSecret string) (*DNSProvider, error) {
|
||||
// NewDNSProvider returns a DNSProvider instance configured for rfc2136
|
||||
// dynamic update. Credentials must be passed in the environment variables:
|
||||
// RFC2136_NAMESERVER, RFC2136_TSIG_ALGORITHM, RFC2136_TSIG_KEY and
|
||||
// RFC2136_TSIG_SECRET. To disable TSIG authentication, leave the TSIG
|
||||
// variables unset. RFC2136_NAMESERVER must be a network address in the form
|
||||
// "host" or "host:port".
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
nameserver := os.Getenv("RFC2136_NAMESERVER")
|
||||
tsigAlgorithm := os.Getenv("RFC2136_TSIG_ALGORITHM")
|
||||
tsigKey := os.Getenv("RFC2136_TSIG_KEY")
|
||||
tsigSecret := os.Getenv("RFC2136_TSIG_SECRET")
|
||||
return NewDNSProviderCredentials(nameserver, tsigAlgorithm, tsigKey, tsigSecret)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for rfc2136 dynamic update. To disable TSIG
|
||||
// authentication, leave the TSIG parameters as empty strings.
|
||||
// nameserver must be a network address in the form "host" or "host:port".
|
||||
func NewDNSProviderCredentials(nameserver, tsigAlgorithm, tsigKey, tsigSecret string) (*DNSProvider, error) {
|
||||
if nameserver == "" {
|
||||
return nil, fmt.Errorf("RFC2136 nameserver missing")
|
||||
}
|
||||
|
||||
// Append the default DNS port if none is specified.
|
||||
if _, _, err := net.SplitHostPort(nameserver); err != nil {
|
||||
if strings.Contains(err.Error(), "missing port") {
|
||||
|
|
|
@ -61,9 +61,9 @@ func TestRFC2136ServerSuccess(t *testing.T) {
|
|||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
provider, err := NewDNSProvider(addrstr, "", "", "")
|
||||
provider, err := NewDNSProviderCredentials(addrstr, "", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err)
|
||||
t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err)
|
||||
}
|
||||
if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err != nil {
|
||||
t.Errorf("Expected Present() to return no error but the error was -> %v", err)
|
||||
|
@ -81,9 +81,9 @@ func TestRFC2136ServerError(t *testing.T) {
|
|||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
provider, err := NewDNSProvider(addrstr, "", "", "")
|
||||
provider, err := NewDNSProviderCredentials(addrstr, "", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err)
|
||||
t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err)
|
||||
}
|
||||
if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err == nil {
|
||||
t.Errorf("Expected Present() to return an error but it did not.")
|
||||
|
@ -103,9 +103,9 @@ func TestRFC2136TsigClient(t *testing.T) {
|
|||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
provider, err := NewDNSProvider(addrstr, "", rfc2136TestTsigKey, rfc2136TestTsigSecret)
|
||||
provider, err := NewDNSProviderCredentials(addrstr, "", rfc2136TestTsigKey, rfc2136TestTsigSecret)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err)
|
||||
t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err)
|
||||
}
|
||||
if err := provider.Present(rfc2136TestDomain, "", rfc2136TestKeyAuth); err != nil {
|
||||
t.Errorf("Expected Present() to return no error but the error was -> %v", err)
|
||||
|
@ -135,9 +135,9 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
|
|||
t.Fatalf("Error packing expect msg: %v", err)
|
||||
}
|
||||
|
||||
provider, err := NewDNSProvider(addrstr, "", "", "")
|
||||
provider, err := NewDNSProviderCredentials(addrstr, "", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err)
|
||||
t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err)
|
||||
}
|
||||
|
||||
if err := provider.Present(rfc2136TestDomain, "", "1234d=="); err != nil {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// Package route53 implements a DNS provider for solving the DNS-01 challenge using route53 DNS.
|
||||
// Package route53 implements a DNS provider for solving the DNS-01 challenge
|
||||
// using route53 DNS.
|
||||
package route53
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -16,25 +18,35 @@ type DNSProvider struct {
|
|||
client *route53.Route53
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance with a configured route53 client.
|
||||
// Authentication is either done using the passed credentials or - when empty - falling back to
|
||||
// the customary AWS credential mechanisms, including the file referenced by $AWS_CREDENTIAL_FILE
|
||||
// (defaulting to $HOME/.aws/credentials) optionally scoped to $AWS_PROFILE, credentials
|
||||
// supplied by the environment variables AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY [ + AWS_SECURITY_TOKEN ],
|
||||
// and finally credentials available via the EC2 instance metadata service.
|
||||
func NewDNSProvider(awsAccessKey, awsSecretKey, awsRegionName string) (*DNSProvider, error) {
|
||||
region, ok := aws.Regions[awsRegionName]
|
||||
// NewDNSProvider returns a DNSProvider instance configured for the AWS
|
||||
// route53 service. The AWS region name must be passed in the environment
|
||||
// variable AWS_REGION.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
regionName := os.Getenv("AWS_REGION")
|
||||
return NewDNSProviderCredentials("", "", regionName)
|
||||
}
|
||||
|
||||
// NewDNSProviderCredentials uses the supplied credentials to return a
|
||||
// DNSProvider instance configured for the AWS route53 service. Authentication
|
||||
// is done using the passed credentials or, if empty, falling back to the
|
||||
// custonmary AWS credential mechanisms, including the file referenced by
|
||||
// $AWS_CREDENTIAL_FILE (defaulting to $HOME/.aws/credentials) optionally
|
||||
// scoped to $AWS_PROFILE, credentials supplied by the environment variables
|
||||
// AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY [ + AWS_SECURITY_TOKEN ], and
|
||||
// finally credentials available via the EC2 instance metadata service.
|
||||
func NewDNSProviderCredentials(accessKey, secretKey, regionName string) (*DNSProvider, error) {
|
||||
region, ok := aws.Regions[regionName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Invalid AWS region name %s", awsRegionName)
|
||||
return nil, fmt.Errorf("Invalid AWS region name %s", regionName)
|
||||
}
|
||||
|
||||
// use aws.GetAuth, which tries really hard to find credentails:
|
||||
// - uses awsAccessKey and awsSecretKey, if provided
|
||||
// - uses accessKey and secretKey, if provided
|
||||
// - uses AWS_PROFILE / AWS_CREDENTIAL_FILE, if provided
|
||||
// - uses AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY and optionally AWS_SECURITY_TOKEN, if provided
|
||||
// - uses EC2 instance metadata credentials (http://169.254.169.254/latest/meta-data/…), if available
|
||||
// ...and otherwise returns an error
|
||||
auth, err := aws.GetAuth(awsAccessKey, awsSecretKey)
|
||||
auth, err := aws.GetAuth(accessKey, secretKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -100,7 +100,8 @@ func makeRoute53Provider(server *testutil.HTTPServer) *DNSProvider {
|
|||
func TestNewDNSProviderValid(t *testing.T) {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "")
|
||||
_, err := NewDNSProvider("123", "123", "us-east-1")
|
||||
os.Setenv("AWS_REGION", "")
|
||||
_, err := NewDNSProviderCredentials("123", "123", "us-east-1")
|
||||
assert.NoError(t, err)
|
||||
restoreRoute53Env()
|
||||
}
|
||||
|
@ -108,7 +109,8 @@ func TestNewDNSProviderValid(t *testing.T) {
|
|||
func TestNewDNSProviderValidEnv(t *testing.T) {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "123")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "123")
|
||||
_, err := NewDNSProvider("", "", "us-east-1")
|
||||
os.Setenv("AWS_REGION", "us-east-1")
|
||||
_, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
restoreRoute53Env()
|
||||
}
|
||||
|
@ -124,7 +126,7 @@ func TestNewDNSProviderMissingAuthErr(t *testing.T) {
|
|||
awsClient := aws.RetryingClient
|
||||
aws.RetryingClient = &http.Client{Timeout: time.Millisecond}
|
||||
|
||||
_, err := NewDNSProvider("", "", "us-east-1")
|
||||
_, err := NewDNSProviderCredentials("", "", "us-east-1")
|
||||
assert.EqualError(t, err, "No valid AWS authentication found")
|
||||
restoreRoute53Env()
|
||||
|
||||
|
@ -133,7 +135,7 @@ func TestNewDNSProviderMissingAuthErr(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNewDNSProviderInvalidRegionErr(t *testing.T) {
|
||||
_, err := NewDNSProvider("123", "123", "us-east-3")
|
||||
_, err := NewDNSProviderCredentials("123", "123", "us-east-3")
|
||||
assert.EqualError(t, err, "Invalid AWS region name us-east-3")
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue