github.com/rothwerx/packer@v0.9.0/builder/amazon/common/access_config.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"strings"
     8  	"unicode"
     9  
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/aws/credentials"
    12  	"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
    13  	"github.com/aws/aws-sdk-go/aws/ec2metadata"
    14  	"github.com/aws/aws-sdk-go/aws/session"
    15  	"github.com/mitchellh/packer/template/interpolate"
    16  )
    17  
    18  // AccessConfig is for common configuration related to AWS access
    19  type AccessConfig struct {
    20  	AccessKey   string `mapstructure:"access_key"`
    21  	SecretKey   string `mapstructure:"secret_key"`
    22  	RawRegion   string `mapstructure:"region"`
    23  	Token       string `mapstructure:"token"`
    24  	ProfileName string `mapstructure:"profile"`
    25  }
    26  
    27  // Config returns a valid aws.Config object for access to AWS services, or
    28  // an error if the authentication and region couldn't be resolved
    29  func (c *AccessConfig) Config() (*aws.Config, error) {
    30  	var creds *credentials.Credentials
    31  
    32  	region, err := c.Region()
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  	config := aws.NewConfig().WithRegion(region).WithMaxRetries(11)
    37  	if c.ProfileName != "" {
    38  		profile, err := NewFromProfile(c.ProfileName)
    39  		if err != nil {
    40  			return nil, err
    41  		}
    42  		creds, err = profile.CredentialsFromProfile(config)
    43  		if err != nil {
    44  			return nil, err
    45  		}
    46  	} else {
    47  		sess := session.New(config)
    48  		creds = credentials.NewChainCredentials([]credentials.Provider{
    49  			&credentials.StaticProvider{Value: credentials.Value{
    50  				AccessKeyID:     c.AccessKey,
    51  				SecretAccessKey: c.SecretKey,
    52  				SessionToken:    c.Token,
    53  			}},
    54  			&credentials.EnvProvider{},
    55  			&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
    56  			&ec2rolecreds.EC2RoleProvider{
    57  				Client: ec2metadata.New(sess),
    58  			},
    59  		})
    60  	}
    61  	return config.WithCredentials(creds), nil
    62  }
    63  
    64  // Region returns the aws.Region object for access to AWS services, requesting
    65  // the region from the instance metadata if possible.
    66  func (c *AccessConfig) Region() (string, error) {
    67  	if c.RawRegion != "" {
    68  		if valid := ValidateRegion(c.RawRegion); valid == false {
    69  			return "", fmt.Errorf("Not a valid region: %s", c.RawRegion)
    70  		}
    71  		return c.RawRegion, nil
    72  	}
    73  
    74  	md, err := GetInstanceMetaData("placement/availability-zone")
    75  	if err != nil {
    76  		return "", err
    77  	}
    78  
    79  	region := strings.TrimRightFunc(string(md), unicode.IsLetter)
    80  	return region, nil
    81  }
    82  
    83  func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
    84  	var errs []error
    85  	if c.RawRegion != "" {
    86  		if valid := ValidateRegion(c.RawRegion); valid == false {
    87  			errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))
    88  		}
    89  	}
    90  
    91  	if len(errs) > 0 {
    92  		return errs
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  func GetInstanceMetaData(path string) (contents []byte, err error) {
    99  	url := "http://169.254.169.254/latest/meta-data/" + path
   100  
   101  	resp, err := http.Get(url)
   102  	if err != nil {
   103  		return
   104  	}
   105  	defer resp.Body.Close()
   106  
   107  	if resp.StatusCode != 200 {
   108  		err = fmt.Errorf("Code %d returned for url %s", resp.StatusCode, url)
   109  		return
   110  	}
   111  
   112  	body, err := ioutil.ReadAll(resp.Body)
   113  	if err != nil {
   114  		return
   115  	}
   116  	return []byte(body), err
   117  }