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

     1  package kubernetes
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"time"
     8  
     9  	"code.cloudfoundry.org/lager"
    10  	"github.com/pf-qiu/concourse/v6/atc/creds"
    11  
    12  	v1 "k8s.io/api/core/v1"
    13  	k8serr "k8s.io/apimachinery/pkg/api/errors"
    14  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    15  	"k8s.io/client-go/kubernetes"
    16  )
    17  
    18  type Secrets struct {
    19  	logger lager.Logger
    20  
    21  	client          kubernetes.Interface
    22  	namespacePrefix string
    23  }
    24  
    25  // NewSecretLookupPaths defines how variables will be searched in the underlying secret manager
    26  func (secrets Secrets) NewSecretLookupPaths(teamName string, pipelineName string, allowRootPath bool) []creds.SecretLookupPath {
    27  	lookupPaths := []creds.SecretLookupPath{}
    28  	if len(pipelineName) > 0 {
    29  		lookupPaths = append(lookupPaths, creds.NewSecretLookupWithPrefix(secrets.namespacePrefix+teamName+"/"+pipelineName+"."))
    30  	}
    31  	lookupPaths = append(lookupPaths, creds.NewSecretLookupWithPrefix(secrets.namespacePrefix+teamName+"/"))
    32  	if allowRootPath {
    33  		lookupPaths = append(lookupPaths, creds.NewSecretLookupWithPrefix(secrets.namespacePrefix+"/"))
    34  	}
    35  	return lookupPaths
    36  }
    37  
    38  // Get retrieves the value and expiration of an individual secret
    39  func (secrets Secrets) Get(secretPath string) (interface{}, *time.Time, bool, error) {
    40  	parts := strings.Split(secretPath, "/")
    41  	if len(parts) != 2 {
    42  		return nil, nil, false, fmt.Errorf("unable to split kubernetes secret path into [namespace]/[secret]: %s", secretPath)
    43  	}
    44  
    45  	var namespace = parts[0]
    46  	var secretName = parts[1]
    47  
    48  	secret, found, err := secrets.findSecret(namespace, secretName)
    49  	if err != nil {
    50  		secrets.logger.Error("failed-to-fetch-secret", err, lager.Data{
    51  			"namespace":   namespace,
    52  			"secret-name": secretName,
    53  		})
    54  		return nil, nil, false, err
    55  	}
    56  
    57  	if found {
    58  		return secrets.getValueFromSecret(secret)
    59  	}
    60  
    61  	secrets.logger.Info("secret-not-found", lager.Data{
    62  		"namespace":   namespace,
    63  		"secret-name": secretName,
    64  	})
    65  
    66  	return nil, nil, false, nil
    67  }
    68  
    69  func (secrets Secrets) getValueFromSecret(secret *v1.Secret) (interface{}, *time.Time, bool, error) {
    70  	val, found := secret.Data["value"]
    71  	if found {
    72  		return string(val), nil, true, nil
    73  	}
    74  
    75  	// TODO: make this smarter since we now have access to ref.Fields
    76  	stringified := map[string]interface{}{}
    77  	for k, v := range secret.Data {
    78  		stringified[k] = string(v)
    79  	}
    80  
    81  	return stringified, nil, true, nil
    82  }
    83  
    84  func (secrets Secrets) findSecret(namespace, name string) (*v1.Secret, bool, error) {
    85  	var secret *v1.Secret
    86  	var err error
    87  
    88  	secret, err = secrets.client.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{})
    89  
    90  	if err != nil && k8serr.IsNotFound(err) {
    91  		return nil, false, nil
    92  	} else if err != nil {
    93  		return nil, false, err
    94  	} else {
    95  		return secret, true, err
    96  	}
    97  }