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

@@ -38,19 +38,23 @@ func NewEventsOperator(client auditing.Client) Interface {
func (eo *eventsOperator) Events(queryParam *v1alpha1.Query,
MutateFilterFunc func(*auditing.Filter)) (*v1alpha1.APIResponse, error) {
filter := &auditing.Filter{
ObjectRefNames: stringutils.Split(queryParam.ObjectRefNameFilter, ","),
ObjectRefNameFuzzy: stringutils.Split(queryParam.ObjectRefNameSearch, ","),
Levels: stringutils.Split(queryParam.LevelFilter, ","),
Verbs: stringutils.Split(queryParam.VerbFilter, ","),
Users: stringutils.Split(queryParam.UserFilter, ","),
UserFuzzy: stringutils.Split(queryParam.UserSearch, ","),
GroupFuzzy: stringutils.Split(queryParam.GroupSearch, ","),
SourceIpFuzzy: stringutils.Split(queryParam.SourceIpSearch, ","),
ObjectRefResources: stringutils.Split(queryParam.ObjectRefResourceFilter, ","),
ObjectRefSubresources: stringutils.Split(queryParam.ObjectRefSubresourceFilter, ","),
ResponseStatus: stringutils.Split(queryParam.ResponseStatusFilter, ","),
StartTime: queryParam.StartTime,
EndTime: queryParam.EndTime,
ObjectRefNamespaces: stringutils.Split(queryParam.ObjectRefNamespaceFilter, ","),
ObjectRefNamespaceFuzzy: stringutils.Split(queryParam.ObjectRefNamespaceSearch, ","),
Workspaces: stringutils.Split(queryParam.WorkspaceFilter, ","),
WorkspaceFuzzy: stringutils.Split(queryParam.WorkspaceSearch, ","),
ObjectRefNames: stringutils.Split(queryParam.ObjectRefNameFilter, ","),
ObjectRefNameFuzzy: stringutils.Split(queryParam.ObjectRefNameSearch, ","),
Levels: stringutils.Split(queryParam.LevelFilter, ","),
Verbs: stringutils.Split(queryParam.VerbFilter, ","),
Users: stringutils.Split(queryParam.UserFilter, ","),
UserFuzzy: stringutils.Split(queryParam.UserSearch, ","),
GroupFuzzy: stringutils.Split(queryParam.GroupSearch, ","),
SourceIpFuzzy: stringutils.Split(queryParam.SourceIpSearch, ","),
ObjectRefResources: stringutils.Split(queryParam.ObjectRefResourceFilter, ","),
ObjectRefSubresources: stringutils.Split(queryParam.ObjectRefSubresourceFilter, ","),
ResponseStatus: stringutils.Split(queryParam.ResponseStatusFilter, ","),
StartTime: queryParam.StartTime,
EndTime: queryParam.EndTime,
}
if MutateFilterFunc != nil {
MutateFilterFunc(filter)
@@ -70,19 +74,19 @@ func (eo *eventsOperator) Events(queryParam *v1alpha1.Query,
var err error
switch queryParam.Operation {
case "histogram":
if len(filter.ObjectRefNamespaceMap) == 0 {
if len(filter.ObjectRefNamespaceMap) == 0 && len(filter.WorkspaceMap) == 0 {
ar.Histogram = &auditing.Histogram{}
} else {
ar.Histogram, err = eo.client.CountOverTime(filter, queryParam.Interval)
}
case "statistics":
if len(filter.ObjectRefNamespaceMap) == 0 {
if len(filter.ObjectRefNamespaceMap) == 0 && len(filter.WorkspaceMap) == 0 {
ar.Statistics = &auditing.Statistics{}
} else {
ar.Statistics, err = eo.client.StatisticsOnResources(filter)
}
default:
if len(filter.ObjectRefNamespaceMap) == 0 {
if len(filter.ObjectRefNamespaceMap) == 0 && len(filter.WorkspaceMap) == 0 {
ar.Events = &auditing.Events{}
} else {
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
}
// 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) {
iNamespaces, err := t.listIntersectedNamespaces(
stringutils.Split(queryParam.WorkspaceFilter, ","),
@@ -870,7 +904,16 @@ func (t *tenantOperator) Auditing(user user.Info, queryParam *auditingv1alpha1.Q
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)
workspaceCreateTimeMap := make(map[string]time.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 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
}
}
// 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,
// 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 &&
@@ -914,11 +981,13 @@ func (t *tenantOperator) Auditing(user user.Info, queryParam *auditingv1alpha1.Q
}
if decision == authorizer.DecisionAllow {
namespaceCreateTimeMap[""] = time.Time{}
workspaceCreateTimeMap[""] = time.Time{}
}
}
return t.auditing.Events(queryParam, func(filter *auditingclient.Filter) {
filter.ObjectRefNamespaceMap = namespaceCreateTimeMap
filter.WorkspaceMap = workspaceCreateTimeMap
})
}