github.com/argoproj/argo-cd@v1.8.7/util/db/gpgkeys.go (about)

     1  package db
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  
     9  	log "github.com/sirupsen/logrus"
    10  
    11  	"github.com/argoproj/argo-cd/common"
    12  	appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
    13  	"github.com/argoproj/argo-cd/util/gpg"
    14  )
    15  
    16  // Validates a single GnuPG key and returns the key's ID
    17  func validatePGPKey(keyData string) (*appsv1.GnuPGPublicKey, error) {
    18  	f, err := ioutil.TempFile("", "gpg-public-key")
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  	defer os.Remove(f.Name())
    23  
    24  	err = ioutil.WriteFile(f.Name(), []byte(keyData), 0600)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	f.Close()
    29  
    30  	parsed, err := gpg.ValidatePGPKeys(f.Name())
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	// Each key/value pair in the config map must exactly contain one public key, with the (short) GPG key ID as key
    36  	if len(parsed) != 1 {
    37  		return nil, fmt.Errorf("More than one key found in input data")
    38  	}
    39  
    40  	var retKey *appsv1.GnuPGPublicKey = nil
    41  	// Is there a better way to get the first element from a map without knowing its key?
    42  	for _, k := range parsed {
    43  		retKey = k
    44  		break
    45  	}
    46  	if retKey != nil {
    47  		retKey.KeyData = keyData
    48  		return retKey, nil
    49  	} else {
    50  		return nil, fmt.Errorf("Could not find the GPG key")
    51  	}
    52  }
    53  
    54  // ListConfiguredGPGPublicKeys returns a list of all configured GPG public keys from the ConfigMap
    55  func (db *db) ListConfiguredGPGPublicKeys(ctx context.Context) (map[string]*appsv1.GnuPGPublicKey, error) {
    56  	log.Debugf("Loading PGP public keys from config map")
    57  	result := make(map[string]*appsv1.GnuPGPublicKey)
    58  	keysCM, err := db.settingsMgr.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	// We have to verify all PGP keys in the ConfigMap to be valid keys before. To do so,
    64  	// we write each single one out to a temporary file and validate them through gpg.
    65  	// This is not optimal, but the executil from argo-pkg does not support writing to
    66  	// stdin of the forked process. So for now, we must live with that.
    67  	for k, p := range keysCM.Data {
    68  		if expectedKeyID := gpg.KeyID(k); expectedKeyID != "" {
    69  			parsedKey, err := validatePGPKey(p)
    70  			if err != nil {
    71  				return nil, fmt.Errorf("Could not parse GPG key for entry '%s': %s", expectedKeyID, err.Error())
    72  			}
    73  			if expectedKeyID != parsedKey.KeyID {
    74  				return nil, fmt.Errorf("Key parsed for entry with key ID '%s' had different key ID '%s'", expectedKeyID, parsedKey.KeyID)
    75  			}
    76  			result[parsedKey.KeyID] = parsedKey
    77  		} else {
    78  			return nil, fmt.Errorf("Found entry with key '%s' in ConfigMap, but this is not a valid PGP key ID", k)
    79  		}
    80  	}
    81  
    82  	return result, nil
    83  }
    84  
    85  // AddGPGPublicKey adds one or more public keys to the configuration
    86  func (db *db) AddGPGPublicKey(ctx context.Context, keyData string) (map[string]*appsv1.GnuPGPublicKey, []string, error) {
    87  	result := make(map[string]*appsv1.GnuPGPublicKey)
    88  	skipped := make([]string, 0)
    89  
    90  	keys, err := gpg.ValidatePGPKeysFromString(keyData)
    91  	if err != nil {
    92  		return nil, nil, err
    93  	}
    94  
    95  	keysCM, err := db.settingsMgr.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
    96  	if err != nil {
    97  		return nil, nil, err
    98  	}
    99  
   100  	if keysCM.Data == nil {
   101  		keysCM.Data = make(map[string]string)
   102  	}
   103  
   104  	for kid, key := range keys {
   105  		if _, ok := keysCM.Data[kid]; ok {
   106  			skipped = append(skipped, kid)
   107  			log.Debugf("Not adding incoming key with kid=%s because it is configured already", kid)
   108  		} else {
   109  			result[kid] = key
   110  			keysCM.Data[kid] = key.KeyData
   111  			log.Debugf("Adding incoming key with kid=%s to database", kid)
   112  		}
   113  	}
   114  
   115  	err = db.settingsMgr.SaveGPGPublicKeyData(ctx, keysCM.Data)
   116  	if err != nil {
   117  		return nil, nil, err
   118  	}
   119  
   120  	return result, skipped, nil
   121  }
   122  
   123  // DeleteGPGPublicKey deletes a GPG public key from the configuration
   124  func (db *db) DeleteGPGPublicKey(ctx context.Context, keyID string) error {
   125  	keysCM, err := db.settingsMgr.GetConfigMapByName(common.ArgoCDGPGKeysConfigMapName)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	if keysCM.Data == nil {
   131  		return fmt.Errorf("No such key configured: %s", keyID)
   132  	}
   133  
   134  	if _, ok := keysCM.Data[keyID]; !ok {
   135  		return fmt.Errorf("No such key configured: %s", keyID)
   136  	}
   137  
   138  	delete(keysCM.Data, keyID)
   139  
   140  	err = db.settingsMgr.SaveGPGPublicKeyData(ctx, keysCM.Data)
   141  	return err
   142  }