github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/creds/ssm/ssm.go (about)

     1  package ssm
     2  
     3  import (
     4  	"strings"
     5  	"time"
     6  
     7  	"github.com/pf-qiu/concourse/v6/atc/creds"
     8  
     9  	"code.cloudfoundry.org/lager"
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/aws/awserr"
    12  	"github.com/aws/aws-sdk-go/service/ssm"
    13  	"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
    14  )
    15  
    16  type Ssm struct {
    17  	log             lager.Logger
    18  	api             ssmiface.SSMAPI
    19  	secretTemplates []*creds.SecretTemplate
    20  }
    21  
    22  func NewSsm(log lager.Logger, api ssmiface.SSMAPI, secretTemplates []*creds.SecretTemplate) *Ssm {
    23  	return &Ssm{
    24  		log:             log,
    25  		api:             api,
    26  		secretTemplates: secretTemplates,
    27  	}
    28  }
    29  
    30  // NewSecretLookupPaths defines how variables will be searched in the underlying secret manager
    31  func (s *Ssm) NewSecretLookupPaths(teamName string, pipelineName string, allowRootPath bool) []creds.SecretLookupPath {
    32  	lookupPaths := []creds.SecretLookupPath{}
    33  	for _, tmpl := range s.secretTemplates {
    34  		if lPath := creds.NewSecretLookupWithTemplate(tmpl, teamName, pipelineName); lPath != nil {
    35  			lookupPaths = append(lookupPaths, lPath)
    36  		}
    37  	}
    38  	return lookupPaths
    39  }
    40  
    41  // Get retrieves the value and expiration of an individual secret
    42  func (s *Ssm) Get(secretPath string) (interface{}, *time.Time, bool, error) {
    43  	// Try to get the parameter as string value, by name
    44  	value, expiration, found, err := s.getParameterByName(secretPath)
    45  	if err != nil {
    46  		s.log.Error("unable to retrieve aws ssm secret by name", err, lager.Data{
    47  			"secretPath": secretPath,
    48  		})
    49  		return nil, nil, false, err
    50  	}
    51  	if found {
    52  		return value, expiration, true, nil
    53  	}
    54  	// Parameter may exist as a complex value so try again using parameter name as root path
    55  	value, expiration, found, err = s.getParameterByPath(secretPath)
    56  	if err != nil {
    57  		s.log.Error("unable to retrieve aws ssm secret by path", err, lager.Data{
    58  			"secretPath": secretPath,
    59  		})
    60  		return nil, nil, false, err
    61  	}
    62  	if found {
    63  		return value, expiration, true, nil
    64  	}
    65  	return nil, nil, false, nil
    66  }
    67  
    68  func (s *Ssm) getParameterByName(name string) (interface{}, *time.Time, bool, error) {
    69  	param, err := s.api.GetParameter(&ssm.GetParameterInput{
    70  		Name:           &name,
    71  		WithDecryption: aws.Bool(true),
    72  	})
    73  	if err == nil {
    74  		return *param.Parameter.Value, nil, true, nil
    75  
    76  	} else if errObj, ok := err.(awserr.Error); ok && errObj.Code() == ssm.ErrCodeParameterNotFound {
    77  		return nil, nil, false, nil
    78  	}
    79  	return nil, nil, false, err
    80  }
    81  
    82  func (s *Ssm) getParameterByPath(path string) (interface{}, *time.Time, bool, error) {
    83  	path = strings.TrimRight(path, "/")
    84  	if path == "" {
    85  		path = "/"
    86  	}
    87  	value := make(map[string]interface{})
    88  	pathQuery := &ssm.GetParametersByPathInput{}
    89  	pathQuery = pathQuery.SetPath(path).SetRecursive(true).SetWithDecryption(true).SetMaxResults(10)
    90  	err := s.api.GetParametersByPathPages(pathQuery, func(page *ssm.GetParametersByPathOutput, lastPage bool) bool {
    91  		for _, param := range page.Parameters {
    92  			value[(*param.Name)[len(path)+1:]] = *param.Value
    93  		}
    94  		return true
    95  	})
    96  	if err != nil {
    97  		return nil, nil, false, err
    98  	}
    99  	if len(value) == 0 {
   100  		return nil, nil, false, nil
   101  	}
   102  	return value, nil, true, nil
   103  }