Skip to content

Commit ba53aeb

Browse files
committed
chore: mask backend sensitive information
1 parent 8b39102 commit ba53aeb

File tree

13 files changed

+128
-15
lines changed

13 files changed

+128
-15
lines changed

api/openapispec/docs.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -5430,9 +5430,7 @@ const docTemplate = `{
54305430
"request.UpdateWorkspaceRequest": {
54315431
"type": "object",
54325432
"required": [
5433-
"backendID",
5434-
"id",
5435-
"owners"
5433+
"id"
54365434
],
54375435
"properties": {
54385436
"backendID": {

api/openapispec/swagger.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -5419,9 +5419,7 @@
54195419
"request.UpdateWorkspaceRequest": {
54205420
"type": "object",
54215421
"required": [
5422-
"backendID",
5423-
"id",
5424-
"owners"
5422+
"id"
54255423
],
54265424
"properties": {
54275425
"backendID": {

api/openapispec/swagger.yaml

-2
Original file line numberDiff line numberDiff line change
@@ -1242,9 +1242,7 @@ definitions:
12421242
type: string
12431243
type: array
12441244
required:
1245-
- backendID
12461245
- id
1247-
- owners
12481246
type: object
12491247
request.WorkspaceConfigs:
12501248
properties:

pkg/apis/api.kusion.io/v1/types.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ const (
250250
BackendGenericOssPrefix = "prefix"
251251
BackendS3Region = "region"
252252
BackendS3ForcePathStyle = "forcePathStyle"
253+
BackendGoogleCredentials = "credentials"
253254

254255
BackendTypeLocal = "local"
255256
BackendTypeOss = "oss"
@@ -422,7 +423,7 @@ func (b *BackendConfig) ToGoogleBackend() *BackendGoogleConfig {
422423
var creds *googleauth.Credentials
423424
bucket, _ := b.Configs[BackendGenericOssBucket].(string)
424425
prefix, _ := b.Configs[BackendGenericOssPrefix].(string)
425-
if credentialsJSON, ok := b.Configs["credentials"].(map[string]any); ok {
426+
if credentialsJSON, ok := b.Configs[BackendGoogleCredentials].(map[string]any); ok {
426427
credentialsBytes, err := json.Marshal(credentialsJSON)
427428
if err != nil {
428429
return nil

pkg/domain/constant/workspace.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package constant
2+
3+
import "errors"
4+
5+
var (
6+
ErrEmptyWorkspaceName = errors.New("workspace must have a name")
7+
ErrInvalidWorkspaceName = errors.New("workspace name can only have alphanumeric characters and underscores with [a-zA-Z0-9_]")
8+
ErrEmptyOwners = errors.New("workspace must have at least one owner")
9+
ErrEmptyBackendID = errors.New("workspace must have a backend id")
10+
)

pkg/domain/request/workspace_request.go

+31-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"net/http"
55

66
v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1"
7+
"kusionstack.io/kusion/pkg/domain/constant"
78
)
89

910
// CreateWorkspaceRequest represents the create request structure for
@@ -33,9 +34,9 @@ type UpdateWorkspaceRequest struct {
3334
// Labels are custom labels associated with the workspace.
3435
Labels map[string]string `json:"labels"`
3536
// Owners is a list of owners for the workspace.
36-
Owners []string `json:"owners" binding:"required"`
37+
Owners []string `json:"owners"`
3738
// BackendID is the configuration backend id associated with the workspace.
38-
BackendID uint `json:"backendID" binding:"required"`
39+
BackendID uint `json:"backendID"`
3940
}
4041

4142
type WorkspaceCredentials struct {
@@ -53,6 +54,34 @@ type WorkspaceConfigs struct {
5354
*v1.Workspace `yaml:",inline" json:",inline"`
5455
}
5556

57+
func (payload *CreateWorkspaceRequest) Validate() error {
58+
if payload.Name == "" {
59+
return constant.ErrEmptyWorkspaceName
60+
}
61+
62+
if validName(payload.Name) {
63+
return constant.ErrInvalidWorkspaceName
64+
}
65+
66+
if payload.BackendID == 0 {
67+
return constant.ErrEmptyBackendID
68+
}
69+
70+
if len(payload.Owners) == 0 {
71+
return constant.ErrEmptyOwners
72+
}
73+
74+
return nil
75+
}
76+
77+
func (payload *UpdateWorkspaceRequest) Validate() error {
78+
if payload.Name != "" && validName(payload.Name) {
79+
return constant.ErrInvalidWorkspaceName
80+
}
81+
82+
return nil
83+
}
84+
5685
func (payload *CreateWorkspaceRequest) Decode(r *http.Request) error {
5786
return decode(r, payload)
5887
}

pkg/server/handler/module/handler.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (h *Handler) DeleteModule() http.HandlerFunc {
9797
// @Failure 429 {object} error "Too Many Requests"
9898
// @Failure 404 {object} error "Not Found"
9999
// @Failure 500 {object} error "Internal Server Error"
100-
// @Router /api/v1/modules/{moduleName} [put]
100+
// @Router /api/v1/modules/{moduleName} [put]
101101
func (h *Handler) UpdateModule() http.HandlerFunc {
102102
return func(w http.ResponseWriter, r *http.Request) {
103103
// Getting stuff from context.
@@ -139,7 +139,7 @@ func (h *Handler) UpdateModule() http.HandlerFunc {
139139
// @Failure 429 {object} error "Too Many Requests"
140140
// @Failure 404 {object} error "Not Found"
141141
// @Failure 500 {object} error "Internal Server Error"
142-
// @Router /api/v1/modules/{moduleName} [get]
142+
// @Router /api/v1/modules/{moduleName} [get]
143143
func (h *Handler) GetModule() http.HandlerFunc {
144144
return func(w http.ResponseWriter, r *http.Request) {
145145
// Getting stuff from context.

pkg/server/handler/stack/handler.go

+6
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ func (h *Handler) UpdateStack() http.HandlerFunc {
128128
return
129129
}
130130

131+
// Validate request payload
132+
if err := requestPayload.Validate(); err != nil {
133+
render.Render(w, r, handler.FailureResponse(ctx, err))
134+
return
135+
}
136+
131137
updatedEntity, err := h.stackManager.UpdateStackByID(ctx, params.StackID, requestPayload)
132138
handler.HandleResult(w, r, ctx, err, updatedEntity)
133139
}

pkg/server/handler/workspace/configs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func (h *Handler) UpdateWorkspaceConfigs() http.HandlerFunc {
116116
// @Failure 429 {object} error "Too Many Requests"
117117
// @Failure 404 {object} error "Not Found"
118118
// @Failure 500 {object} error "Internal Server Error"
119-
// @Router /api/v1/workspaces/{workspaceID}/configs/mod-deps [post]
119+
// @Router /api/v1/workspaces/{workspaceID}/configs/mod-deps [post]
120120
func (h *Handler) CreateWorkspaceModDeps() http.HandlerFunc {
121121
return func(w http.ResponseWriter, r *http.Request) {
122122
// Getting stuff from context.

pkg/server/handler/workspace/handler.go

+12
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ func (h *Handler) CreateWorkspace() http.HandlerFunc {
4343
return
4444
}
4545

46+
// Validate request payload
47+
if err := requestPayload.Validate(); err != nil {
48+
render.Render(w, r, handler.FailureResponse(ctx, err))
49+
return
50+
}
51+
4652
createdEntity, err := h.workspaceManager.CreateWorkspace(ctx, requestPayload)
4753
handler.HandleResult(w, r, ctx, err, createdEntity)
4854
}
@@ -108,6 +114,12 @@ func (h *Handler) UpdateWorkspace() http.HandlerFunc {
108114
return
109115
}
110116

117+
// Validate request payload
118+
if err := requestPayload.Validate(); err != nil {
119+
render.Render(w, r, handler.FailureResponse(ctx, err))
120+
return
121+
}
122+
111123
updatedEntity, err := h.workspaceManager.UpdateWorkspaceByID(ctx, params.WorkspaceID, requestPayload)
112124
handler.HandleResult(w, r, ctx, err, updatedEntity)
113125
}

pkg/server/manager/backend/backend_manager.go

+27-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ func (m *BackendManager) ListBackends(ctx context.Context, filter *entity.Backen
2222
}
2323
return nil, err
2424
}
25+
26+
for i, entity := range backendEntities.Backends {
27+
entity, err := MaskBackendSensitiveInfo(entity)
28+
if err != nil {
29+
return nil, err
30+
}
31+
backendEntities.Backends[i] = entity
32+
}
2533
return backendEntities, nil
2634
}
2735

@@ -33,6 +41,12 @@ func (m *BackendManager) GetBackendByID(ctx context.Context, id uint) (*entity.B
3341
}
3442
return nil, err
3543
}
44+
45+
existingEntity, err = MaskBackendSensitiveInfo(existingEntity)
46+
if err != nil {
47+
return nil, err
48+
}
49+
3650
return existingEntity, nil
3751
}
3852

@@ -71,6 +85,12 @@ func (m *BackendManager) UpdateBackendByID(ctx context.Context, id uint, request
7185
if err != nil {
7286
return nil, err
7387
}
88+
89+
updatedEntity, err = MaskBackendSensitiveInfo(updatedEntity)
90+
if err != nil {
91+
return nil, err
92+
}
93+
7494
return updatedEntity, nil
7595
}
7696

@@ -86,7 +106,13 @@ func (m *BackendManager) CreateBackend(ctx context.Context, requestPayload reque
86106
if err != nil {
87107
return nil, err
88108
}
89-
return &createdEntity, nil
109+
110+
maskedEntity, err := MaskBackendSensitiveInfo(&createdEntity)
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
return maskedEntity, nil
90116
}
91117

92118
func (m *BackendManager) BuildBackendFilter(ctx context.Context, query *url.Values) (*entity.BackendFilter, error) {

pkg/server/manager/backend/types.go

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var (
1010
ErrGettingNonExistingBackend = errors.New("the backend does not exist")
1111
ErrUpdatingNonExistingBackend = errors.New("the backend to update does not exist")
1212
ErrInvalidBackendID = errors.New("the backend ID should be a uuid")
13+
ErrInternalServerError = errors.New("internal server error")
1314
)
1415

1516
type BackendManager struct {

pkg/server/manager/backend/util.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package backend
2+
3+
import (
4+
v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1"
5+
"kusionstack.io/kusion/pkg/domain/entity"
6+
)
7+
8+
// MaskBackendSensitiveInfo is a helper function to mask sensitive information in backend
9+
func MaskBackendSensitiveInfo(entity *entity.Backend) (*entity.Backend, error) {
10+
if entity == nil {
11+
return nil, ErrInternalServerError
12+
}
13+
14+
// mask oss secret key
15+
if _, ok := entity.BackendConfig.Configs[v1.BackendGenericOssSK]; ok {
16+
entity.BackendConfig.Configs[v1.BackendGenericOssSK] = "**********"
17+
}
18+
19+
// mask google credentials
20+
if credentialsJSON, ok := entity.BackendConfig.Configs[v1.BackendGoogleCredentials].(map[string]any); ok {
21+
maskSensitiveInfo(credentialsJSON)
22+
entity.BackendConfig.Configs[v1.BackendGoogleCredentials] = credentialsJSON
23+
}
24+
return entity, nil
25+
}
26+
27+
func maskSensitiveInfo(credentials map[string]any) {
28+
sensitiveFields := []string{"private_key", "client_email", "client_id"}
29+
for _, field := range sensitiveFields {
30+
if _, ok := credentials[field]; ok {
31+
credentials[field] = "**********"
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)