Merge pull request #2672 from wanjunlei/auditing-log

make ws admin can be aware of anything happened in its workspace.
This commit is contained in:
KubeSphere CI Bot
2020-07-30 13:33:51 +08:00
committed by GitHub
7 changed files with 218 additions and 69 deletions

View File

@@ -260,8 +260,7 @@ func (s *APIServer) buildHandlerChain(stopCh <-chan struct{}) {
if s.Config.AuditingOptions.Enable { if s.Config.AuditingOptions.Enable {
handler = filters.WithAuditing(handler, handler = filters.WithAuditing(handler,
audit.NewAuditing(s.InformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Lister(), audit.NewAuditing(s.InformerFactory, s.Config.AuditingOptions.WebhookUrl, stopCh))
s.Config.AuditingOptions.WebhookUrl, stopCh))
} }
var authorizers authorizer.Authorizer var authorizers authorizer.Authorizer

View File

@@ -12,9 +12,14 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/apis/audit"
"k8s.io/klog" "k8s.io/klog"
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
auditv1alpha1 "kubesphere.io/kubesphere/pkg/apiserver/auditing/v1alpha1" auditv1alpha1 "kubesphere.io/kubesphere/pkg/apiserver/auditing/v1alpha1"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/apiserver/request" "kubesphere.io/kubesphere/pkg/apiserver/request"
"kubesphere.io/kubesphere/pkg/client/listers/auditing/v1alpha1" "kubesphere.io/kubesphere/pkg/client/listers/auditing/v1alpha1"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/devops"
"kubesphere.io/kubesphere/pkg/utils/iputil" "kubesphere.io/kubesphere/pkg/utils/iputil"
"net" "net"
"net/http" "net/http"
@@ -37,16 +42,18 @@ type Auditing interface {
} }
type auditing struct { type auditing struct {
lister v1alpha1.WebhookLister webhookLister v1alpha1.WebhookLister
cache chan *auditv1alpha1.EventList devopsGetter v1alpha3.Interface
backend *Backend cache chan *auditv1alpha1.EventList
backend *Backend
} }
func NewAuditing(lister v1alpha1.WebhookLister, url string, stopCh <-chan struct{}) Auditing { func NewAuditing(informers informers.InformerFactory, url string, stopCh <-chan struct{}) Auditing {
a := &auditing{ a := &auditing{
lister: lister, webhookLister: informers.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Lister(),
cache: make(chan *auditv1alpha1.EventList, DefaultCacheCapacity), devopsGetter: devops.New(informers.KubeSphereSharedInformerFactory()),
cache: make(chan *auditv1alpha1.EventList, DefaultCacheCapacity),
} }
a.backend = NewBackend(url, ChannelCapacity, a.cache, SendTimeout, stopCh) a.backend = NewBackend(url, ChannelCapacity, a.cache, SendTimeout, stopCh)
@@ -54,7 +61,7 @@ func NewAuditing(lister v1alpha1.WebhookLister, url string, stopCh <-chan struct
} }
func (a *auditing) getAuditLevel() audit.Level { func (a *auditing) getAuditLevel() audit.Level {
wh, err := a.lister.Get(DefaultWebhook) wh, err := a.webhookLister.Get(DefaultWebhook)
if err != nil { if err != nil {
klog.V(8).Info(err) klog.V(8).Info(err)
return audit.LevelNone return audit.LevelNone
@@ -73,7 +80,7 @@ func (a *auditing) Enabled() bool {
} }
func (a *auditing) K8sAuditingEnabled() bool { func (a *auditing) K8sAuditingEnabled() bool {
wh, err := a.lister.Get(DefaultWebhook) wh, err := a.webhookLister.Get(DefaultWebhook)
if err != nil { if err != nil {
klog.V(8).Info(err) klog.V(8).Info(err)
return false return false
@@ -105,6 +112,7 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo
} }
e := &auditv1alpha1.Event{ e := &auditv1alpha1.Event{
Devops: info.DevOps,
Workspace: info.Workspace, Workspace: info.Workspace,
Cluster: info.Cluster, Cluster: info.Cluster,
Event: audit.Event{ Event: audit.Event{
@@ -115,7 +123,7 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo
Stage: audit.StageResponseComplete, Stage: audit.StageResponseComplete,
ImpersonatedUser: nil, ImpersonatedUser: nil,
UserAgent: req.UserAgent(), UserAgent: req.UserAgent(),
RequestReceivedTimestamp: v1.NewMicroTime(time.Now()), RequestReceivedTimestamp: v1.NowMicro(),
Annotations: nil, Annotations: nil,
ObjectRef: &audit.ObjectReference{ ObjectRef: &audit.ObjectReference{
Resource: info.Resource, Resource: info.Resource,
@@ -130,16 +138,22 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo
}, },
} }
// Handle the devops request which request url matched /devops/{devops}/kind. // Get the workspace which the devops project be in.
if len(info.Parts) >= 3 && info.Parts[0] == "devops" { if len(e.Devops) > 0 && len(e.Workspace) == 0 {
e.ObjectRef.Subresource = "" res, err := a.devopsGetter.List("", query.New())
e.Devops = info.Parts[1] if err != nil {
// set resource as kind klog.Error(err)
e.ObjectRef.Resource = info.Parts[2] }
// If the request url matched /devops/{devops}/kind/{kind}, set resource name as {kind} for _, obj := range res.Items {
if len(info.Parts) >= 4 { d := obj.(*devopsv1alpha3.DevOpsProject)
e.ObjectRef.Name = info.Parts[3]
if d.Name == e.Devops {
e.Workspace = d.Labels["kubesphere.io/workspace"]
} else if d.Status.AdminNamespace == e.Devops {
e.Workspace = d.Labels["kubesphere.io/workspace"]
e.Devops = d.Name
}
} }
} }
@@ -185,7 +199,7 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo
func (a *auditing) LogResponseObject(e *auditv1alpha1.Event, resp *ResponseCapture) { func (a *auditing) LogResponseObject(e *auditv1alpha1.Event, resp *ResponseCapture) {
e.StageTimestamp = v1.NewMicroTime(time.Now()) e.StageTimestamp = v1.NowMicro()
e.ResponseStatus = &v1.Status{Code: int32(resp.StatusCode())} e.ResponseStatus = &v1.Status{Code: int32(resp.StatusCode())}
if e.Level.GreaterOrEqual(audit.LevelRequestResponse) { if e.Level.GreaterOrEqual(audit.LevelRequestResponse) {
e.ResponseObject = &runtime.Unknown{Raw: resp.Bytes()} e.ResponseObject = &runtime.Unknown{Raw: resp.Bytes()}

View File

@@ -9,11 +9,12 @@ import (
"k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/apis/audit"
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
k8srequest "k8s.io/apiserver/pkg/endpoints/request" k8srequest "k8s.io/apiserver/pkg/endpoints/request"
fakek8s "k8s.io/client-go/kubernetes/fake"
auditingv1alpha1 "kubesphere.io/kubesphere/pkg/apis/auditing/v1alpha1" auditingv1alpha1 "kubesphere.io/kubesphere/pkg/apis/auditing/v1alpha1"
v1alpha12 "kubesphere.io/kubesphere/pkg/apiserver/auditing/v1alpha1" v1alpha12 "kubesphere.io/kubesphere/pkg/apiserver/auditing/v1alpha1"
"kubesphere.io/kubesphere/pkg/apiserver/request" "kubesphere.io/kubesphere/pkg/apiserver/request"
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/utils/iputil" "kubesphere.io/kubesphere/pkg/utils/iputil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@@ -37,13 +38,15 @@ func TestGetAuditLevel(t *testing.T) {
}, },
} }
informer := ksinformers.NewSharedInformerFactory(fake.NewSimpleClientset(), noResyncPeriodFunc()) ksClient := fake.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset()
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, nil, nil, nil, nil)
a := auditing{ a := auditing{
lister: informer.Auditing().V1alpha1().Webhooks().Lister(), webhookLister: fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Lister(),
} }
err := informer.Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook) err := fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -64,13 +67,15 @@ func TestAuditing_Enabled(t *testing.T) {
}, },
} }
informer := ksinformers.NewSharedInformerFactory(fake.NewSimpleClientset(), noResyncPeriodFunc()) ksClient := fake.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset()
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, nil, nil, nil, nil)
a := auditing{ a := auditing{
lister: informer.Auditing().V1alpha1().Webhooks().Lister(), webhookLister: fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Lister(),
} }
err := informer.Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook) err := fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -92,13 +97,15 @@ func TestAuditing_K8sAuditingEnabled(t *testing.T) {
}, },
} }
informer := ksinformers.NewSharedInformerFactory(fake.NewSimpleClientset(), noResyncPeriodFunc()) ksClient := fake.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset()
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, nil, nil, nil, nil)
a := auditing{ a := auditing{
lister: informer.Auditing().V1alpha1().Webhooks().Lister(), webhookLister: fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Lister(),
} }
err := informer.Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook) err := fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -120,13 +127,15 @@ func TestAuditing_LogRequestObject(t *testing.T) {
}, },
} }
informer := ksinformers.NewSharedInformerFactory(fake.NewSimpleClientset(), noResyncPeriodFunc()) ksClient := fake.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset()
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, nil, nil, nil, nil)
a := auditing{ a := auditing{
lister: informer.Auditing().V1alpha1().Webhooks().Lister(), webhookLister: fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Lister(),
} }
err := informer.Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook) err := fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -208,13 +217,15 @@ func TestAuditing_LogResponseObject(t *testing.T) {
}, },
} }
informer := ksinformers.NewSharedInformerFactory(fake.NewSimpleClientset(), noResyncPeriodFunc()) ksClient := fake.NewSimpleClientset()
k8sClient := fakek8s.NewSimpleClientset()
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, nil, nil, nil, nil)
a := auditing{ a := auditing{
lister: informer.Auditing().V1alpha1().Webhooks().Lister(), webhookLister: fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Lister(),
} }
err := informer.Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook) err := fakeInformerFactory.KubeSphereSharedInformerFactory().Auditing().V1alpha1().Webhooks().Informer().GetIndexer().Add(webhook)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@@ -38,19 +38,23 @@ func NewEventsOperator(client auditing.Client) Interface {
func (eo *eventsOperator) Events(queryParam *v1alpha1.Query, func (eo *eventsOperator) Events(queryParam *v1alpha1.Query,
MutateFilterFunc func(*auditing.Filter)) (*v1alpha1.APIResponse, error) { MutateFilterFunc func(*auditing.Filter)) (*v1alpha1.APIResponse, error) {
filter := &auditing.Filter{ filter := &auditing.Filter{
ObjectRefNames: stringutils.Split(queryParam.ObjectRefNameFilter, ","), ObjectRefNamespaces: stringutils.Split(queryParam.ObjectRefNamespaceFilter, ","),
ObjectRefNameFuzzy: stringutils.Split(queryParam.ObjectRefNameSearch, ","), ObjectRefNamespaceFuzzy: stringutils.Split(queryParam.ObjectRefNamespaceSearch, ","),
Levels: stringutils.Split(queryParam.LevelFilter, ","), Workspaces: stringutils.Split(queryParam.WorkspaceFilter, ","),
Verbs: stringutils.Split(queryParam.VerbFilter, ","), WorkspaceFuzzy: stringutils.Split(queryParam.WorkspaceSearch, ","),
Users: stringutils.Split(queryParam.UserFilter, ","), ObjectRefNames: stringutils.Split(queryParam.ObjectRefNameFilter, ","),
UserFuzzy: stringutils.Split(queryParam.UserSearch, ","), ObjectRefNameFuzzy: stringutils.Split(queryParam.ObjectRefNameSearch, ","),
GroupFuzzy: stringutils.Split(queryParam.GroupSearch, ","), Levels: stringutils.Split(queryParam.LevelFilter, ","),
SourceIpFuzzy: stringutils.Split(queryParam.SourceIpSearch, ","), Verbs: stringutils.Split(queryParam.VerbFilter, ","),
ObjectRefResources: stringutils.Split(queryParam.ObjectRefResourceFilter, ","), Users: stringutils.Split(queryParam.UserFilter, ","),
ObjectRefSubresources: stringutils.Split(queryParam.ObjectRefSubresourceFilter, ","), UserFuzzy: stringutils.Split(queryParam.UserSearch, ","),
ResponseStatus: stringutils.Split(queryParam.ResponseStatusFilter, ","), GroupFuzzy: stringutils.Split(queryParam.GroupSearch, ","),
StartTime: queryParam.StartTime, SourceIpFuzzy: stringutils.Split(queryParam.SourceIpSearch, ","),
EndTime: queryParam.EndTime, ObjectRefResources: stringutils.Split(queryParam.ObjectRefResourceFilter, ","),
ObjectRefSubresources: stringutils.Split(queryParam.ObjectRefSubresourceFilter, ","),
ResponseStatus: stringutils.Split(queryParam.ResponseStatusFilter, ","),
StartTime: queryParam.StartTime,
EndTime: queryParam.EndTime,
} }
if MutateFilterFunc != nil { if MutateFilterFunc != nil {
MutateFilterFunc(filter) MutateFilterFunc(filter)
@@ -70,19 +74,19 @@ func (eo *eventsOperator) Events(queryParam *v1alpha1.Query,
var err error var err error
switch queryParam.Operation { switch queryParam.Operation {
case "histogram": case "histogram":
if len(filter.ObjectRefNamespaceMap) == 0 { if len(filter.ObjectRefNamespaceMap) == 0 && len(filter.WorkspaceMap) == 0 {
ar.Histogram = &auditing.Histogram{} ar.Histogram = &auditing.Histogram{}
} else { } else {
ar.Histogram, err = eo.client.CountOverTime(filter, queryParam.Interval) ar.Histogram, err = eo.client.CountOverTime(filter, queryParam.Interval)
} }
case "statistics": case "statistics":
if len(filter.ObjectRefNamespaceMap) == 0 { if len(filter.ObjectRefNamespaceMap) == 0 && len(filter.WorkspaceMap) == 0 {
ar.Statistics = &auditing.Statistics{} ar.Statistics = &auditing.Statistics{}
} else { } else {
ar.Statistics, err = eo.client.StatisticsOnResources(filter) ar.Statistics, err = eo.client.StatisticsOnResources(filter)
} }
default: default:
if len(filter.ObjectRefNamespaceMap) == 0 { if len(filter.ObjectRefNamespaceMap) == 0 && len(filter.WorkspaceMap) == 0 {
ar.Events = &auditing.Events{} ar.Events = &auditing.Events{}
} else { } else {
ar.Events, err = eo.client.SearchAuditingEvent(filter, queryParam.From, queryParam.Size, queryParam.Sort) ar.Events, err = eo.client.SearchAuditingEvent(filter, queryParam.From, queryParam.Size, queryParam.Sort)

View File

@@ -609,6 +609,40 @@ func (t *tenantOperator) listIntersectedNamespaces(workspaces, workspaceSubstrs,
return iNamespaces, nil return iNamespaces, nil
} }
// listIntersectedWorkspaces returns a list of workspaces that MUST meet ALL the following filters:
// 1. If `workspaces` is not empty, the workspace SHOULD be one of the specified workpsaces.
// 2. Else if `workspaceSubstrs` is not empty, the workspace SHOULD be contains one of the specified substrings.
// 3. Else, return all workspace in the cluster.
func (t *tenantOperator) listIntersectedWorkspaces(workspaces, workspaceSubstrs []string) ([]*tenantv1alpha1.Workspace, error) {
var (
workspaceSet = stringSet(workspaces)
iWorkspaces []*tenantv1alpha1.Workspace
)
result, err := t.resourceGetter.List("workspaces", "", query.New())
if err != nil {
return nil, err
}
for _, obj := range result.Items {
ws, ok := obj.(*tenantv1alpha1.Workspace)
if !ok {
continue
}
if len(workspaceSet) > 0 {
if _, ok := workspaceSet[ws.Name]; !ok {
continue
}
}
if len(workspaceSubstrs) > 0 && !stringContains(ws.Name, workspaceSubstrs) {
continue
}
iWorkspaces = append(iWorkspaces, ws)
}
return iWorkspaces, nil
}
func (t *tenantOperator) Events(user user.Info, queryParam *eventsv1alpha1.Query) (*eventsv1alpha1.APIResponse, error) { func (t *tenantOperator) Events(user user.Info, queryParam *eventsv1alpha1.Query) (*eventsv1alpha1.APIResponse, error) {
iNamespaces, err := t.listIntersectedNamespaces( iNamespaces, err := t.listIntersectedNamespaces(
stringutils.Split(queryParam.WorkspaceFilter, ","), stringutils.Split(queryParam.WorkspaceFilter, ","),
@@ -870,7 +904,16 @@ func (t *tenantOperator) Auditing(user user.Info, queryParam *auditingv1alpha1.Q
return nil, err return nil, err
} }
iWorkspaces, err := t.listIntersectedWorkspaces(
stringutils.Split(queryParam.WorkspaceFilter, ","),
stringutils.Split(queryParam.WorkspaceSearch, ","))
if err != nil {
klog.Error(err)
return nil, err
}
namespaceCreateTimeMap := make(map[string]time.Time) namespaceCreateTimeMap := make(map[string]time.Time)
workspaceCreateTimeMap := make(map[string]time.Time)
// Now auditing and event have the same authorization mechanism, so we can determine whether the user // Now auditing and event have the same authorization mechanism, so we can determine whether the user
// has permission to view the auditing log in ns by judging whether the user has the permission to view the event in ns. // has permission to view the auditing log in ns by judging whether the user has the permission to view the event in ns.
@@ -894,6 +937,30 @@ func (t *tenantOperator) Auditing(user user.Info, queryParam *auditingv1alpha1.Q
namespaceCreateTimeMap[ns.Name] = ns.CreationTimestamp.Time namespaceCreateTimeMap[ns.Name] = ns.CreationTimestamp.Time
} }
} }
// Now auditing and event have the same authorization mechanism, so we can determine whether the user
// has permission to view the auditing log in ws by judging whether the user has the permission to view the event in ws.
for _, ws := range iWorkspaces {
listEvts := authorizer.AttributesRecord{
User: user,
Verb: "list",
APIGroup: "",
APIVersion: "v1",
Workspace: ws.Name,
Resource: "events",
ResourceRequest: true,
ResourceScope: request.WorkspaceScope,
}
decision, _, err := t.authorizer.Authorize(listEvts)
if err != nil {
klog.Error(err)
return nil, err
}
if decision == authorizer.DecisionAllow {
workspaceCreateTimeMap[ws.Name] = ws.CreationTimestamp.Time
}
}
// If there are no ns and ws query conditions, // If there are no ns and ws query conditions,
// those events with empty `objectRef.namespace` will also be listed when user can list all events // those events with empty `objectRef.namespace` will also be listed when user can list all events
if len(queryParam.WorkspaceFilter) == 0 && len(queryParam.ObjectRefNamespaceFilter) == 0 && if len(queryParam.WorkspaceFilter) == 0 && len(queryParam.ObjectRefNamespaceFilter) == 0 &&
@@ -914,11 +981,13 @@ func (t *tenantOperator) Auditing(user user.Info, queryParam *auditingv1alpha1.Q
} }
if decision == authorizer.DecisionAllow { if decision == authorizer.DecisionAllow {
namespaceCreateTimeMap[""] = time.Time{} namespaceCreateTimeMap[""] = time.Time{}
workspaceCreateTimeMap[""] = time.Time{}
} }
} }
return t.auditing.Events(queryParam, func(filter *auditingclient.Filter) { return t.auditing.Events(queryParam, func(filter *auditingclient.Filter) {
filter.ObjectRefNamespaceMap = namespaceCreateTimeMap filter.ObjectRefNamespaceMap = namespaceCreateTimeMap
filter.WorkspaceMap = workspaceCreateTimeMap
}) })
} }

View File

@@ -305,7 +305,7 @@ func parseToQueryPart(f *auditing.Filter) interface{} {
"bool": &b, "bool": &b,
} }
if len(f.ObjectRefNamespaceMap) > 0 { if len(f.ObjectRefNamespaceMap) > 0 || len(f.WorkspaceMap) > 0 {
bi := BoolBody{MinimumShouldMatch: &mini} bi := BoolBody{MinimumShouldMatch: &mini}
for k, v := range f.ObjectRefNamespaceMap { for k, v := range f.ObjectRefNamespaceMap {
bi.Should = append(bi.Should, map[string]interface{}{ bi.Should = append(bi.Should, map[string]interface{}{
@@ -322,6 +322,23 @@ func parseToQueryPart(f *auditing.Filter) interface{} {
}, },
}) })
} }
for k, v := range f.WorkspaceMap {
bi.Should = append(bi.Should, map[string]interface{}{
"bool": &BoolBody{
Filter: []map[string]interface{}{{
"match_phrase": map[string]string{"Workspace.keyword": k},
}, {
"range": map[string]interface{}{
"RequestReceivedTimestamp": map[string]interface{}{
"gte": v,
},
},
}},
},
})
}
if len(bi.Should) > 0 { if len(bi.Should) > 0 {
b.Filter = append(b.Filter, map[string]interface{}{"bool": &bi}) b.Filter = append(b.Filter, map[string]interface{}{"bool": &bi})
} }
@@ -343,6 +360,36 @@ func parseToQueryPart(f *auditing.Filter) interface{} {
return &bi return &bi
} }
if len(f.ObjectRefNamespaces) > 0 {
if bi := shouldBoolbody("match_phrase", "ObjectRef.Namespace.keyword",
f.ObjectRefNamespaces, nil); bi != nil {
b.Filter = append(b.Filter, map[string]interface{}{"bool": bi})
}
}
if len(f.ObjectRefNamespaceFuzzy) > 0 {
if bi := shouldBoolbody("wildcard", "ObjectRef.Namespace",
f.ObjectRefNamespaceFuzzy, func(s string) string {
return fmt.Sprintf("*" + s + "*")
}); bi != nil {
b.Filter = append(b.Filter, map[string]interface{}{"bool": bi})
}
}
if len(f.Workspaces) > 0 {
if bi := shouldBoolbody("match_phrase", "Workspace.keyword",
f.Workspaces, nil); bi != nil {
b.Filter = append(b.Filter, map[string]interface{}{"bool": bi})
}
}
if len(f.WorkspaceFuzzy) > 0 {
if bi := shouldBoolbody("wildcard", "Workspace",
f.WorkspaceFuzzy, func(s string) string {
return fmt.Sprintf("*" + s + "*")
}); bi != nil {
b.Filter = append(b.Filter, map[string]interface{}{"bool": bi})
}
}
if len(f.ObjectRefNames) > 0 { if len(f.ObjectRefNames) > 0 {
if bi := shouldBoolbody("match_phrase_prefix", "ObjectRef.Name.keyword", if bi := shouldBoolbody("match_phrase_prefix", "ObjectRef.Name.keyword",
f.ObjectRefNames, nil); bi != nil { f.ObjectRefNames, nil); bi != nil {

View File

@@ -27,21 +27,26 @@ type Client interface {
} }
type Filter struct { type Filter struct {
ObjectRefNamespaceMap map[string]time.Time ObjectRefNamespaceMap map[string]time.Time
ObjectRefNames []string WorkspaceMap map[string]time.Time
ObjectRefNameFuzzy []string ObjectRefNamespaces []string
Levels []string ObjectRefNamespaceFuzzy []string
Verbs []string Workspaces []string
Users []string WorkspaceFuzzy []string
UserFuzzy []string ObjectRefNames []string
GroupFuzzy []string ObjectRefNameFuzzy []string
SourceIpFuzzy []string Levels []string
ObjectRefResources []string Verbs []string
ObjectRefSubresources []string Users []string
ResponseCodes []int32 UserFuzzy []string
ResponseStatus []string GroupFuzzy []string
StartTime *time.Time SourceIpFuzzy []string
EndTime *time.Time ObjectRefResources []string
ObjectRefSubresources []string
ResponseCodes []int32
ResponseStatus []string
StartTime *time.Time
EndTime *time.Time
} }
type Event map[string]interface{} type Event map[string]interface{}