diff --git a/src/common/definitions.go b/src/common/definitions.go index 6bbe0f56ba..ad987e28c1 100644 --- a/src/common/definitions.go +++ b/src/common/definitions.go @@ -553,6 +553,15 @@ const ( // BKExtendResourceNameField the audit extend resource name field BKExtendResourceNameField = "extend_resource_name" + // BKAuditAppCodeField + BKAuditAppCodeField = "code" + + // BKAuditSceneContextOpUser op_user + BKAuditSceneContextOpUser = "audit_context.op_user" + BKAuditSceneContextScene = "audit_context.scene" + BKAuditSceneContextSceneTraceId = "audit_context.scene_trace_id" + BKAuditSceneContextSceneDesc = "audit_context.scene_desc" + // BKLabelField the audit resource name field BKLabelField = "label" diff --git a/src/common/http/header/accessor.go b/src/common/http/header/accessor.go index 32e68f0ec6..4e68633e71 100644 --- a/src/common/http/header/accessor.go +++ b/src/common/http/header/accessor.go @@ -216,3 +216,13 @@ func IsInnerReq(header http.Header) bool { func SetIsInnerReqHeader(header http.Header) { header.Set(IsInnerReqHeader, "true") } + +// GetAuditSceneHeader get audit scene from http header +func GetAuditSceneHeader(header http.Header) string { + return header.Get(XBkCmdbAudit) +} + +// SetAuditSceneHeader set audit scene to http header +func SetAuditSceneHeader(header http.Header, value string) { + header.Set(XBkCmdbAudit, value) +} diff --git a/src/common/http/header/header.go b/src/common/http/header/header.go index d07cc4422b..505aace9e0 100644 --- a/src/common/http/header/header.go +++ b/src/common/http/header/header.go @@ -76,3 +76,7 @@ const ( // IsInnerReqHeader is the http header key that represents if request is an inner request IsInnerReqHeader = "X-Bkcmdb-Is-Inner-Request" ) + +const ( + XBkCmdbAudit = "X-Bkcmdb-Audit" +) diff --git a/src/common/http/header/util/util.go b/src/common/http/header/util/util.go index 22adbdbc0d..3e72f2424e 100644 --- a/src/common/http/header/util/util.go +++ b/src/common/http/header/util/util.go @@ -37,6 +37,7 @@ func CCHeader(header http.Header) http.Header { httpheader.SetSupplierAccount(newHeader, httpheader.GetSupplierAccount(header)) httpheader.SetAppCode(newHeader, httpheader.GetAppCode(header)) httpheader.SetReqRealIP(newHeader, httpheader.GetReqRealIP(header)) + httpheader.SetAuditSceneHeader(newHeader, httpheader.GetAuditSceneHeader(header)) if httpheader.IsReqFromWeb(header) { httpheader.SetReqFromWeb(newHeader) } @@ -91,6 +92,7 @@ func NewHeader(header http.Header) http.Header { httpheader.SetTXId(newHeader, httpheader.GetTXId(header)) httpheader.SetTXTimeout(newHeader, httpheader.GetTXTimeout(header)) + httpheader.SetAuditSceneHeader(newHeader, httpheader.GetAuditSceneHeader(header)) if httpheader.IsReqFromWeb(header) { httpheader.SetReqFromWeb(newHeader) diff --git a/src/common/metadata/audit.go b/src/common/metadata/audit.go index 4eff5d04f6..d11eec0339 100644 --- a/src/common/metadata/audit.go +++ b/src/common/metadata/audit.go @@ -96,6 +96,11 @@ type AuditQueryCondition struct { FuzzyQuery bool `json:"fuzzy_query"` // Condition is used for new way to search audit log by user or resource_name Condition []querybuilder.AtomRule `json:"condition"` + + Code string `json:"code" bson:"code"` + OpScene string `json:"op_scene" bson:"op_scene"` + OpUser string `json:"op_user" bson:"op_user"` + OpSceneTraceId string `json:"op_scene_trace_id" bson:"op_scene_trace_id"` } // Validate is a AuditQueryCondition validator to validate user resource_name condition whether exist at the same time @@ -170,10 +175,24 @@ type InstAuditCondition struct { ResourceType ResourceType `json:"resource_type" ` Action []ActionType `json:"action"` OperationTime OperationTimeCondition `json:"operation_time"` + + Code string `json:"code"` + OpScene string `json:"op_scene" bson:"op_scene"` + OpUser string `json:"op_user" bson:"op_user"` + OpSceneTraceId string `json:"op_scene_trace_id" bson:"op_scene_trace_id"` + // ID is an audit record's id ID []int64 `json:"id"` } +// AuditSceneHeader audit scene header context +type AuditSceneHeader struct { + Scene string `json:"scene" bson:"scene"` + SceneDesc string `json:"scene_desc" bson:"scene_desc"` + SceneTraceId string `json:"scene_trace_id" bson:"scene_trace_id"` + OpUser string `json:"op_user" bson:"op_user"` +} + // AuditLog struct for audit log type AuditLog struct { ID int64 `json:"id" bson:"id"` @@ -209,42 +228,46 @@ type AuditLog struct { RequestID string `json:"rid,omitempty" bson:"rid,omitempty"` // todo ExtendResourceName for the temporary solution of ipv6 ExtendResourceName string `json:"extend_resource_name" bson:"extend_resource_name"` + // AuditContext for the audit scene + AuditContext AuditSceneHeader `json:"audit_context" bson:"audit_context"` } type bsonAuditLog struct { - ID int64 `json:"id" bson:"id"` - AuditType AuditType `json:"audit_type" bson:"audit_type"` - SupplierAccount string `json:"bk_supplier_account" bson:"bk_supplier_account"` - User string `json:"user" bson:"user"` - ResourceType ResourceType `json:"resource_type" bson:"resource_type"` - Action ActionType `json:"action" bson:"action"` - OperateFrom OperateFromType `json:"operate_from" bson:"operate_from"` - OperationTime Time `json:"operation_time" bson:"operation_time"` - OperationDetail bson.Raw `json:"operation_detail" bson:"operation_detail"` - BusinessID int64 `json:"bk_biz_id" bson:"bk_biz_id"` - ResourceID interface{} `json:"resource_id" bson:"resource_id"` - ResourceName string `json:"resource_name" bson:"resource_name"` - AppCode string `json:"code" bson:"code"` - RequestID string `json:"rid" bson:"rid"` - ExtendResourceName string `json:"extend_resource_name" bson:"extend_resource_name"` + ID int64 `json:"id" bson:"id"` + AuditType AuditType `json:"audit_type" bson:"audit_type"` + SupplierAccount string `json:"bk_supplier_account" bson:"bk_supplier_account"` + User string `json:"user" bson:"user"` + ResourceType ResourceType `json:"resource_type" bson:"resource_type"` + Action ActionType `json:"action" bson:"action"` + OperateFrom OperateFromType `json:"operate_from" bson:"operate_from"` + OperationTime Time `json:"operation_time" bson:"operation_time"` + OperationDetail bson.Raw `json:"operation_detail" bson:"operation_detail"` + BusinessID int64 `json:"bk_biz_id" bson:"bk_biz_id"` + ResourceID interface{} `json:"resource_id" bson:"resource_id"` + ResourceName string `json:"resource_name" bson:"resource_name"` + AppCode string `json:"code" bson:"code"` + RequestID string `json:"rid" bson:"rid"` + ExtendResourceName string `json:"extend_resource_name" bson:"extend_resource_name"` + AuditContext AuditSceneHeader `json:"audit_context" bson:"audit_context"` } type jsonAuditLog struct { - ID int64 `json:"id" bson:"id"` - AuditType AuditType `json:"audit_type" bson:"audit_type"` - SupplierAccount string `json:"bk_supplier_account" bson:"bk_supplier_account"` - User string `json:"user" bson:"user"` - ResourceType ResourceType `json:"resource_type" bson:"resource_type"` - Action ActionType `json:"action" bson:"action"` - OperateFrom OperateFromType `json:"operate_from" bson:"operate_from"` - OperationTime Time `json:"operation_time" bson:"operation_time"` - OperationDetail json.RawMessage `json:"operation_detail" bson:"operation_detail"` - BusinessID int64 `json:"bk_biz_id" bson:"bk_biz_id"` - ResourceID interface{} `json:"resource_id" bson:"resource_id"` - ResourceName string `json:"resource_name" bson:"resource_name"` - AppCode string `json:"code" bson:"code"` - RequestID string `json:"rid" bson:"rid"` - ExtendResourceName string `json:"extend_resource_name" bson:"extend_resource_name"` + ID int64 `json:"id" bson:"id"` + AuditType AuditType `json:"audit_type" bson:"audit_type"` + SupplierAccount string `json:"bk_supplier_account" bson:"bk_supplier_account"` + User string `json:"user" bson:"user"` + ResourceType ResourceType `json:"resource_type" bson:"resource_type"` + Action ActionType `json:"action" bson:"action"` + OperateFrom OperateFromType `json:"operate_from" bson:"operate_from"` + OperationTime Time `json:"operation_time" bson:"operation_time"` + OperationDetail json.RawMessage `json:"operation_detail" bson:"operation_detail"` + BusinessID int64 `json:"bk_biz_id" bson:"bk_biz_id"` + ResourceID interface{} `json:"resource_id" bson:"resource_id"` + ResourceName string `json:"resource_name" bson:"resource_name"` + AppCode string `json:"code" bson:"code"` + RequestID string `json:"rid" bson:"rid"` + ExtendResourceName string `json:"extend_resource_name" bson:"extend_resource_name"` + AuditContext AuditSceneHeader `json:"audit_context" bson:"audit_context"` } // DetailFactory TODO @@ -293,6 +316,7 @@ func (auditLog *AuditLog) UnmarshalJSON(data []byte) error { auditLog.AppCode = audit.AppCode auditLog.RequestID = audit.RequestID auditLog.ExtendResourceName = audit.ExtendResourceName + auditLog.AuditContext = audit.AuditContext if audit.OperationDetail == nil { return nil @@ -357,6 +381,7 @@ func (auditLog *AuditLog) UnmarshalBSON(data []byte) error { auditLog.AppCode = audit.AppCode auditLog.RequestID = audit.RequestID auditLog.ExtendResourceName = audit.ExtendResourceName + auditLog.AuditContext = audit.AuditContext if audit.OperationDetail == nil { return nil @@ -416,6 +441,7 @@ func (auditLog AuditLog) MarshalBSON() ([]byte, error) { audit.AppCode = auditLog.AppCode audit.RequestID = auditLog.RequestID audit.ExtendResourceName = auditLog.ExtendResourceName + audit.AuditContext = auditLog.AuditContext var err error switch val := auditLog.OperationDetail.(type) { default: diff --git a/src/scene_server/admin_server/imports.go b/src/scene_server/admin_server/imports.go index 8bbe7cbe46..e584cc985e 100644 --- a/src/scene_server/admin_server/imports.go +++ b/src/scene_server/admin_server/imports.go @@ -120,5 +120,6 @@ import ( _ "configcenter/src/scene_server/admin_server/upgrader/y3.14.202405141035" _ "configcenter/src/scene_server/admin_server/upgrader/y3.14.202410100930" _ "configcenter/src/scene_server/admin_server/upgrader/y3.14.202502101200" + _ "configcenter/src/scene_server/admin_server/upgrader/y3.14.202601121450" _ "configcenter/src/scene_server/admin_server/upgrader/y3.14.202603231000" ) diff --git a/src/scene_server/admin_server/upgrader/y3.14.202601121450/add_audit_scene_index.go b/src/scene_server/admin_server/upgrader/y3.14.202601121450/add_audit_scene_index.go new file mode 100644 index 0000000000..18b5a9521c --- /dev/null +++ b/src/scene_server/admin_server/upgrader/y3.14.202601121450/add_audit_scene_index.go @@ -0,0 +1,92 @@ +/* + * Tencent is pleased to support the open source community by making + * 蓝鲸智云 - 配置平台 (BlueKing - Configuration System) available. + * Copyright (C) 2017 Tencent. All rights reserved. + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://opensource.org/licenses/MIT + * 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. + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package y3_14_202601121450 + +import ( + "configcenter/src/common/metadata" + "context" + "fmt" + + "configcenter/src/common" + "configcenter/src/common/blog" + "configcenter/src/scene_server/admin_server/upgrader" + "configcenter/src/storage/dal" + "configcenter/src/storage/dal/types" + + "go.mongodb.org/mongo-driver/bson" +) + +func addAuditLogSceneIndex(ctx context.Context, db dal.RDB, conf *upgrader.Config) error { + idxArr, err := db.Table(common.BKTableNameAuditLog).Indexes(ctx) + if err != nil { + blog.Errorf("get table %s index error. err:%s", common.BKTableNameAuditLog, err.Error()) + return err + } + err = db.Table(common.BKTableNameAuditLog).AddColumn(ctx, "audit_context", metadata.AuditSceneHeader{}) + if err != nil { + return fmt.Errorf("cc_AuditLog add column [audit_context] err:%w", err) + } + createIdxArr := []types.Index{ + { + Keys: bson.D{ + {common.BKOperationTimeField, 1}, + {common.BKAuditSceneContextSceneTraceId, 1}, + }, + Name: "index_audit_context_scene_trace_id", + Unique: true, + Background: true, + ExpireAfterSeconds: 0, + PartialFilterExpression: map[string]interface{}{ + common.BKAuditSceneContextSceneTraceId: bson.D{{common.BKDBGT, ""}}, + }, + }, + { + Name: "index_audit_context_op", Keys: bson.D{ + {common.BKOperationTimeField, 1}, + {common.BKAuditSceneContextScene, 1}, + {common.BKAuditSceneContextOpUser, 1}, + {common.BKAuditAppCodeField, 1}, + }, Background: true, Unique: false, + PartialFilterExpression: map[string]interface{}{ + common.BKOperationTimeField: bson.D{{common.BKDBExists, true}}, + common.BKAuditSceneContextSceneTraceId: bson.D{{common.BKDBExists, true}}, + }}, + } + + for _, idx := range createIdxArr { + exist := false + for _, existIdx := range idxArr { + if existIdx.Name == idx.Name { + exist = true + break + } + } + if exist { + if err := db.Table(common.BKTableNameAuditLog).DropIndex(ctx, idx.Name); err != nil { + blog.Errorf("add audit log index error. err:%s", err.Error()) + return err + } + } + if err := db.Table(common.BKTableNameAuditLog).CreateIndex(ctx, idx); err != nil && !db.IsDuplicatedError(err) { + blog.ErrorJSON("create index to BKTableNameAuditLog error, err:%s, current index:%s, "+ + "all create index:%s", err.Error(), idx, createIdxArr) + return err + } + } + + return nil +} diff --git a/src/scene_server/admin_server/upgrader/y3.14.202601121450/pkg.go b/src/scene_server/admin_server/upgrader/y3.14.202601121450/pkg.go new file mode 100644 index 0000000000..3259406874 --- /dev/null +++ b/src/scene_server/admin_server/upgrader/y3.14.202601121450/pkg.go @@ -0,0 +1,42 @@ +/* + * Tencent is pleased to support the open source community by making + * 蓝鲸智云 - 配置平台 (BlueKing - Configuration System) available. + * Copyright (C) 2017 Tencent. All rights reserved. + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://opensource.org/licenses/MIT + * 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. + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package y3_14_202601121450 + +import ( + "context" + + "configcenter/src/common/blog" + "configcenter/src/scene_server/admin_server/upgrader" + "configcenter/src/storage/dal" +) + +func init() { + upgrader.RegistUpgrader("y3.14.202601121450", upgrade) +} + +func upgrade(ctx context.Context, db dal.RDB, conf *upgrader.Config) (err error) { + + blog.Infof("start execute y3.14.202601121450") + err = addAuditLogSceneIndex(ctx, db, conf) + if err != nil { + blog.Errorf("upgrade y3.14.202601121450 add audit log scene index failed, error: %v", err) + return err + } + blog.Infof("execute y3.14.202601121450, add audit log scene index success!") + + return nil +} diff --git a/src/scene_server/topo_server/service/auditlog.go b/src/scene_server/topo_server/service/auditlog.go index 8226f44ec7..849df48a3b 100644 --- a/src/scene_server/topo_server/service/auditlog.go +++ b/src/scene_server/topo_server/service/auditlog.go @@ -60,9 +60,12 @@ func (s *Service) SearchAuditList(ctx *rest.Contexts) { // the front-end table display fields fields := []string{common.BKFieldID, common.BKUser, common.BKResourceTypeField, common.BKActionField, common.BKOperationTimeField, common.BKAppIDField, common.BKResourceIDField, common.BKResourceNameField, - common.BKExtendResourceNameField} + common.BKExtendResourceNameField, + common.BKAuditAppCodeField, + common.BKAuditSceneContextScene, common.BKAuditSceneContextOpUser, common.BKAuditSceneContextSceneTraceId, + common.BKAuditSceneContextSceneDesc, + } - cond := mapstr.MapStr{} condition := query.Condition if err := condition.Validate(); err != nil { blog.Errorf("condition, user and resource_name cannot exist at the same time") @@ -70,6 +73,8 @@ func (s *Service) SearchAuditList(ctx *rest.Contexts) { return } + cond := mapstr.MapStr{} + // parse front-end condition to db search cond for _, item := range condition.Condition { if item.Operator != querybuilder.OperatorIn && item.Operator != querybuilder.OperatorNotIn { @@ -175,6 +180,19 @@ func (s *Service) parseAuditCond(kit *rest.Kit, condition metadata.AuditQueryCon cond[common.BKResourceIDField] = condition.ResourceID } + if len(condition.Code) > 0 { + cond[common.BKAuditAppCodeField] = condition.Code + } + if len(condition.OpScene) > 0 { + cond[common.BKAuditSceneContextScene] = condition.OpScene + } + if len(condition.OpUser) > 0 { + cond[common.BKAuditSceneContextOpUser] = condition.OpUser + } + if len(condition.OpSceneTraceId) > 0 { + cond[common.BKAuditSceneContextSceneTraceId] = condition.OpSceneTraceId + } + if condition.ObjID != "" { switch condition.ResourceType { case metadata.ModelInstanceRes: @@ -311,7 +329,11 @@ func (s *Service) SearchInstAudit(ctx *rest.Contexts) { fields := make([]string, 0) if !query.WithDetail { fields = []string{common.BKFieldID, common.BKUser, common.BKResourceTypeField, common.BKActionField, - common.BKOperationTimeField, common.BKAppIDField, common.BKResourceIDField, common.BKResourceNameField} + common.BKOperationTimeField, common.BKAppIDField, common.BKResourceIDField, common.BKResourceNameField, + common.BKAuditAppCodeField, + common.BKAuditSceneContextScene, common.BKAuditSceneContextOpUser, common.BKAuditSceneContextSceneTraceId, + common.BKAuditSceneContextSceneDesc, + } } auditQuery := metadata.QueryCondition{Condition: cond, Fields: fields, Page: query.Page} @@ -345,6 +367,18 @@ func buildInstAuditCondition(ctx *rest.Contexts, query metadata.InstAuditConditi if query.ResourceType != "" { cond[common.BKResourceTypeField] = query.ResourceType } + if len(query.Code) > 0 { + cond[common.BKAuditAppCodeField] = query.Code + } + if len(query.OpScene) > 0 { + cond[common.BKAuditSceneContextScene] = query.OpScene + } + if len(query.OpUser) > 0 { + cond[common.BKAuditSceneContextOpUser] = query.OpUser + } + if len(query.OpSceneTraceId) > 0 { + cond[common.BKAuditSceneContextSceneTraceId] = query.OpSceneTraceId + } if len(query.Action) > 0 { cond[common.BKActionField] = map[string]interface{}{common.BKDBIN: query.Action} diff --git a/src/source_controller/coreservice/core/auditlog/audit.go b/src/source_controller/coreservice/core/auditlog/audit.go index 7d3f842176..f455bd198f 100644 --- a/src/source_controller/coreservice/core/auditlog/audit.go +++ b/src/source_controller/coreservice/core/auditlog/audit.go @@ -17,6 +17,8 @@ package auditlog import ( + "encoding/json" + "fmt" "strings" "time" @@ -46,6 +48,13 @@ func New() core.AuditOperation { func (m *auditManager) CreateAuditLog(kit *rest.Kit, logs ...metadata.AuditLog) error { logRows := make([]metadata.AuditLog, 0) + var sceneHeader metadata.AuditSceneHeader + if header := httpheader.GetAuditSceneHeader(kit.Header); len(header) > 0 { + err := json.NewDecoder(strings.NewReader(header)).Decode(&sceneHeader) + if err != nil { + return fmt.Errorf("decode scene header failed,header:%s, err: %s", header, err.Error()) + } + } ids, err := mongodb.Client().NextSequences(kit.Ctx, common.BKTableNameAuditLog, len(logs)) if err != nil { blog.Errorf("get next audit log id failed, err: %s", err.Error()) @@ -53,6 +62,7 @@ func (m *auditManager) CreateAuditLog(kit *rest.Kit, logs ...metadata.AuditLog) } for index, log := range logs { + log.AuditContext = sceneHeader if log.OperationDetail == nil { continue }