chore: migrate to aws-sdk-go-v2 (lightsail, route53) (#1973)
This commit is contained in:
parent
ed14dda361
commit
fc47c35e89
14 changed files with 317 additions and 213 deletions
|
@ -95,7 +95,7 @@ Alternatively, you can also set the `Resource` to `*` (wildcard), which allow to
|
|||
## More information
|
||||
|
||||
|
||||
- [Go client](https://github.com/aws/aws-sdk-go/)
|
||||
- [Go client](https://github.com/aws/aws-sdk-go-v2)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/lightsail/lightsail.toml -->
|
||||
|
|
|
@ -178,7 +178,7 @@ Replace `Z11111112222222333333` with your hosted zone ID and `example.com` with
|
|||
## More information
|
||||
|
||||
- [API documentation](https://docs.aws.amazon.com/Route53/latest/APIReference/API_Operations_Amazon_Route_53.html)
|
||||
- [Go client](https://github.com/aws/aws-sdk-go/aws)
|
||||
- [Go client](https://github.com/aws/aws-sdk-go-v2)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/route53/route53.toml -->
|
||||
|
|
16
go.mod
16
go.mod
|
@ -3,6 +3,7 @@ module github.com/go-acme/lego/v4
|
|||
go 1.19
|
||||
|
||||
// github.com/exoscale/egoscale v1.19.0 => It is an error, please don't use it.
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.2.3
|
||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
|
||||
|
@ -17,7 +18,12 @@ require (
|
|||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755
|
||||
github.com/aws/aws-sdk-go v1.39.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.19.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.28
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.27
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3
|
||||
github.com/cenkalti/backoff/v4 v4.2.1
|
||||
github.com/civo/civogo v0.3.11
|
||||
github.com/cloudflare/cloudflare-go v0.70.0
|
||||
|
@ -89,6 +95,14 @@ require (
|
|||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect
|
||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
|
|
31
go.sum
31
go.sum
|
@ -74,8 +74,34 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
|
|||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo=
|
||||
github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go-v2 v1.19.0 h1:klAT+y3pGFBU/qVf1uzwttpBbiuozJYWzNLHioyDJ+k=
|
||||
github.com/aws/aws-sdk-go-v2 v1.19.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.28 h1:TINEaKyh1Td64tqFvn09iYpKiWjmHYrG1fa91q2gnqw=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.28/go.mod h1:nIL+4/8JdAuNHEjn/gPEXqtnS02Q3NXB/9Z7o5xE4+A=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.27 h1:dz0yr/yR1jweAnsCx+BmjerUILVPQ6FS5AwF/OyG1kA=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.27/go.mod h1:syOqAek45ZXZp29HlnRS/BNgMIW6uiRmeuQsz4Qh2UE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 h1:kP3Me6Fy3vdi+9uHd7YLr6ewPxRL+PU6y15urfTaamU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5/go.mod h1:Gj7tm95r+QsDoN2Fhuz/3npQvcZbkEf5mL70n3Xfluc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 h1:hMUCiE3Zi5AHrRNGf5j985u0WyqI6r2NULhUfo0N/No=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35/go.mod h1:ipR5PvpSPqIqL5Mi82BxLnfMkHVbmco8kUwO2xrCi0M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 h1:yOpYx+FTBdpk/g+sBU6Cb1H0U/TLEcYYp66mYqsPpcc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29/go.mod h1:M/eUABlDbw2uVrdAn+UsI6M727qp2fxkp8K0ejcBDUY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 h1:8r5m1BoAWkn0TDC34lUculryf7nUF25EgIMdjvGCkgo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36/go.mod h1:Rmw2M1hMVTwiUhjwMoIBFWFJMhvJbct06sSidxInkhY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 h1:IiDolu/eLmuB18DRZibj77n1hHQT7z12jnGO7Ze3pLc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29/go.mod h1:fDbkK4o7fpPXWn8YAPmTieAMuB9mk/VgvW64uaUqxd4=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2 h1:PwNeYoonBzmTdCztKiiutws3U24KrnDBuabzRfIlZY4=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2/go.mod h1:gQhLZrTEath4zik5ixIe6axvgY5jJrgSBDJ360Fxnco=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4 h1:p4mTxJfCAyiTT4Wp6p/mOPa6j5MqCSRGot8qZwFs+Z0=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4/go.mod h1:VBLWpaHvhQNeu7N9rMEf00SWeOONb/HvaDUxe/7b44k=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 h1:sWDv7cMITPcZ21QdreULwxOOAmE05JjEsT6fCDtDA9k=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13/go.mod h1:DfX0sWuT46KpcqbMhJ9QWtxAIP1VozkDWf8VAkByjYY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 h1:BFubHS/xN5bjl818QaroN6mQdjneYQ+AOx44KNXlyH4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13/go.mod h1:BzqsVVFduubEmzrVtUFQQIQdFqvUItF8XUq2EnS8Wog=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 h1:e5mnydVdCVWxP+5rPAGi2PYxC7u2OZgH1ypC114H04U=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3/go.mod h1:yVGZA1CPkmUhBdA039jXNJJG7/6t+G+EBWmFq23xqnY=
|
||||
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
|
||||
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
|
@ -220,6 +246,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
|
|
|
@ -51,6 +51,11 @@ func (e *EnvTest) WithLiveTestRequirements(keys ...string) *EnvTest {
|
|||
panic(fmt.Sprintf("Unauthorized action, the env var %s is not managed or it's not the key of the domain.", key))
|
||||
}
|
||||
|
||||
if e.domainKey == key {
|
||||
countValuedVars++
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := e.values[key]; ok {
|
||||
countValuedVars++
|
||||
}
|
||||
|
|
|
@ -148,6 +148,22 @@ func TestEnvTest(t *testing.T) {
|
|||
assert.Equal(t, "", envTest.GetDomain())
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "WithLiveTestRequirements with domain as requirement",
|
||||
envVars: map[string]string{
|
||||
envVar01: "A",
|
||||
envVar02: "B",
|
||||
},
|
||||
envTestSetup: func() *tester.EnvTest {
|
||||
return tester.NewEnvTest(envVar01, envVar02).WithDomain(envVarDomain).WithLiveTestRequirements(envVar02, envVarDomain)
|
||||
},
|
||||
expected: func(t *testing.T, envTest *tester.EnvTest) {
|
||||
assert.True(t, envTest.IsLiveTest())
|
||||
assert.Equal(t, "A", envTest.GetValue(envVar01))
|
||||
assert.Equal(t, "B", envTest.GetValue(envVar02))
|
||||
assert.Equal(t, "", envTest.GetDomain())
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "WithLiveTestRequirements non required var missing",
|
||||
envVars: map[string]string{
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
package lightsail
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/aws/retry"
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/lightsail"
|
||||
awstypes "github.com/aws/aws-sdk-go-v2/service/lightsail/types"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/platform/config/env"
|
||||
)
|
||||
|
@ -32,27 +33,6 @@ const (
|
|||
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||
)
|
||||
|
||||
// customRetryer implements the client.Retryer interface by composing the DefaultRetryer.
|
||||
// It controls the logic for retrying recoverable request errors (e.g. when rate limits are exceeded).
|
||||
type customRetryer struct {
|
||||
client.DefaultRetryer
|
||||
}
|
||||
|
||||
// RetryRules overwrites the DefaultRetryer's method.
|
||||
// It uses a basic exponential backoff algorithm that returns an initial
|
||||
// delay of ~400ms with an upper limit of ~30 seconds which should prevent
|
||||
// causing a high number of consecutive throttling errors.
|
||||
// For reference: Route 53 enforces an account-wide(!) 5req/s query limit.
|
||||
func (c customRetryer) RetryRules(r *request.Request) time.Duration {
|
||||
retryCount := r.RetryCount
|
||||
if retryCount > 7 {
|
||||
retryCount = 7
|
||||
}
|
||||
|
||||
delay := (1 << uint(retryCount)) * (rand.Intn(50) + 200)
|
||||
return time.Duration(delay) * time.Millisecond
|
||||
}
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider.
|
||||
type Config struct {
|
||||
DNSZone string
|
||||
|
@ -71,7 +51,7 @@ func NewDefaultConfig() *Config {
|
|||
|
||||
// DNSProvider implements the challenge.Provider interface.
|
||||
type DNSProvider struct {
|
||||
client *lightsail.Lightsail
|
||||
client *lightsail.Client
|
||||
config *Config
|
||||
}
|
||||
|
||||
|
@ -102,35 +82,55 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, errors.New("lightsail: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
retryer := customRetryer{}
|
||||
retryer.NumMaxRetries = maxRetries
|
||||
ctx := context.Background()
|
||||
|
||||
conf := aws.NewConfig().WithRegion(config.Region)
|
||||
sess, err := session.NewSession(request.WithRetryer(conf, retryer))
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx,
|
||||
awsconfig.WithRegion(config.Region),
|
||||
awsconfig.WithRetryer(func() aws.Retryer {
|
||||
return retry.NewStandard(func(options *retry.StandardOptions) {
|
||||
options.MaxAttempts = maxRetries
|
||||
|
||||
// It uses a basic exponential backoff algorithm that returns an initial
|
||||
// delay of ~400ms with an upper limit of ~30 seconds which should prevent
|
||||
// causing a high number of consecutive throttling errors.
|
||||
// For reference: Route 53 enforces an account-wide(!) 5req/s query limit.
|
||||
options.Backoff = retry.BackoffDelayerFunc(func(attempt int, err error) (time.Duration, error) {
|
||||
retryCount := attempt
|
||||
if retryCount > 7 {
|
||||
retryCount = 7
|
||||
}
|
||||
|
||||
delay := (1 << uint(retryCount)) * (rand.Intn(50) + 200)
|
||||
return time.Duration(delay) * time.Millisecond, nil
|
||||
})
|
||||
})
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
config: config,
|
||||
client: lightsail.New(sess),
|
||||
client: lightsail.NewFromConfig(cfg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record using the specified parameters.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
func (d *DNSProvider) Present(domain, _, keyAuth string) error {
|
||||
ctx := context.Background()
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
params := &lightsail.CreateDomainEntryInput{
|
||||
DomainName: aws.String(d.config.DNSZone),
|
||||
DomainEntry: &lightsail.DomainEntry{
|
||||
DomainEntry: &awstypes.DomainEntry{
|
||||
Name: aws.String(info.EffectiveFQDN),
|
||||
Target: aws.String(strconv.Quote(info.Value)),
|
||||
Type: aws.String("TXT"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := d.client.CreateDomainEntry(params)
|
||||
_, err := d.client.CreateDomainEntry(ctx, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("lightsail: %w", err)
|
||||
}
|
||||
|
@ -139,19 +139,20 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
}
|
||||
|
||||
// CleanUp removes the TXT record matching the specified parameters.
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
|
||||
ctx := context.Background()
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
params := &lightsail.DeleteDomainEntryInput{
|
||||
DomainName: aws.String(d.config.DNSZone),
|
||||
DomainEntry: &lightsail.DomainEntry{
|
||||
DomainEntry: &awstypes.DomainEntry{
|
||||
Name: aws.String(info.EffectiveFQDN),
|
||||
Type: aws.String("TXT"),
|
||||
Target: aws.String(strconv.Quote(info.Value)),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := d.client.DeleteDomainEntry(params)
|
||||
_, err := d.client.DeleteDomainEntry(ctx, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("lightsail: %w", err)
|
||||
}
|
||||
|
|
|
@ -56,4 +56,4 @@ Alternatively, you can also set the `Resource` to `*` (wildcard), which allow to
|
|||
LIGHTSAIL_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
||||
|
||||
[Links]
|
||||
GoClient = "https://github.com/aws/aws-sdk-go/"
|
||||
GoClient = "https://github.com/aws/aws-sdk-go-v2"
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package lightsail
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/lightsail"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -24,13 +25,15 @@ func TestLiveTTL(t *testing.T) {
|
|||
err = provider.Present(domain, "foo", "bar")
|
||||
require.NoError(t, err)
|
||||
|
||||
// we need a separate Lightsail client here as the one in the DNS provider is
|
||||
// unexported.
|
||||
// we need a separate Lightsail client here as the one in the DNS provider is unexported.
|
||||
fqdn := "_acme-challenge." + domain
|
||||
sess, err := session.NewSession()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
svc := lightsail.New(sess)
|
||||
svc := lightsail.NewFromConfig(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
|
@ -44,15 +47,24 @@ func TestLiveTTL(t *testing.T) {
|
|||
DomainName: aws.String(domain),
|
||||
}
|
||||
|
||||
resp, err := svc.GetDomain(params)
|
||||
resp, err := svc.GetDomain(ctx, params)
|
||||
require.NoError(t, err)
|
||||
|
||||
entries := resp.Domain.DomainEntries
|
||||
for _, entry := range entries {
|
||||
if aws.StringValue(entry.Type) == "TXT" && aws.StringValue(entry.Name) == fqdn {
|
||||
if deref(entry.Type) == "TXT" && deref(entry.Name) == fqdn {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatalf("Could not find a TXT record for _acme-challenge.%s", domain)
|
||||
}
|
||||
|
||||
func deref[T string | int | int32 | int64 | bool](v *T) T {
|
||||
if v == nil {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
return *v
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package lightsail
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/service/lightsail"
|
||||
"github.com/go-acme/lego/v4/platform/tester"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -29,23 +31,26 @@ var envTest = tester.NewEnvTest(
|
|||
WithDomain(EnvDNSZone).
|
||||
WithLiveTestRequirements(envAwsAccessKeyID, envAwsSecretAccessKey, EnvDNSZone)
|
||||
|
||||
func makeProvider(serverURL string) (*DNSProvider, error) {
|
||||
config := &aws.Config{
|
||||
Credentials: credentials.NewStaticCredentials("abc", "123", " "),
|
||||
Endpoint: aws.String(serverURL),
|
||||
Region: aws.String("mock-region"),
|
||||
MaxRetries: aws.Int(1),
|
||||
type endpointResolverMock struct {
|
||||
endpoint string
|
||||
}
|
||||
|
||||
func (e endpointResolverMock) ResolveEndpoint(_, _ string, _ ...interface{}) (aws.Endpoint, error) {
|
||||
return aws.Endpoint{URL: e.endpoint}, nil
|
||||
}
|
||||
|
||||
func makeProvider(serverURL string) *DNSProvider {
|
||||
config := aws.Config{
|
||||
Credentials: credentials.NewStaticCredentialsProvider("abc", "123", " "),
|
||||
Region: "mock-region",
|
||||
EndpointResolverWithOptions: endpointResolverMock{endpoint: serverURL},
|
||||
RetryMaxAttempts: 1,
|
||||
}
|
||||
|
||||
sess, err := session.NewSession(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return &DNSProvider{
|
||||
client: lightsail.NewFromConfig(config),
|
||||
config: NewDefaultConfig(),
|
||||
}
|
||||
|
||||
conf := NewDefaultConfig()
|
||||
|
||||
client := lightsail.New(sess)
|
||||
return &DNSProvider{client: client, config: conf}, nil
|
||||
}
|
||||
|
||||
func TestCredentialsFromEnv(t *testing.T) {
|
||||
|
@ -56,15 +61,19 @@ func TestCredentialsFromEnv(t *testing.T) {
|
|||
_ = os.Setenv(envAwsSecretAccessKey, "123")
|
||||
_ = os.Setenv(envAwsRegion, "us-east-1")
|
||||
|
||||
config := &aws.Config{
|
||||
CredentialsChainVerboseErrors: aws.Bool(true),
|
||||
}
|
||||
|
||||
sess, err := session.NewSession(config)
|
||||
ctx := context.Background()
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = sess.Config.Credentials.Get()
|
||||
cs, err := cfg.Credentials.Retrieve(ctx)
|
||||
require.NoError(t, err, "Expected credentials to be set from environment")
|
||||
|
||||
expected := aws.Credentials{
|
||||
AccessKeyID: "123",
|
||||
SecretAccessKey: "123",
|
||||
Source: "EnvConfigCredentials",
|
||||
}
|
||||
assert.Equal(t, expected, cs)
|
||||
}
|
||||
|
||||
func TestDNSProvider_Present(t *testing.T) {
|
||||
|
@ -74,12 +83,11 @@ func TestDNSProvider_Present(t *testing.T) {
|
|||
|
||||
serverURL := newMockServer(t, mockResponses)
|
||||
|
||||
provider, err := makeProvider(serverURL)
|
||||
require.NoError(t, err)
|
||||
provider := makeProvider(serverURL)
|
||||
|
||||
domain := "example.com"
|
||||
keyAuth := "123456d=="
|
||||
|
||||
err = provider.Present(domain, "", keyAuth)
|
||||
err := provider.Present(domain, "", keyAuth)
|
||||
require.NoError(t, err, "Expected Present to return no error")
|
||||
}
|
||||
|
|
|
@ -2,19 +2,21 @@
|
|||
package route53
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/aws/retry"
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||
awstypes "github.com/aws/aws-sdk-go-v2/service/route53/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/platform/config/env"
|
||||
"github.com/go-acme/lego/v4/platform/wait"
|
||||
|
@ -55,7 +57,7 @@ type Config struct {
|
|||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
|
||||
Client *route53.Route53
|
||||
Client *route53.Client
|
||||
}
|
||||
|
||||
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
||||
|
@ -74,31 +76,10 @@ func NewDefaultConfig() *Config {
|
|||
|
||||
// DNSProvider implements the challenge.Provider interface.
|
||||
type DNSProvider struct {
|
||||
client *route53.Route53
|
||||
client *route53.Client
|
||||
config *Config
|
||||
}
|
||||
|
||||
// customRetryer implements the client.Retryer interface by composing the DefaultRetryer.
|
||||
// It controls the logic for retrying recoverable request errors (e.g. when rate limits are exceeded).
|
||||
type customRetryer struct {
|
||||
client.DefaultRetryer
|
||||
}
|
||||
|
||||
// RetryRules overwrites the DefaultRetryer's method.
|
||||
// It uses a basic exponential backoff algorithm:
|
||||
// that returns an initial delay of ~400ms with an upper limit of ~30 seconds,
|
||||
// which should prevent causing a high number of consecutive throttling errors.
|
||||
// For reference: Route 53 enforces an account-wide(!) 5req/s query limit.
|
||||
func (d customRetryer) RetryRules(r *request.Request) time.Duration {
|
||||
retryCount := r.RetryCount
|
||||
if retryCount > 7 {
|
||||
retryCount = 7
|
||||
}
|
||||
|
||||
delay := (1 << uint(retryCount)) * (rand.Intn(50) + 200)
|
||||
return time.Duration(delay) * time.Millisecond
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance configured for the AWS Route 53 service.
|
||||
//
|
||||
// AWS Credentials are automatically detected in the following locations and prioritized in the following order:
|
||||
|
@ -124,13 +105,15 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return &DNSProvider{client: config.Client, config: config}, nil
|
||||
}
|
||||
|
||||
sess, err := createSession(config)
|
||||
ctx := context.Background()
|
||||
|
||||
cfg, err := createAWSConfig(ctx, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
client: route53.New(sess),
|
||||
client: route53.NewFromConfig(cfg),
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
@ -142,14 +125,15 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
|
||||
// Present creates a TXT record using the specified parameters.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
ctx := context.Background()
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
hostedZoneID, err := d.getHostedZoneID(info.EffectiveFQDN)
|
||||
hostedZoneID, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: failed to determine hosted zone ID: %w", err)
|
||||
}
|
||||
|
||||
records, err := d.getExistingRecordSets(hostedZoneID, info.EffectiveFQDN)
|
||||
records, err := d.getExistingRecordSets(ctx, hostedZoneID, info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: %w", err)
|
||||
}
|
||||
|
@ -158,39 +142,41 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
|
||||
var found bool
|
||||
for _, record := range records {
|
||||
if aws.StringValue(record.Value) == realValue {
|
||||
if deref(record.Value) == realValue {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
records = append(records, &route53.ResourceRecord{Value: aws.String(realValue)})
|
||||
records = append(records, awstypes.ResourceRecord{Value: aws.String(realValue)})
|
||||
}
|
||||
|
||||
recordSet := &route53.ResourceRecordSet{
|
||||
recordSet := &awstypes.ResourceRecordSet{
|
||||
Name: aws.String(info.EffectiveFQDN),
|
||||
Type: aws.String("TXT"),
|
||||
Type: "TXT",
|
||||
TTL: aws.Int64(int64(d.config.TTL)),
|
||||
ResourceRecords: records,
|
||||
}
|
||||
|
||||
err = d.changeRecord(route53.ChangeActionUpsert, hostedZoneID, recordSet)
|
||||
err = d.changeRecord(ctx, awstypes.ChangeActionUpsert, hostedZoneID, recordSet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanUp removes the TXT record matching the specified parameters.
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
ctx := context.Background()
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
hostedZoneID, err := d.getHostedZoneID(info.EffectiveFQDN)
|
||||
hostedZoneID, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine Route 53 hosted zone ID: %w", err)
|
||||
}
|
||||
|
||||
records, err := d.getExistingRecordSets(hostedZoneID, info.EffectiveFQDN)
|
||||
records, err := d.getExistingRecordSets(ctx, hostedZoneID, info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: %w", err)
|
||||
}
|
||||
|
@ -199,33 +185,33 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
recordSet := &route53.ResourceRecordSet{
|
||||
recordSet := &awstypes.ResourceRecordSet{
|
||||
Name: aws.String(info.EffectiveFQDN),
|
||||
Type: aws.String("TXT"),
|
||||
Type: "TXT",
|
||||
TTL: aws.Int64(int64(d.config.TTL)),
|
||||
ResourceRecords: records,
|
||||
}
|
||||
|
||||
err = d.changeRecord(route53.ChangeActionDelete, hostedZoneID, recordSet)
|
||||
err = d.changeRecord(ctx, awstypes.ChangeActionDelete, hostedZoneID, recordSet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route53: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) changeRecord(action, hostedZoneID string, recordSet *route53.ResourceRecordSet) error {
|
||||
func (d *DNSProvider) changeRecord(ctx context.Context, action awstypes.ChangeAction, hostedZoneID string, recordSet *awstypes.ResourceRecordSet) error {
|
||||
recordSetInput := &route53.ChangeResourceRecordSetsInput{
|
||||
HostedZoneId: aws.String(hostedZoneID),
|
||||
ChangeBatch: &route53.ChangeBatch{
|
||||
ChangeBatch: &awstypes.ChangeBatch{
|
||||
Comment: aws.String("Managed by Lego"),
|
||||
Changes: []*route53.Change{{
|
||||
Action: aws.String(action),
|
||||
Changes: []awstypes.Change{{
|
||||
Action: action,
|
||||
ResourceRecordSet: recordSet,
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := d.client.ChangeResourceRecordSets(recordSetInput)
|
||||
resp, err := d.client.ChangeResourceRecordSets(ctx, recordSetInput)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to change record set: %w", err)
|
||||
}
|
||||
|
@ -235,26 +221,26 @@ func (d *DNSProvider) changeRecord(action, hostedZoneID string, recordSet *route
|
|||
return wait.For("route53", d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
|
||||
reqParams := &route53.GetChangeInput{Id: changeID}
|
||||
|
||||
resp, err := d.client.GetChange(reqParams)
|
||||
resp, err := d.client.GetChange(ctx, reqParams)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to query change status: %w", err)
|
||||
}
|
||||
|
||||
if aws.StringValue(resp.ChangeInfo.Status) == route53.ChangeStatusInsync {
|
||||
if resp.ChangeInfo.Status == awstypes.ChangeStatusInsync {
|
||||
return true, nil
|
||||
}
|
||||
return false, fmt.Errorf("unable to retrieve change: ID=%s", aws.StringValue(changeID))
|
||||
return false, fmt.Errorf("unable to retrieve change: ID=%s", deref(changeID))
|
||||
})
|
||||
}
|
||||
|
||||
func (d *DNSProvider) getExistingRecordSets(hostedZoneID, fqdn string) ([]*route53.ResourceRecord, error) {
|
||||
func (d *DNSProvider) getExistingRecordSets(ctx context.Context, hostedZoneID, fqdn string) ([]awstypes.ResourceRecord, error) {
|
||||
listInput := &route53.ListResourceRecordSetsInput{
|
||||
HostedZoneId: aws.String(hostedZoneID),
|
||||
StartRecordName: aws.String(fqdn),
|
||||
StartRecordType: aws.String("TXT"),
|
||||
StartRecordType: "TXT",
|
||||
}
|
||||
|
||||
recordSetsOutput, err := d.client.ListResourceRecordSets(listInput)
|
||||
recordSetsOutput, err := d.client.ListResourceRecordSets(ctx, listInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -263,10 +249,10 @@ func (d *DNSProvider) getExistingRecordSets(hostedZoneID, fqdn string) ([]*route
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
var records []*route53.ResourceRecord
|
||||
var records []awstypes.ResourceRecord
|
||||
|
||||
for _, recordSet := range recordSetsOutput.ResourceRecordSets {
|
||||
if aws.StringValue(recordSet.Name) == fqdn {
|
||||
if deref(recordSet.Name) == fqdn {
|
||||
records = append(records, recordSet.ResourceRecords...)
|
||||
}
|
||||
}
|
||||
|
@ -274,7 +260,7 @@ func (d *DNSProvider) getExistingRecordSets(hostedZoneID, fqdn string) ([]*route
|
|||
return records, nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
||||
func (d *DNSProvider) getHostedZoneID(ctx context.Context, fqdn string) (string, error) {
|
||||
if d.config.HostedZoneID != "" {
|
||||
return d.config.HostedZoneID, nil
|
||||
}
|
||||
|
@ -288,7 +274,7 @@ func (d *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
|||
reqParams := &route53.ListHostedZonesByNameInput{
|
||||
DNSName: aws.String(dns01.UnFqdn(authZone)),
|
||||
}
|
||||
resp, err := d.client.ListHostedZonesByName(reqParams)
|
||||
resp, err := d.client.ListHostedZonesByName(ctx, reqParams)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -296,8 +282,8 @@ func (d *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
|||
var hostedZoneID string
|
||||
for _, hostedZone := range resp.HostedZones {
|
||||
// .Name has a trailing dot
|
||||
if !aws.BoolValue(hostedZone.Config.PrivateZone) && aws.StringValue(hostedZone.Name) == authZone {
|
||||
hostedZoneID = aws.StringValue(hostedZone.Id)
|
||||
if !hostedZone.Config.PrivateZone && deref(hostedZone.Name) == authZone {
|
||||
hostedZoneID = deref(hostedZone.Id)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -311,45 +297,60 @@ func (d *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
|
|||
return hostedZoneID, nil
|
||||
}
|
||||
|
||||
func createSession(config *Config) (*session.Session, error) {
|
||||
if err := createSessionCheckParams(config); err != nil {
|
||||
return nil, err
|
||||
func createAWSConfig(ctx context.Context, config *Config) (aws.Config, error) {
|
||||
if err := createAWSConfigCheckParams(config); err != nil {
|
||||
return aws.Config{}, err
|
||||
}
|
||||
|
||||
retry := customRetryer{}
|
||||
retry.NumMaxRetries = config.MaxRetries
|
||||
optFns := []func(options *awsconfig.LoadOptions) error{
|
||||
awsconfig.WithRetryer(func() aws.Retryer {
|
||||
return retry.NewStandard(func(options *retry.StandardOptions) {
|
||||
options.MaxAttempts = config.MaxRetries
|
||||
|
||||
// It uses a basic exponential backoff algorithm that returns an initial
|
||||
// delay of ~400ms with an upper limit of ~30 seconds which should prevent
|
||||
// causing a high number of consecutive throttling errors.
|
||||
// For reference: Route 53 enforces an account-wide(!) 5req/s query limit.
|
||||
options.Backoff = retry.BackoffDelayerFunc(func(attempt int, err error) (time.Duration, error) {
|
||||
retryCount := attempt
|
||||
if retryCount > 7 {
|
||||
retryCount = 7
|
||||
}
|
||||
|
||||
delay := (1 << uint(retryCount)) * (rand.Intn(50) + 200)
|
||||
return time.Duration(delay) * time.Millisecond, nil
|
||||
})
|
||||
})
|
||||
}),
|
||||
}
|
||||
|
||||
awsConfig := aws.NewConfig()
|
||||
if config.AccessKeyID != "" && config.SecretAccessKey != "" {
|
||||
awsConfig = awsConfig.WithCredentials(credentials.NewStaticCredentials(config.AccessKeyID, config.SecretAccessKey, config.SessionToken))
|
||||
optFns = append(optFns,
|
||||
awsconfig.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(config.AccessKeyID, config.SecretAccessKey, config.SessionToken)),
|
||||
)
|
||||
}
|
||||
|
||||
if config.Region != "" {
|
||||
awsConfig = awsConfig.WithRegion(config.Region)
|
||||
optFns = append(optFns, awsconfig.WithRegion(config.Region))
|
||||
}
|
||||
|
||||
sessionCfg := request.WithRetryer(awsConfig, retry)
|
||||
|
||||
sess, err := session.NewSessionWithOptions(session.Options{Config: *sessionCfg})
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx, optFns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return aws.Config{}, err
|
||||
}
|
||||
|
||||
if config.AssumeRoleArn == "" {
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
return session.NewSession(&aws.Config{
|
||||
Region: sess.Config.Region,
|
||||
Credentials: stscreds.NewCredentials(sess, config.AssumeRoleArn, func(arp *stscreds.AssumeRoleProvider) {
|
||||
if config.AssumeRoleArn != "" {
|
||||
cfg.Credentials = stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), config.AssumeRoleArn, func(options *stscreds.AssumeRoleOptions) {
|
||||
if config.ExternalID != "" {
|
||||
arp.ExternalID = &config.ExternalID
|
||||
options.ExternalID = &config.ExternalID
|
||||
}
|
||||
}),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func createSessionCheckParams(config *Config) error {
|
||||
func createAWSConfigCheckParams(config *Config) error {
|
||||
if config == nil {
|
||||
return errors.New("config is nil")
|
||||
}
|
||||
|
@ -364,3 +365,12 @@ func createSessionCheckParams(config *Config) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deref[T string | int | int32 | int64 | bool](v *T) T {
|
||||
if v == nil {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
return *v
|
||||
}
|
||||
|
|
|
@ -140,4 +140,4 @@ Replace `Z11111112222222333333` with your hosted zone ID and `example.com` with
|
|||
|
||||
[Links]
|
||||
API = "https://docs.aws.amazon.com/Route53/latest/APIReference/API_Operations_Amazon_Route_53.html"
|
||||
GoClient = "https://github.com/aws/aws-sdk-go/aws"
|
||||
GoClient = "https://github.com/aws/aws-sdk-go-v2"
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package route53
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -26,9 +27,13 @@ func TestLiveTTL(t *testing.T) {
|
|||
|
||||
// we need a separate R53 client here as the one in the DNS provider is unexported.
|
||||
fqdn := "_acme-challenge." + domain + "."
|
||||
sess, err := session.NewSession()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx)
|
||||
require.NoError(t, err)
|
||||
svc := route53.New(sess)
|
||||
|
||||
svc := route53.NewFromConfig(cfg)
|
||||
|
||||
defer func() {
|
||||
errC := provider.CleanUp(domain, "foo", "bar")
|
||||
|
@ -37,17 +42,17 @@ func TestLiveTTL(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
zoneID, err := provider.getHostedZoneID(fqdn)
|
||||
zoneID, err := provider.getHostedZoneID(context.Background(), fqdn)
|
||||
require.NoError(t, err)
|
||||
|
||||
params := &route53.ListResourceRecordSetsInput{
|
||||
HostedZoneId: aws.String(zoneID),
|
||||
}
|
||||
resp, err := svc.ListResourceRecordSets(params)
|
||||
resp, err := svc.ListResourceRecordSets(ctx, params)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, v := range resp.ResourceRecordSets {
|
||||
if aws.StringValue(v.Name) == fqdn && aws.StringValue(v.Type) == "TXT" && aws.Int64Value(v.TTL) == 10 {
|
||||
if deref(v.Name) == fqdn && v.Type == "TXT" && deref(v.TTL) == 10 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package route53
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||
"github.com/go-acme/lego/v4/platform/tester"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -28,21 +29,26 @@ var envTest = tester.NewEnvTest(
|
|||
WithDomain(envDomain).
|
||||
WithLiveTestRequirements(EnvAccessKeyID, EnvSecretAccessKey, EnvRegion, envDomain)
|
||||
|
||||
type endpointResolverMock struct {
|
||||
endpoint string
|
||||
}
|
||||
|
||||
func (e endpointResolverMock) ResolveEndpoint(_, _ string, _ ...interface{}) (aws.Endpoint, error) {
|
||||
return aws.Endpoint{URL: e.endpoint}, nil
|
||||
}
|
||||
|
||||
func makeTestProvider(t *testing.T, serverURL string) *DNSProvider {
|
||||
t.Helper()
|
||||
|
||||
config := &aws.Config{
|
||||
Credentials: credentials.NewStaticCredentials("abc", "123", " "),
|
||||
Endpoint: aws.String(serverURL),
|
||||
Region: aws.String("mock-region"),
|
||||
MaxRetries: aws.Int(1),
|
||||
cfg := aws.Config{
|
||||
Credentials: credentials.NewStaticCredentialsProvider("abc", "123", " "),
|
||||
Region: "mock-region",
|
||||
EndpointResolverWithOptions: endpointResolverMock{endpoint: serverURL},
|
||||
RetryMaxAttempts: 1,
|
||||
}
|
||||
|
||||
sess, err := session.NewSession(config)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &DNSProvider{
|
||||
client: route53.New(sess),
|
||||
client: route53.NewFromConfig(cfg),
|
||||
config: NewDefaultConfig(),
|
||||
}
|
||||
}
|
||||
|
@ -55,22 +61,21 @@ func Test_loadCredentials_FromEnv(t *testing.T) {
|
|||
_ = os.Setenv(EnvSecretAccessKey, "456")
|
||||
_ = os.Setenv(EnvRegion, "us-east-1")
|
||||
|
||||
config := &aws.Config{
|
||||
CredentialsChainVerboseErrors: aws.Bool(true),
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
sess, err := session.NewSession(config)
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, err := sess.Config.Credentials.Get()
|
||||
value, err := cfg.Credentials.Retrieve(ctx)
|
||||
require.NoError(t, err, "Expected credentials to be set from environment")
|
||||
|
||||
expected := credentials.Value{
|
||||
expected := aws.Credentials{
|
||||
AccessKeyID: "123",
|
||||
SecretAccessKey: "456",
|
||||
SessionToken: "",
|
||||
ProviderName: "EnvConfigCredentials",
|
||||
Source: "EnvConfigCredentials",
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, value)
|
||||
}
|
||||
|
||||
|
@ -78,13 +83,12 @@ func Test_loadRegion_FromEnv(t *testing.T) {
|
|||
defer envTest.RestoreEnv()
|
||||
envTest.ClearEnv()
|
||||
|
||||
os.Setenv(EnvRegion, route53.CloudWatchRegionUsEast1)
|
||||
_ = os.Setenv(EnvRegion, "foo")
|
||||
|
||||
sess, err := session.NewSession(aws.NewConfig())
|
||||
cfg, err := awsconfig.LoadDefaultConfig(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
region := aws.StringValue(sess.Config.Region)
|
||||
assert.Equal(t, route53.CloudWatchRegionUsEast1, region, "Region")
|
||||
assert.Equal(t, "foo", cfg.Region, "Region")
|
||||
}
|
||||
|
||||
func Test_getHostedZoneID_FromEnv(t *testing.T) {
|
||||
|
@ -93,12 +97,12 @@ func Test_getHostedZoneID_FromEnv(t *testing.T) {
|
|||
|
||||
expectedZoneID := "zoneID"
|
||||
|
||||
os.Setenv(EnvHostedZoneID, expectedZoneID)
|
||||
_ = os.Setenv(EnvHostedZoneID, expectedZoneID)
|
||||
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
hostedZoneID, err := provider.getHostedZoneID("whatever")
|
||||
hostedZoneID, err := provider.getHostedZoneID(context.Background(), "whatever")
|
||||
require.NoError(t, err, "HostedZoneID")
|
||||
|
||||
assert.Equal(t, expectedZoneID, hostedZoneID)
|
||||
|
@ -144,7 +148,7 @@ func TestNewDefaultConfig(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
envTest.ClearEnv()
|
||||
for key, value := range test.envVars {
|
||||
os.Setenv(key, value)
|
||||
_ = os.Setenv(key, value)
|
||||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
|
@ -156,9 +160,9 @@ func TestNewDefaultConfig(t *testing.T) {
|
|||
|
||||
func TestDNSProvider_Present(t *testing.T) {
|
||||
mockResponses := MockResponseMap{
|
||||
"/2013-04-01/hostedzonesbyname": {StatusCode: 200, Body: ListHostedZonesByNameResponse},
|
||||
"/2013-04-01/hostedzone/ABCDEFG/rrset/": {StatusCode: 200, Body: ChangeResourceRecordSetsResponse},
|
||||
"/2013-04-01/change/123456": {StatusCode: 200, Body: GetChangeResponse},
|
||||
"/2013-04-01/hostedzonesbyname": {StatusCode: 200, Body: ListHostedZonesByNameResponse},
|
||||
"/2013-04-01/hostedzone/ABCDEFG/rrset": {StatusCode: 200, Body: ChangeResourceRecordSetsResponse},
|
||||
"/2013-04-01/change/123456": {StatusCode: 200, Body: GetChangeResponse},
|
||||
"/2013-04-01/hostedzone/ABCDEFG/rrset?name=_acme-challenge.example.com.&type=TXT": {
|
||||
StatusCode: 200,
|
||||
Body: "",
|
||||
|
@ -178,12 +182,12 @@ func TestDNSProvider_Present(t *testing.T) {
|
|||
require.NoError(t, err, "Expected Present to return no error")
|
||||
}
|
||||
|
||||
func TestCreateSession(t *testing.T) {
|
||||
func Test_createAWSConfig(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
env map[string]string
|
||||
config *Config
|
||||
wantCreds credentials.Value
|
||||
wantCreds aws.Credentials
|
||||
wantDefaultChain bool
|
||||
wantRegion string
|
||||
wantErr string
|
||||
|
@ -218,11 +222,11 @@ func TestCreateSession(t *testing.T) {
|
|||
AccessKeyID: "one",
|
||||
SecretAccessKey: "two",
|
||||
},
|
||||
wantCreds: credentials.Value{
|
||||
wantCreds: aws.Credentials{
|
||||
AccessKeyID: "one",
|
||||
SecretAccessKey: "two",
|
||||
SessionToken: "",
|
||||
ProviderName: credentials.StaticProviderName,
|
||||
Source: credentials.StaticCredentialsName,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -232,11 +236,11 @@ func TestCreateSession(t *testing.T) {
|
|||
SecretAccessKey: "two",
|
||||
SessionToken: "three",
|
||||
},
|
||||
wantCreds: credentials.Value{
|
||||
wantCreds: aws.Credentials{
|
||||
AccessKeyID: "one",
|
||||
SecretAccessKey: "two",
|
||||
SessionToken: "three",
|
||||
ProviderName: credentials.StaticProviderName,
|
||||
Source: credentials.StaticCredentialsName,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -268,24 +272,26 @@ func TestCreateSession(t *testing.T) {
|
|||
|
||||
envTest.Apply(test.env)
|
||||
|
||||
sess, err := createSession(test.config)
|
||||
ctx := context.Background()
|
||||
|
||||
cfg, err := createAWSConfig(ctx, test.config)
|
||||
requireErr(t, err, test.wantErr)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
gotCreds, err := sess.Config.Credentials.Get()
|
||||
gotCreds, err := cfg.Credentials.Retrieve(ctx)
|
||||
|
||||
if test.wantDefaultChain {
|
||||
assert.NotEqual(t, credentials.StaticProviderName, gotCreds.ProviderName)
|
||||
assert.NotEqual(t, credentials.StaticCredentialsName, gotCreds.Source)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.wantCreds, gotCreds)
|
||||
}
|
||||
|
||||
if test.wantRegion != "" {
|
||||
assert.Equal(t, test.wantRegion, aws.StringValue(sess.Config.Region))
|
||||
assert.Equal(t, test.wantRegion, cfg.Region)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue