forked from TrueCloudLab/lego
dns/route53: Allow specifying hosted zone ID (#345)
* dns/route53: Allow specifying hosted zone ID This commit adds support for specifying hosted zone ID via the environment variable AWS_HOSTED_ZONE_ID. If this is not specified, the previous discovery process is used. This is useful in environments where multiple hosted zones for the same domain name are present in an account. * dns/route53: Fix up getHostedZoneID method params Now that getHostedZoneID is a method on the DNSProvider struct, there is no reason for it to take the Route53 client as a parameter - we can simply use the reference stored in the struct.
This commit is contained in:
parent
dd74b99f8d
commit
b2aab0377c
4 changed files with 39 additions and 7 deletions
2
cli.go
2
cli.go
|
@ -215,7 +215,7 @@ Here is an example bash command using the CloudFlare DNS provider:
|
|||
fmt.Fprintln(w, "\tnamecheap:\tNAMECHEAP_API_USER, NAMECHEAP_API_KEY")
|
||||
fmt.Fprintln(w, "\trackspace:\tRACKSPACE_USER, RACKSPACE_API_KEY")
|
||||
fmt.Fprintln(w, "\trfc2136:\tRFC2136_TSIG_KEY, RFC2136_TSIG_SECRET,\n\t\tRFC2136_TSIG_ALGORITHM, RFC2136_NAMESERVER")
|
||||
fmt.Fprintln(w, "\troute53:\tAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION")
|
||||
fmt.Fprintln(w, "\troute53:\tAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_HOSTED_ZONE_ID")
|
||||
fmt.Fprintln(w, "\tdyn:\tDYN_CUSTOMER_NAME, DYN_USER_NAME, DYN_PASSWORD")
|
||||
fmt.Fprintln(w, "\tvultr:\tVULTR_API_KEY")
|
||||
fmt.Fprintln(w, "\tovh:\tOVH_ENDPOINT, OVH_APPLICATION_KEY, OVH_APPLICATION_SECRET, OVH_CONSUMER_KEY")
|
||||
|
|
|
@ -5,6 +5,7 @@ package route53
|
|||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -23,7 +24,8 @@ const (
|
|||
|
||||
// DNSProvider implements the acme.ChallengeProvider interface
|
||||
type DNSProvider struct {
|
||||
client *route53.Route53
|
||||
client *route53.Route53
|
||||
hostedZoneID string
|
||||
}
|
||||
|
||||
// customRetryer implements the client.Retryer interface by composing the
|
||||
|
@ -58,14 +60,22 @@ func (d customRetryer) RetryRules(r *request.Request) time.Duration {
|
|||
// 2. Shared credentials file (defaults to ~/.aws/credentials)
|
||||
// 3. Amazon EC2 IAM role
|
||||
//
|
||||
// If AWS_HOSTED_ZONE_ID is not set, Lego tries to determine the correct
|
||||
// public hosted zone via the FQDN.
|
||||
//
|
||||
// See also: https://github.com/aws/aws-sdk-go/wiki/configuring-sdk
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
hostedZoneID := os.Getenv("AWS_HOSTED_ZONE_ID")
|
||||
|
||||
r := customRetryer{}
|
||||
r.NumMaxRetries = maxRetries
|
||||
config := request.WithRetryer(aws.NewConfig(), r)
|
||||
client := route53.New(session.New(config))
|
||||
|
||||
return &DNSProvider{client: client}, nil
|
||||
return &DNSProvider{
|
||||
client: client,
|
||||
hostedZoneID: hostedZoneID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record using the specified parameters
|
||||
|
@ -83,7 +93,7 @@ func (r *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
}
|
||||
|
||||
func (r *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error {
|
||||
hostedZoneID, err := getHostedZoneID(fqdn, r.client)
|
||||
hostedZoneID, err := r.getHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to determine Route 53 hosted zone ID: %v", err)
|
||||
}
|
||||
|
@ -124,7 +134,11 @@ func (r *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error {
|
|||
})
|
||||
}
|
||||
|
||||
func getHostedZoneID(fqdn string, client *route53.Route53) (string, error) {
|
||||
func (r *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
||||
if r.hostedZoneID != "" {
|
||||
return r.hostedZoneID, nil
|
||||
}
|
||||
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -134,7 +148,7 @@ func getHostedZoneID(fqdn string, client *route53.Route53) (string, error) {
|
|||
reqParams := &route53.ListHostedZonesByNameInput{
|
||||
DNSName: aws.String(acme.UnFqdn(authZone)),
|
||||
}
|
||||
resp, err := client.ListHostedZonesByName(reqParams)
|
||||
resp, err := r.client.ListHostedZonesByName(reqParams)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestRoute53TTL(t *testing.T) {
|
|||
// unexported.
|
||||
fqdn := "_acme-challenge." + m["route53Domain"] + "."
|
||||
svc := route53.New(session.New())
|
||||
zoneID, err := getHostedZoneID(fqdn, svc)
|
||||
zoneID, err := provider.getHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
provider.CleanUp(m["route53Domain"], "foo", "bar")
|
||||
t.Fatalf("Fatal: %s", err.Error())
|
||||
|
|
|
@ -16,18 +16,21 @@ var (
|
|||
route53Secret string
|
||||
route53Key string
|
||||
route53Region string
|
||||
route53Zone string
|
||||
)
|
||||
|
||||
func init() {
|
||||
route53Key = os.Getenv("AWS_ACCESS_KEY_ID")
|
||||
route53Secret = os.Getenv("AWS_SECRET_ACCESS_KEY")
|
||||
route53Region = os.Getenv("AWS_REGION")
|
||||
route53Zone = os.Getenv("AWS_HOSTED_ZONE_ID")
|
||||
}
|
||||
|
||||
func restoreRoute53Env() {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", route53Key)
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", route53Secret)
|
||||
os.Setenv("AWS_REGION", route53Region)
|
||||
os.Setenv("AWS_HOSTED_ZONE_ID", route53Zone)
|
||||
}
|
||||
|
||||
func makeRoute53Provider(ts *httptest.Server) *DNSProvider {
|
||||
|
@ -67,6 +70,21 @@ func TestRegionFromEnv(t *testing.T) {
|
|||
restoreRoute53Env()
|
||||
}
|
||||
|
||||
func TestHostedZoneIDFromEnv(t *testing.T) {
|
||||
const testZoneID = "testzoneid"
|
||||
|
||||
defer restoreRoute53Env()
|
||||
os.Setenv("AWS_HOSTED_ZONE_ID", testZoneID)
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
assert.NoError(t, err, "Expected no error constructing DNSProvider")
|
||||
|
||||
fqdn, err := provider.getHostedZoneID("whatever")
|
||||
assert.NoError(t, err, "Expected FQDN to be resolved to environment variable value")
|
||||
|
||||
assert.Equal(t, testZoneID, fqdn)
|
||||
}
|
||||
|
||||
func TestRoute53Present(t *testing.T) {
|
||||
mockResponses := MockResponseMap{
|
||||
"/2013-04-01/hostedzonesbyname": MockResponse{StatusCode: 200, Body: ListHostedZonesByNameResponse},
|
||||
|
|
Loading…
Reference in a new issue