github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/provider/ec2/credentials.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ec2
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  
    12  	"github.com/juju/errors"
    13  	"github.com/juju/utils"
    14  	"gopkg.in/amz.v3/aws"
    15  	"gopkg.in/ini.v1"
    16  
    17  	"github.com/juju/juju/cloud"
    18  )
    19  
    20  type environProviderCredentials struct{}
    21  
    22  // CredentialSchemas is part of the environs.ProviderCredentials interface.
    23  func (environProviderCredentials) CredentialSchemas() map[cloud.AuthType]cloud.CredentialSchema {
    24  	return map[cloud.AuthType]cloud.CredentialSchema{
    25  		cloud.AccessKeyAuthType: {
    26  			{
    27  				"access-key",
    28  				cloud.CredentialAttr{
    29  					Description: "The EC2 access key",
    30  				},
    31  			}, {
    32  				"secret-key",
    33  				cloud.CredentialAttr{
    34  					Description: "The EC2 secret key",
    35  					Hidden:      true,
    36  				},
    37  			},
    38  		},
    39  	}
    40  }
    41  
    42  // DetectCredentials is part of the environs.ProviderCredentials interface.
    43  func (e environProviderCredentials) DetectCredentials() (*cloud.CloudCredential, error) {
    44  	dir := credentialsDir()
    45  	credsFile := filepath.Join(dir, "credentials")
    46  	credInfo, err := ini.LooseLoad(credsFile)
    47  	if err != nil {
    48  		return nil, errors.Annotate(err, "loading AWS credentials file")
    49  	}
    50  	credInfo.NameMapper = ini.TitleUnderscore
    51  
    52  	// There's always a section called "DEFAULT" for top level items.
    53  	if len(credInfo.Sections()) == 1 {
    54  		// No standard AWS credentials so try environment variables.
    55  		return e.detectEnvCredentials()
    56  	}
    57  
    58  	type accessKeyValues struct {
    59  		AwsAccessKeyId     string
    60  		AwsSecretAccessKey string
    61  	}
    62  	result := cloud.CloudCredential{
    63  		AuthCredentials: make(map[string]cloud.Credential),
    64  	}
    65  	for _, credName := range credInfo.SectionStrings() {
    66  		if credName == ini.DEFAULT_SECTION {
    67  			// No credentials at top level.
    68  			continue
    69  		}
    70  		values := new(accessKeyValues)
    71  		if err := credInfo.Section(credName).MapTo(values); err != nil {
    72  			return nil, errors.Annotatef(err, "invalid credential attributes in section %q", credName)
    73  		}
    74  		// Basic validation check
    75  		if values.AwsAccessKeyId == "" || values.AwsSecretAccessKey == "" {
    76  			logger.Warningf("missing aws credential attributes in credentials file section %q", credName)
    77  			continue
    78  		}
    79  		accessKeyCredential := cloud.NewCredential(
    80  			cloud.AccessKeyAuthType,
    81  			map[string]string{
    82  				"access-key": values.AwsAccessKeyId,
    83  				"secret-key": values.AwsSecretAccessKey,
    84  			},
    85  		)
    86  		accessKeyCredential.Label = fmt.Sprintf("aws credential %q", credName)
    87  		result.AuthCredentials[credName] = accessKeyCredential
    88  	}
    89  
    90  	// See if there's also a default region defined.
    91  	configFile := filepath.Join(dir, "config")
    92  	configInfo, err := ini.LooseLoad(configFile)
    93  	if err != nil {
    94  		return nil, errors.Annotate(err, "loading AWS config file")
    95  	}
    96  	result.DefaultRegion = configInfo.Section("default").Key("region").String()
    97  	return &result, nil
    98  }
    99  
   100  func credentialsDir() string {
   101  	if runtime.GOOS == "windows" {
   102  		return filepath.Join(os.Getenv("USERPROFILE"), ".aws")
   103  	}
   104  	return filepath.Join(utils.Home(), ".aws")
   105  }
   106  
   107  func (environProviderCredentials) detectEnvCredentials() (*cloud.CloudCredential, error) {
   108  	auth, err := aws.EnvAuth()
   109  	if err != nil {
   110  		return nil, errors.NewNotFound(err, "credentials not found")
   111  	}
   112  	accessKeyCredential := cloud.NewCredential(
   113  		cloud.AccessKeyAuthType,
   114  		map[string]string{
   115  			"access-key": auth.AccessKey,
   116  			"secret-key": auth.SecretKey,
   117  		},
   118  	)
   119  	user, err := utils.LocalUsername()
   120  	if err != nil {
   121  		return nil, errors.Trace(err)
   122  	}
   123  	accessKeyCredential.Label = fmt.Sprintf("aws credential %q", user)
   124  	return &cloud.CloudCredential{
   125  		AuthCredentials: map[string]cloud.Credential{
   126  			user: accessKeyCredential,
   127  		}}, nil
   128  }