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  }