github.com/polarismesh/polaris@v1.17.8/config/config_chain.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package config 19 20 import ( 21 "context" 22 "encoding/base64" 23 24 apiconfig "github.com/polarismesh/specification/source/go/api/v1/config_manage" 25 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 26 "go.uber.org/zap" 27 28 api "github.com/polarismesh/polaris/common/api/v1" 29 "github.com/polarismesh/polaris/common/model" 30 "github.com/polarismesh/polaris/common/utils" 31 ) 32 33 // ConfigFileChain 34 type ConfigFileChain interface { 35 // Init 36 Init(svr *Server) 37 // Name 38 Name() string 39 // BeforeCreateFile 40 BeforeCreateFile(context.Context, *model.ConfigFile) *apiconfig.ConfigResponse 41 // AfterGetFile 42 AfterGetFile(context.Context, *model.ConfigFile) (*model.ConfigFile, error) 43 // BeforeUpdateFile 44 BeforeUpdateFile(context.Context, *model.ConfigFile) *apiconfig.ConfigResponse 45 // AfterGetFileRelease 46 AfterGetFileRelease(context.Context, *model.ConfigFileRelease) (*model.ConfigFileRelease, error) 47 // AfterGetFileHistory 48 AfterGetFileHistory(context.Context, *model.ConfigFileReleaseHistory) (*model.ConfigFileReleaseHistory, error) 49 } 50 51 type CryptoConfigFileChain struct { 52 svr *Server 53 } 54 55 func (chain *CryptoConfigFileChain) Init(svr *Server) { 56 chain.svr = svr 57 } 58 59 func (chain *CryptoConfigFileChain) Name() string { 60 return "CryptoConfigFileChain" 61 } 62 63 // BeforeCreateFile 64 func (chain *CryptoConfigFileChain) BeforeCreateFile(ctx context.Context, 65 file *model.ConfigFile) *apiconfig.ConfigResponse { 66 // 配置加密 67 if !file.IsEncrypted() { 68 return nil 69 } 70 if err := chain.encryptConfigFile(ctx, file, file.GetEncryptAlgo(), ""); err != nil { 71 log.Error("[Config][Service] encrypt config file error.", utils.RequestID(ctx), 72 utils.ZapNamespace(file.Namespace), utils.ZapGroup(file.Group), 73 utils.ZapFileName(file.Name), zap.Error(err)) 74 return api.NewConfigResponseWithInfo(apimodel.Code_EncryptConfigFileException, err.Error()) 75 } 76 return nil 77 } 78 79 // AfterCreateFile 80 func (chain *CryptoConfigFileChain) AfterGetFile(ctx context.Context, 81 file *model.ConfigFile) (*model.ConfigFile, error) { 82 if file.IsEncrypted() { 83 file.Encrypt = true 84 } 85 86 encryptAlgo := file.GetEncryptAlgo() 87 dataKey := file.GetEncryptDataKey() 88 plainContent, err := chain.decryptConfigFileContent(dataKey, encryptAlgo, file.Content) 89 90 // TODO: 这个逻辑需要优化,在1.17.3处理 91 // 前一次发布的配置并未加密,现在准备发布的配置是开启了加密的,因此这里可能配置就是一个未加密的状态 92 // 这里就直接原样返回 93 if err == nil && plainContent != "" { 94 file.Content = plainContent 95 } 96 if err != nil { 97 log.Error("[Config][Chain][Crypto] decrypt config file content", 98 utils.ZapNamespace(file.Namespace), utils.ZapGroup(file.Group), 99 utils.ZapFileName(file.Name), zap.Error(err)) 100 } 101 delete(file.Metadata, utils.ConfigFileTagKeyDataKey) 102 return file, nil 103 } 104 105 // BeforeUpdateFile 106 func (chain *CryptoConfigFileChain) BeforeUpdateFile(ctx context.Context, 107 file *model.ConfigFile) *apiconfig.ConfigResponse { 108 109 // 配置加密 110 encryAlgo := file.GetEncryptAlgo() 111 encryDataKey := file.GetEncryptDataKey() 112 // 算法以传进来的参数为准 113 if file.IsEncrypted() { 114 // 如果加密算法进行了调整,dataKey 需要重新生成 115 if err := chain.encryptConfigFile(ctx, file, encryAlgo, encryDataKey); err != nil { 116 log.Error("[Config][Service] update encrypt config file error.", utils.RequestID(ctx), 117 utils.ZapNamespace(file.Namespace), utils.ZapGroup(file.Group), utils.ZapFileName(file.Name), 118 zap.Error(err)) 119 return api.NewConfigResponseWithInfo(apimodel.Code_EncryptConfigFileException, err.Error()) 120 } 121 } else { 122 chain.cleanEncryptConfigFileInfo(ctx, file) 123 } 124 return nil 125 } 126 127 // AfterGetFileRelease 128 func (chain *CryptoConfigFileChain) AfterGetFileRelease(ctx context.Context, 129 release *model.ConfigFileRelease) (*model.ConfigFileRelease, error) { 130 131 s := chain.svr 132 // decryptConfigFileRelease 解密配置文件发布纪录 133 if s.cryptoManager == nil || release == nil { 134 return release, nil 135 } 136 encryptAlgo := release.GetEncryptAlgo() 137 encryptDataKey := release.GetEncryptDataKey() 138 plainContent, err := chain.decryptConfigFileContent(encryptDataKey, encryptAlgo, release.Content) 139 if err == nil && plainContent != "" { 140 release.Content = plainContent 141 } 142 if err != nil { 143 log.Error("[Config][Chain][Crypto] decrypt release config file content", 144 utils.ZapNamespace(release.Namespace), utils.ZapGroup(release.Group), 145 utils.ZapFileName(release.Name), zap.Error(err)) 146 } 147 return release, nil 148 } 149 150 // AfterGetFileHistory 151 func (chain *CryptoConfigFileChain) AfterGetFileHistory(ctx context.Context, 152 history *model.ConfigFileReleaseHistory) (*model.ConfigFileReleaseHistory, error) { 153 if history == nil { 154 return history, nil 155 } 156 if !history.IsEncrypted() { 157 return history, nil 158 } 159 encryptAlgo := history.GetEncryptAlgo() 160 dataKey := history.GetEncryptDataKey() 161 plainContent, err := chain.decryptConfigFileContent(dataKey, encryptAlgo, history.Content) 162 if err == nil && plainContent != "" { 163 history.Content = plainContent 164 } else { 165 log.Error("[Config][Chain][Crypto] decrypt history config file content", 166 utils.ZapNamespace(history.Namespace), utils.ZapGroup(history.Group), 167 utils.ZapFileName(history.Name), zap.Error(err)) 168 } 169 return history, err 170 } 171 172 // decryptConfigFileContent 解密配置文件 173 func (chain *CryptoConfigFileChain) decryptConfigFileContent(dataKey, algorithm, content string) (string, error) { 174 cryptoMgr := chain.svr.cryptoManager 175 if cryptoMgr == nil { 176 return "", nil 177 } 178 // 没有加密算法不解密 179 if algorithm == "" { 180 return "", nil 181 } 182 crypto, err := cryptoMgr.GetCrypto(algorithm) 183 if err != nil { 184 return "", err 185 } 186 if crypto == nil { 187 return "", nil 188 } 189 dateKeyBytes, err := base64.StdEncoding.DecodeString(dataKey) 190 if err != nil { 191 return "", err 192 } 193 // 解密 194 plainContent, err := crypto.Decrypt(content, dateKeyBytes) 195 if err != nil { 196 return "", err 197 } 198 return plainContent, nil 199 } 200 201 // cleanEncryptConfigFileInfo 清理配置加密文件的内容信息 202 func (chain *CryptoConfigFileChain) cleanEncryptConfigFileInfo(ctx context.Context, configFile *model.ConfigFile) { 203 delete(configFile.Metadata, utils.ConfigFileTagKeyDataKey) 204 delete(configFile.Metadata, utils.ConfigFileTagKeyEncryptAlgo) 205 delete(configFile.Metadata, utils.ConfigFileTagKeyUseEncrypted) 206 } 207 208 // encryptConfigFile 加密配置文件 209 func (chain *CryptoConfigFileChain) encryptConfigFile(ctx context.Context, configFile *model.ConfigFile, 210 algorithm string, dataKey string) error { 211 212 s := chain.svr 213 if s.cryptoManager == nil || configFile == nil { 214 return nil 215 } 216 crypto, err := s.cryptoManager.GetCrypto(algorithm) 217 if err != nil { 218 return err 219 } 220 221 var dateKeyBytes []byte 222 if dataKey == "" { 223 dateKeyBytes, err = crypto.GenerateKey() 224 if err != nil { 225 return err 226 } 227 } else { 228 dateKeyBytes, err = base64.StdEncoding.DecodeString(dataKey) 229 if err != nil { 230 return err 231 } 232 } 233 content := configFile.Content 234 cipherContent, err := crypto.Encrypt(content, dateKeyBytes) 235 if err != nil { 236 return err 237 } 238 configFile.Content = cipherContent 239 if len(configFile.Metadata) == 0 { 240 configFile.Metadata = map[string]string{} 241 } 242 configFile.Metadata[utils.ConfigFileTagKeyDataKey] = base64.StdEncoding.EncodeToString(dateKeyBytes) 243 configFile.Metadata[utils.ConfigFileTagKeyEncryptAlgo] = algorithm 244 configFile.Metadata[utils.ConfigFileTagKeyUseEncrypted] = "true" 245 246 return nil 247 } 248 249 type ReleaseConfigFileChain struct { 250 svr *Server 251 } 252 253 func (chain *ReleaseConfigFileChain) Init(svr *Server) { 254 chain.svr = svr 255 } 256 257 func (chain *ReleaseConfigFileChain) Name() string { 258 return "CryptoConfigFileChain" 259 } 260 261 // BeforeCreateFile 262 func (chain *ReleaseConfigFileChain) BeforeCreateFile(ctx context.Context, 263 file *model.ConfigFile) *apiconfig.ConfigResponse { 264 return nil 265 } 266 267 // AfterCreateFile 268 func (chain *ReleaseConfigFileChain) AfterGetFile(ctx context.Context, 269 file *model.ConfigFile) (*model.ConfigFile, error) { 270 271 namespace := file.Namespace 272 group := file.Group 273 name := file.Name 274 275 // 填充发布信息 276 activeFile := chain.svr.fileCache.GetActiveRelease(namespace, group, name) 277 if activeFile != nil { 278 // 如果最后一次发布的内容和当前文件内容一致,则展示最后一次发布状态。否则说明文件有修改,待发布 279 if activeFile.Content == file.OriginContent { 280 file.Status = utils.ReleaseTypeNormal 281 file.ReleaseBy = activeFile.ModifyBy 282 file.ReleaseTime = activeFile.ModifyTime 283 } else { 284 file.Status = utils.ReleaseStatusToRelease 285 } 286 } else { 287 // 如果从来没有发布过,也是待发布状态 288 file.Status = utils.ReleaseStatusToRelease 289 } 290 return file, nil 291 } 292 293 // BeforeUpdateFile 294 func (chain *ReleaseConfigFileChain) BeforeUpdateFile(ctx context.Context, 295 file *model.ConfigFile) *apiconfig.ConfigResponse { 296 return nil 297 } 298 299 // AfterGetFileRelease 300 func (chain *ReleaseConfigFileChain) AfterGetFileRelease(ctx context.Context, 301 release *model.ConfigFileRelease) (*model.ConfigFileRelease, error) { 302 return release, nil 303 } 304 305 // AfterGetFileHistory 306 func (chain *ReleaseConfigFileChain) AfterGetFileHistory(ctx context.Context, 307 history *model.ConfigFileReleaseHistory) (*model.ConfigFileReleaseHistory, error) { 308 return history, nil 309 }