From 52452d06f6a2143d0db6e5ef71cb87a01ccb4b10 Mon Sep 17 00:00:00 2001 From: Luca Guerra Date: Mon, 9 Dec 2024 16:51:13 +0000 Subject: [PATCH] new(plugins/k8saudit): add subject name fields Signed-off-by: Luca Guerra --- plugins/k8saudit/README.md | 4 ++ plugins/k8saudit/pkg/k8saudit/extract.go | 66 ++++++++++++++++++++++++ plugins/k8saudit/pkg/k8saudit/fields.go | 24 +++++++++ 3 files changed, 94 insertions(+) diff --git a/plugins/k8saudit/README.md b/plugins/k8saudit/README.md index 77e43df9..4f4a3f72 100644 --- a/plugins/k8saudit/README.md +++ b/plugins/k8saudit/README.md @@ -46,6 +46,10 @@ The event source for Kubernetes Audit Events is `k8s_audit`. | `ka.target.subresource` | `string` | None | The target object subresource | | `ka.target.pod.name` | `string` | None | The target pod name | | `ka.req.binding.subjects` | `string (list)` | None | When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding | +| `ka.req.binding.subjects.user_names` | `string (list)` | None | When the request object refers to a cluster role binding, the subject user names being linked by the binding | +| `ka.req.binding.subjects.serviceaccount_names` | `string (list)` | None | When the request object refers to a cluster role binding, the subject service account names being linked by the binding | +| `ka.req.binding.subjects.serviceaccount_ns_names` | `string (list)` | None | When the request object refers to a cluster role binding, the subject serviceaccount namespaced names being linked by the binding, e.g. a list containing: mynamespace:myserviceaccount | +| `ka.req.binding.subjects.group_names` | `string (list)` | None | When the request object refers to a cluster role binding, the subject group names being linked by the binding | | `ka.req.binding.role` | `string` | None | When the request object refers to a cluster role binding, the role being linked by the binding | | `ka.req.binding.subject.has_name` | `string` | Key, Required | Deprecated, always returns "N/A". Only provided for backwards compatibility | | `ka.req.configmap.name` | `string` | None | If the request object refers to a configmap, the configmap name | diff --git a/plugins/k8saudit/pkg/k8saudit/extract.go b/plugins/k8saudit/pkg/k8saudit/extract.go index 945efa08..38a0554e 100644 --- a/plugins/k8saudit/pkg/k8saudit/extract.go +++ b/plugins/k8saudit/pkg/k8saudit/extract.go @@ -183,6 +183,30 @@ func (e *Plugin) ExtractFromJSON(req sdk.ExtractRequest, jsonValue *fastjson.Val } case "ka.req.binding.subjects": return e.extractFromKeys(req, jsonValue, "requestObject", "subjects") + case "ka.req.binding.subjects.user_names": + names, err := e.readSubjectNamesByKind(jsonValue, "User") + if err != nil { + return err + } + req.SetValue(names) + case "ka.req.binding.subjects.serviceaccount_names": + names, err := e.readSubjectNamesByKind(jsonValue, "ServiceAccount") + if err != nil { + return err + } + req.SetValue(names) + case "ka.req.binding.subjects.serviceaccount_ns_names": + names, err := e.readSubjectNamesByKind(jsonValue, "NamespacedServiceAccount") + if err != nil { + return err + } + req.SetValue(names) + case "ka.req.binding.subjects.group_names": + names, err := e.readSubjectNamesByKind(jsonValue, "Group") + if err != nil { + return err + } + req.SetValue(names) case "ka.req.binding.role": return e.extractFromKeys(req, jsonValue, "requestObject", "roleRef", "name") case "ka.req.binding.subject.has_name": @@ -478,6 +502,48 @@ func (e *Plugin) arrayAsStringsWithDefault(values []*fastjson.Value, defaultValu return res } +func (e *Plugin) readSubjectNamesByKind(jsonValue *fastjson.Value, kind string) ([]string, error) { + res := []string{} + jsonSubjects := jsonValue.Get("requestObject", "subjects") + if jsonSubjects == nil { + return res, nil + } + if jsonSubjects.Type() != fastjson.TypeArray { + return nil, ErrExtractWrongType + } + + namespacedServiceAccount := false + if kind == "NamespacedServiceAccount" { + namespacedServiceAccount = true + kind = "ServiceAccount" + } + + for _, subject := range jsonSubjects.GetArray() { + if subject.Get("kind") != nil && subject.Get("name") != nil { + subjectKind, err := e.jsonValueAsString(subject.Get("kind")) + if err != nil { + continue + } + if subjectKind == kind { + name, err := e.jsonValueAsString(subject.Get("name")) + if err != nil { + continue + } + if namespacedServiceAccount { + namespace, err := e.jsonValueAsString(subject.Get("namespace")) + if err != nil { + continue + } + name = namespace + ":" + name + } + res = append(res, name) + } + } + } + + return res, nil +} + // note: this returns an error on nil values func (e *Plugin) readContainerImages(jsonValue *fastjson.Value, indexFilter int) ([]string, error) { arr, err := e.getValuesRecursive(jsonValue, indexFilter, "requestObject", "spec", "containers", "image") diff --git a/plugins/k8saudit/pkg/k8saudit/fields.go b/plugins/k8saudit/pkg/k8saudit/fields.go index 1ffe54fe..cea76f0f 100644 --- a/plugins/k8saudit/pkg/k8saudit/fields.go +++ b/plugins/k8saudit/pkg/k8saudit/fields.go @@ -120,6 +120,30 @@ func (k *Plugin) Fields() []sdk.FieldEntry { Desc: "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding", IsList: true, }, + { + Type: "string", + Name: "ka.req.binding.subjects.user_names", + Desc: "When the request object refers to a cluster role binding, the subject user names being linked by the binding", + IsList: true, + }, + { + Type: "string", + Name: "ka.req.binding.subjects.serviceaccount_names", + Desc: "When the request object refers to a cluster role binding, the subject service account names being linked by the binding", + IsList: true, + }, + { + Type: "string", + Name: "ka.req.binding.subjects.serviceaccount_ns_names", + Desc: "When the request object refers to a cluster role binding, the subject serviceaccount namespaced names being linked by the binding, e.g. a list containing: mynamespace:myserviceaccount", + IsList: true, + }, + { + Type: "string", + Name: "ka.req.binding.subjects.group_names", + Desc: "When the request object refers to a cluster role binding, the subject group names being linked by the binding", + IsList: true, + }, { Type: "string", Name: "ka.req.binding.role",