github.com/Axway/agent-sdk@v1.1.101/pkg/cmd/properties/resolver/secretResolver.go (about)

     1  package resolver
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"reflect"
     8  	"strings"
     9  
    10  	"github.com/Axway/agent-sdk/pkg/agent"
    11  	coreapi "github.com/Axway/agent-sdk/pkg/api"
    12  	management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
    13  	"github.com/Axway/agent-sdk/pkg/cache"
    14  	"github.com/Axway/agent-sdk/pkg/cmd/properties"
    15  	"github.com/Axway/agent-sdk/pkg/util/log"
    16  )
    17  
    18  const (
    19  	secretConfigPrefix  = "@Secret."
    20  	secretMapItemPrefix = "SecretResource_"
    21  )
    22  
    23  // SecretResolver - Interface to resolve secret reference
    24  type SecretResolver interface {
    25  	properties.SecretPropertyResolver
    26  	ResetResolver()
    27  }
    28  
    29  type secretResolver struct {
    30  	SecretResolver
    31  	secretsCache cache.Cache
    32  }
    33  
    34  // NewSecretResolver - create a new secret resolver
    35  func NewSecretResolver() SecretResolver {
    36  	return &secretResolver{
    37  		secretsCache: cache.New(),
    38  	}
    39  }
    40  
    41  // parseSecretRef - parses the secret reference with prefixed secret name ane key
    42  func (s *secretResolver) parseSecretRef(secretRef string) (string, string) {
    43  	// parse secret and key from @Secret.secretName.key
    44  	secretRef = strings.TrimSpace(secretRef)
    45  	if strings.HasPrefix(secretRef, secretConfigPrefix) {
    46  		secretRef = secretRef[len(secretConfigPrefix):]
    47  		secretRefElements := strings.Split(secretRef, ".")
    48  		if len(secretRefElements) > 1 {
    49  			return secretRefElements[0], strings.Join(secretRefElements[1:], ".")
    50  		}
    51  	}
    52  	return "", ""
    53  }
    54  
    55  func (s *secretResolver) getSecret(secretName string) (*management.Secret, error) {
    56  	secretResourceURL := agent.GetCentralConfig().GetEnvironmentURL() + "/secrets/" + secretName
    57  
    58  	response, err := agent.GetCentralClient().ExecuteAPI(coreapi.GET, secretResourceURL, nil, nil)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	secret := &management.Secret{}
    63  	err = json.Unmarshal(response, secret)
    64  	return secret, err
    65  }
    66  
    67  func (s *secretResolver) parseKeyValueFromSecretSpec(secret *management.Secret, key string) (string, error) {
    68  	// Return empty string if secret key not found
    69  	keyVal, ok := secret.Spec.Data[key]
    70  	if !ok {
    71  		msg := fmt.Sprintf("key %s not found in secret %s", key, secret.Name)
    72  		return "", errors.New(msg)
    73  	}
    74  	return keyVal, nil
    75  }
    76  
    77  func (s *secretResolver) ResolveSecret(secretRef string) (string, error) {
    78  	// Do not parse secret reference until central config is parsed and initialized
    79  	// secret ref be applied to agent config only and not central config
    80  	cfg := agent.GetCentralConfig()
    81  	if cfg == nil || reflect.ValueOf(cfg).IsNil() {
    82  		return secretRef, nil
    83  	}
    84  
    85  	// If usage reporting is offline, do not resolve secretclear
    86  	if agent.GetCentralConfig().GetUsageReportingConfig().IsOfflineMode() && strings.HasPrefix(secretRef, secretConfigPrefix) {
    87  		msg := "Securing password with @Secret resource is not possible when running agent in offline mode."
    88  		log.Debugf("@Secret reference %s is not valid when offline mode is true.", secretRef)
    89  		return "", errors.New(msg)
    90  	}
    91  
    92  	secretName, key := s.parseSecretRef(secretRef)
    93  	if secretName != "" && key != "" {
    94  		var secret *management.Secret
    95  		// Get cached secret to resolve key
    96  		cachedSecret, err := s.secretsCache.Get(secretMapItemPrefix + secretName)
    97  		if err != nil {
    98  			// Secret not cached, get the secret from API server
    99  			secret, err = s.getSecret(secretName)
   100  			if err != nil {
   101  				log.Trace(err.Error())
   102  				msg := fmt.Sprintf("unable to resolve secret %s", secretName)
   103  				return "", errors.New(msg)
   104  			}
   105  			s.secretsCache.Set(secretMapItemPrefix+secret.GetName(), secret)
   106  		} else {
   107  			secret, _ = cachedSecret.(*management.Secret)
   108  		}
   109  		keyVal, err := s.parseKeyValueFromSecretSpec(secret, key)
   110  		if err != nil {
   111  			return "", err
   112  		}
   113  		return keyVal, nil
   114  	}
   115  	// Not a secret ref, return it as value
   116  	return secretRef, nil
   117  }
   118  
   119  func (s *secretResolver) ResetResolver() {
   120  	s.secretsCache = cache.New()
   121  }