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 }