package main
import (
+ "bufio"
"bytes"
"context"
"crypto/sha256"
if v.Bucket == "" {
return errors.New("DriverParameters: Bucket must be provided")
}
- if v.IAMRole == "" && (v.AccessKey == "" || v.SecretKey == "") {
- return errors.New("DriverParameters: either IAMRole or literal credentials (AccessKey and SecretKey) must be provided")
- }
if v.IndexPageSize == 0 {
v.IndexPageSize = 1000
}
}
func (v *S3Volume) bootstrapIAMCredentials() error {
- if v.IAMRole == "" {
+ if v.AccessKey != "" || v.SecretKey != "" {
+ if v.IAMRole != "" {
+ return errors.New("invalid DriverParameters: AccessKey and SecretKey must be blank if IAMRole is specified")
+ }
return nil
}
ttl, err := v.updateIAMCredentials()
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Minute))
defer cancel()
+ metadataBaseURL := "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
+
var url string
if strings.Contains(v.IAMRole, "://") {
// Configuration provides complete URL (used by tests)
url = v.IAMRole
- } else {
+ } else if v.IAMRole != "" {
// Configuration provides IAM role name and we use the
// AWS metadata endpoint
- url = "http://169.254.169.254/latest/meta-data/iam/security-credentials/" + v.IAMRole
+ url = metadataBaseURL + v.IAMRole
+ } else {
+ url = metadataBaseURL
+ v.logger.WithField("URL", url).Debug("looking up IAM role name")
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return 0, fmt.Errorf("error setting up request %s: %s", url, err)
+ }
+ resp, err := http.DefaultClient.Do(req.WithContext(ctx))
+ if err != nil {
+ return 0, fmt.Errorf("error getting %s: %s", url, err)
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode == http.StatusNotFound {
+ return 0, fmt.Errorf("this instance does not have an IAM role assigned -- either assign a role, or configure AccessKey and SecretKey explicitly in DriverParameters (error getting %s: HTTP status %s)", url, resp.Status)
+ } else if resp.StatusCode != http.StatusOK {
+ return 0, fmt.Errorf("error getting %s: HTTP status %s", url, resp.Status)
+ }
+ body := bufio.NewReader(resp.Body)
+ var role string
+ _, err = fmt.Fscanf(body, "%s\n", &role)
+ if err != nil {
+ return 0, fmt.Errorf("error reading response from %s: %s", url, err)
+ }
+ if n, _ := body.Read(make([]byte, 64)); n > 0 {
+ v.logger.Warnf("ignoring additional data returned by metadata endpoint %s after the single role name that we expected", url)
+ }
+ v.logger.WithField("Role", role).Debug("looked up IAM role name")
+ url = url + role
}
+
v.logger.WithField("URL", url).Debug("getting credentials")
req, err := http.NewRequest("GET", url, nil)
if err != nil {