Commit 58aa139f authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #48836 from ericchiang/audit-policy-subresource-resource-name

Automatic merge from submit-queue (batch tested with PRs 51574, 51534, 49257, 44680, 48836) audit policy: support subresources and resource names Updates #48561 policy: - level: Metadata resources: - group: "" resources ["pods/logs"] - level: None resources: - group: "" resources: ["configmaps"] resourceNames: ["controller-leader"] The top level resource no longer matches the subresource. For example "pods" no longer matches requests to the logs subresource on pods. ```release-note Audit policy supports matching subresources and resource names, but the top level resource no longer matches the subresouce. For example "pods" no longer matches requests to the logs subresource of pods. Use "pods/logs" to match subresources. ``` /cc @sttts @soltysh @crassirostris @ihmccreery @timstclair
parents 43a40f7a 9caff690
...@@ -215,10 +215,17 @@ type GroupResources struct { ...@@ -215,10 +215,17 @@ type GroupResources struct {
// The empty string represents the core API group. // The empty string represents the core API group.
// +optional // +optional
Group string Group string
// Resources is a list of resources within the API group. // Resources is a list of resources within the API group. Subresources are
// Any empty list implies every resource kind in the API group. // matched using a "/" to indicate the subresource. For example, "pods/logs"
// would match request to the logs subresource of pods. The top level resource
// does not match subresources, "pods" doesn't match "pods/logs".
// +optional // +optional
Resources []string Resources []string
// ResourceNames is a list of resource instance names that the policy matches.
// Using this field requires Resources to be specified.
// An empty list implies that every instance of the resource is matched.
// +optional
ResourceNames []string
} }
// ObjectReference contains enough information to let you inspect or modify the referred object. // ObjectReference contains enough information to let you inspect or modify the referred object.
......
...@@ -106,10 +106,18 @@ message GroupResources { ...@@ -106,10 +106,18 @@ message GroupResources {
// +optional // +optional
optional string group = 1; optional string group = 1;
// Resources is a list of resources within the API group. // Resources is a list of resources within the API group. Subresources are
// Any empty list implies every resource kind in the API group. // matched using a "/" to indicate the subresource. For example, "pods/logs"
// would match request to the logs subresource of pods. The top level resource
// does not match subresources, "pods" doesn't match "pods/logs".
// +optional // +optional
repeated string resources = 2; repeated string resources = 2;
// ResourceNames is a list of resource instance names that the policy matches.
// Using this field requires Resources to be specified.
// An empty list implies that every instance of the resource is matched.
// +optional
repeated string resourceNames = 3;
} }
// ObjectReference contains enough information to let you inspect or modify the referred object. // ObjectReference contains enough information to let you inspect or modify the referred object.
......
...@@ -2887,14 +2887,15 @@ func (x *GroupResources) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -2887,14 +2887,15 @@ func (x *GroupResources) CodecEncodeSelf(e *codec1978.Encoder) {
} else { } else {
yysep2 := !z.EncBinary() yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [2]bool var yyq2 [3]bool
_, _, _ = yysep2, yyq2, yy2arr2 _, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false const yyr2 bool = false
yyq2[0] = x.Group != "" yyq2[0] = x.Group != ""
yyq2[1] = len(x.Resources) != 0 yyq2[1] = len(x.Resources) != 0
yyq2[2] = len(x.ResourceNames) != 0
var yynn2 int var yynn2 int
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
r.EncodeArrayStart(2) r.EncodeArrayStart(3)
} else { } else {
yynn2 = 0 yynn2 = 0
for _, b := range yyq2 { for _, b := range yyq2 {
...@@ -2964,6 +2965,39 @@ func (x *GroupResources) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -2964,6 +2965,39 @@ func (x *GroupResources) CodecEncodeSelf(e *codec1978.Encoder) {
} }
} }
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[2] {
if x.ResourceNames == nil {
r.EncodeNil()
} else {
yym10 := z.EncBinary()
_ = yym10
if false {
} else {
z.F.EncSliceStringV(x.ResourceNames, false, e)
}
}
} else {
r.EncodeNil()
}
} else {
if yyq2[2] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("resourceNames"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
if x.ResourceNames == nil {
r.EncodeNil()
} else {
yym11 := z.EncBinary()
_ = yym11
if false {
} else {
z.F.EncSliceStringV(x.ResourceNames, false, e)
}
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234) z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else { } else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234) z.EncSendContainerState(codecSelfer_containerMapEnd1234)
...@@ -3048,6 +3082,18 @@ func (x *GroupResources) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { ...@@ -3048,6 +3082,18 @@ func (x *GroupResources) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
z.F.DecSliceStringX(yyv6, false, d) z.F.DecSliceStringX(yyv6, false, d)
} }
} }
case "resourceNames":
if r.TryDecodeAsNil() {
x.ResourceNames = nil
} else {
yyv8 := &x.ResourceNames
yym9 := z.DecBinary()
_ = yym9
if false {
} else {
z.F.DecSliceStringX(yyv8, false, d)
}
}
default: default:
z.DecStructFieldNotFound(-1, yys3) z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3 } // end switch yys3
...@@ -3059,16 +3105,16 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { ...@@ -3059,16 +3105,16 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yyj8 int var yyj10 int
var yyb8 bool var yyb10 bool
var yyhl8 bool = l >= 0 var yyhl10 bool = l >= 0
yyj8++ yyj10++
if yyhl8 { if yyhl10 {
yyb8 = yyj8 > l yyb10 = yyj10 > l
} else { } else {
yyb8 = r.CheckBreak() yyb10 = r.CheckBreak()
} }
if yyb8 { if yyb10 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -3076,21 +3122,21 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { ...@@ -3076,21 +3122,21 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Group = "" x.Group = ""
} else { } else {
yyv9 := &x.Group yyv11 := &x.Group
yym10 := z.DecBinary() yym12 := z.DecBinary()
_ = yym10 _ = yym12
if false { if false {
} else { } else {
*((*string)(yyv9)) = r.DecodeString() *((*string)(yyv11)) = r.DecodeString()
} }
} }
yyj8++ yyj10++
if yyhl8 { if yyhl10 {
yyb8 = yyj8 > l yyb10 = yyj10 > l
} else { } else {
yyb8 = r.CheckBreak() yyb10 = r.CheckBreak()
} }
if yyb8 { if yyb10 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -3098,26 +3144,48 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { ...@@ -3098,26 +3144,48 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Resources = nil x.Resources = nil
} else { } else {
yyv11 := &x.Resources yyv13 := &x.Resources
yym12 := z.DecBinary() yym14 := z.DecBinary()
_ = yym12 _ = yym14
if false {
} else {
z.F.DecSliceStringX(yyv13, false, d)
}
}
yyj10++
if yyhl10 {
yyb10 = yyj10 > l
} else {
yyb10 = r.CheckBreak()
}
if yyb10 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.ResourceNames = nil
} else {
yyv15 := &x.ResourceNames
yym16 := z.DecBinary()
_ = yym16
if false { if false {
} else { } else {
z.F.DecSliceStringX(yyv11, false, d) z.F.DecSliceStringX(yyv15, false, d)
} }
} }
for { for {
yyj8++ yyj10++
if yyhl8 { if yyhl10 {
yyb8 = yyj8 > l yyb10 = yyj10 > l
} else { } else {
yyb8 = r.CheckBreak() yyb10 = r.CheckBreak()
} }
if yyb8 { if yyb10 {
break break
} }
z.DecSendContainerState(codecSelfer_containerArrayElem1234) z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj8-1, "") z.DecStructFieldNotFound(yyj10-1, "")
} }
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} }
...@@ -4063,7 +4131,7 @@ func (x codecSelfer1234) decSliceGroupResources(v *[]GroupResources, d *codec197 ...@@ -4063,7 +4131,7 @@ func (x codecSelfer1234) decSliceGroupResources(v *[]GroupResources, d *codec197
yyrg1 := len(yyv1) > 0 yyrg1 := len(yyv1) > 0
yyv21 := yyv1 yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 40) yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 64)
if yyrt1 { if yyrt1 {
if yyrl1 <= cap(yyv1) { if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1] yyv1 = yyv1[:yyrl1]
......
...@@ -216,10 +216,17 @@ type GroupResources struct { ...@@ -216,10 +216,17 @@ type GroupResources struct {
// The empty string represents the core API group. // The empty string represents the core API group.
// +optional // +optional
Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"` Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"`
// Resources is a list of resources within the API group. // Resources is a list of resources within the API group. Subresources are
// Any empty list implies every resource kind in the API group. // matched using a "/" to indicate the subresource. For example, "pods/logs"
// would match request to the logs subresource of pods. The top level resource
// does not match subresources, "pods" doesn't match "pods/logs".
// +optional // +optional
Resources []string `json:"resources,omitempty" protobuf:"bytes,2,rep,name=resources"` Resources []string `json:"resources,omitempty" protobuf:"bytes,2,rep,name=resources"`
// ResourceNames is a list of resource instance names that the policy matches.
// Using this field requires Resources to be specified.
// An empty list implies that every instance of the resource is matched.
// +optional
ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,3,rep,name=resourceNames"`
} }
// ObjectReference contains enough information to let you inspect or modify the referred object. // ObjectReference contains enough information to let you inspect or modify the referred object.
......
...@@ -132,6 +132,7 @@ func Convert_audit_EventList_To_v1alpha1_EventList(in *audit.EventList, out *Eve ...@@ -132,6 +132,7 @@ func Convert_audit_EventList_To_v1alpha1_EventList(in *audit.EventList, out *Eve
func autoConvert_v1alpha1_GroupResources_To_audit_GroupResources(in *GroupResources, out *audit.GroupResources, s conversion.Scope) error { func autoConvert_v1alpha1_GroupResources_To_audit_GroupResources(in *GroupResources, out *audit.GroupResources, s conversion.Scope) error {
out.Group = in.Group out.Group = in.Group
out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources)) out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
out.ResourceNames = *(*[]string)(unsafe.Pointer(&in.ResourceNames))
return nil return nil
} }
...@@ -143,6 +144,7 @@ func Convert_v1alpha1_GroupResources_To_audit_GroupResources(in *GroupResources, ...@@ -143,6 +144,7 @@ func Convert_v1alpha1_GroupResources_To_audit_GroupResources(in *GroupResources,
func autoConvert_audit_GroupResources_To_v1alpha1_GroupResources(in *audit.GroupResources, out *GroupResources, s conversion.Scope) error { func autoConvert_audit_GroupResources_To_v1alpha1_GroupResources(in *audit.GroupResources, out *GroupResources, s conversion.Scope) error {
out.Group = in.Group out.Group = in.Group
out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources)) out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
out.ResourceNames = *(*[]string)(unsafe.Pointer(&in.ResourceNames))
return nil return nil
} }
......
...@@ -190,6 +190,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) { ...@@ -190,6 +190,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) {
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.ResourceNames != nil {
in, out := &in.ResourceNames, &out.ResourceNames
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }
......
...@@ -209,10 +209,17 @@ type GroupResources struct { ...@@ -209,10 +209,17 @@ type GroupResources struct {
// The empty string represents the core API group. // The empty string represents the core API group.
// +optional // +optional
Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"` Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"`
// Resources is a list of resources within the API group. // Resources is a list of resources within the API group. Subresources are
// Any empty list implies every resource kind in the API group. // matched using a "/" to indicate the subresource. For example, "pods/logs"
// would match request to the logs subresource of pods. The top level resource
// does not match subresources, "pods" doesn't match "pods/logs".
// +optional // +optional
Resources []string `json:"resources,omitempty" protobuf:"bytes,2,rep,name=resources"` Resources []string `json:"resources,omitempty" protobuf:"bytes,2,rep,name=resources"`
// ResourceNames is a list of resource instance names that the policy matches.
// Using this field requires Resources to be specified.
// An empty list implies that every instance of the resource is matched.
// +optional
ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,3,rep,name=resourceNames"`
} }
// ObjectReference contains enough information to let you inspect or modify the referred object. // ObjectReference contains enough information to let you inspect or modify the referred object.
......
...@@ -132,6 +132,7 @@ func Convert_audit_EventList_To_v1beta1_EventList(in *audit.EventList, out *Even ...@@ -132,6 +132,7 @@ func Convert_audit_EventList_To_v1beta1_EventList(in *audit.EventList, out *Even
func autoConvert_v1beta1_GroupResources_To_audit_GroupResources(in *GroupResources, out *audit.GroupResources, s conversion.Scope) error { func autoConvert_v1beta1_GroupResources_To_audit_GroupResources(in *GroupResources, out *audit.GroupResources, s conversion.Scope) error {
out.Group = in.Group out.Group = in.Group
out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources)) out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
out.ResourceNames = *(*[]string)(unsafe.Pointer(&in.ResourceNames))
return nil return nil
} }
...@@ -143,6 +144,7 @@ func Convert_v1beta1_GroupResources_To_audit_GroupResources(in *GroupResources, ...@@ -143,6 +144,7 @@ func Convert_v1beta1_GroupResources_To_audit_GroupResources(in *GroupResources,
func autoConvert_audit_GroupResources_To_v1beta1_GroupResources(in *audit.GroupResources, out *GroupResources, s conversion.Scope) error { func autoConvert_audit_GroupResources_To_v1beta1_GroupResources(in *audit.GroupResources, out *GroupResources, s conversion.Scope) error {
out.Group = in.Group out.Group = in.Group
out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources)) out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
out.ResourceNames = *(*[]string)(unsafe.Pointer(&in.ResourceNames))
return nil return nil
} }
......
...@@ -190,6 +190,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) { ...@@ -190,6 +190,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) {
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.ResourceNames != nil {
in, out := &in.ResourceNames, &out.ResourceNames
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }
......
...@@ -88,16 +88,18 @@ func validateResources(groupResources []audit.GroupResources, fldPath *field.Pat ...@@ -88,16 +88,18 @@ func validateResources(groupResources []audit.GroupResources, fldPath *field.Pat
var allErrs field.ErrorList var allErrs field.ErrorList
for _, groupResource := range groupResources { for _, groupResource := range groupResources {
// The empty string represents the core API group. // The empty string represents the core API group.
if len(groupResource.Group) == 0 { if len(groupResource.Group) != 0 {
continue // Group names must be lower case and be valid DNS subdomains.
// reference: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md
// an error is returned for group name like rbac.authorization.k8s.io/v1beta1
// rbac.authorization.k8s.io is the valid one
if msgs := validation.NameIsDNSSubdomain(groupResource.Group, false); len(msgs) != 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), groupResource.Group, strings.Join(msgs, ",")))
}
} }
// Group names must be lower case and be valid DNS subdomains. if len(groupResource.ResourceNames) > 0 && len(groupResource.Resources) == 0 {
// reference: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceNames"), groupResource.ResourceNames, "using resourceNames requires at least one resource"))
// an error is returned for group name like rbac.authorization.k8s.io/v1beta1
// rbac.authorization.k8s.io is the valid one
if msgs := validation.NameIsDNSSubdomain(groupResource.Group, false); len(msgs) != 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), groupResource.Group, strings.Join(msgs, ",")))
} }
} }
return allErrs return allErrs
......
...@@ -102,6 +102,12 @@ func TestValidatePolicy(t *testing.T) { ...@@ -102,6 +102,12 @@ func TestValidatePolicy(t *testing.T) {
"/metrics", "/metrics",
}, },
}, },
{ // ResourceNames without Resources
Level: audit.LevelMetadata,
Verbs: []string{"get"},
Resources: []audit.GroupResources{{ResourceNames: []string{"leader"}}},
Namespaces: []string{"kube-system"},
},
} }
errorCases := []audit.Policy{} errorCases := []audit.Policy{}
for _, rule := range invalidRules { for _, rule := range invalidRules {
......
...@@ -188,6 +188,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) { ...@@ -188,6 +188,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) {
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.ResourceNames != nil {
in, out := &in.ResourceNames, &out.ResourceNames
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }
......
...@@ -143,6 +143,15 @@ func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool ...@@ -143,6 +143,15 @@ func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool
apiGroup := attrs.GetAPIGroup() apiGroup := attrs.GetAPIGroup()
resource := attrs.GetResource() resource := attrs.GetResource()
// If subresource, the resource in the policy must match "(resource)/(subresource)"
//
// TODO: consider adding options like "pods/*" to match all subresources.
if sr := attrs.GetSubresource(); sr != "" {
resource = resource + "/" + sr
}
name := attrs.GetName()
for _, gr := range r.Resources { for _, gr := range r.Resources {
if gr.Group == apiGroup { if gr.Group == apiGroup {
if len(gr.Resources) == 0 { if len(gr.Resources) == 0 {
...@@ -150,7 +159,9 @@ func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool ...@@ -150,7 +159,9 @@ func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool
} }
for _, res := range gr.Resources { for _, res := range gr.Resources {
if res == resource { if res == resource {
return true if len(gr.ResourceNames) == 0 || hasString(gr.ResourceNames, name) {
return true
}
} }
} }
} }
......
...@@ -61,6 +61,18 @@ func TestChecker(t *testing.T) { ...@@ -61,6 +61,18 @@ func TestChecker(t *testing.T) {
ResourceRequest: false, ResourceRequest: false,
Path: "/logs/kubelet.log", Path: "/logs/kubelet.log",
}, },
"subresource": &authorizer.AttributesRecord{
User: tim,
Verb: "get",
Namespace: "default",
APIGroup: "", // Core
APIVersion: "v1",
Resource: "pods",
Subresource: "log",
Name: "busybox",
ResourceRequest: true,
Path: "/api/v1/namespaces/default/pods/busybox",
},
} }
rules := map[string]audit.PolicyRule{ rules := map[string]audit.PolicyRule{
...@@ -88,6 +100,11 @@ func TestChecker(t *testing.T) { ...@@ -88,6 +100,11 @@ func TestChecker(t *testing.T) {
Verbs: []string{"get"}, Verbs: []string{"get"},
Resources: []audit.GroupResources{{Resources: []string{"pods"}}}, Resources: []audit.GroupResources{{Resources: []string{"pods"}}},
}, },
"getPodLogs": {
Level: audit.LevelRequest,
Verbs: []string{"get"},
Resources: []audit.GroupResources{{Resources: []string{"pods/log"}}},
},
"getClusterRoles": { "getClusterRoles": {
Level: audit.LevelRequestResponse, Level: audit.LevelRequestResponse,
Verbs: []string{"get"}, Verbs: []string{"get"},
...@@ -111,6 +128,14 @@ func TestChecker(t *testing.T) { ...@@ -111,6 +128,14 @@ func TestChecker(t *testing.T) {
"/metrics", "/metrics",
}, },
}, },
"clusterRoleEdit": {
Level: audit.LevelRequest,
Resources: []audit.GroupResources{{
Group: "rbac.authorization.k8s.io",
Resources: []string{"clusterroles"},
ResourceNames: []string{"edit"},
}},
},
} }
test := func(req string, expected audit.Level, ruleNames ...string) { test := func(req string, expected audit.Level, ruleNames ...string) {
...@@ -135,6 +160,7 @@ func TestChecker(t *testing.T) { ...@@ -135,6 +160,7 @@ func TestChecker(t *testing.T) {
test("namespaced", audit.LevelNone, "getMetrics") test("namespaced", audit.LevelNone, "getMetrics")
test("namespaced", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default") test("namespaced", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default")
test("namespaced", audit.LevelRequestResponse, "getMetrics", "getPods", "default") test("namespaced", audit.LevelRequestResponse, "getMetrics", "getPods", "default")
test("namespaced", audit.LevelRequestResponse, "getPodLogs", "getPods")
test("cluster", audit.LevelMetadata, "default") test("cluster", audit.LevelMetadata, "default")
test("cluster", audit.LevelNone, "create") test("cluster", audit.LevelNone, "create")
...@@ -143,10 +169,12 @@ func TestChecker(t *testing.T) { ...@@ -143,10 +169,12 @@ func TestChecker(t *testing.T) {
test("cluster", audit.LevelNone, "serviceAccounts") test("cluster", audit.LevelNone, "serviceAccounts")
test("cluster", audit.LevelNone, "getPods") test("cluster", audit.LevelNone, "getPods")
test("cluster", audit.LevelRequestResponse, "getClusterRoles") test("cluster", audit.LevelRequestResponse, "getClusterRoles")
test("cluster", audit.LevelRequest, "clusterRoleEdit", "getClusterRoles")
test("cluster", audit.LevelNone, "getLogs") test("cluster", audit.LevelNone, "getLogs")
test("cluster", audit.LevelNone, "getMetrics") test("cluster", audit.LevelNone, "getMetrics")
test("cluster", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default") test("cluster", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default")
test("cluster", audit.LevelRequestResponse, "getMetrics", "getClusterRoles", "default") test("cluster", audit.LevelRequestResponse, "getMetrics", "getClusterRoles", "default")
test("cluster", audit.LevelNone, "getPodLogs", "getPods")
test("nonResource", audit.LevelMetadata, "default") test("nonResource", audit.LevelMetadata, "default")
test("nonResource", audit.LevelNone, "create") test("nonResource", audit.LevelNone, "create")
...@@ -159,4 +187,8 @@ func TestChecker(t *testing.T) { ...@@ -159,4 +187,8 @@ func TestChecker(t *testing.T) {
test("nonResource", audit.LevelNone, "getMetrics") test("nonResource", audit.LevelNone, "getMetrics")
test("nonResource", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default") test("nonResource", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default")
test("nonResource", audit.LevelRequestResponse, "getLogs", "getClusterRoles", "default") test("nonResource", audit.LevelRequestResponse, "getLogs", "getClusterRoles", "default")
test("nonResource", audit.LevelNone, "getPodLogs", "getPods")
test("subresource", audit.LevelRequest, "getPodLogs", "getPods")
test("subresource", audit.LevelRequest, "getPods", "getPodLogs")
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment