New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kubernetes audit logs: improve field mapping #3414
Kubernetes audit logs: improve field mapping #3414
Conversation
Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, great work. A few things I noticed:
Missing field:
requestObject.spec.containers.securityContext.runasuser
type: integer
These fields should be nested under spec., not spec.container. :
- requestObject.spec.HostNetwork
- requestObject.spec.HostIPC
- requestObject.spec.HostPID
These may need to be flattened so that I can search on the whole object (hope I'm understanding flattened correctly):
- requestObject.spec.volumes.hostPath.path
- responseObject.spec.volumes.hostPath.path
These may need to be nested objects instead of arrays so that I can search for specific 'resources' that are attached to 'verbs'; I'm not sure how best to do this though. Can we flatten the fields first and then link them together? I'm not sure if that's an option but maybe we can use the rules.apiGroup field as the link between each rules.resources and rules.verbs pairing? I would want to be able to search for something like requestObject.rules.resources: pods/exec and requestObject.rules.verbs: create but would only want a hit back if those two groups were linked to the same rules.apiGroup. Because it's possible to have the rules.verb: create but it's attached to a different group of resources like "cronjobs" under a different apiGroups.
requestObject.rules.resources
requestObject.rules.verbs
responseObject.rules.resources
responseObject.rules.verbs
"kubernetes":{
"audit":{
"annotations":{
"authorization_k8s_io/decision":"allow",
"authorization_k8s_io/reason":"RBAC: allowed by ClusterRoleBinding \"system:controller:clusterrole-aggregation-controller\" of ClusterRole \"system:controller:clusterrole-aggregation-controller\" to ServiceAccount \"clusterrole-aggregation-controller/kube-system\""
},
"apiVersion":"audit.k8s.io/v1",
"auditID":"492ef3d2-698a-4529-ada4-6ac0e3a9246e",
"kind":"Event",
"level":"RequestResponse",
"objectRef":{
"apiGroup":"rbac.authorization.k8s.io",
"apiVersion":"v1",
"name":"admin",
"resource":"clusterroles"
},
"requestObject":{
"apiVersion":"rbac.authorization.k8s.io/v1",
"kind":"ClusterRole",
"metadata":{
"name":"admin"
},
"rules":[
{
"apiGroups":[
""
],
"resources":[
"pods/attach",
"pods/exec",
"pods/portforward",
"pods/proxy",
"secrets",
"services/proxy"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
""
],
"resources":[
"serviceaccounts"
],
"verbs":[
"impersonate"
]
},
{
"apiGroups":[
""
],
"resources":[
"pods",
"pods/attach",
"pods/exec",
"pods/portforward",
"pods/proxy"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
""
],
"resources":[
"configmaps",
"events",
"persistentvolumeclaims",
"replicationcontrollers",
"replicationcontrollers/scale",
"secrets",
"serviceaccounts",
"services",
"services/proxy"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"apps"
],
"resources":[
"daemonsets",
"deployments",
"deployments/rollback",
"deployments/scale",
"replicasets",
"replicasets/scale",
"statefulsets",
"statefulsets/scale"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"autoscaling"
],
"resources":[
"horizontalpodautoscalers"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"batch"
],
"resources":[
"cronjobs",
"jobs"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"extensions"
],
"resources":[
"daemonsets",
"deployments",
"deployments/rollback",
"deployments/scale",
"ingresses",
"networkpolicies",
"replicasets",
"replicasets/scale",
"replicationcontrollers/scale"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"policy"
],
"resources":[
"poddisruptionbudgets"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"networking.k8s.io"
],
"resources":[
"ingresses",
"networkpolicies"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"metrics.k8s.io"
],
"resources":[
"pods",
"nodes"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
""
],
"resources":[
"configmaps",
"endpoints",
"persistentvolumeclaims",
"persistentvolumeclaims/status",
"pods",
"replicationcontrollers",
"replicationcontrollers/scale",
"serviceaccounts",
"services",
"services/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
""
],
"resources":[
"bindings",
"events",
"limitranges",
"namespaces/status",
"pods/log",
"pods/status",
"replicationcontrollers/status",
"resourcequotas",
"resourcequotas/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
""
],
"resources":[
"namespaces"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"discovery.k8s.io"
],
"resources":[
"endpointslices"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"apps"
],
"resources":[
"controllerrevisions",
"daemonsets",
"daemonsets/status",
"deployments",
"deployments/scale",
"deployments/status",
"replicasets",
"replicasets/scale",
"replicasets/status",
"statefulsets",
"statefulsets/scale",
"statefulsets/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"autoscaling"
],
"resources":[
"horizontalpodautoscalers",
"horizontalpodautoscalers/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"batch"
],
"resources":[
"cronjobs",
"cronjobs/status",
"jobs",
"jobs/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"extensions"
],
"resources":[
"daemonsets",
"daemonsets/status",
"deployments",
"deployments/scale",
"deployments/status",
"ingresses",
"ingresses/status",
"networkpolicies",
"replicasets",
"replicasets/scale",
"replicasets/status",
"replicationcontrollers/scale"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"policy"
],
"resources":[
"poddisruptionbudgets",
"poddisruptionbudgets/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"networking.k8s.io"
],
"resources":[
"ingresses",
"ingresses/status",
"networkpolicies"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"authorization.k8s.io"
],
"resources":[
"localsubjectaccessreviews"
],
"verbs":[
"create"
]
},
{
"apiGroups":[
"rbac.authorization.k8s.io"
],
"resources":[
"rolebindings",
"roles"
],
"verbs":[
"create",
"delete",
"deletecollection",
"get",
"list",
"patch",
"update",
"watch"
]
}
]
},
"requestReceivedTimestamp":"2022-05-20T20:53:43.652860Z",
"requestURI":"/apis/rbac.authorization.k8s.io/v1/clusterroles/admin?fieldManager=clusterrole-aggregation-controller\u0026force=true",
"responseObject":{
"aggregationRule":{
"clusterRoleSelectors":[
{
"matchLabels":{
"rbac.authorization.k8s.io/aggregate-to-admin":"true"
}
}
]
},
"apiVersion":"rbac.authorization.k8s.io/v1",
"kind":"ClusterRole",
"metadata":{
"annotations":{
"rbac.authorization.kubernetes.io/autoupdate":"true"
},
"creationTimestamp":"2022-05-20T20:53:29Z",
"labels":{
"kubernetes.io/bootstrapping":"rbac-defaults"
},
"managedFields":[
{
"apiVersion":"rbac.authorization.k8s.io/v1",
"fieldsType":"FieldsV1",
"fieldsV1":{
"f:rules":{
}
},
"manager":"clusterrole-aggregation-controller",
"operation":"Apply",
"time":"2022-05-20T20:53:43Z"
},
{
"apiVersion":"rbac.authorization.k8s.io/v1",
"fieldsType":"FieldsV1",
"fieldsV1":{
"f:aggregationRule":{
".":{
},
"f:clusterRoleSelectors":{
}
},
"f:metadata":{
"f:annotations":{
".":{
},
"f:rbac.authorization.kubernetes.io/autoupdate":{
}
},
"f:labels":{
".":{
},
"f:kubernetes.io/bootstrapping":{
}
}
}
},
"manager":"k3s",
"operation":"Update",
"time":"2022-05-20T20:53:29Z"
}
],
"name":"admin",
"resourceVersion":"509",
"uid":"ee78f4af-1057-454f-b0a3-d9d2e963162e"
},
"rules":[
{
"apiGroups":[
""
],
"resources":[
"pods/attach",
"pods/exec",
"pods/portforward",
"pods/proxy",
"secrets",
"services/proxy"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
""
],
"resources":[
"serviceaccounts"
],
"verbs":[
"impersonate"
]
},
{
"apiGroups":[
""
],
"resources":[
"pods",
"pods/attach",
"pods/exec",
"pods/portforward",
"pods/proxy"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
""
],
"resources":[
"configmaps",
"events",
"persistentvolumeclaims",
"replicationcontrollers",
"replicationcontrollers/scale",
"secrets",
"serviceaccounts",
"services",
"services/proxy"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"apps"
],
"resources":[
"daemonsets",
"deployments",
"deployments/rollback",
"deployments/scale",
"replicasets",
"replicasets/scale",
"statefulsets",
"statefulsets/scale"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"autoscaling"
],
"resources":[
"horizontalpodautoscalers"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"batch"
],
"resources":[
"cronjobs",
"jobs"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"extensions"
],
"resources":[
"daemonsets",
"deployments",
"deployments/rollback",
"deployments/scale",
"ingresses",
"networkpolicies",
"replicasets",
"replicasets/scale",
"replicationcontrollers/scale"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"policy"
],
"resources":[
"poddisruptionbudgets"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"networking.k8s.io"
],
"resources":[
"ingresses",
"networkpolicies"
],
"verbs":[
"create",
"delete",
"deletecollection",
"patch",
"update"
]
},
{
"apiGroups":[
"metrics.k8s.io"
],
"resources":[
"pods",
"nodes"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
""
],
"resources":[
"configmaps",
"endpoints",
"persistentvolumeclaims",
"persistentvolumeclaims/status",
"pods",
"replicationcontrollers",
"replicationcontrollers/scale",
"serviceaccounts",
"services",
"services/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
""
],
"resources":[
"bindings",
"events",
"limitranges",
"namespaces/status",
"pods/log",
"pods/status",
"replicationcontrollers/status",
"resourcequotas",
"resourcequotas/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
""
],
"resources":[
"namespaces"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"discovery.k8s.io"
],
"resources":[
"endpointslices"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"apps"
],
"resources":[
"controllerrevisions",
"daemonsets",
"daemonsets/status",
"deployments",
"deployments/scale",
"deployments/status",
"replicasets",
"replicasets/scale",
"replicasets/status",
"statefulsets",
"statefulsets/scale",
"statefulsets/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"autoscaling"
],
"resources":[
"horizontalpodautoscalers",
"horizontalpodautoscalers/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"batch"
],
"resources":[
"cronjobs",
"cronjobs/status",
"jobs",
"jobs/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"extensions"
],
"resources":[
"daemonsets",
"daemonsets/status",
"deployments",
"deployments/scale",
"deployments/status",
"ingresses",
"ingresses/status",
"networkpolicies",
"replicasets",
"replicasets/scale",
"replicasets/status",
"replicationcontrollers/scale"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"policy"
],
"resources":[
"poddisruptionbudgets",
"poddisruptionbudgets/status"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"networking.k8s.io"
],
"resources":[
"ingresses",
"ingresses/status",
"networkpolicies"
],
"verbs":[
"get",
"list",
"watch"
]
},
{
"apiGroups":[
"authorization.k8s.io"
],
"resources":[
"localsubjectaccessreviews"
],
"verbs":[
"create"
]
},
{
"apiGroups":[
"rbac.authorization.k8s.io"
],
"resources":[
"rolebindings",
"roles"
],
"verbs":[
"create",
"delete",
"deletecollection",
"get",
"list",
"patch",
"update",
"watch"
]
}
]
},
"responseStatus":{
"code":200,
"metadata":{
}
},
"sourceIPs":[
"127.0.0.1"
],
"stage":"ResponseComplete",
"stageTimestamp":"2022-05-20T20:53:43.655728Z",
"user":{
"groups":[
"system:serviceaccounts",
"system:serviceaccounts:kube-system",
"system:authenticated"
],
"uid":"08f61082-e1cd-412d-8f2c-87fbd3d1f400",
"username":"system:serviceaccount:kube-system:clusterrole-aggregation-controller"
},
"userAgent":"k3s/v1.22.7+k3s1 (linux/amd64) kubernetes/8432d7f/system:serviceaccount:kube-system:clusterrole-aggregation-controller",
"verb":"patch"
}
Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
packages/kubernetes/data_stream/audit_logs/agent/stream/stream.yml.hbs
Outdated
Show resolved
Hide resolved
Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
🌐 Coverage report
|
type: flattened | ||
- name: rules | ||
dynamic: true | ||
type: nested |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@imays11 fyi, with query as on the screenshot, it seems to give the desired result:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Question, what would happen if another resource group had the verb "list" but secrets did not. Would running that query still capture those results?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would running that query still capture those results?
No.
I have 2 documents, first with
"resources": [
"services",
"endpoints",
"secrets"
],
"verbs": [
"get",
"list",
"watch"
]
second with (no list
):
"resources": [
"services",
"endpoints",
"secrets"
],
"verbs": [
"get",
"watch"
]
query kubernetes.audit.requestObject.rules:{ resources : "secrets" and verbs : "watch"}
capture 2 documents:
query kubernetes.audit.requestObject.rules:{ resources : "secrets" and verbs : "list"}
gives only 1:
Is it expected outcome for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that is perfect! Thank you @tetianakravchenko
- name: volumeMounts | ||
type: flattened | ||
- name: volumes.hostPath | ||
type: flattened |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@imays11 fyi:
the same situation is with volumeMounts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
type: integer | ||
- name: volumeMounts | ||
type: flattened | ||
- name: volumes.hostPath |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one level up in the original:
- name: volumes.hostPath |
Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should be on the same level, I've changed the fields ordering to make it clear - f4b6798
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice thanks
Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
…t.metadata -> kubernetes.audit.requestObject.metadata Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
Signed-off-by: Tetiana Kravchenko tetiana.kravchenko@elastic.co
What does this PR do?
Audit logs are missing important fields, needed for security team to create detection rules.
Checklist
changelog.yml
file.Author's Checklist
How to test this PR locally
audit-policy.yaml
with:kind config:
create cluster:
/var/log/kubernetes/kube-apiserver-audit-1.log
Related issues
Screenshots