diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer/fuzzer.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer/fuzzer.go index 1ec4464c5b3..a7c4d69d63a 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer/fuzzer.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer/fuzzer.go @@ -50,5 +50,20 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} { } } }, + func(o *audit.ObjectReference, c fuzz.Continue) { + c.FuzzNoCustom(o) + switch c.Intn(3) { + case 0: + // core api group + o.APIGroup = "" + o.APIVersion = "v1" + case 1: + // other group + o.APIGroup = "rbac.authorization.k8s.io" + o.APIVersion = "v1beta1" + default: + // use random value. + } + }, } } diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go index cfea0550661..b9f60cfe03c 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go @@ -231,6 +231,11 @@ type ObjectReference struct { Name string // +optional UID types.UID + // APIGroup is the name of the API group that contains the referred object. + // The empty string represents the core API group. + // +optional + APIGroup string + // APIVersion is the version of the API group that contains the referred object. // +optional APIVersion string // +optional diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/conversion.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/conversion.go new file mode 100644 index 00000000000..5f9cc5c1e11 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/conversion.go @@ -0,0 +1,54 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "strings" + + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apiserver/pkg/apis/audit" +) + +func Convert_audit_ObjectReference_To_v1alpha1_ObjectReference(in *audit.ObjectReference, out *ObjectReference, s conversion.Scope) error { + // Begin by copying all fields + if err := autoConvert_audit_ObjectReference_To_v1alpha1_ObjectReference(in, out, s); err != nil { + return err + } + // empty string means the core api group + if in.APIGroup == "" { + out.APIVersion = in.APIVersion + } else { + out.APIVersion = in.APIGroup + "/" + in.APIVersion + } + return nil +} + +func Convert_v1alpha1_ObjectReference_To_audit_ObjectReference(in *ObjectReference, out *audit.ObjectReference, s conversion.Scope) error { + // Begin by copying all fields + if err := autoConvert_v1alpha1_ObjectReference_To_audit_ObjectReference(in, out, s); err != nil { + return err + } + i := strings.LastIndex(in.APIVersion, "/") + if i == -1 { + // In fact it should always contain a "/" + out.APIVersion = in.APIVersion + } else { + out.APIGroup = in.APIVersion[:i] + out.APIVersion = in.APIVersion[i+1:] + } + return nil +} diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/conversion_test.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/conversion_test.go new file mode 100644 index 00000000000..38918e75b36 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/conversion_test.go @@ -0,0 +1,94 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + auditinternal "k8s.io/apiserver/pkg/apis/audit" +) + +var scheme = runtime.NewScheme() + +func init() { + addKnownTypes(scheme) + internalGV := schema.GroupVersion{Group: auditinternal.GroupName, Version: runtime.APIVersionInternal} + scheme.AddKnownTypes(internalGV, + &auditinternal.Event{}, + ) + RegisterConversions(scheme) +} + +func TestConversion(t *testing.T) { + scheme.Log(t) + + testcases := []struct { + desc string + old *ObjectReference + expected *auditinternal.ObjectReference + }{ + { + "core group", + &ObjectReference{ + APIVersion: "/v1", + }, + &auditinternal.ObjectReference{ + APIVersion: "v1", + APIGroup: "", + }, + }, + { + "other groups", + &ObjectReference{ + APIVersion: "rbac.authorization.k8s.io/v1beta1", + }, + &auditinternal.ObjectReference{ + APIVersion: "v1beta1", + APIGroup: "rbac.authorization.k8s.io", + }, + }, + { + "all empty", + &ObjectReference{}, + &auditinternal.ObjectReference{}, + }, + { + "invalid apiversion should not cause painc", + &ObjectReference{ + APIVersion: "invalid version without slash", + }, + &auditinternal.ObjectReference{ + APIVersion: "invalid version without slash", + APIGroup: "", + }, + }, + } + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + internal := &auditinternal.ObjectReference{} + if err := scheme.Convert(tc.old, internal, nil); err != nil { + t.Errorf("unexpected error: %v", err) + } + if !reflect.DeepEqual(internal, tc.expected) { + t.Errorf("expected\n\t%#v, got \n\t%#v", tc.expected, internal) + } + }) + } +} diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go index 1ecac858854..ccf6a039b02 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go @@ -225,10 +225,15 @@ type ObjectReference struct { Name string `json:"name,omitempty" protobuf:"bytes,3,opt,name=name"` // +optional UID types.UID `json:"uid,omitempty" protobuf:"bytes,4,opt,name=uid,casttype=k8s.io/apimachinery/pkg/types.UID"` + // APIGroup is the name of the API group that contains the referred object. + // The empty string represents the core API group. // +optional - APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,5,opt,name=apiVersion"` + APIGroup string `json:"apiGroup,omitempty" protobuf:"bytes,5,opt,name=apiGroup"` + // APIVersion is the version of the API group that contains the referred object. // +optional - ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,6,opt,name=resourceVersion"` + APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,6,opt,name=apiVersion"` // +optional - Subresource string `json:"subresource,omitempty" protobuf:"bytes,7,opt,name=subresource"` + ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,7,opt,name=resourceVersion"` + // +optional + Subresource string `json:"subresource,omitempty" protobuf:"bytes,8,opt,name=subresource"` } diff --git a/staging/src/k8s.io/apiserver/pkg/audit/request.go b/staging/src/k8s.io/apiserver/pkg/audit/request.go index 26807485c60..c2547ac3733 100644 --- a/staging/src/k8s.io/apiserver/pkg/audit/request.go +++ b/staging/src/k8s.io/apiserver/pkg/audit/request.go @@ -97,7 +97,8 @@ func NewEventFromRequest(req *http.Request, level auditinternal.Level, attribs a Name: attribs.GetName(), Resource: attribs.GetResource(), Subresource: attribs.GetSubresource(), - APIVersion: attribs.GetAPIGroup() + "/" + attribs.GetAPIVersion(), + APIGroup: attribs.GetAPIGroup(), + APIVersion: attribs.GetAPIVersion(), } } @@ -132,6 +133,7 @@ func LogRequestObject(ae *audit.Event, obj runtime.Object, gvr schema.GroupVersi } // TODO: ObjectRef should include the API group. if len(ae.ObjectRef.APIVersion) == 0 { + ae.ObjectRef.APIGroup = gvr.Group ae.ObjectRef.APIVersion = gvr.Version } if len(ae.ObjectRef.Resource) == 0 { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit_test.go index c6e27981188..a5b483da02f 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit_test.go @@ -923,6 +923,12 @@ func TestAuditJson(t *testing.T) { } else if expectedID != event.AuditID { t.Errorf("[%s] Audits for one request should share the same AuditID, %s differs from %s", test.desc, expectedID, event.AuditID) } + if event.ObjectRef.APIVersion != "v1" { + t.Errorf("[%s] Unexpected apiVersion: %s", test.desc, event.ObjectRef.APIVersion) + } + if event.ObjectRef.APIGroup != "" { + t.Errorf("[%s] Unexpected apiGroup: %s", test.desc, event.ObjectRef.APIGroup) + } if (event.ResponseStatus == nil) != (expect.ResponseStatus == nil) { t.Errorf("[%s] Unexpected ResponseStatus: %v", test.desc, event.ResponseStatus) continue