github.com/sentienttechnologies/studio-go-runner@v0.0.0-20201118202441-6d21f2ced8ee/internal/runner/aws.go (about)

     1  // Copyright 2018-2020 (c) Cognizant Digital Business, Evolutionary AI. All rights reserved. Issued under the Apache 2.0 License.
     2  
     3  package runner
     4  
     5  // This file contains the implementation of functions related to AWS.
     6  //
     7  // Especially functions related to the credentials file handling
     8  
     9  import (
    10  	"bufio"
    11  	"bytes"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/aws/aws-sdk-go/aws/credentials"
    17  
    18  	"github.com/go-stack/stack"
    19  	"github.com/jjeffery/kv" // MIT License
    20  )
    21  
    22  // AWSCred is used to encapsulate the credentials that are to be used to access an AWS resource
    23  // suhc as an S3 bucket for example.
    24  //
    25  type AWSCred struct {
    26  	Project string
    27  	Region  string
    28  	Creds   *credentials.Credentials
    29  }
    30  
    31  // AWSExtractCreds can be used to populate a set of credentials from a pair of config and
    32  // credentials files typicall found in the ~/.aws directory by AWS clients
    33  //
    34  func AWSExtractCreds(filenames []string) (cred *AWSCred, err kv.Error) {
    35  
    36  	cred = &AWSCred{
    37  		Project: "aws_" + filepath.Base(filepath.Dir(filenames[0])),
    38  	}
    39  
    40  	credsDone := false
    41  
    42  	// AWS Does not read the region automatically from the config so lets read it here
    43  	for _, aFile := range filenames {
    44  		wasConfig := func() bool {
    45  			f, err := os.Open(filepath.Clean(aFile))
    46  			if err != nil {
    47  				return false
    48  			}
    49  			if len(cred.Region) == 0 {
    50  				scan := bufio.NewScanner(f)
    51  				for scan.Scan() {
    52  					line := scan.Text()
    53  					line = strings.Replace(line, " ", "", -1)
    54  					if strings.HasPrefix(strings.ToLower(line), "region=") {
    55  						tokens := strings.SplitN(line, "=", 2)
    56  						cred.Region = tokens[1]
    57  						return true
    58  					}
    59  				}
    60  			}
    61  
    62  			f.Close()
    63  			return false
    64  		}()
    65  
    66  		if !credsDone && !wasConfig {
    67  			cred.Creds = credentials.NewSharedCredentials(aFile, "default")
    68  			credsDone = true
    69  		}
    70  	}
    71  
    72  	if len(cred.Region) == 0 {
    73  		return nil, kv.NewError("none of the supplied files defined a region").With("stack", stack.Trace().TrimRuntime()).With("files", filenames)
    74  	}
    75  
    76  	if !credsDone {
    77  		return nil, kv.NewError("credentials never loaded").With("stack", stack.Trace().TrimRuntime()).With("files", filenames)
    78  	}
    79  	return cred, nil
    80  }
    81  
    82  // IsAWS can detect if pods running within a Kubernetes cluster are actually being hosted on an EC2 instance
    83  //
    84  func IsAWS() (aws bool, err kv.Error) {
    85  	fn := "/sys/devices/virtual/dmi/id/product_uuid"
    86  	uuidFile, errGo := os.Open(fn)
    87  	if errGo != nil {
    88  		return false, kv.Wrap(errGo).With("stack", stack.Trace().TrimRuntime()).With("file", fn)
    89  	}
    90  	defer uuidFile.Close()
    91  
    92  	signature := []byte{'E', 'C', '2'}
    93  	buffer := make([]byte, len(signature))
    94  
    95  	cnt, errGo := uuidFile.Read(buffer)
    96  	if errGo != nil {
    97  		return false, kv.Wrap(errGo).With("stack", stack.Trace().TrimRuntime()).With("file", fn)
    98  	}
    99  	if cnt != len(signature) {
   100  		return false, kv.NewError("invalid signature").
   101  			With("file", fn, "buffer", string(buffer), "cnt", cnt).
   102  			With("stack", stack.Trace().TrimRuntime())
   103  	}
   104  
   105  	return 0 == bytes.Compare(buffer, signature), nil
   106  }