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