feat: Allow wildcard '*' for API groups in audit policy rules

This commit is contained in:
Christian Muuß
2026-01-29 08:17:10 +00:00
parent 9c915e357f
commit ea3bfd9ea0
8 changed files with 50 additions and 3 deletions

View File

@@ -64867,7 +64867,7 @@ func schema_pkg_apis_audit_v1_GroupResources(ref common.ReferenceCallback) commo
Properties: map[string]spec.Schema{
"group": {
SchemaProps: spec.SchemaProps{
Description: "Group is the name of the API group that contains the resources. The empty string represents the core API group.",
Description: "Group is the name of the API group that contains the resources. The empty string represents the core API group. `*` matches all groups",
Type: []string{"string"},
Format: "",
},

View File

@@ -275,6 +275,7 @@ type PolicyRule struct {
type GroupResources struct {
// Group is the name of the API group that contains the resources.
// The empty string represents the core API group.
// `*` matches all groups
// +optional
Group string
// Resources is a list of resources this rule applies to.

View File

@@ -135,6 +135,7 @@ message EventList {
message GroupResources {
// Group is the name of the API group that contains the resources.
// The empty string represents the core API group.
// `*` matches all groups
// +optional
optional string group = 1;

View File

@@ -278,6 +278,7 @@ type PolicyRule struct {
type GroupResources struct {
// Group is the name of the API group that contains the resources.
// The empty string represents the core API group.
// `*` matches all groups
// +optional
Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"`
// Resources is a list of resources this rule applies to.

View File

@@ -98,7 +98,7 @@ func validateResources(groupResources []audit.GroupResources, fldPath *field.Pat
var allErrs field.ErrorList
for _, groupResource := range groupResources {
// The empty string represents the core API group.
if len(groupResource.Group) != 0 {
if len(groupResource.Group) != 0 && groupResource.Group != "*" {
// Group names must be lower case and be valid DNS subdomains.
// reference: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md
// an error is returned for group name like rbac.authorization.k8s.io/v1beta1

View File

@@ -191,7 +191,7 @@ func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool
name := attrs.GetName()
for _, gr := range r.Resources {
if gr.Group == apiGroup {
if gr.Group == apiGroup || gr.Group == "*" {
if len(gr.Resources) == 0 {
return true
}

View File

@@ -84,6 +84,17 @@ var (
ResourceRequest: true,
Path: "/api/v1/namespaces/default/pods/busybox",
},
"ClusterRoleUpdate": &authorizer.AttributesRecord{
User: tim,
Verb: "update",
APIGroup: "rbac.authorization.k8s.io",
APIVersion: "v1beta1",
Resource: "clusterroles",
Subresource: "status",
Name: "somerole",
ResourceRequest: true,
Path: "/apis/rbac.authorization.k8s.io/v1beta1/clusterroles/somerole",
},
}
rules = map[string]audit.PolicyRule{
@@ -140,6 +151,14 @@ var (
}},
Namespaces: []string{""},
},
"getGroupWildCardMatchingWithSubresourceWildcardMatching": {
Level: audit.LevelRequestResponse,
Verbs: []string{"update"},
Resources: []audit.GroupResources{{
Group: "*",
Resources: []string{"*/status"},
}},
},
"getLogs": {
Level: audit.LevelRequestResponse,
Verbs: []string{"get"},
@@ -242,6 +261,7 @@ func testAuditLevel(t *testing.T, stages []audit.Stage) {
test(t, "Unauthorized", audit.LevelMetadata, stages, stages, "tims", "default")
test(t, "Unauthorized", audit.LevelNone, stages, stages, "humans")
test(t, "Unauthorized", audit.LevelMetadata, stages, stages, "humans", "default")
test(t, "ClusterRoleUpdate", audit.LevelRequestResponse, stages, stages, "getGroupWildCardMatchingWithSubresourceWildcardMatching")
}
func TestChecker(t *testing.T) {

View File

@@ -99,6 +99,11 @@ rules:
resources:
- group: "apps"
resources: ["deployments/scale"]
- level: Request
namespaces: ["wildcard-group-audit-request"]
resources:
- group: "*"
resources: ["deployments"]
`
nonAdmissionWebhookNamespace = "no-webhook-namespace"
@@ -375,6 +380,25 @@ func runTestWithVersion(t *testing.T, version string) {
},
},
},
{
auditLevel: auditinternal.LevelRequest,
namespace: "wildcard-group-audit-request",
expEvents: []utils.AuditEvent{
{
Level: auditinternal.LevelRequest,
Stage: auditinternal.StageResponseComplete,
RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments", "wildcard-group-audit-request"),
Verb: "create",
Code: 201,
User: auditTestUser,
Resource: "deployments",
Namespace: "wildcard-group-audit-request",
RequestObject: true,
ResponseObject: false,
AuthorizeDecision: "allow",
},
},
},
}
for _, tc := range tcs {