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 }