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 d6d15adb583..f9d37e54caa 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go @@ -238,6 +238,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/BUILD b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/BUILD index a406946d84e..654b9f0f4af 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/BUILD @@ -3,11 +3,13 @@ package(default_visibility = ["//visibility:public"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", + "go_test", ) go_library( name = "go_default_library", srcs = [ + "conversion.go", "doc.go", "generated.pb.go", "register.go", @@ -46,3 +48,14 @@ filegroup( srcs = ["generated.proto"], visibility = ["//visibility:public"], ) + +go_test( + name = "go_default_test", + srcs = ["conversion_test.go"], + library = ":go_default_library", + deps = [ + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", + ], +) 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/v1alpha1/zz_generated.conversion.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go index ddd12c1dfcd..bdf1fad1018 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go @@ -69,7 +69,15 @@ func autoConvert_v1alpha1_Event_To_audit_Event(in *Event, out *audit.Event, s co } out.ImpersonatedUser = (*audit.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs)) - out.ObjectRef = (*audit.ObjectReference)(unsafe.Pointer(in.ObjectRef)) + if in.ObjectRef != nil { + in, out := &in.ObjectRef, &out.ObjectRef + *out = new(audit.ObjectReference) + if err := Convert_v1alpha1_ObjectReference_To_audit_ObjectReference(*in, *out, s); err != nil { + return err + } + } else { + out.ObjectRef = nil + } out.ResponseStatus = (*v1.Status)(unsafe.Pointer(in.ResponseStatus)) out.RequestObject = (*runtime.Unknown)(unsafe.Pointer(in.RequestObject)) out.ResponseObject = (*runtime.Unknown)(unsafe.Pointer(in.ResponseObject)) @@ -95,7 +103,15 @@ func autoConvert_audit_Event_To_v1alpha1_Event(in *audit.Event, out *Event, s co } out.ImpersonatedUser = (*authentication_v1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs)) - out.ObjectRef = (*ObjectReference)(unsafe.Pointer(in.ObjectRef)) + if in.ObjectRef != nil { + in, out := &in.ObjectRef, &out.ObjectRef + *out = new(ObjectReference) + if err := Convert_audit_ObjectReference_To_v1alpha1_ObjectReference(*in, *out, s); err != nil { + return err + } + } else { + out.ObjectRef = nil + } out.ResponseStatus = (*v1.Status)(unsafe.Pointer(in.ResponseStatus)) out.RequestObject = (*runtime.Unknown)(unsafe.Pointer(in.RequestObject)) out.ResponseObject = (*runtime.Unknown)(unsafe.Pointer(in.ResponseObject)) @@ -109,7 +125,17 @@ func Convert_audit_Event_To_v1alpha1_Event(in *audit.Event, out *Event, s conver func autoConvert_v1alpha1_EventList_To_audit_EventList(in *EventList, out *audit.EventList, s conversion.Scope) error { out.ListMeta = in.ListMeta - out.Items = *(*[]audit.Event)(unsafe.Pointer(&in.Items)) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]audit.Event, len(*in)) + for i := range *in { + if err := Convert_v1alpha1_Event_To_audit_Event(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } return nil } @@ -120,7 +146,17 @@ func Convert_v1alpha1_EventList_To_audit_EventList(in *EventList, out *audit.Eve func autoConvert_audit_EventList_To_v1alpha1_EventList(in *audit.EventList, out *EventList, s conversion.Scope) error { out.ListMeta = in.ListMeta - out.Items = *(*[]Event)(unsafe.Pointer(&in.Items)) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Event, len(*in)) + for i := range *in { + if err := Convert_audit_Event_To_v1alpha1_Event(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } return nil } @@ -164,27 +200,18 @@ func autoConvert_v1alpha1_ObjectReference_To_audit_ObjectReference(in *ObjectRef return nil } -// Convert_v1alpha1_ObjectReference_To_audit_ObjectReference is an autogenerated conversion function. -func Convert_v1alpha1_ObjectReference_To_audit_ObjectReference(in *ObjectReference, out *audit.ObjectReference, s conversion.Scope) error { - return autoConvert_v1alpha1_ObjectReference_To_audit_ObjectReference(in, out, s) -} - func autoConvert_audit_ObjectReference_To_v1alpha1_ObjectReference(in *audit.ObjectReference, out *ObjectReference, s conversion.Scope) error { out.Resource = in.Resource out.Namespace = in.Namespace out.Name = in.Name out.UID = types.UID(in.UID) + // WARNING: in.APIGroup requires manual conversion: does not exist in peer-type out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.Subresource = in.Subresource return nil } -// Convert_audit_ObjectReference_To_v1alpha1_ObjectReference is an autogenerated conversion function. -func Convert_audit_ObjectReference_To_v1alpha1_ObjectReference(in *audit.ObjectReference, out *ObjectReference, s conversion.Scope) error { - return autoConvert_audit_ObjectReference_To_v1alpha1_ObjectReference(in, out, s) -} - func autoConvert_v1alpha1_Policy_To_audit_Policy(in *Policy, out *audit.Policy, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta out.Rules = *(*[]audit.PolicyRule)(unsafe.Pointer(&in.Rules)) 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 b60b78ec49f..87a95a85efb 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 @@ -232,10 +232,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/apis/audit/v1beta1/zz_generated.conversion.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go index 98ebeaf53d9..df704ef29e3 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go @@ -158,6 +158,7 @@ func autoConvert_v1beta1_ObjectReference_To_audit_ObjectReference(in *ObjectRefe out.Namespace = in.Namespace out.Name = in.Name out.UID = types.UID(in.UID) + out.APIGroup = in.APIGroup out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.Subresource = in.Subresource @@ -174,6 +175,7 @@ func autoConvert_audit_ObjectReference_To_v1beta1_ObjectReference(in *audit.Obje out.Namespace = in.Namespace out.Name = in.Name out.UID = types.UID(in.UID) + out.APIGroup = in.APIGroup out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.Subresource = in.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