github.com/bshelton229/agent@v3.5.4+incompatible/agent/s3.go (about)

     1  package agent
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/aws/credentials"
    10  	"github.com/aws/aws-sdk-go/aws/defaults"
    11  	"github.com/aws/aws-sdk-go/aws/endpoints"
    12  	"github.com/aws/aws-sdk-go/aws/session"
    13  	"github.com/aws/aws-sdk-go/service/s3"
    14  	"github.com/buildkite/agent/logger"
    15  )
    16  
    17  type credentialsProvider struct {
    18  	retrieved bool
    19  }
    20  
    21  func (e *credentialsProvider) Retrieve() (creds credentials.Value, err error) {
    22  	e.retrieved = false
    23  
    24  	creds.AccessKeyID = os.Getenv("BUILDKITE_S3_ACCESS_KEY_ID")
    25  	if creds.AccessKeyID == "" {
    26  		creds.AccessKeyID = os.Getenv("BUILDKITE_S3_ACCESS_KEY")
    27  	}
    28  
    29  	creds.SecretAccessKey = os.Getenv("BUILDKITE_S3_SECRET_ACCESS_KEY")
    30  	if creds.SecretAccessKey == "" {
    31  		creds.SecretAccessKey = os.Getenv("BUILDKITE_S3_SECRET_KEY")
    32  	}
    33  
    34  	if creds.AccessKeyID == "" {
    35  		err = errors.New("BUILDKITE_S3_ACCESS_KEY_ID or BUILDKITE_S3_ACCESS_KEY not found in environment")
    36  	}
    37  	if creds.SecretAccessKey == "" {
    38  		err = errors.New("BUILDKITE_S3_SECRET_ACCESS_KEY or BUILDKITE_S3_SECRET_KEY not found in environment")
    39  	}
    40  
    41  	e.retrieved = true
    42  	return
    43  }
    44  
    45  func (e *credentialsProvider) IsExpired() bool {
    46  	return !e.retrieved
    47  }
    48  
    49  func awsS3RegionFromEnv() (region string, err error) {
    50  	regionName := "us-east-1"
    51  	if os.Getenv("BUILDKITE_S3_DEFAULT_REGION") != "" {
    52  		regionName = os.Getenv("BUILDKITE_S3_DEFAULT_REGION")
    53  	} else {
    54  		var err error
    55  		regionName, err = awsRegion()
    56  		if err != nil {
    57  			return "", err
    58  		}
    59  	}
    60  
    61  	// Check to make sure the region exists.
    62  	resolver := endpoints.DefaultResolver()
    63  	partitions := resolver.(endpoints.EnumPartitions).Partitions()
    64  
    65  	for _, p := range partitions {
    66  		for id := range p.Regions() {
    67  			if id == regionName {
    68  				return regionName, nil
    69  			}
    70  		}
    71  	}
    72  
    73  	return "", fmt.Errorf("Unknown AWS S3 Region %q", regionName)
    74  }
    75  
    76  func awsS3Session(region string) (*session.Session, error) {
    77  	// Chicken and egg... but this is kinda how they do it in the sdk
    78  	sess, err := session.NewSession()
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	sess.Config.Region = aws.String(region)
    84  
    85  	sess.Config.Credentials = credentials.NewChainCredentials(
    86  		[]credentials.Provider{
    87  			&credentialsProvider{},
    88  			&credentials.EnvProvider{},
    89  			// EC2 and ECS meta-data providers
    90  			defaults.RemoteCredProvider(*sess.Config, sess.Handlers),
    91  		})
    92  
    93  	return sess, nil
    94  }
    95  
    96  func newS3Client(bucket string) (*s3.S3, error) {
    97  	region, err := awsS3RegionFromEnv()
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	sess, err := awsS3Session(region)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	logger.Debug("Authorizing S3 credentials and finding bucket `%s` in region `%s`...", bucket, region)
   108  
   109  	s3client := s3.New(sess)
   110  
   111  	// Test the authentication by trying to list the first 0 objects in the bucket.
   112  	_, err = s3client.ListObjects(&s3.ListObjectsInput{
   113  		Bucket:  aws.String(bucket),
   114  		MaxKeys: aws.Int64(0),
   115  	})
   116  	if err != nil {
   117  		if err == credentials.ErrNoValidProvidersFoundInChain {
   118  			return nil, fmt.Errorf("Could not find a valid authentication strategy to connect to S3. Try setting BUILDKITE_S3_ACCESS_KEY and BUILDKITE_S3_SECRET_KEY")
   119  		}
   120  		return nil, fmt.Errorf("Failed to authenticate to bucket `%s` in region `%s` (%s)", bucket, region, err.Error())
   121  	}
   122  
   123  	return s3client, nil
   124  }