github.com/argoproj/argo-cd/v3@v3.2.1/util/db/secrets.go (about)

     1  package db
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"hash/fnv"
     7  	"net/netip"
     8  	"net/url"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  
    13  	log "github.com/sirupsen/logrus"
    14  	corev1 "k8s.io/api/core/v1"
    15  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    16  	"k8s.io/apimachinery/pkg/fields"
    17  	"k8s.io/apimachinery/pkg/labels"
    18  	"k8s.io/apimachinery/pkg/selection"
    19  	informersv1 "k8s.io/client-go/informers/core/v1"
    20  	"k8s.io/client-go/tools/cache"
    21  
    22  	"github.com/argoproj/argo-cd/v3/common"
    23  	"github.com/argoproj/argo-cd/v3/util"
    24  )
    25  
    26  func (db *db) listSecretsByType(types ...string) ([]*corev1.Secret, error) {
    27  	labelSelector := labels.NewSelector()
    28  	req, err := labels.NewRequirement(common.LabelKeySecretType, selection.Equals, types)
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  	labelSelector = labelSelector.Add(*req)
    33  
    34  	secretsLister, err := db.settingsMgr.GetSecretsLister()
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	secrets, err := secretsLister.Secrets(db.ns).List(labelSelector)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	// SecretNamespaceLister lists all Secrets in the indexer for a given namespace.
    43  	// Objects returned by the lister must be treated as read-only.
    44  	// To allow us to modify the secrets, make a copy
    45  	secrets = util.SliceCopy(secrets)
    46  	return secrets, nil
    47  }
    48  
    49  func boolOrFalse(secret *corev1.Secret, key string) (bool, error) {
    50  	val, present := secret.Data[key]
    51  	if !present {
    52  		return false, nil
    53  	}
    54  
    55  	return strconv.ParseBool(string(val))
    56  }
    57  
    58  func intOrZero(secret *corev1.Secret, key string) (int64, error) {
    59  	val, present := secret.Data[key]
    60  	if !present {
    61  		return 0, nil
    62  	}
    63  
    64  	return strconv.ParseInt(string(val), 10, 64)
    65  }
    66  
    67  func updateSecretBool(secret *corev1.Secret, key string, value bool) {
    68  	if _, present := secret.Data[key]; present || value {
    69  		secret.Data[key] = []byte(strconv.FormatBool(value))
    70  	}
    71  }
    72  
    73  func updateSecretInt(secret *corev1.Secret, key string, value int64) {
    74  	if _, present := secret.Data[key]; present || value != 0 {
    75  		secret.Data[key] = []byte(strconv.FormatInt(value, 10))
    76  	}
    77  }
    78  
    79  func updateSecretString(secret *corev1.Secret, key, value string) {
    80  	if _, present := secret.Data[key]; present || value != "" {
    81  		secret.Data[key] = []byte(value)
    82  	}
    83  }
    84  
    85  func (db *db) createSecret(ctx context.Context, secret *corev1.Secret) (*corev1.Secret, error) {
    86  	return db.kubeclientset.CoreV1().Secrets(db.ns).Create(ctx, secret, metav1.CreateOptions{})
    87  }
    88  
    89  func addSecretMetadata(secret *corev1.Secret, secretType string) {
    90  	if secret.Annotations == nil {
    91  		secret.Annotations = map[string]string{}
    92  	}
    93  	secret.Annotations[common.AnnotationKeyManagedBy] = common.AnnotationValueManagedByArgoCD
    94  
    95  	if secret.Labels == nil {
    96  		secret.Labels = map[string]string{}
    97  	}
    98  	secret.Labels[common.LabelKeySecretType] = secretType
    99  }
   100  
   101  func (db *db) deleteSecret(ctx context.Context, secret *corev1.Secret) error {
   102  	var err error
   103  
   104  	canDelete := secret.Annotations != nil && secret.Annotations[common.AnnotationKeyManagedBy] == common.AnnotationValueManagedByArgoCD
   105  	if canDelete {
   106  		err = db.kubeclientset.CoreV1().Secrets(db.ns).Delete(ctx, secret.Name, metav1.DeleteOptions{})
   107  	} else {
   108  		delete(secret.Labels, common.LabelKeySecretType)
   109  		_, err = db.kubeclientset.CoreV1().Secrets(db.ns).Update(ctx, secret, metav1.UpdateOptions{})
   110  	}
   111  
   112  	return err
   113  }
   114  
   115  func (db *db) watchSecrets(ctx context.Context,
   116  	secretType string,
   117  	handleAddEvent func(secret *corev1.Secret),
   118  	handleModEvent func(oldSecret *corev1.Secret, newSecret *corev1.Secret),
   119  	handleDeleteEvent func(secret *corev1.Secret),
   120  ) {
   121  	secretListOptions := func(options *metav1.ListOptions) {
   122  		labelSelector := fields.ParseSelectorOrDie(common.LabelKeySecretType + "=" + secretType)
   123  		options.LabelSelector = labelSelector.String()
   124  	}
   125  	secretEventHandler := cache.ResourceEventHandlerFuncs{
   126  		AddFunc: func(obj any) {
   127  			if secretObj, ok := obj.(*corev1.Secret); ok {
   128  				handleAddEvent(secretObj)
   129  			}
   130  		},
   131  		DeleteFunc: func(obj any) {
   132  			if secretObj, ok := obj.(*corev1.Secret); ok {
   133  				handleDeleteEvent(secretObj)
   134  			}
   135  		},
   136  		UpdateFunc: func(oldObj, newObj any) {
   137  			if oldSecretObj, ok := oldObj.(*corev1.Secret); ok {
   138  				if newSecretObj, ok := newObj.(*corev1.Secret); ok {
   139  					handleModEvent(oldSecretObj, newSecretObj)
   140  				}
   141  			}
   142  		},
   143  	}
   144  
   145  	indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
   146  	clusterSecretInformer := informersv1.NewFilteredSecretInformer(db.kubeclientset, db.ns, 3*time.Minute, indexers, secretListOptions)
   147  	_, err := clusterSecretInformer.AddEventHandler(secretEventHandler)
   148  	if err != nil {
   149  		log.Error(err)
   150  	}
   151  
   152  	log.Info("Starting secretInformer for", secretType)
   153  	go func() {
   154  		clusterSecretInformer.Run(ctx.Done())
   155  		log.Info("secretInformer for", secretType, "cancelled")
   156  	}()
   157  	<-ctx.Done()
   158  }
   159  
   160  // URIToSecretName hashes an uri address to the secret name using a formula.
   161  // Part of the uri address is incorporated for debugging purposes
   162  func URIToSecretName(uriType, uri string) (string, error) {
   163  	parsedURI, err := url.ParseRequestURI(uri)
   164  	if err != nil {
   165  		return "", err
   166  	}
   167  	host := parsedURI.Host
   168  	if strings.HasPrefix(host, "[") {
   169  		last := strings.Index(host, "]")
   170  		if last >= 0 {
   171  			addr, err := netip.ParseAddr(host[1:last])
   172  			if err != nil {
   173  				return "", err
   174  			}
   175  			host = strings.ReplaceAll(addr.String(), ":", "-")
   176  		}
   177  	} else {
   178  		last := strings.Index(host, ":")
   179  		if last >= 0 {
   180  			host = host[0:last]
   181  		}
   182  	}
   183  	h := fnv.New32a()
   184  	_, _ = h.Write([]byte(uri))
   185  	host = strings.ToLower(host)
   186  	return fmt.Sprintf("%s-%s-%v", uriType, host, h.Sum32()), nil
   187  }