From 7393ef91fa09d57297c37691dea969221b569982 Mon Sep 17 00:00:00 2001 From: wanjunlei Date: Thu, 18 Jun 2020 22:49:00 +0800 Subject: [PATCH] processing audit information of non-standard request Signed-off-by: wanjunlei --- pkg/apiserver/auditing/backend.go | 30 ++++++++++++++-- pkg/apiserver/auditing/types.go | 37 +++++++++++++------ pkg/apiserver/auditing/v1alpha1/event.go | 9 ++++- pkg/apiserver/filters/auditing.go | 6 ++++ pkg/kapis/devops/v1alpha2/devops.go | 45 ++++++++++++++++++++++++ pkg/kapis/iam/v1alpha2/handler.go | 25 +++++++++++++ 6 files changed, 138 insertions(+), 14 deletions(-) diff --git a/pkg/apiserver/auditing/backend.go b/pkg/apiserver/auditing/backend.go index fd6a5cdb5..f79a97c69 100644 --- a/pkg/apiserver/auditing/backend.go +++ b/pkg/apiserver/auditing/backend.go @@ -86,12 +86,14 @@ func (b *Backend) worker() { <-b.semCh }() - bs, err := json.Marshal(event) + bs, err := b.eventToBytes(event) if err != nil { - klog.Errorf("json marshal error, %s", err) + klog.V(6).Infof("json marshal error, %s", err) return } + klog.V(8).Infof("%s", string(bs)) + response, err := b.client.Post(b.url, "application/json", bytes.NewBuffer(bs)) if err != nil { klog.Errorf("send audit event[%s] error, %s", event.Items[0].AuditID, err) @@ -107,3 +109,27 @@ func (b *Backend) worker() { go send(event) } } + +func (b *Backend) eventToBytes(event *v1alpha1.EventList) ([]byte, error) { + + if bs, err := json.Marshal(event); err == nil { + return bs, nil + } + + // Normally, the serialization failure is caused by the failure of RequestObject or ResponseObject serialization. + // To ensure the integrity of the auditing event to the greatest extent, + // it is necessary to delete RequestObject or ResponseObject and and then try to serialize again. + if event.Items[0].RequestObject != nil { + if _, err := json.Marshal(event.Items[0].RequestObject); err != nil { + event.Items[0].RequestObject = nil + } + } + + if event.Items[0].ResponseObject != nil { + if _, err := json.Marshal(event.Items[0].ResponseObject); err != nil { + event.Items[0].ResponseObject = nil + } + } + + return json.Marshal(event) +} diff --git a/pkg/apiserver/auditing/types.go b/pkg/apiserver/auditing/types.go index 353072df0..f73939b7a 100644 --- a/pkg/apiserver/auditing/types.go +++ b/pkg/apiserver/auditing/types.go @@ -122,6 +122,19 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo }, } + // Handle the devops request which request url matched /devops/{devops}/kind. + if len(info.Parts) >= 3 && info.Parts[0] == "devops" { + e.ObjectRef.Subresource = "" + e.Devops = info.Parts[1] + // set resource as kind + e.ObjectRef.Resource = info.Parts[2] + + // If the request url matched /devops/{devops}/kind/{kind}, set resource name as {kind} + if len(info.Parts) >= 4 { + e.ObjectRef.Name = info.Parts[3] + } + } + ips := make([]string, 1) ips[0] = iputil.RemoteIp(req) e.SourceIPs = ips @@ -137,7 +150,7 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo } } - if e.Level.GreaterOrEqual(audit.LevelRequest) && req.ContentLength > 0 { + if (e.Level.GreaterOrEqual(audit.LevelRequest) || e.Verb == "create") && req.ContentLength > 0 { body, err := ioutil.ReadAll(req.Body) if err != nil { klog.Error(err) @@ -145,7 +158,18 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo } _ = req.Body.Close() req.Body = ioutil.NopCloser(bytes.NewBuffer(body)) - e.RequestObject = &runtime.Unknown{Raw: body} + + if e.Level.GreaterOrEqual(audit.LevelRequest) { + e.RequestObject = &runtime.Unknown{Raw: body} + } + + // For resource creating request, get resource name from the request body. + if info.Verb == "create" { + obj := &auditv1alpha1.Object{} + if err := json.Unmarshal(body, obj); err == nil { + e.ObjectRef.Name = obj.Name + } + } } return e @@ -153,11 +177,6 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo func (a *auditing) LogResponseObject(e *auditv1alpha1.Event, resp *ResponseCapture, info *request.RequestInfo) { - // Auditing should igonre k8s request when k8s auditing is enabled. - if info.IsKubernetesRequest && a.K8sAuditingEnabled() { - return - } - e.StageTimestamp = v1.NewMicroTime(time.Now()) e.ResponseStatus = &v1.Status{Code: int32(resp.StatusCode())} if e.Level.GreaterOrEqual(audit.LevelRequestResponse) { @@ -168,10 +187,6 @@ func (a *auditing) LogResponseObject(e *auditv1alpha1.Event, resp *ResponseCaptu } func (a *auditing) cacheEvent(e auditv1alpha1.Event) { - if klog.V(8) { - bs, _ := json.Marshal(e) - klog.Infof("%s", string(bs)) - } eventList := &auditv1alpha1.EventList{} eventList.Items = append(eventList.Items, e) diff --git a/pkg/apiserver/auditing/v1alpha1/event.go b/pkg/apiserver/auditing/v1alpha1/event.go index ae1294ae6..a48d1ecc2 100644 --- a/pkg/apiserver/auditing/v1alpha1/event.go +++ b/pkg/apiserver/auditing/v1alpha1/event.go @@ -1,6 +1,9 @@ package v1alpha1 -import "k8s.io/apiserver/pkg/apis/audit" +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apiserver/pkg/apis/audit" +) type Event struct { // Devops project @@ -18,3 +21,7 @@ type Event struct { type EventList struct { Items []Event } + +type Object struct { + v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` +} diff --git a/pkg/apiserver/filters/auditing.go b/pkg/apiserver/filters/auditing.go index 17a734275..e17d84de0 100644 --- a/pkg/apiserver/filters/auditing.go +++ b/pkg/apiserver/filters/auditing.go @@ -26,6 +26,12 @@ func WithAuditing(handler http.Handler, a auditing.Auditing) http.Handler { return } + // Auditing should igonre k8s request when k8s auditing is enabled. + if info.IsKubernetesRequest && a.K8sAuditingEnabled() { + handler.ServeHTTP(w, req) + return + } + e := a.LogRequestObject(req, info) req = req.WithContext(request.WithAuditEvent(req.Context(), e)) resp := auditing.NewResponseCapture(w) diff --git a/pkg/kapis/devops/v1alpha2/devops.go b/pkg/kapis/devops/v1alpha2/devops.go index 382cf972c..d22478b8b 100644 --- a/pkg/kapis/devops/v1alpha2/devops.go +++ b/pkg/kapis/devops/v1alpha2/devops.go @@ -20,6 +20,7 @@ import ( "github.com/emicklei/go-restful" log "k8s.io/klog" "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/request" "kubesphere.io/kubesphere/pkg/models/devops" "net/http" "strings" @@ -92,6 +93,12 @@ func (h *ProjectPipelineHandler) StopPipeline(req *restful.Request, resp *restfu return } + if event := request.AuditEventFrom(req.Request.Context()); event != nil { + event.ObjectRef.Resource = "pipelines.runs" + event.ObjectRef.Name = pipelineName + "." + runId + event.Verb = "stop" + } + resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON) resp.WriteAsJson(res) } @@ -107,6 +114,12 @@ func (h *ProjectPipelineHandler) ReplayPipeline(req *restful.Request, resp *rest return } + if event := request.AuditEventFrom(req.Request.Context()); event != nil { + event.ObjectRef.Resource = "pipelines.runs" + event.ObjectRef.Name = pipelineName + "." + runId + event.Verb = "replay" + } + resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON) resp.WriteAsJson(res) } @@ -121,6 +134,11 @@ func (h *ProjectPipelineHandler) RunPipeline(req *restful.Request, resp *restful return } + if event := request.AuditEventFrom(req.Request.Context()); event != nil { + event.ObjectRef.Resource = "pipelines.runs" + event.ObjectRef.Name = pipelineName + "." + res.ID + } + resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON) resp.WriteAsJson(res) } @@ -215,6 +233,11 @@ func (h *ProjectPipelineHandler) SubmitInputStep(req *restful.Request, resp *res return } + if event := request.AuditEventFrom(req.Request.Context()); event != nil { + event.ObjectRef.Resource = "pipelines.runs.nodes.step" + event.ObjectRef.Name = pipelineName + "." + runId + "." + nodeId + "." + stepId + } + resp.Write(res) } @@ -274,6 +297,12 @@ func (h *ProjectPipelineHandler) StopBranchPipeline(req *restful.Request, resp * return } + if event := request.AuditEventFrom(req.Request.Context()); event != nil { + event.ObjectRef.Resource = "pipelines.branches.runs" + event.ObjectRef.Name = pipelineName + "." + branchName + "." + runId + event.Verb = "stop" + } + resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON) resp.WriteAsJson(res) } @@ -290,6 +319,12 @@ func (h *ProjectPipelineHandler) ReplayBranchPipeline(req *restful.Request, resp return } + if event := request.AuditEventFrom(req.Request.Context()); event != nil { + event.ObjectRef.Resource = "pipelines.branches.runs" + event.ObjectRef.Name = pipelineName + "." + branchName + "." + runId + event.Verb = "replay" + } + resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON) resp.WriteAsJson(res) } @@ -305,6 +340,11 @@ func (h *ProjectPipelineHandler) RunBranchPipeline(req *restful.Request, resp *r return } + if event := request.AuditEventFrom(req.Request.Context()); event != nil { + event.ObjectRef.Resource = "pipelines.branches.runs" + event.ObjectRef.Name = pipelineName + "." + branchName + "." + res.ID + } + resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON) resp.WriteAsJson(res) } @@ -407,6 +447,11 @@ func (h *ProjectPipelineHandler) SubmitBranchInputStep(req *restful.Request, res return } + if event := request.AuditEventFrom(req.Request.Context()); event != nil { + event.ObjectRef.Resource = "pipelines.branches.runs.nodes.steps" + event.ObjectRef.Name = pipelineName + "." + branchName + "." + runId + "." + nodeId + "." + stepId + } + resp.Write(res) } diff --git a/pkg/kapis/iam/v1alpha2/handler.go b/pkg/kapis/iam/v1alpha2/handler.go index c5353dcb2..1934fe3f9 100644 --- a/pkg/kapis/iam/v1alpha2/handler.go +++ b/pkg/kapis/iam/v1alpha2/handler.go @@ -10,6 +10,7 @@ import ( iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options" "kubesphere.io/kubesphere/pkg/apiserver/query" + requestinfo "kubesphere.io/kubesphere/pkg/apiserver/request" "kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/im" servererr "kubesphere.io/kubesphere/pkg/server/errors" @@ -821,6 +822,14 @@ func (h *iamHandler) CreateWorkspaceMembers(request *restful.Request, response * } } + if event := requestinfo.AuditEventFrom(request.Request.Context()); event != nil { + name := "" + for _, member := range members { + name += member.Username + ", " + } + name = strings.TrimSuffix(name, ", ") + event.ObjectRef.Name = name + } response.WriteEntity(members) } @@ -899,6 +908,14 @@ func (h *iamHandler) CreateNamespaceMembers(request *restful.Request, response * } } + if event := requestinfo.AuditEventFrom(request.Request.Context()); event != nil { + name := "" + for _, member := range members { + name += member.Username + ", " + } + name = strings.TrimSuffix(name, ", ") + event.ObjectRef.Name = name + } response.WriteEntity(members) } @@ -980,6 +997,14 @@ func (h *iamHandler) CreateClusterMembers(request *restful.Request, response *re } } + if event := requestinfo.AuditEventFrom(request.Request.Context()); event != nil { + name := "" + for _, member := range members { + name += member.Username + ", " + } + name = strings.TrimSuffix(name, ", ") + event.ObjectRef.Name = name + } response.WriteEntity(members) }