lego/acme/dns_challenge_route53.go

95 lines
2.8 KiB
Go
Raw Normal View History

package acme
import (
"fmt"
"math"
"strings"
"github.com/mitchellh/goamz/aws"
"github.com/mitchellh/goamz/route53"
)
// DNSProviderRoute53 is an implementation of the DNSProvider interface
type DNSProviderRoute53 struct {
client *route53.Route53
}
// NewDNSProviderRoute53 returns a DNSProviderRoute53 instance with a configured route53 client.
// Authentication is either done using the passed credentials or - when empty -
// using the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
func NewDNSProviderRoute53(awsAccessKey, awsSecretKey, awsRegionName string) (*DNSProviderRoute53, error) {
region, ok := aws.Regions[awsRegionName]
if !ok {
return nil, fmt.Errorf("Invalid AWS region name %s", awsRegionName)
}
var auth aws.Auth
// First try passed in credentials
if awsAccessKey != "" && awsSecretKey != "" {
auth = aws.Auth{awsAccessKey, awsSecretKey, ""}
} else {
// try getting credentials from environment
envAuth, err := aws.EnvAuth()
if err != nil {
return nil, fmt.Errorf("AWS credentials missing")
}
auth = envAuth
}
client := route53.New(auth, region)
return &DNSProviderRoute53{client: client}, nil
}
// CreateTXTRecord creates a TXT record using the specified parameters
func (r *DNSProviderRoute53) CreateTXTRecord(fqdn, value string, ttl int) error {
return r.changeRecord("UPSERT", fqdn, value, ttl)
}
// RemoveTXTRecord removes the TXT record matching the specified parameters
func (r *DNSProviderRoute53) RemoveTXTRecord(fqdn, value string, ttl int) error {
return r.changeRecord("DELETE", fqdn, value, ttl)
}
func (r *DNSProviderRoute53) changeRecord(action, fqdn, value string, ttl int) error {
hostedZoneID, err := r.getHostedZoneID(fqdn)
if err != nil {
return err
}
recordSet := newTXTRecordSet(fqdn, value, ttl)
update := route53.Change{action, recordSet}
changes := []route53.Change{update}
req := route53.ChangeResourceRecordSetsRequest{Comment: "Created by Lego", Changes: changes}
_, err = r.client.ChangeResourceRecordSets(hostedZoneID, &req)
return err
}
func (r *DNSProviderRoute53) getHostedZoneID(fqdn string) (string, error) {
zoneResp, err := r.client.ListHostedZones("", math.MaxInt32)
if err != nil {
return "", err
}
var hostedZone route53.HostedZone
for _, zone := range zoneResp.HostedZones {
//if strings.HasSuffix(domain, strings.Trim(zone.Name, ".")) {
if strings.HasSuffix(fqdn, zone.Name) {
if len(zone.Name) > len(hostedZone.Name) {
hostedZone = zone
}
}
}
if hostedZone.ID == "" {
return "", fmt.Errorf("No Route53 zone found for domain %s", fqdn)
}
return hostedZone.ID, nil
}
func newTXTRecordSet(fqdn, value string, ttl int) route53.ResourceRecordSet {
return route53.ResourceRecordSet{
Name: fqdn,
Type: "TXT",
Records: []string{value},
TTL: ttl,
}
}