From 89f3308088382e4eaa9362f0b565e461f78f1971 Mon Sep 17 00:00:00 2001 From: Jean-Laurent de Morlhon Date: Fri, 15 Jan 2016 11:05:50 +0100 Subject: [PATCH] Use ~/.aws/credentials file when no access/secret is given in cli Signed-off-by: Jean-Laurent de Morlhon --- docs/drivers/aws.md | 44 +++++++++++---- drivers/amazonec2/amazonec2.go | 16 +++++- drivers/amazonec2/amazonec2_test.go | 85 +++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 13 deletions(-) diff --git a/docs/drivers/aws.md b/docs/drivers/aws.md index 308093d59a..aae8303dfd 100644 --- a/docs/drivers/aws.md +++ b/docs/drivers/aws.md @@ -10,21 +10,44 @@ parent="smn_machine_drivers" # Amazon Web Services -Create machines on [Amazon Web Services](http://aws.amazon.com). To create machines on [Amazon Web Services](http://aws.amazon.com), you must supply two required parameters: +Create machines on [Amazon Web Services](http://aws.amazon.com). -- Access Key ID -- Secret Access Key +To create machines on [Amazon Web Services](http://aws.amazon.com), you must supply two parameters: the AWS Access Key ID and the AWS Secret Access Key. -Obtain your IDs and Keys from AWS. -To create the machine instance, specify `--driver amazonec2` and the three required parameters. +## Configuring credentials + +Before using the amazonec2 driver, ensure that you've configured credentials. + +### AWS credential file +One way to configure credentials is to use the standard credential file for Amazon AWS `~/.aws/credentials` file, which might look like: + + [default] + aws_access_key_id = AKID1234567890 + aws_secret_access_key = MY-SECRET-KEY + +You can learn more about the credentials file from this [blog post](http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs). + +This is the simplest case, you can then create a new machine with: + + $ docker-machine create --driver amazonec2 aws01 + +### Command line flags +Alternatively, you can use the flags `--amazonec2-access-key` and `--amazonec2-secret-key` on the command line: $ docker-machine create --driver amazonec2 --amazonec2-access-key AKI******* --amazonec2-secret-key 8T93C******* aws01 +### Environment variables +You can use environment variables: + + $ export AWS_ACCESS_KEY_ID=AKID1234567890 + $ export AWS_SECRET_ACCESS_KEY=MY-SECRET-KEY + $ docker-machine create --driver amazonec2 aws01 + ## Options -- `--amazonec2-access-key`: **required** Your access key id for the Amazon Web Services API. -- `--amazonec2-secret-key`: **required** Your secret access key for the Amazon Web Services API. +- `--amazonec2-access-key`: Your access key id for the Amazon Web Services API. +- `--amazonec2-secret-key`: Your secret access key for the Amazon Web Services API. - `--amazonec2-session-token`: Your session token for the Amazon Web Services API. - `--amazonec2-ami`: The AMI ID of the instance to use. - `--amazonec2-region`: The region to use when launching the instance. @@ -66,8 +89,8 @@ Environment variables and default values: | CLI option | Environment variable | Default | | ---------------------------------------- | ----------------------- | ---------------- | -| **`--amazonec2-access-key`** | `AWS_ACCESS_KEY_ID` | - | -| **`--amazonec2-secret-key`** | `AWS_SECRET_ACCESS_KEY` | - | +| `--amazonec2-access-key` | `AWS_ACCESS_KEY_ID` | - | +| `--amazonec2-secret-key` | `AWS_SECRET_ACCESS_KEY` | - | | `--amazonec2-session-token` | `AWS_SESSION_TOKEN` | - | | `--amazonec2-ami` | `AWS_AMI` | `ami-5f709f34` | | `--amazonec2-region` | `AWS_DEFAULT_REGION` | `us-east-1` | @@ -90,8 +113,7 @@ Environment variables and default values: | `--amazonec2-use-ebs-optimized-instance` | - | `false` | ## Security Group - -Note that a security group will be created and associated to the host. This security group will have the following ports opened inbound : +Note that a security group will be created and associated to the host. This security group will have the following ports opened inbound: - ssh (22/tcp) - docker (2376/tcp) diff --git a/drivers/amazonec2/amazonec2.go b/drivers/amazonec2/amazonec2.go index d853379f36..8f2dbc5e01 100644 --- a/drivers/amazonec2/amazonec2.go +++ b/drivers/amazonec2/amazonec2.go @@ -48,8 +48,8 @@ const ( var ( dockerPort = 2376 swarmPort = 3376 - errorMissingAccessKeyOption = errors.New("amazonec2 driver requires the --amazonec2-access-key option") - errorMissingSecretKeyOption = errors.New("amazonec2 driver requires the --amazonec2-secret-key option") + errorMissingAccessKeyOption = errors.New("amazonec2 driver requires the --amazonec2-access-key option or proper credentials in ~/.aws/credentials") + errorMissingSecretKeyOption = errors.New("amazonec2 driver requires the --amazonec2-secret-key option or proper credentials in ~/.aws/credentials") errorNoVPCIdFound = errors.New("amazonec2 driver requires either the --amazonec2-subnet-id or --amazonec2-vpc-id option or an AWS Account with a default vpc-id") ) @@ -285,6 +285,18 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.UseEbsOptimizedInstance = flags.Bool("amazonec2-use-ebs-optimized-instance") d.SetSwarmConfigFromFlags(flags) + if d.AccessKey == "" && d.SecretKey == "" { + credentials, err := d.awsCredentials.NewSharedCredentials("", "").Get() + if err != nil { + log.Debug("Could not load credentials from ~/.aws/credentials") + } else { + log.Debug("Successfully loaded credentials from ~/.aws/credentials") + d.AccessKey = credentials.AccessKeyID + d.SecretKey = credentials.SecretAccessKey + d.SessionToken = credentials.SessionToken + } + } + if d.AccessKey == "" { return errorMissingAccessKeyOption } diff --git a/drivers/amazonec2/amazonec2_test.go b/drivers/amazonec2/amazonec2_test.go index fb0b6f2b34..9c933e7afe 100644 --- a/drivers/amazonec2/amazonec2_test.go +++ b/drivers/amazonec2/amazonec2_test.go @@ -282,11 +282,96 @@ func TestDescribeAccountAttributeFails(t *testing.T) { assert.Empty(t, vpc) } +func TestAccessKeyIsMandatory(t *testing.T) { + driver := NewDriver("machineFoo", "path") + driver.clientFactory = func() Ec2Client { return &fakeEC2{} } + driver.awsCredentials = &cliCredentials{} + options := &commandstest.FakeFlagger{ + Data: map[string]interface{}{ + "name": "test", + "amazonec2-region": "us-east-1", + "amazonec2-zone": "e", + }, + } + + err := driver.SetConfigFromFlags(options) + + assert.Equal(t, err, errorMissingAccessKeyOption) } +func TestAccessKeyIsMandatoryEvenIfSecretKeyIsPassed(t *testing.T) { + driver := NewDriver("machineFoo", "path") + driver.clientFactory = func() Ec2Client { return &fakeEC2{} } + driver.awsCredentials = &cliCredentials{} + options := &commandstest.FakeFlagger{ + Data: map[string]interface{}{ + "name": "test", + "amazonec2-secret-key": "123", + "amazonec2-region": "us-east-1", + "amazonec2-zone": "e", + }, + } + + err := driver.SetConfigFromFlags(options) + + assert.Equal(t, err, errorMissingAccessKeyOption) } +func TestSecretKeyIsMandatory(t *testing.T) { + driver := NewDriver("machineFoo", "path") + driver.clientFactory = func() Ec2Client { return &fakeEC2{} } + driver.awsCredentials = &cliCredentials{} + options := &commandstest.FakeFlagger{ + Data: map[string]interface{}{ + "name": "test", + "amazonec2-access-key": "foobar", + "amazonec2-region": "us-east-1", + "amazonec2-zone": "e", + }, + } + + err := driver.SetConfigFromFlags(options) + + assert.Equal(t, err, errorMissingSecretKeyOption) } +func TestLoadingFromCredentialsWorked(t *testing.T) { + driver := NewDriver("machineFoo", "path") + driver.clientFactory = func() Ec2Client { return &fakeEC2WithLogin{} } + driver.awsCredentials = &fileCredentials{} + options := &commandstest.FakeFlagger{ + Data: map[string]interface{}{ + "name": "test", + "amazonec2-region": "us-east-1", + "amazonec2-zone": "e", + }, + } + + err := driver.SetConfigFromFlags(options) + + assert.NoError(t, err) + assert.Equal(t, "access", driver.AccessKey) + assert.Equal(t, "secret", driver.SecretKey) + assert.Equal(t, "token", driver.SessionToken) } +func TestPassingBothCLIArgWorked(t *testing.T) { + driver := NewDriver("machineFoo", "path") + driver.clientFactory = func() Ec2Client { return &fakeEC2WithLogin{} } + driver.awsCredentials = &cliCredentials{} + options := &commandstest.FakeFlagger{ + Data: map[string]interface{}{ + "name": "test", + "amazonec2-access-key": "foobar", + "amazonec2-secret-key": "123", + "amazonec2-region": "us-east-1", + "amazonec2-zone": "e", + }, + } + + err := driver.SetConfigFromFlags(options) + + assert.NoError(t, err) + assert.Equal(t, "foobar", driver.AccessKey) + assert.Equal(t, "123", driver.SecretKey) +}