[plugin/route53] Cleanup AWS config/credentials setup. (#5370)

Signed-off-by: Dmitry Ilyevsky <ilyevsky@gmail.com>
This commit is contained in:
dilyevsky
2022-05-09 10:35:42 -07:00
committed by GitHub
parent be009ed672
commit 2895b06732
3 changed files with 33 additions and 36 deletions

View File

@@ -9,7 +9,7 @@
The route53 plugin is useful for serving zones from resource record The route53 plugin is useful for serving zones from resource record
sets in AWS route53. This plugin supports all Amazon Route 53 records sets in AWS route53. This plugin supports all Amazon Route 53 records
([https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html)). ([https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html)).
The route53 plugin can be used when coredns is deployed on AWS or elsewhere. The route53 plugin can be used when CoreDNS is deployed on AWS or elsewhere.
## Syntax ## Syntax
@@ -31,9 +31,9 @@ route53 [ZONE:HOSTED_ZONE_ID...] {
accessed. accessed.
* **AWS\_ACCESS\_KEY\_ID** and **AWS\_SECRET\_ACCESS\_KEY** the AWS access key ID and secret access key * **AWS\_ACCESS\_KEY\_ID** and **AWS\_SECRET\_ACCESS\_KEY** the AWS access key ID and secret access key
to be used when query AWS (optional). If they are not provided, then coredns tries to access to be used when querying AWS (optional). If they are not provided, CoreDNS tries to access
AWS credentials the same way as AWS CLI, e.g., environmental variables, AWS credentials file, AWS credentials the same way as AWS CLI - environment variables, shared credential file (and optionally
instance profile credentials, etc. shared config file if `AWS_SDK_LOAD_CONFIG` env is set), and lastly EC2 Instance Roles.
Note the usage of `aws_access_key` has been deprecated and may be removed in future versions. Instead, Note the usage of `aws_access_key` has been deprecated and may be removed in future versions. Instead,
user can use other methods to pass crentials, e.g., with environmental variable `AWS_ACCESS_KEY_ID` and user can use other methods to pass crentials, e.g., with environmental variable `AWS_ACCESS_KEY_ID` and
`AWS_SECRET_ACCESS_KEY`, respectively. `AWS_SECRET_ACCESS_KEY`, respectively.
@@ -41,9 +41,12 @@ route53 [ZONE:HOSTED_ZONE_ID...] {
* `aws_endpoint` can be used to control the endpoint to use when querying AWS (optional). **ENDPOINT** is the * `aws_endpoint` can be used to control the endpoint to use when querying AWS (optional). **ENDPOINT** is the
URL of the endpoint to use. If this is not provided the default AWS endpoint resolution will occur. URL of the endpoint to use. If this is not provided the default AWS endpoint resolution will occur.
* `credentials` is used for reading the credential **FILENAME** and setting the **PROFILE** name for a given * `credentials` is used for overriding the shared credentials **FILENAME** and the **PROFILE** name for a
zone. **PROFILE** is the AWS account profile name. Defaults to `default`. **FILENAME** is the given zone. **PROFILE** is the AWS account profile name. Defaults to `default`. **FILENAME** is the
AWS credentials filename, defaults to `~/.aws/credentials`. AWS shared credentials filename, defaults to `~/.aws/credentials`. CoreDNS will only load shared credentials
file and not shared config file (`~/.aws/config`) by default. Set `AWS_SDK_LOAD_CONFIG` env variable to
a truthy value to enable also loading of `~/.aws/config` (e.g. if you want to provide assumed IAM role
configuration). Will be ignored if static keys are set via `aws_access_key`.
* `fallthrough` If zone matches and no record can be generated, pass request to the next plugin. * `fallthrough` If zone matches and no record can be generated, pass request to the next plugin.
If **ZONES** is omitted, then fallthrough happens for all zones for which the plugin is If **ZONES** is omitted, then fallthrough happens for all zones for which the plugin is

View File

@@ -3,6 +3,7 @@ package route53
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -26,8 +27,8 @@ var log = clog.NewWithPlugin("route53")
func init() { plugin.Register("route53", setup) } func init() { plugin.Register("route53", setup) }
// exposed for testing // exposed for testing
var f = func(credential *credentials.Credentials, endpoint *string) route53iface.Route53API { var f = func(opts session.Options) route53iface.Route53API {
return route53.New(session.Must(session.NewSession(&aws.Config{Credentials: credential, Endpoint: endpoint}))) return route53.New(session.Must(session.NewSessionWithOptions(opts)))
} }
func setup(c *caddy.Controller) error { func setup(c *caddy.Controller) error {
@@ -35,16 +36,15 @@ func setup(c *caddy.Controller) error {
keyPairs := map[string]struct{}{} keyPairs := map[string]struct{}{}
keys := map[string][]string{} keys := map[string][]string{}
// Route53 plugin attempts to find AWS credentials by using ChainCredentials. // Route53 plugin attempts to load AWS credentials following default SDK chaining.
// And the order of that provider chain is as follows: // The order configuration is loaded in is:
// Static AWS keys -> Environment Variables -> Credentials file -> IAM role // * Static AWS keys set in Corefile (deprecated)
// With that said, even though a user doesn't define any credentials in // * Environment Variables
// Corefile, we should still attempt to read the default credentials file, // * Shared Credentials file
// ~/.aws/credentials with the default profile. // * Shared Configuration file (if AWS_SDK_LOAD_CONFIG is set to truthy value)
sharedProvider := &credentials.SharedCredentialsProvider{} // * EC2 Instance Metadata (credentials only)
var providers []credentials.Provider opts := session.Options{}
var fall fall.F var fall fall.F
var endpoint string
refresh := time.Duration(1) * time.Minute // default update frequency to 1 minute refresh := time.Duration(1) * time.Minute // default update frequency to 1 minute
@@ -74,16 +74,11 @@ func setup(c *caddy.Controller) error {
if len(v) < 2 { if len(v) < 2 {
return plugin.Error("route53", c.Errf("invalid access key: '%v'", v)) return plugin.Error("route53", c.Errf("invalid access key: '%v'", v))
} }
providers = append(providers, &credentials.StaticProvider{ opts.Config.Credentials = credentials.NewStaticCredentials(v[0], v[1], "")
Value: credentials.Value{
AccessKeyID: v[0],
SecretAccessKey: v[1],
},
})
log.Warningf("Save aws_access_key in Corefile has been deprecated, please use other authentication methods instead") log.Warningf("Save aws_access_key in Corefile has been deprecated, please use other authentication methods instead")
case "aws_endpoint": case "aws_endpoint":
if c.NextArg() { if c.NextArg() {
endpoint = c.Val() opts.Config.Endpoint = aws.String(c.Val())
} else { } else {
return plugin.Error("route53", c.ArgErr()) return plugin.Error("route53", c.ArgErr())
} }
@@ -91,12 +86,17 @@ func setup(c *caddy.Controller) error {
c.RemainingArgs() // eats args c.RemainingArgs() // eats args
case "credentials": case "credentials":
if c.NextArg() { if c.NextArg() {
sharedProvider.Profile = c.Val() opts.Profile = c.Val()
} else { } else {
return c.ArgErr() return c.ArgErr()
} }
if c.NextArg() { if c.NextArg() {
sharedProvider.Filename = c.Val() opts.SharedConfigFiles = []string{c.Val()}
// If AWS_SDK_LOAD_CONFIG is set also load ~/.aws/config to stay consistent
// with default SDK behavior.
if ok, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG")); ok {
opts.SharedConfigFiles = append(opts.SharedConfigFiles, defaults.SharedConfigFilename())
}
} }
case "fallthrough": case "fallthrough":
fall.SetZonesFromArgs(c.RemainingArgs()) fall.SetZonesFromArgs(c.RemainingArgs())
@@ -122,13 +122,7 @@ func setup(c *caddy.Controller) error {
} }
} }
session, err := session.NewSession(&aws.Config{}) client := f(opts)
if err != nil {
return plugin.Error("route53", err)
}
providers = append(providers, &credentials.EnvProvider{}, sharedProvider, defaults.RemoteCredProvider(*session.Config, session.Handlers))
client := f(credentials.NewChainCredentials(providers), &endpoint)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
h, err := New(ctx, client, keys, refresh) h, err := New(ctx, client, keys, refresh)
if err != nil { if err != nil {

View File

@@ -5,12 +5,12 @@ import (
"github.com/coredns/caddy" "github.com/coredns/caddy"
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/route53/route53iface" "github.com/aws/aws-sdk-go/service/route53/route53iface"
) )
func TestSetupRoute53(t *testing.T) { func TestSetupRoute53(t *testing.T) {
f = func(credential *credentials.Credentials, endpoint *string) route53iface.Route53API { f = func(opts session.Options) route53iface.Route53API {
return fakeRoute53{} return fakeRoute53{}
} }