github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/migration/encryption.go (about) 1 package migration 2 3 import ( 4 "database/sql" 5 "errors" 6 7 "code.cloudfoundry.org/lager" 8 "github.com/pf-qiu/concourse/v6/atc/db/encryption" 9 ) 10 11 var encryptedColumns = []encryptedColumn{ 12 {"teams", "legacy_auth", "id"}, 13 {"resources", "config", "id"}, 14 {"jobs", "config", "id"}, 15 {"resource_types", "config", "id"}, 16 {"builds", "private_plan", "id"}, 17 {"cert_cache", "cert", "domain"}, 18 {"pipelines", "var_sources", "id"}, 19 } 20 21 type encryptedColumn struct { 22 Table string 23 Column string 24 PrimaryKey string 25 } 26 27 func (self migrator) encryptPlaintext(key *encryption.Key) error { 28 logger := self.logger.Session("encrypt") 29 for _, ec := range encryptedColumns { 30 rows, err := self.db.Query(` 31 SELECT ` + ec.PrimaryKey + `, ` + ec.Column + ` 32 FROM ` + ec.Table + ` 33 WHERE nonce IS NULL 34 AND ` + ec.Column + ` IS NOT NULL 35 `) 36 if err != nil { 37 return err 38 } 39 40 tLog := logger.Session("table", lager.Data{ 41 "table": ec.Table, 42 }) 43 44 encryptedRows := 0 45 46 for rows.Next() { 47 var ( 48 primaryKey interface{} 49 val sql.NullString 50 ) 51 52 err := rows.Scan(&primaryKey, &val) 53 if err != nil { 54 tLog.Error("failed-to-scan", err) 55 return err 56 } 57 58 if !val.Valid { 59 continue 60 } 61 62 rLog := tLog.Session("row", lager.Data{ 63 "primary-key": primaryKey, 64 }) 65 66 encrypted, nonce, err := key.Encrypt([]byte(val.String)) 67 if err != nil { 68 rLog.Error("failed-to-encrypt", err) 69 return err 70 } 71 72 _, err = self.db.Exec(` 73 UPDATE `+ec.Table+` 74 SET `+ec.Column+` = $1, nonce = $2 75 WHERE `+ec.PrimaryKey+` = $3 76 `, encrypted, nonce, primaryKey) 77 if err != nil { 78 rLog.Error("failed-to-update", err) 79 return err 80 } 81 82 encryptedRows++ 83 } 84 85 if encryptedRows > 0 { 86 tLog.Info("encrypted-existing-plaintext-data", lager.Data{ 87 "rows": encryptedRows, 88 }) 89 } 90 } 91 92 return nil 93 } 94 95 func (self migrator) decryptToPlaintext(oldKey *encryption.Key) error { 96 logger := self.logger.Session("decrypt") 97 for _, ec := range encryptedColumns { 98 rows, err := self.db.Query(` 99 SELECT ` + ec.PrimaryKey + `, nonce, ` + ec.Column + ` 100 FROM ` + ec.Table + ` 101 WHERE nonce IS NOT NULL 102 `) 103 if err != nil { 104 return err 105 } 106 107 tLog := logger.Session("table", lager.Data{ 108 "table": ec.Table, 109 }) 110 111 decryptedRows := 0 112 113 for rows.Next() { 114 var ( 115 primaryKey interface{} 116 val, nonce string 117 ) 118 119 err := rows.Scan(&primaryKey, &nonce, &val) 120 if err != nil { 121 tLog.Error("failed-to-scan", err) 122 return err 123 } 124 125 rLog := tLog.Session("row", lager.Data{ 126 "primary-key": primaryKey, 127 }) 128 129 decrypted, err := oldKey.Decrypt(val, &nonce) 130 if err != nil { 131 rLog.Error("failed-to-decrypt", err) 132 return err 133 } 134 135 _, err = self.db.Exec(` 136 UPDATE `+ec.Table+` 137 SET `+ec.Column+` = $1, nonce = NULL 138 WHERE `+ec.PrimaryKey+` = $2 139 `, decrypted, primaryKey) 140 if err != nil { 141 rLog.Error("failed-to-update", err) 142 return err 143 } 144 145 decryptedRows++ 146 } 147 148 if decryptedRows > 0 { 149 tLog.Info("decrypted-existing-encrypted-data", lager.Data{ 150 "rows": decryptedRows, 151 }) 152 } 153 } 154 155 return nil 156 } 157 158 var ErrEncryptedWithUnknownKey = errors.New("row encrypted with neither old nor new key") 159 160 func (self migrator) encryptWithNewKey(newKey *encryption.Key, oldKey *encryption.Key) error { 161 logger := self.logger.Session("rotate") 162 for _, ec := range encryptedColumns { 163 rows, err := self.db.Query(` 164 SELECT ` + ec.PrimaryKey + `, nonce, ` + ec.Column + ` 165 FROM ` + ec.Table + ` 166 WHERE nonce IS NOT NULL 167 `) 168 if err != nil { 169 return err 170 } 171 172 tLog := logger.Session("table", lager.Data{ 173 "table": ec.Table, 174 }) 175 176 encryptedRows := 0 177 178 for rows.Next() { 179 var ( 180 primaryKey interface{} 181 val, nonce string 182 ) 183 184 err := rows.Scan(&primaryKey, &nonce, &val) 185 if err != nil { 186 tLog.Error("failed-to-scan", err) 187 return err 188 } 189 190 rLog := tLog.Session("row", lager.Data{ 191 "primary-key": primaryKey, 192 }) 193 194 decrypted, err := oldKey.Decrypt(val, &nonce) 195 if err != nil { 196 _, err = newKey.Decrypt(val, &nonce) 197 if err == nil { 198 rLog.Debug("already-encrypted-with-new-key") 199 continue 200 } 201 202 logger.Error("failed-to-decrypt-with-either-key", err) 203 return ErrEncryptedWithUnknownKey 204 } 205 206 encrypted, newNonce, err := newKey.Encrypt(decrypted) 207 if err != nil { 208 rLog.Error("failed-to-encrypt", err) 209 return err 210 } 211 212 _, err = self.db.Exec(` 213 UPDATE `+ec.Table+` 214 SET `+ec.Column+` = $1, nonce = $2 215 WHERE `+ec.PrimaryKey+` = $3 216 `, encrypted, newNonce, primaryKey) 217 if err != nil { 218 rLog.Error("failed-to-update", err) 219 return err 220 } 221 222 encryptedRows++ 223 } 224 225 if encryptedRows > 0 { 226 tLog.Info("re-encrypted-existing-encrypted-data", lager.Data{ 227 "rows": encryptedRows, 228 }) 229 } 230 } 231 232 return nil 233 }