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 }