github.com/opendevstack/tailor@v1.3.5-0.20220119161809-cab064e60a67/pkg/commands/secrets.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "regexp" 8 "strings" 9 10 "github.com/opendevstack/tailor/pkg/cli" 11 "github.com/opendevstack/tailor/pkg/openshift" 12 "github.com/opendevstack/tailor/pkg/utils" 13 ) 14 15 // GenerateKey generates a GPG key using specified email (and optionally name). 16 func GenerateKey(secretsOptions *cli.SecretsOptions, email, name string) error { 17 emailParts := strings.Split(email, "@") 18 if len(name) == 0 { 19 name = emailParts[0] 20 } 21 entity, err := utils.CreateEntity(name, email) 22 if err != nil { 23 return fmt.Errorf("Failed to generate keypair: %s", err) 24 } 25 publicKeyFilename := strings.Replace(emailParts[0], ".", "-", -1) + ".key" 26 if _, err := os.Stat(publicKeyFilename); err == nil { 27 return fmt.Errorf("'%s' already exists", publicKeyFilename) 28 } 29 err = utils.PrintPublicKey(entity, publicKeyFilename) 30 if err != nil { 31 return err 32 } 33 fmt.Printf("Public Key written to %s. This file can be committed.\n", publicKeyFilename) 34 privateKeyFilename := secretsOptions.PrivateKey 35 if _, err := os.Stat(privateKeyFilename); err == nil { 36 return fmt.Errorf("'%s' already exists", privateKeyFilename) 37 } 38 err = utils.PrintPrivateKey(entity, privateKeyFilename) 39 if err != nil { 40 return err 41 } 42 fmt.Printf("Private Key written to %s. This file MUST NOT be committed.\n", privateKeyFilename) 43 return nil 44 } 45 46 // Reveal prints the clear-text of an encrypted file to STDOUT. 47 func Reveal(secretsOptions *cli.SecretsOptions, filename string) error { 48 if _, err := os.Stat(filename); os.IsNotExist(err) { 49 return fmt.Errorf("'%s' does not exist", filename) 50 } 51 encryptedContent, err := utils.ReadFile(filename) 52 if err != nil { 53 return fmt.Errorf("Could not read file: %s", err) 54 } 55 decryptedContent, err := openshift.DecryptedParams( 56 encryptedContent, 57 secretsOptions.PrivateKey, 58 secretsOptions.Passphrase, 59 ) 60 if err != nil { 61 return fmt.Errorf("Could not decrypt file: %s", err) 62 } 63 fmt.Println(decryptedContent) 64 return nil 65 } 66 67 // ReEncrypt decrypts given file(s) and encrypts all params again. 68 // This allows to share the secrets with a new keypair. 69 func ReEncrypt(secretsOptions *cli.SecretsOptions, filename string) error { 70 if len(filename) > 0 { 71 err := reEncrypt(filename, secretsOptions.PrivateKey, secretsOptions.Passphrase, secretsOptions.PublicKeyDir) 72 if err != nil { 73 return err 74 } 75 } else { 76 paramDir := secretsOptions.ParamDir 77 files, err := ioutil.ReadDir(paramDir) 78 if err != nil { 79 return err 80 } 81 filePattern := ".*\\.env.enc$" 82 re := regexp.MustCompile(filePattern) 83 for _, file := range files { 84 matched := re.MatchString(file.Name()) 85 if !matched { 86 continue 87 } 88 filename := paramDir + string(os.PathSeparator) + file.Name() 89 err := reEncrypt(filename, secretsOptions.PrivateKey, secretsOptions.Passphrase, secretsOptions.PublicKeyDir) 90 if err != nil { 91 return err 92 } 93 } 94 } 95 return nil 96 } 97 98 // Edit opens given filen in cleartext in $EDITOR, then encrypts the content on save. 99 func Edit(secretsOptions *cli.SecretsOptions, filename string) error { 100 encryptedContent, err := utils.ReadFile(filename) 101 if err != nil { 102 if os.IsNotExist(err) { 103 cli.DebugMsg(filename, "does not exist, creating empty file") 104 } else { 105 return fmt.Errorf("Could not read file: %s", err) 106 } 107 } 108 109 cleartextContent, err := openshift.DecryptedParams( 110 encryptedContent, 111 secretsOptions.PrivateKey, 112 secretsOptions.Passphrase, 113 ) 114 if err != nil { 115 return fmt.Errorf("Could not decrypt file: %s", err) 116 } 117 118 editedContent, err := cli.EditEnvFile(cleartextContent) 119 if err != nil { 120 return fmt.Errorf("Could not edit file: %s", err) 121 } 122 123 err = writeEncryptedContent( 124 filename, 125 editedContent, 126 encryptedContent, 127 secretsOptions.PrivateKey, 128 secretsOptions.Passphrase, 129 secretsOptions.PublicKeyDir, 130 ) 131 if err != nil { 132 return fmt.Errorf("Could not write file: %s", err) 133 } 134 return nil 135 } 136 137 func reEncrypt(filename, privateKey, passphrase, publicKeyDir string) error { 138 encryptedContent, err := utils.ReadFile(filename) 139 if err != nil { 140 return fmt.Errorf("Could not read file: %s", err) 141 } 142 143 cleartextContent, err := openshift.DecryptedParams( 144 encryptedContent, 145 privateKey, 146 passphrase, 147 ) 148 if err != nil { 149 return fmt.Errorf("Could not decrypt file: %s", err) 150 } 151 152 return writeEncryptedContent( 153 filename, 154 cleartextContent, 155 "", // empty because all values should be re-encrypted 156 privateKey, 157 passphrase, 158 publicKeyDir, 159 ) 160 } 161 162 func writeEncryptedContent(filename, newContent, previousContent, privateKey, passphrase, publicKeyDir string) error { 163 updatedContent, err := openshift.EncryptedParams( 164 newContent, 165 previousContent, 166 publicKeyDir, 167 privateKey, 168 passphrase, 169 ) 170 if err != nil { 171 return fmt.Errorf("Could not encrypt content: %s", err) 172 } 173 174 err = ioutil.WriteFile(filename, []byte(updatedContent), 0644) 175 if err != nil { 176 return fmt.Errorf("Could not write file: %s", err) 177 } 178 return nil 179 }