Skip to content

Commit

Permalink
支持配置加密功能
Browse files Browse the repository at this point in the history
  • Loading branch information
raywlwang committed May 22, 2023
1 parent febe7c0 commit d9edebc
Show file tree
Hide file tree
Showing 38 changed files with 1,668 additions and 99 deletions.
13 changes: 13 additions & 0 deletions apiserver/httpserver/config_console_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,16 @@ func (h *HTTPServer) CreateConfigFileTemplate(req *restful.Request, rsp *restful

handler.WriteHeaderAndProto(h.configServer.CreateConfigFileTemplate(ctx, configFileTemplate))
}

// GetAllConfigEncryptAlgorithm get all config encrypt algorithm
func (h *HTTPServer) GetAllConfigEncryptAlgorithms(req *restful.Request, rsp *restful.Response) {
handler := &httpcommon.Handler{
Request: req,
Response: rsp,
}
response := h.configServer.GetAllConfigEncryptAlgorithms(handler.ParseHeaderContext())
configLog.Info("response",
zap.Uint32("code", response.GetCode().GetValue()),
)
handler.WriteHeaderAndProto(response)
}
2 changes: 2 additions & 0 deletions apiserver/httpserver/config_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ func (h *HTTPServer) bindConfigConsoleEndpoint(ws *restful.WebService) {
ws.Route(docs.EnrichBatchDeleteConfigFileApiDocs(ws.POST("/configfiles/batchdelete").To(h.BatchDeleteConfigFile)))
ws.Route(docs.EnrichExportConfigFileApiDocs(ws.POST("/configfiles/export").To(h.ExportConfigFile)))
ws.Route(docs.EnrichImportConfigFileApiDocs(ws.POST("/configfiles/import").To(h.ImportConfigFile)))
ws.Route(docs.EnrichGetAllConfigEncryptAlgorithmsApiDocs(ws.GET("/configfiles/encryptalgorithm").
To(h.GetAllConfigEncryptAlgorithms)))

// 配置文件发布
ws.Route(docs.EnrichPublishConfigFileApiDocs(ws.POST("/configfiles/release").To(h.PublishConfigFile)))
Expand Down
6 changes: 6 additions & 0 deletions apiserver/httpserver/docs/config_server_apidoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ func EnrichImportConfigFileApiDocs(r *restful.RouteBuilder) *restful.RouteBuilde
" \"namespace\":\"someNamespace\",\n \"group\":\"someGroup\"\n }\n]\n```")
}

func EnrichGetAllConfigEncryptAlgorithmsApiDocs(r *restful.RouteBuilder) *restful.RouteBuilder {
return r.
Doc("获取配置加密算法").
Metadata(restfulspec.KeyOpenAPITags, configConsoleApiTags)
}

func EnrichPublishConfigFileApiDocs(r *restful.RouteBuilder) *restful.RouteBuilder {
return r.
Doc("发布配置文件").
Expand Down
33 changes: 32 additions & 1 deletion cache/config_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ type Entry struct {
Content string
Md5 string
Version uint64
DataKey string
// 创建的时候,设置过期时间
ExpireTime time.Time
// 标识是否是空缓存
Expand Down Expand Up @@ -239,7 +240,7 @@ func (fc *fileCache) GetOrLoadIfAbsent(namespace, group, fileName string) (*Entr
// 从数据库中加载数据
atomic.AddInt32(&fc.loadCnt, 1)

file, err := fc.storage.GetConfigFileRelease(nil, namespace, group, fileName)
file, dataKey, err := fc.getConfigFileReleaseAndDataKey(namespace, group, fileName)
if err != nil {
configLog.Error("[Config][Cache] load config file release error.",
zap.String("namespace", namespace),
Expand Down Expand Up @@ -269,6 +270,7 @@ func (fc *fileCache) GetOrLoadIfAbsent(namespace, group, fileName string) (*Entr
Content: file.Content,
Md5: file.Md5,
Version: file.Version,
DataKey: dataKey,
ExpireTime: fc.getExpireTime(),
}

Expand All @@ -287,6 +289,35 @@ func (fc *fileCache) GetOrLoadIfAbsent(namespace, group, fileName string) (*Entr
return newEntry, nil
}

func (fc *fileCache) getConfigFileReleaseAndDataKey(
namespace, group, fileName string) (*model.ConfigFileRelease, string, error) {
file, err := fc.storage.GetConfigFileRelease(nil, namespace, group, fileName)
if err != nil {
configLog.Error("[Config][Cache] load config file release error.",
zap.String("namespace", namespace),
zap.String("group", group),
zap.String("fileName", fileName),
zap.Error(err))
return nil, "", err
}
tags, err := fc.storage.QueryTagByConfigFile(namespace, group, fileName)
if err != nil {
configLog.Error("[Config][Cache] load config file tag error.",
zap.String("namespace", namespace),
zap.String("group", group),
zap.String("fileName", fileName),
zap.Error(err))
return nil, "", err
}
var dataKey string
for _, tag := range tags {
if tag.Key == utils.ConfigFileTagKeyDataKey {
dataKey = tag.Value
}
}
return file, dataKey, nil
}

// Remove 删除缓存对象
func (fc *fileCache) Remove(namespace, group, fileName string) {
atomic.AddInt32(&fc.removeCnt, 1)
Expand Down
21 changes: 21 additions & 0 deletions cache/config_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ func TestGetAndRemoveAndReloadConfigFile(t *testing.T) {
// Mock 数据
configFile := assembleConfigFile()
configFileRelease := assembleConfigFileRelease(configFile)
configFileTags := assembelConfigFileTags(configFile)

// 前三次调用返回一个值,第四次调用返回另外一个值,默认更新
mockedStorage.EXPECT().GetConfigFileRelease(nil, testNamespace, testGroup, testFile).Return(configFileRelease, nil).Times(3)
mockedStorage.EXPECT().QueryTagByConfigFile(testNamespace, testGroup, testFile).Return(configFileTags, nil).Times(3)

for i := 0; i < 100; i++ {
go func() {
Expand Down Expand Up @@ -93,9 +95,11 @@ func TestConcurrentGetConfigFile(t *testing.T) {
// Mock 数据
configFile := assembleConfigFile()
configFileRelease := assembleConfigFileRelease(configFile)
configFileTags := assembelConfigFileTags(configFile)

// 一共调用三次,
mockedStorage.EXPECT().GetConfigFileRelease(nil, testNamespace, testGroup, testFile).Return(configFileRelease, nil).Times(1)
mockedStorage.EXPECT().QueryTagByConfigFile(testNamespace, testGroup, testFile).Return(configFileTags, nil).Times(1)

for i := 0; i < 1000; i++ {
go func() {
Expand All @@ -121,7 +125,9 @@ func TestUpdateCache(t *testing.T) {
configFileRelease := assembleConfigFileRelease(configFile)
configFileRelease.Content = firstValue
configFileRelease.Version = firstVersion
configFileTags := assembelConfigFileTags(configFile)
first := mockedStorage.EXPECT().GetConfigFileRelease(nil, testNamespace, testGroup, testFile).Return(configFileRelease, nil).Times(1)
mockedStorage.EXPECT().QueryTagByConfigFile(testNamespace, testGroup, testFile).Return(configFileTags, nil).Times(1)

// 第二次调用返会值
secondValue := "secondValue"
Expand All @@ -130,7 +136,9 @@ func TestUpdateCache(t *testing.T) {
configFileRelease2 := assembleConfigFileRelease(configFile2)
configFileRelease2.Content = secondValue
configFileRelease2.Version = secondVersion
configFileTags = assembelConfigFileTags(configFile)
second := mockedStorage.EXPECT().GetConfigFileRelease(nil, testNamespace, testGroup, testFile).Return(configFileRelease2, nil).Times(1)
mockedStorage.EXPECT().QueryTagByConfigFile(testNamespace, testGroup, testFile).Return(configFileTags, nil).Times(1)

gomock.InOrder(first, second)

Expand Down Expand Up @@ -190,6 +198,19 @@ func assembleConfigFileRelease(configFile *model.ConfigFile) *model.ConfigFileRe
}
}

func assembelConfigFileTags(configFile *model.ConfigFile) []*model.ConfigFileTag {
tags := []*model.ConfigFileTag{
{
Key: utils.ConfigFileTagKeyDataKey,
Value: "data key",
Namespace: configFile.Namespace,
Group: configFile.Group,
FileName: configFile.Name,
},
}
return tags
}

func assembleConfigFileGroup() *model.ConfigFileGroup {
return &model.ConfigFileGroup{
Id: uint64(100),
Expand Down
26 changes: 26 additions & 0 deletions common/api/v1/config_file_response_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/golang/protobuf/ptypes/wrappers"
apiconfig "github.com/polarismesh/specification/source/go/api/v1/config_manage"
apimodel "github.com/polarismesh/specification/source/go/api/v1/model"
"google.golang.org/protobuf/types/known/wrapperspb"
)

func NewConfigClientResponse(
Expand Down Expand Up @@ -100,6 +101,14 @@ func NewConfigFileBatchQueryResponse(
}
}

func NewConfigFileBatchQueryResponseWithMessage(
code apimodel.Code, message string) *apiconfig.ConfigBatchQueryResponse {
return &apiconfig.ConfigBatchQueryResponse{
Code: &wrappers.UInt32Value{Value: uint32(code)},
Info: &wrappers.StringValue{Value: code2info[uint32(code)]},
}
}

func NewConfigFileTemplateResponse(
code apimodel.Code, template *apiconfig.ConfigFileTemplate) *apiconfig.ConfigResponse {
return &apiconfig.ConfigResponse{
Expand Down Expand Up @@ -176,3 +185,20 @@ func NewConfigFileExportResponse(code apimodel.Code, data []byte) *apiconfig.Con
Data: &wrappers.BytesValue{Value: data},
}
}

func NewConfigFileExportResponseWithMessage(code apimodel.Code, message string) *apiconfig.ConfigExportResponse {
return &apiconfig.ConfigExportResponse{
Code: &wrappers.UInt32Value{Value: uint32(code)},
Info: &wrappers.StringValue{Value: code2info[uint32(code)] + ":" + message},
}
}

func NewConfigEncryptAlgorithmResponse(code apimodel.Code,
algorithms []*wrapperspb.StringValue) *apiconfig.ConfigEncryptAlgorithmResponse {
resp := &apiconfig.ConfigEncryptAlgorithmResponse{
Code: &wrappers.UInt32Value{Value: uint32(code)},
Info: &wrappers.StringValue{Value: code2info[uint32(code)]},
Algorithms: algorithms,
}
return resp
}
121 changes: 121 additions & 0 deletions common/rsa/rsa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Tencent is pleased to support the open source community by making Polaris available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package rsa

import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
)

// RSAKey RSA key pair
type RSAKey struct {
PrivateKey string
PublicKey string
}

// GenerateKey generate RSA key pair
func GenerateRSAKey() (*RSAKey, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
return nil, err
}
rsaKey := &RSAKey{
PrivateKey: base64.StdEncoding.EncodeToString(x509.MarshalPKCS1PrivateKey(privateKey)),
PublicKey: base64.StdEncoding.EncodeToString(x509.MarshalPKCS1PublicKey(&privateKey.PublicKey)),
}
return rsaKey, nil
}

// Encrypt RSA encrypt plaintext using public key
func Encrypt(plaintext, publicKey []byte) ([]byte, error) {
pub, err := x509.ParsePKCS1PublicKey(publicKey)
if err != nil {
return nil, err
}
totalLen := len(plaintext)
segLen := pub.Size() - 11
start := 0
buffer := bytes.Buffer{}
for start < totalLen {
end := start + segLen
if end > totalLen {
end = totalLen
}
seg, err := rsa.EncryptPKCS1v15(rand.Reader, pub, plaintext[start:end])
if err != nil {
return nil, err
}
buffer.Write(seg)
start = end
}
return buffer.Bytes(), nil
}

// Decrypt RSA decrypt ciphertext using private key
func Decrypt(ciphertext, privateKey []byte) ([]byte, error) {
priv, err := x509.ParsePKCS1PrivateKey(privateKey)
if err != nil {
return nil, err
}
keySize := priv.Size()
totalLen := len(ciphertext)
start := 0
buffer := bytes.Buffer{}
for start < totalLen {
end := start + keySize
if end > totalLen {
end = totalLen
}
seg, err := rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext[start:end])
if err != nil {
return nil, err
}
buffer.Write(seg)
start = end
}
return buffer.Bytes(), nil
}

// EncryptToBase64 RSA encrypt plaintext and base64 encode ciphertext
func EncryptToBase64(plaintext []byte, base64PublicKey string) (string, error) {
pub, err := base64.StdEncoding.DecodeString(base64PublicKey)
if err != nil {
return "", err
}
ciphertext, err := Encrypt(plaintext, pub)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(ciphertext), nil
}

// DecryptFromBase64 base64 decode ciphertext and RSA decrypt
func DecryptFromBase64(base64Ciphertext, base64PrivateKey string) ([]byte, error) {
priv, err := base64.StdEncoding.DecodeString(base64PrivateKey)
if err != nil {
return nil, err
}
ciphertext, err := base64.StdEncoding.DecodeString(base64Ciphertext)
if err != nil {
return nil, err
}
return Decrypt(ciphertext, priv)
}

0 comments on commit d9edebc

Please sign in to comment.