Add support for additional AWS authentication sources
AWS client tools commonly support passing credentials via `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY`, but supporting only this is insufficient. For example, access key IDs provided by STS require passing in `AWS_SECURITY_TOKEN` as a third value, and EC2 instances are often provided dynamic credentials at runtime via the EC2 metadata service. This changeset makes `lego` attempt to find credentials in the same way that the `aws` CLI tool attempts to find credentials. The result is even less auth code than before because `goamz` provides all this with `aws.GetAuth()`.
This commit is contained in:
parent
1198444908
commit
13e01e1751
2 changed files with 27 additions and 19 deletions
|
@ -15,29 +15,29 @@ type DNSProviderRoute53 struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDNSProviderRoute53 returns a DNSProviderRoute53 instance with a configured route53 client.
|
// NewDNSProviderRoute53 returns a DNSProviderRoute53 instance with a configured route53 client.
|
||||||
// Authentication is either done using the passed credentials or - when empty -
|
// Authentication is either done using the passed credentials or - when empty - falling back to
|
||||||
// using the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
// the customary AWS credential mechanisms, including the file refernced 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 NewDNSProviderRoute53(awsAccessKey, awsSecretKey, awsRegionName string) (*DNSProviderRoute53, error) {
|
func NewDNSProviderRoute53(awsAccessKey, awsSecretKey, awsRegionName string) (*DNSProviderRoute53, error) {
|
||||||
region, ok := aws.Regions[awsRegionName]
|
region, ok := aws.Regions[awsRegionName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("Invalid AWS region name %s", awsRegionName)
|
return nil, fmt.Errorf("Invalid AWS region name %s", awsRegionName)
|
||||||
}
|
}
|
||||||
|
|
||||||
var auth aws.Auth
|
// use aws.GetAuth, which tries really hard to find credentails:
|
||||||
// First try passed in credentials
|
// - uses awsAccessKey and awsSecretKey, if provided
|
||||||
if awsAccessKey != "" && awsSecretKey != "" {
|
// - uses AWS_PROFILE / AWS_CREDENTIAL_FILE, if provided
|
||||||
auth = aws.Auth{awsAccessKey, awsSecretKey, ""}
|
// - 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
|
||||||
|
if auth, err := aws.GetAuth(awsAccessKey, awsSecretKey); err != nil {
|
||||||
|
return nil, err
|
||||||
} else {
|
} 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)
|
client := route53.New(auth, region)
|
||||||
return &DNSProviderRoute53{client: client}, nil
|
return &DNSProviderRoute53{client: client}, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present creates a TXT record using the specified parameters
|
// Present creates a TXT record using the specified parameters
|
||||||
|
|
|
@ -13,6 +13,8 @@ import (
|
||||||
var (
|
var (
|
||||||
route53Secret string
|
route53Secret string
|
||||||
route53Key string
|
route53Key string
|
||||||
|
awsCredentialFile string
|
||||||
|
homeDir string
|
||||||
testServer *testutil.HTTPServer
|
testServer *testutil.HTTPServer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,6 +71,8 @@ var serverResponseMap = testutil.ResponseMap{
|
||||||
func init() {
|
func init() {
|
||||||
route53Key = os.Getenv("AWS_ACCESS_KEY_ID")
|
route53Key = os.Getenv("AWS_ACCESS_KEY_ID")
|
||||||
route53Secret = os.Getenv("AWS_SECRET_ACCESS_KEY")
|
route53Secret = os.Getenv("AWS_SECRET_ACCESS_KEY")
|
||||||
|
awsCredentialFile = os.Getenv("AWS_CREDENTIAL_FILE")
|
||||||
|
homeDir = os.Getenv("HOME")
|
||||||
testServer = testutil.NewHTTPServer()
|
testServer = testutil.NewHTTPServer()
|
||||||
testServer.Start()
|
testServer.Start()
|
||||||
}
|
}
|
||||||
|
@ -76,6 +80,8 @@ func init() {
|
||||||
func restoreRoute53Env() {
|
func restoreRoute53Env() {
|
||||||
os.Setenv("AWS_ACCESS_KEY_ID", route53Key)
|
os.Setenv("AWS_ACCESS_KEY_ID", route53Key)
|
||||||
os.Setenv("AWS_SECRET_ACCESS_KEY", route53Secret)
|
os.Setenv("AWS_SECRET_ACCESS_KEY", route53Secret)
|
||||||
|
os.Setenv("AWS_CREDENTIAL_FILE", awsCredentialFile)
|
||||||
|
os.Setenv("HOME", homeDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRoute53TestServer() *testutil.HTTPServer {
|
func makeRoute53TestServer() *testutil.HTTPServer {
|
||||||
|
@ -108,8 +114,10 @@ func TestNewDNSProviderRoute53ValidEnv(t *testing.T) {
|
||||||
func TestNewDNSProviderRoute53MissingAuthErr(t *testing.T) {
|
func TestNewDNSProviderRoute53MissingAuthErr(t *testing.T) {
|
||||||
os.Setenv("AWS_ACCESS_KEY_ID", "")
|
os.Setenv("AWS_ACCESS_KEY_ID", "")
|
||||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "")
|
os.Setenv("AWS_SECRET_ACCESS_KEY", "")
|
||||||
|
os.Setenv("AWS_CREDENTIAL_FILE", "") // in case test machine has this variable set
|
||||||
|
os.Setenv("HOME", "/") // in case test machine has ~/.aws/credentials
|
||||||
_, err := NewDNSProviderRoute53("", "", "us-east-1")
|
_, err := NewDNSProviderRoute53("", "", "us-east-1")
|
||||||
assert.EqualError(t, err, "AWS credentials missing")
|
assert.EqualError(t, err, "No valid AWS authentication found")
|
||||||
restoreRoute53Env()
|
restoreRoute53Env()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue