storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/config-encrypted.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2019 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "bytes" 21 "fmt" 22 "path" 23 "unicode/utf8" 24 25 "storj.io/minio/cmd/config" 26 "storj.io/minio/cmd/logger" 27 "storj.io/minio/pkg/auth" 28 "storj.io/minio/pkg/kms" 29 "storj.io/minio/pkg/madmin" 30 ) 31 32 func handleEncryptedConfigBackend(objAPI ObjectLayer) error { 33 encrypted, err := checkBackendEncrypted(objAPI) 34 if err != nil { 35 return fmt.Errorf("Unable to encrypt config %w", err) 36 } 37 if err = migrateConfigPrefixToEncrypted(objAPI, encrypted); err != nil { 38 return fmt.Errorf("Unable to migrate all config at .minio.sys/config/: %w", err) 39 } 40 return nil 41 } 42 43 const backendEncryptedFile = "backend-encrypted" 44 45 var backendEncryptedMigrationComplete = []byte("encrypted") 46 47 func checkBackendEncrypted(objAPI ObjectLayer) (bool, error) { 48 data, err := readConfig(GlobalContext, objAPI, backendEncryptedFile) 49 if err != nil && err != errConfigNotFound { 50 return false, err 51 } 52 return err == nil && bytes.Equal(data, backendEncryptedMigrationComplete), nil 53 } 54 55 // decryptData - decrypts input data with more that one credentials, 56 func decryptData(edata []byte, creds ...auth.Credentials) ([]byte, error) { 57 var err error 58 var data []byte 59 for _, cred := range creds { 60 data, err = madmin.DecryptData(cred.String(), bytes.NewReader(edata)) 61 if err != nil { 62 if err == madmin.ErrMaliciousData { 63 continue 64 } 65 return nil, err 66 } 67 break 68 } 69 return data, err 70 } 71 72 func migrateConfigPrefixToEncrypted(objAPI ObjectLayer, encrypted bool) error { 73 if !encrypted { 74 return nil 75 } 76 if encrypted { 77 if GlobalKMS != nil { 78 stat, err := GlobalKMS.Stat() 79 if err != nil { 80 return err 81 } 82 logger.Info("Attempting to re-encrypt config, IAM users and policies on MinIO with %q (%s)", stat.DefaultKey, stat.Name) 83 } else { 84 logger.Info("Attempting to migrate encrypted config, IAM users and policies on MinIO to a plaintext format. To encrypt all MinIO config data a KMS is needed") 85 } 86 } 87 88 var marker string 89 for { 90 res, err := objAPI.ListObjects(GlobalContext, minioMetaBucket, minioConfigPrefix, marker, "", maxObjectList) 91 if err != nil { 92 return err 93 } 94 for _, obj := range res.Objects { 95 data, err := readConfig(GlobalContext, objAPI, obj.Name) 96 if err != nil { 97 return err 98 } 99 100 if !utf8.Valid(data) { 101 data, err = decryptData(data, globalActiveCred) 102 if err != nil { 103 return fmt.Errorf("Decrypting config failed %w, possibly credentials are incorrect", err) 104 } 105 } 106 if GlobalKMS != nil { 107 data, err = config.EncryptBytes(GlobalKMS, data, kms.Context{ 108 obj.Bucket: path.Join(obj.Bucket, obj.Name), 109 }) 110 if err != nil { 111 return err 112 } 113 } 114 if err = saveConfig(GlobalContext, objAPI, obj.Name, data); err != nil { 115 return err 116 } 117 } 118 119 if !res.IsTruncated { 120 break 121 } 122 marker = res.NextMarker 123 } 124 if encrypted { 125 if GlobalKMS != nil { 126 logger.Info("Migration of encrypted config data completed. All config data is now encrypted with the KMS") 127 } else { 128 logger.Info("Migration of encrypted config data completed. All config data is now stored in plaintext") 129 } 130 } 131 return deleteConfig(GlobalContext, globalObjectAPI, backendEncryptedFile) 132 }