mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
Merge pull request #49115 from CaoShuFeng/audit_beta
Automatic merge from submit-queue (batch tested with PRs 49115, 47480) Upgrade advanced audit to version v1beta1 This change does nothing but only upgrades advanced audit to version v1beta1. There will be following up changes which does real effect to advanced audit feature. After this change audit policy file should contain apiVersion and kind and has such format: ``` apiVersion: audit.k8s.io/v1alpha1 kind: Policy rules: - level: None ``` or use the v1beta1 policy: ``` apiVersion: audit.k8s.io/v1beta1 kind: Policy rules: - level: None ``` Updates #48561 **Release note**: ``` Upgrade advanced audit to version v1beta1. ```
This commit is contained in:
commit
49bee177b2
@ -607,6 +607,7 @@ staging/src/k8s.io/apiserver/pkg/apis/apiserver
|
||||
staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1
|
||||
staging/src/k8s.io/apiserver/pkg/apis/audit
|
||||
staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1
|
||||
staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1
|
||||
staging/src/k8s.io/apiserver/pkg/apis/audit/validation
|
||||
staging/src/k8s.io/apiserver/pkg/apis/example
|
||||
staging/src/k8s.io/apiserver/pkg/apis/example/v1
|
||||
|
@ -51,6 +51,7 @@ openapi_library(
|
||||
"k8s.io/apimachinery/pkg/util/intstr",
|
||||
"k8s.io/apimachinery/pkg/version",
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1alpha1",
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1beta1",
|
||||
"k8s.io/apiserver/pkg/apis/example/v1",
|
||||
"k8s.io/client-go/pkg/version",
|
||||
"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1",
|
||||
|
@ -34,8 +34,10 @@ filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer:all-srcs",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/install:all-srcs",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1:all-srcs",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1:all-srcs",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/validation:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
|
27
staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer/BUILD
Normal file
27
staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer/BUILD
Normal file
@ -0,0 +1,27 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fuzzer.go"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
53
staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer/fuzzer.go
Normal file
53
staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer/fuzzer.go
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
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 fuzzer
|
||||
|
||||
import (
|
||||
fuzz "github.com/google/gofuzz"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
)
|
||||
|
||||
// Funcs returns the fuzzer functions for the audit api group.
|
||||
func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(e *audit.Event, c fuzz.Continue) {
|
||||
switch c.RandBool() {
|
||||
case true:
|
||||
e.RequestObject = nil
|
||||
case false:
|
||||
e.RequestObject = &runtime.Unknown{
|
||||
TypeMeta: runtime.TypeMeta{APIVersion: "", Kind: ""},
|
||||
Raw: []byte(`{"apiVersion":"","kind":"Pod","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
}
|
||||
switch c.RandBool() {
|
||||
case true:
|
||||
e.ResponseObject = nil
|
||||
case false:
|
||||
e.ResponseObject = &runtime.Unknown{
|
||||
TypeMeta: runtime.TypeMeta{APIVersion: "", Kind: ""},
|
||||
Raw: []byte(`{"apiVersion":"","kind":"Pod","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"])
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
@ -15,6 +16,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -30,3 +32,13 @@ filegroup(
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["roundtrip_test.go"],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/fuzzer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
)
|
||||
|
||||
// Install registers the API group and adds types to a scheme
|
||||
@ -32,12 +33,13 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r
|
||||
if err := announced.NewGroupMetaFactory(
|
||||
&announced.GroupMetaFactoryArgs{
|
||||
GroupName: audit.GroupName,
|
||||
VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version},
|
||||
VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version, v1alpha1.SchemeGroupVersion.Version},
|
||||
// Any Kind that is not namespaced must be cluster scoped.
|
||||
RootScopedKinds: sets.NewString("Event", "Policy"),
|
||||
AddInternalObjectsToScheme: audit.AddToScheme,
|
||||
},
|
||||
announced.VersionToSchemeFunc{
|
||||
v1beta1.SchemeGroupVersion.Version: v1beta1.AddToScheme,
|
||||
v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme,
|
||||
},
|
||||
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
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 install
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
|
||||
"k8s.io/apiserver/pkg/apis/audit/fuzzer"
|
||||
)
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
roundtrip.RoundTripTestForAPIGroup(t, Install, fuzzer.Funcs)
|
||||
}
|
44
staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/BUILD
Normal file
44
staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/BUILD
Normal file
@ -0,0 +1,44 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.conversion.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
"zz_generated.defaults.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/authentication/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
23
staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/doc.go
Normal file
23
staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/doc.go
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
|
||||
// +groupName=audit.k8s.io
|
||||
package v1beta1 // import "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "audit.k8s.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addKnownTypes)
|
||||
}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Event{},
|
||||
&EventList{},
|
||||
&Policy{},
|
||||
&PolicyList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
234
staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go
Normal file
234
staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
authnv1 "k8s.io/api/authentication/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// Header keys used by the audit system.
|
||||
const (
|
||||
// Header to hold the audit ID as the request is propagated through the serving hierarchy. The
|
||||
// Audit-ID header should be set by the first server to receive the request (e.g. the federation
|
||||
// server or kube-aggregator).
|
||||
HeaderAuditID = "Audit-ID"
|
||||
)
|
||||
|
||||
// Level defines the amount of information logged during auditing
|
||||
type Level string
|
||||
|
||||
// Valid audit levels
|
||||
const (
|
||||
// LevelNone disables auditing
|
||||
LevelNone Level = "None"
|
||||
// LevelMetadata provides the basic level of auditing.
|
||||
LevelMetadata Level = "Metadata"
|
||||
// LevelRequest provides Metadata level of auditing, and additionally
|
||||
// logs the request object (does not apply for non-resource requests).
|
||||
LevelRequest Level = "Request"
|
||||
// LevelRequestResponse provides Request level of auditing, and additionally
|
||||
// logs the response object (does not apply for non-resource requests).
|
||||
LevelRequestResponse Level = "RequestResponse"
|
||||
)
|
||||
|
||||
// Stage defines the stages in request handling that audit events may be generated.
|
||||
type Stage string
|
||||
|
||||
// Valid audit stages.
|
||||
const (
|
||||
// The stage for events generated as soon as the audit handler receives the request, and before it
|
||||
// is delegated down the handler chain.
|
||||
StageRequestReceived = "RequestReceived"
|
||||
// The stage for events generated once the response headers are sent, but before the response body
|
||||
// is sent. This stage is only generated for long-running requests (e.g. watch).
|
||||
StageResponseStarted = "ResponseStarted"
|
||||
// The stage for events generated once the response body has been completed, and no more bytes
|
||||
// will be sent.
|
||||
StageResponseComplete = "ResponseComplete"
|
||||
// The stage for events generated when a panic occured.
|
||||
StagePanic = "Panic"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Event captures all the information that can be included in an API audit log.
|
||||
type Event struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// ObjectMeta is included for interoperability with API infrastructure.
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// AuditLevel at which event was generated
|
||||
Level Level `json:"level" protobuf:"bytes,2,opt,name=level,casttype=Level"`
|
||||
|
||||
// Time the request reached the apiserver.
|
||||
Timestamp metav1.Time `json:"timestamp" protobuf:"bytes,3,opt,name=timestamp"`
|
||||
// Unique audit ID, generated for each request.
|
||||
AuditID types.UID `json:"auditID" protobuf:"bytes,4,opt,name=auditID,casttype=k8s.io/apimachinery/pkg/types.UID"`
|
||||
// Stage of the request handling when this event instance was generated.
|
||||
Stage Stage `json:"stage" protobuf:"bytes,5,opt,name=stage,casttype=Stage"`
|
||||
|
||||
// RequestURI is the request URI as sent by the client to a server.
|
||||
RequestURI string `json:"requestURI" protobuf:"bytes,6,opt,name=requestURI"`
|
||||
// Verb is the kubernetes verb associated with the request.
|
||||
// For non-resource requests, this is the lower-cased HTTP method.
|
||||
Verb string `json:"verb" protobuf:"bytes,7,opt,name=verb"`
|
||||
// Authenticated user information.
|
||||
User authnv1.UserInfo `json:"user" protobuf:"bytes,8,opt,name=user"`
|
||||
// Impersonated user information.
|
||||
// +optional
|
||||
ImpersonatedUser *authnv1.UserInfo `json:"impersonatedUser,omitempty" protobuf:"bytes,9,opt,name=impersonatedUser"`
|
||||
// Source IPs, from where the request originated and intermediate proxies.
|
||||
// +optional
|
||||
SourceIPs []string `json:"sourceIPs,omitempty" protobuf:"bytes,10,rep,name=sourceIPs"`
|
||||
// Object reference this request is targeted at.
|
||||
// Does not apply for List-type requests, or non-resource requests.
|
||||
// +optional
|
||||
ObjectRef *ObjectReference `json:"objectRef,omitempty" protobuf:"bytes,11,opt,name=objectRef"`
|
||||
// The response status, populated even when the ResponseObject is not a Status type.
|
||||
// For successful responses, this will only include the Code and StatusSuccess.
|
||||
// For non-status type error responses, this will be auto-populated with the error Message.
|
||||
// +optional
|
||||
ResponseStatus *metav1.Status `json:"responseStatus,omitempty" protobuf:"bytes,12,opt,name=responseStatus"`
|
||||
|
||||
// API object from the request, in JSON format. The RequestObject is recorded as-is in the request
|
||||
// (possibly re-encoded as JSON), prior to version conversion, defaulting, admission or
|
||||
// merging. It is an external versioned object type, and may not be a valid object on its own.
|
||||
// Omitted for non-resource requests. Only logged at Request Level and higher.
|
||||
// +optional
|
||||
RequestObject *runtime.Unknown `json:"requestObject,omitempty" protobuf:"bytes,13,opt,name=requestObject"`
|
||||
// API object returned in the response, in JSON. The ResponseObject is recorded after conversion
|
||||
// to the external type, and serialized as JSON. Omitted for non-resource requests. Only logged
|
||||
// at Response Level.
|
||||
// +optional
|
||||
ResponseObject *runtime.Unknown `json:"responseObject,omitempty" protobuf:"bytes,14,opt,name=responseObject"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// EventList is a list of audit Events.
|
||||
type EventList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
Items []Event `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Policy defines the configuration of audit logging, and the rules for how different request
|
||||
// categories are logged.
|
||||
type Policy struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// ObjectMeta is included for interoperability with API infrastructure.
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Rules specify the audit Level a request should be recorded at.
|
||||
// A request may match multiple rules, in which case the FIRST matching rule is used.
|
||||
// The default audit level is None, but can be overridden by a catch-all rule at the end of the list.
|
||||
// PolicyRules are strictly ordered.
|
||||
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// PolicyList is a list of audit Policies.
|
||||
type PolicyList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
Items []Policy `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// PolicyRule maps requests based off metadata to an audit Level.
|
||||
// Requests must match the rules of every field (an intersection of rules).
|
||||
type PolicyRule struct {
|
||||
// The Level that requests matching this rule are recorded at.
|
||||
Level Level `json:"level" protobuf:"bytes,1,opt,name=level,casttype=Level"`
|
||||
|
||||
// The users (by authenticated user name) this rule applies to.
|
||||
// An empty list implies every user.
|
||||
// +optional
|
||||
Users []string `json:"users,omitempty" protobuf:"bytes,2,rep,name=users"`
|
||||
// The user groups this rule applies to. A user is considered matching
|
||||
// if it is a member of any of the UserGroups.
|
||||
// An empty list implies every user group.
|
||||
// +optional
|
||||
UserGroups []string `json:"userGroups,omitempty" protobuf:"bytes,3,rep,name=userGroups"`
|
||||
|
||||
// The verbs that match this rule.
|
||||
// An empty list implies every verb.
|
||||
// +optional
|
||||
Verbs []string `json:"verbs,omitempty" protobuf:"bytes,4,rep,name=verbs"`
|
||||
|
||||
// Rules can apply to API resources (such as "pods" or "secrets"),
|
||||
// non-resource URL paths (such as "/api"), or neither, but not both.
|
||||
// If neither is specified, the rule is treated as a default for all URLs.
|
||||
|
||||
// Resources that this rule matches. An empty list implies all kinds in all API groups.
|
||||
// +optional
|
||||
Resources []GroupResources `json:"resources,omitempty" protobuf:"bytes,5,rep,name=resources"`
|
||||
// Namespaces that this rule matches.
|
||||
// The empty string "" matches non-namespaced resources.
|
||||
// An empty list implies every namespace.
|
||||
// +optional
|
||||
Namespaces []string `json:"namespaces,omitempty" protobuf:"bytes,6,rep,name=namespaces"`
|
||||
|
||||
// NonResourceURLs is a set of URL paths that should be audited.
|
||||
// *s are allowed, but only as the full, final step in the path.
|
||||
// Examples:
|
||||
// "/metrics" - Log requests for apiserver metrics
|
||||
// "/healthz*" - Log all health checks
|
||||
// +optional
|
||||
NonResourceURLs []string `json:"nonResourceURLs,omitempty" protobuf:"bytes,7,rep,name=nonResourceURLs"`
|
||||
}
|
||||
|
||||
// GroupResources represents resource kinds in an API group.
|
||||
type GroupResources struct {
|
||||
// Group is the name of the API group that contains the resources.
|
||||
// The empty string represents the core API group.
|
||||
// +optional
|
||||
Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"`
|
||||
// Resources is a list of resources within the API group.
|
||||
// Any empty list implies every resource kind in the API group.
|
||||
// +optional
|
||||
Resources []string `json:"resources,omitempty" protobuf:"bytes,2,rep,name=resources"`
|
||||
}
|
||||
|
||||
// ObjectReference contains enough information to let you inspect or modify the referred object.
|
||||
type ObjectReference struct {
|
||||
// +optional
|
||||
Resource string `json:"resource,omitempty" protobuf:"bytes,1,opt,name=resource"`
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty" protobuf:"bytes,2,opt,name=namespace"`
|
||||
// +optional
|
||||
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"`
|
||||
// +optional
|
||||
APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,5,opt,name=apiVersion"`
|
||||
// +optional
|
||||
ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,6,opt,name=resourceVersion"`
|
||||
// +optional
|
||||
Subresource string `json:"subresource,omitempty" protobuf:"bytes,7,opt,name=subresource"`
|
||||
}
|
@ -0,0 +1,272 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by conversion-gen. Do not edit it manually!
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
authentication_v1 "k8s.io/api/authentication/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
audit "k8s.io/apiserver/pkg/apis/audit"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
localSchemeBuilder.Register(RegisterConversions)
|
||||
}
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedConversionFuncs(
|
||||
Convert_v1beta1_Event_To_audit_Event,
|
||||
Convert_audit_Event_To_v1beta1_Event,
|
||||
Convert_v1beta1_EventList_To_audit_EventList,
|
||||
Convert_audit_EventList_To_v1beta1_EventList,
|
||||
Convert_v1beta1_GroupResources_To_audit_GroupResources,
|
||||
Convert_audit_GroupResources_To_v1beta1_GroupResources,
|
||||
Convert_v1beta1_ObjectReference_To_audit_ObjectReference,
|
||||
Convert_audit_ObjectReference_To_v1beta1_ObjectReference,
|
||||
Convert_v1beta1_Policy_To_audit_Policy,
|
||||
Convert_audit_Policy_To_v1beta1_Policy,
|
||||
Convert_v1beta1_PolicyList_To_audit_PolicyList,
|
||||
Convert_audit_PolicyList_To_v1beta1_PolicyList,
|
||||
Convert_v1beta1_PolicyRule_To_audit_PolicyRule,
|
||||
Convert_audit_PolicyRule_To_v1beta1_PolicyRule,
|
||||
)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_Event_To_audit_Event(in *Event, out *audit.Event, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
out.Level = audit.Level(in.Level)
|
||||
out.Timestamp = in.Timestamp
|
||||
out.AuditID = types.UID(in.AuditID)
|
||||
out.Stage = audit.Stage(in.Stage)
|
||||
out.RequestURI = in.RequestURI
|
||||
out.Verb = in.Verb
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.User, &out.User, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ImpersonatedUser = (*audit.UserInfo)(unsafe.Pointer(in.ImpersonatedUser))
|
||||
out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs))
|
||||
out.ObjectRef = (*audit.ObjectReference)(unsafe.Pointer(in.ObjectRef))
|
||||
out.ResponseStatus = (*v1.Status)(unsafe.Pointer(in.ResponseStatus))
|
||||
out.RequestObject = (*runtime.Unknown)(unsafe.Pointer(in.RequestObject))
|
||||
out.ResponseObject = (*runtime.Unknown)(unsafe.Pointer(in.ResponseObject))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_Event_To_audit_Event is an autogenerated conversion function.
|
||||
func Convert_v1beta1_Event_To_audit_Event(in *Event, out *audit.Event, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_Event_To_audit_Event(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_audit_Event_To_v1beta1_Event(in *audit.Event, out *Event, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
out.Level = Level(in.Level)
|
||||
out.Timestamp = in.Timestamp
|
||||
out.AuditID = types.UID(in.AuditID)
|
||||
out.Stage = Stage(in.Stage)
|
||||
out.RequestURI = in.RequestURI
|
||||
out.Verb = in.Verb
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.User, &out.User, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ImpersonatedUser = (*authentication_v1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser))
|
||||
out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs))
|
||||
out.ObjectRef = (*ObjectReference)(unsafe.Pointer(in.ObjectRef))
|
||||
out.ResponseStatus = (*v1.Status)(unsafe.Pointer(in.ResponseStatus))
|
||||
out.RequestObject = (*runtime.Unknown)(unsafe.Pointer(in.RequestObject))
|
||||
out.ResponseObject = (*runtime.Unknown)(unsafe.Pointer(in.ResponseObject))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_audit_Event_To_v1beta1_Event is an autogenerated conversion function.
|
||||
func Convert_audit_Event_To_v1beta1_Event(in *audit.Event, out *Event, s conversion.Scope) error {
|
||||
return autoConvert_audit_Event_To_v1beta1_Event(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_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))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_EventList_To_audit_EventList is an autogenerated conversion function.
|
||||
func Convert_v1beta1_EventList_To_audit_EventList(in *EventList, out *audit.EventList, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_EventList_To_audit_EventList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_audit_EventList_To_v1beta1_EventList(in *audit.EventList, out *EventList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items == nil {
|
||||
out.Items = make([]Event, 0)
|
||||
} else {
|
||||
out.Items = *(*[]Event)(unsafe.Pointer(&in.Items))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_audit_EventList_To_v1beta1_EventList is an autogenerated conversion function.
|
||||
func Convert_audit_EventList_To_v1beta1_EventList(in *audit.EventList, out *EventList, s conversion.Scope) error {
|
||||
return autoConvert_audit_EventList_To_v1beta1_EventList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_GroupResources_To_audit_GroupResources(in *GroupResources, out *audit.GroupResources, s conversion.Scope) error {
|
||||
out.Group = in.Group
|
||||
out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_GroupResources_To_audit_GroupResources is an autogenerated conversion function.
|
||||
func Convert_v1beta1_GroupResources_To_audit_GroupResources(in *GroupResources, out *audit.GroupResources, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_GroupResources_To_audit_GroupResources(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_audit_GroupResources_To_v1beta1_GroupResources(in *audit.GroupResources, out *GroupResources, s conversion.Scope) error {
|
||||
out.Group = in.Group
|
||||
out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_audit_GroupResources_To_v1beta1_GroupResources is an autogenerated conversion function.
|
||||
func Convert_audit_GroupResources_To_v1beta1_GroupResources(in *audit.GroupResources, out *GroupResources, s conversion.Scope) error {
|
||||
return autoConvert_audit_GroupResources_To_v1beta1_GroupResources(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_ObjectReference_To_audit_ObjectReference(in *ObjectReference, out *audit.ObjectReference, s conversion.Scope) error {
|
||||
out.Resource = in.Resource
|
||||
out.Namespace = in.Namespace
|
||||
out.Name = in.Name
|
||||
out.UID = types.UID(in.UID)
|
||||
out.APIVersion = in.APIVersion
|
||||
out.ResourceVersion = in.ResourceVersion
|
||||
out.Subresource = in.Subresource
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_ObjectReference_To_audit_ObjectReference is an autogenerated conversion function.
|
||||
func Convert_v1beta1_ObjectReference_To_audit_ObjectReference(in *ObjectReference, out *audit.ObjectReference, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_ObjectReference_To_audit_ObjectReference(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_audit_ObjectReference_To_v1beta1_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)
|
||||
out.APIVersion = in.APIVersion
|
||||
out.ResourceVersion = in.ResourceVersion
|
||||
out.Subresource = in.Subresource
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_audit_ObjectReference_To_v1beta1_ObjectReference is an autogenerated conversion function.
|
||||
func Convert_audit_ObjectReference_To_v1beta1_ObjectReference(in *audit.ObjectReference, out *ObjectReference, s conversion.Scope) error {
|
||||
return autoConvert_audit_ObjectReference_To_v1beta1_ObjectReference(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_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))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_Policy_To_audit_Policy is an autogenerated conversion function.
|
||||
func Convert_v1beta1_Policy_To_audit_Policy(in *Policy, out *audit.Policy, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_Policy_To_audit_Policy(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_audit_Policy_To_v1beta1_Policy(in *audit.Policy, out *Policy, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if in.Rules == nil {
|
||||
out.Rules = make([]PolicyRule, 0)
|
||||
} else {
|
||||
out.Rules = *(*[]PolicyRule)(unsafe.Pointer(&in.Rules))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_audit_Policy_To_v1beta1_Policy is an autogenerated conversion function.
|
||||
func Convert_audit_Policy_To_v1beta1_Policy(in *audit.Policy, out *Policy, s conversion.Scope) error {
|
||||
return autoConvert_audit_Policy_To_v1beta1_Policy(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_PolicyList_To_audit_PolicyList(in *PolicyList, out *audit.PolicyList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]audit.Policy)(unsafe.Pointer(&in.Items))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_PolicyList_To_audit_PolicyList is an autogenerated conversion function.
|
||||
func Convert_v1beta1_PolicyList_To_audit_PolicyList(in *PolicyList, out *audit.PolicyList, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_PolicyList_To_audit_PolicyList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_audit_PolicyList_To_v1beta1_PolicyList(in *audit.PolicyList, out *PolicyList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items == nil {
|
||||
out.Items = make([]Policy, 0)
|
||||
} else {
|
||||
out.Items = *(*[]Policy)(unsafe.Pointer(&in.Items))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_audit_PolicyList_To_v1beta1_PolicyList is an autogenerated conversion function.
|
||||
func Convert_audit_PolicyList_To_v1beta1_PolicyList(in *audit.PolicyList, out *PolicyList, s conversion.Scope) error {
|
||||
return autoConvert_audit_PolicyList_To_v1beta1_PolicyList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_PolicyRule_To_audit_PolicyRule(in *PolicyRule, out *audit.PolicyRule, s conversion.Scope) error {
|
||||
out.Level = audit.Level(in.Level)
|
||||
out.Users = *(*[]string)(unsafe.Pointer(&in.Users))
|
||||
out.UserGroups = *(*[]string)(unsafe.Pointer(&in.UserGroups))
|
||||
out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
|
||||
out.Resources = *(*[]audit.GroupResources)(unsafe.Pointer(&in.Resources))
|
||||
out.Namespaces = *(*[]string)(unsafe.Pointer(&in.Namespaces))
|
||||
out.NonResourceURLs = *(*[]string)(unsafe.Pointer(&in.NonResourceURLs))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_PolicyRule_To_audit_PolicyRule is an autogenerated conversion function.
|
||||
func Convert_v1beta1_PolicyRule_To_audit_PolicyRule(in *PolicyRule, out *audit.PolicyRule, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_PolicyRule_To_audit_PolicyRule(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_audit_PolicyRule_To_v1beta1_PolicyRule(in *audit.PolicyRule, out *PolicyRule, s conversion.Scope) error {
|
||||
out.Level = Level(in.Level)
|
||||
out.Users = *(*[]string)(unsafe.Pointer(&in.Users))
|
||||
out.UserGroups = *(*[]string)(unsafe.Pointer(&in.UserGroups))
|
||||
out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
|
||||
out.Resources = *(*[]GroupResources)(unsafe.Pointer(&in.Resources))
|
||||
out.Namespaces = *(*[]string)(unsafe.Pointer(&in.Namespaces))
|
||||
out.NonResourceURLs = *(*[]string)(unsafe.Pointer(&in.NonResourceURLs))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_audit_PolicyRule_To_v1beta1_PolicyRule is an autogenerated conversion function.
|
||||
func Convert_audit_PolicyRule_To_v1beta1_PolicyRule(in *audit.PolicyRule, out *PolicyRule, s conversion.Scope) error {
|
||||
return autoConvert_audit_PolicyRule_To_v1beta1_PolicyRule(in, out, s)
|
||||
}
|
@ -0,0 +1,336 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/authentication/v1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(RegisterDeepCopies)
|
||||
}
|
||||
|
||||
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
|
||||
// to allow building arbitrary schemes.
|
||||
//
|
||||
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
|
||||
func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedDeepCopyFuncs(
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Event).DeepCopyInto(out.(*Event))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Event{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*EventList).DeepCopyInto(out.(*EventList))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&EventList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*GroupResources).DeepCopyInto(out.(*GroupResources))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&GroupResources{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*ObjectReference).DeepCopyInto(out.(*ObjectReference))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&ObjectReference{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Policy).DeepCopyInto(out.(*Policy))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Policy{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*PolicyList).DeepCopyInto(out.(*PolicyList))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&PolicyList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*PolicyRule).DeepCopyInto(out.(*PolicyRule))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&PolicyRule{})},
|
||||
)
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Event) DeepCopyInto(out *Event) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Timestamp.DeepCopyInto(&out.Timestamp)
|
||||
in.User.DeepCopyInto(&out.User)
|
||||
if in.ImpersonatedUser != nil {
|
||||
in, out := &in.ImpersonatedUser, &out.ImpersonatedUser
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(v1.UserInfo)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.SourceIPs != nil {
|
||||
in, out := &in.SourceIPs, &out.SourceIPs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ObjectRef != nil {
|
||||
in, out := &in.ObjectRef, &out.ObjectRef
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(ObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ResponseStatus != nil {
|
||||
in, out := &in.ResponseStatus, &out.ResponseStatus
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(meta_v1.Status)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.RequestObject != nil {
|
||||
in, out := &in.RequestObject, &out.RequestObject
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(runtime.Unknown)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.ResponseObject != nil {
|
||||
in, out := &in.ResponseObject, &out.ResponseObject
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(runtime.Unknown)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Event.
|
||||
func (in *Event) DeepCopy() *Event {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Event)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Event) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *EventList) DeepCopyInto(out *EventList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Event, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventList.
|
||||
func (in *EventList) DeepCopy() *EventList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(EventList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *EventList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *GroupResources) DeepCopyInto(out *GroupResources) {
|
||||
*out = *in
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupResources.
|
||||
func (in *GroupResources) DeepCopy() *GroupResources {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(GroupResources)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ObjectReference) DeepCopyInto(out *ObjectReference) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectReference.
|
||||
func (in *ObjectReference) DeepCopy() *ObjectReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ObjectReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Policy) DeepCopyInto(out *Policy) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Policy.
|
||||
func (in *Policy) DeepCopy() *Policy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Policy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Policy) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PolicyList) DeepCopyInto(out *PolicyList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Policy, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyList.
|
||||
func (in *PolicyList) DeepCopy() *PolicyList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PolicyList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *PolicyList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PolicyRule) DeepCopyInto(out *PolicyRule) {
|
||||
*out = *in
|
||||
if in.Users != nil {
|
||||
in, out := &in.Users, &out.Users
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserGroups != nil {
|
||||
in, out := &in.UserGroups, &out.UserGroups
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Verbs != nil {
|
||||
in, out := &in.Verbs, &out.Verbs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make([]GroupResources, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Namespaces != nil {
|
||||
in, out := &in.Namespaces, &out.Namespaces
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.NonResourceURLs != nil {
|
||||
in, out := &in.NonResourceURLs, &out.NonResourceURLs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyRule.
|
||||
func (in *PolicyRule) DeepCopy() *PolicyRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PolicyRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by defaulter-gen. Do not edit it manually!
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
// All generated defaulters are covering - they call all nested defaulters.
|
||||
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
return nil
|
||||
}
|
@ -30,6 +30,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -20,6 +20,7 @@ go_test(
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/plugin/pkg/audit/webhook:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -34,6 +35,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/validation:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
"k8s.io/apiserver/pkg/apis/audit/validation"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
|
||||
@ -38,16 +39,10 @@ func LoadPolicyFromFile(filePath string) (*auditinternal.Policy, error) {
|
||||
return nil, fmt.Errorf("failed to read file path %q: %+v", filePath, err)
|
||||
}
|
||||
|
||||
policyVersioned := &auditv1alpha1.Policy{}
|
||||
|
||||
decoder := audit.Codecs.UniversalDecoder(auditv1alpha1.SchemeGroupVersion)
|
||||
if err := runtime.DecodeInto(decoder, policyDef, policyVersioned); err != nil {
|
||||
return nil, fmt.Errorf("failed decoding file %q: %v", filePath, err)
|
||||
}
|
||||
|
||||
policy := &auditinternal.Policy{}
|
||||
if err := audit.Scheme.Convert(policyVersioned, policy, nil); err != nil {
|
||||
return nil, fmt.Errorf("failed converting policy: %v", err)
|
||||
decoder := audit.Codecs.UniversalDecoder(auditv1beta1.SchemeGroupVersion, auditv1alpha1.SchemeGroupVersion)
|
||||
if err := runtime.DecodeInto(decoder, policyDef, policy); err != nil {
|
||||
return nil, fmt.Errorf("failed decoding file %q: %v", filePath, err)
|
||||
}
|
||||
|
||||
if err := validation.ValidatePolicy(policy); err != nil {
|
||||
|
@ -24,12 +24,36 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
// import to call webhook's init() function to register audit.Policy to schema
|
||||
_ "k8s.io/apiserver/plugin/pkg/audit/webhook"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const policyDef = `
|
||||
const policyDefV1alpha1 = `
|
||||
apiVersion: audit.k8s.io/v1beta1
|
||||
kind: Policy
|
||||
rules:
|
||||
- level: None
|
||||
nonResourceURLs:
|
||||
- /healthz*
|
||||
- /version
|
||||
- level: RequestResponse
|
||||
users: ["tim"]
|
||||
userGroups: ["testers", "developers"]
|
||||
verbs: ["patch", "delete", "create"]
|
||||
resources:
|
||||
- group: ""
|
||||
- group: "rbac.authorization.k8s.io"
|
||||
resources: ["clusterroles", "clusterrolebindings"]
|
||||
namespaces: ["default", "kube-system"]
|
||||
- level: Metadata
|
||||
`
|
||||
|
||||
const policyDefV1beta1 = `
|
||||
apiVersion: audit.k8s.io/v1beta1
|
||||
kind: Policy
|
||||
rules:
|
||||
- level: None
|
||||
nonResourceURLs:
|
||||
@ -66,13 +90,32 @@ var expectedPolicy = &audit.Policy{
|
||||
}},
|
||||
}
|
||||
|
||||
func TestParser(t *testing.T) {
|
||||
func TestParserV1alpha1(t *testing.T) {
|
||||
// Create a policy file.
|
||||
f, err := ioutil.TempFile("", "policy.yaml")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
_, err = f.WriteString(policyDef)
|
||||
_, err = f.WriteString(policyDefV1alpha1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
policy, err := LoadPolicyFromFile(f.Name())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, policy.Rules, 3) // Sanity check.
|
||||
if !reflect.DeepEqual(policy, expectedPolicy) {
|
||||
t.Errorf("Unexpected policy! Diff:\n%s", diff.ObjectDiff(policy, expectedPolicy))
|
||||
}
|
||||
}
|
||||
|
||||
func TestParserV1beta1(t *testing.T) {
|
||||
// Create a policy file.
|
||||
f, err := ioutil.TempFile("", "policy.yaml")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
_, err = f.WriteString(policyDefV1beta1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
)
|
||||
|
||||
var Scheme = runtime.NewScheme()
|
||||
@ -31,4 +32,5 @@ var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
func init() {
|
||||
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||
v1alpha1.AddToScheme(Scheme)
|
||||
v1beta1.AddToScheme(Scheme)
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ go_test(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
|
||||
|
@ -37,7 +37,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/audit/policy"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
@ -441,7 +441,7 @@ func TestAuditJson(t *testing.T) {
|
||||
verb string
|
||||
auditID string
|
||||
handler func(http.ResponseWriter, *http.Request)
|
||||
expected []auditv1alpha1.Event
|
||||
expected []auditv1beta1.Event
|
||||
respHeader bool
|
||||
}{
|
||||
// short running requests with read-only verb
|
||||
@ -451,7 +451,7 @@ func TestAuditJson(t *testing.T) {
|
||||
"GET",
|
||||
"",
|
||||
func(http.ResponseWriter, *http.Request) {},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "get",
|
||||
@ -474,7 +474,7 @@ func TestAuditJson(t *testing.T) {
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Write([]byte("foo"))
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "get",
|
||||
@ -497,7 +497,7 @@ func TestAuditJson(t *testing.T) {
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
panic("kaboom")
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "get",
|
||||
@ -519,7 +519,7 @@ func TestAuditJson(t *testing.T) {
|
||||
"PUT",
|
||||
"",
|
||||
func(http.ResponseWriter, *http.Request) {},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "update",
|
||||
@ -543,7 +543,7 @@ func TestAuditJson(t *testing.T) {
|
||||
w.Write([]byte("foo"))
|
||||
time.Sleep(delay)
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "update",
|
||||
@ -567,7 +567,7 @@ func TestAuditJson(t *testing.T) {
|
||||
w.WriteHeader(403)
|
||||
w.Write([]byte("foo"))
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "update",
|
||||
@ -590,7 +590,7 @@ func TestAuditJson(t *testing.T) {
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
panic("kaboom")
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "update",
|
||||
@ -614,7 +614,7 @@ func TestAuditJson(t *testing.T) {
|
||||
w.Write([]byte("foo"))
|
||||
panic("kaboom")
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "update",
|
||||
@ -636,7 +636,7 @@ func TestAuditJson(t *testing.T) {
|
||||
"GET",
|
||||
"",
|
||||
func(http.ResponseWriter, *http.Request) {},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "watch",
|
||||
@ -665,7 +665,7 @@ func TestAuditJson(t *testing.T) {
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Write([]byte("foo"))
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "watch",
|
||||
@ -694,7 +694,7 @@ func TestAuditJson(t *testing.T) {
|
||||
func(http.ResponseWriter, *http.Request) {
|
||||
time.Sleep(delay)
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "watch",
|
||||
@ -724,7 +724,7 @@ func TestAuditJson(t *testing.T) {
|
||||
time.Sleep(delay)
|
||||
w.WriteHeader(403)
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "watch",
|
||||
@ -753,7 +753,7 @@ func TestAuditJson(t *testing.T) {
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Write([]byte("foo"))
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "watch",
|
||||
@ -783,7 +783,7 @@ func TestAuditJson(t *testing.T) {
|
||||
w.WriteHeader(403)
|
||||
w.Write([]byte("foo"))
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "watch",
|
||||
@ -812,7 +812,7 @@ func TestAuditJson(t *testing.T) {
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
panic("kaboom")
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "watch",
|
||||
@ -836,7 +836,7 @@ func TestAuditJson(t *testing.T) {
|
||||
w.Write([]byte("foo"))
|
||||
panic("kaboom")
|
||||
},
|
||||
[]auditv1alpha1.Event{
|
||||
[]auditv1beta1.Event{
|
||||
{
|
||||
Stage: auditinternal.StageRequestReceived,
|
||||
Verb: "watch",
|
||||
@ -892,8 +892,8 @@ func TestAuditJson(t *testing.T) {
|
||||
expectedID := types.UID("")
|
||||
for i, expect := range test.expected {
|
||||
// decode events back to check json elements.
|
||||
event := &auditv1alpha1.Event{}
|
||||
decoder := audit.Codecs.UniversalDecoder(auditv1alpha1.SchemeGroupVersion)
|
||||
event := &auditv1beta1.Event{}
|
||||
decoder := audit.Codecs.UniversalDecoder(auditv1beta1.SchemeGroupVersion)
|
||||
if err := runtime.DecodeInto(decoder, []byte(line[i]), event); err != nil {
|
||||
t.Errorf("failed decoding line %s: %v", line[i], err)
|
||||
continue
|
||||
|
@ -51,6 +51,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory:go_default_library",
|
||||
|
@ -25,6 +25,8 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/audit/policy"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
@ -237,7 +239,8 @@ func (o *AuditWebhookOptions) applyTo(c *server.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, o.Mode)
|
||||
// TODO: switch to beta
|
||||
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, o.Mode, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing audit webhook: %v", err)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ go_library(
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
)
|
||||
|
||||
@ -66,7 +66,8 @@ func (b *backend) logEvent(ev *auditinternal.Event) {
|
||||
case FormatLegacy:
|
||||
line = audit.EventString(ev) + "\n"
|
||||
case FormatJson:
|
||||
bs, err := runtime.Encode(audit.Codecs.LegacyCodec(auditv1alpha1.SchemeGroupVersion), ev)
|
||||
// TODO(audit): figure out a general way to let the client choose their preferred version
|
||||
bs, err := runtime.Encode(audit.Codecs.LegacyCodec(auditv1beta1.SchemeGroupVersion), ev)
|
||||
if err != nil {
|
||||
audit.HandlePluginError("log", err, ev)
|
||||
return
|
||||
|
@ -8,15 +8,20 @@ load(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["webhook_test.go"],
|
||||
srcs = [
|
||||
"webhook_test.go",
|
||||
"webhook_v1alpha1_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/require:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api/v1:go_default_library",
|
||||
],
|
||||
@ -35,6 +40,7 @@ go_library(
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/install:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/webhook:go_default_library",
|
||||
],
|
||||
|
@ -33,6 +33,7 @@ import (
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/apis/audit/install"
|
||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/util/webhook"
|
||||
)
|
||||
@ -70,12 +71,12 @@ const pluginName = "webhook"
|
||||
// NewBackend returns an audit backend that sends events over HTTP to an external service.
|
||||
// The mode indicates the caching behavior of the webhook. Either blocking (ModeBlocking)
|
||||
// or buffered with batch POSTs (ModeBatch).
|
||||
func NewBackend(kubeConfigFile string, mode string) (audit.Backend, error) {
|
||||
func NewBackend(kubeConfigFile string, mode string, groupVersions []schema.GroupVersion) (audit.Backend, error) {
|
||||
switch mode {
|
||||
case ModeBatch:
|
||||
return newBatchWebhook(kubeConfigFile)
|
||||
return newBatchWebhook(kubeConfigFile, groupVersions)
|
||||
case ModeBlocking:
|
||||
return newBlockingWebhook(kubeConfigFile)
|
||||
return newBlockingWebhook(kubeConfigFile, groupVersions)
|
||||
default:
|
||||
return nil, fmt.Errorf("webhook mode %q is not in list of known modes (%s)",
|
||||
mode, strings.Join(AllowedModes, ","))
|
||||
@ -87,24 +88,25 @@ var (
|
||||
//
|
||||
// Can we make these passable to NewGenericWebhook?
|
||||
groupFactoryRegistry = make(announced.APIGroupFactoryRegistry)
|
||||
groupVersions = []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion}
|
||||
registry = registered.NewOrDie("")
|
||||
// TODO(audit): figure out a general way to let the client choose their preferred version
|
||||
registry = registered.NewOrDie("")
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.RegisterVersions(groupVersions)
|
||||
if err := registry.EnableVersions(groupVersions...); err != nil {
|
||||
panic(fmt.Sprintf("failed to enable version %v", groupVersions))
|
||||
allGVs := []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion, auditv1beta1.SchemeGroupVersion}
|
||||
registry.RegisterVersions(allGVs)
|
||||
if err := registry.EnableVersions(allGVs...); err != nil {
|
||||
panic(fmt.Sprintf("failed to enable version %v", allGVs))
|
||||
}
|
||||
install.Install(groupFactoryRegistry, registry, audit.Scheme)
|
||||
}
|
||||
|
||||
func loadWebhook(configFile string) (*webhook.GenericWebhook, error) {
|
||||
func loadWebhook(configFile string, groupVersions []schema.GroupVersion) (*webhook.GenericWebhook, error) {
|
||||
return webhook.NewGenericWebhook(registry, audit.Codecs, configFile, groupVersions, 0)
|
||||
}
|
||||
|
||||
func newBlockingWebhook(configFile string) (*blockingBackend, error) {
|
||||
w, err := loadWebhook(configFile)
|
||||
func newBlockingWebhook(configFile string, groupVersions []schema.GroupVersion) (*blockingBackend, error) {
|
||||
w, err := loadWebhook(configFile, groupVersions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -139,8 +141,8 @@ func (b *blockingBackend) processEvents(ev ...*auditinternal.Event) error {
|
||||
return b.w.RestClient.Post().Body(&list).Do().Error()
|
||||
}
|
||||
|
||||
func newBatchWebhook(configFile string) (*batchBackend, error) {
|
||||
w, err := loadWebhook(configFile)
|
||||
func newBatchWebhook(configFile string, groupVersions []schema.GroupVersion) (*batchBackend, error) {
|
||||
w, err := loadWebhook(configFile, groupVersions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@ -33,19 +34,22 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/client-go/tools/clientcmd/api/v1"
|
||||
)
|
||||
|
||||
// newWebhookHandler returns a handler which recieves webhook events and decodes the
|
||||
// request body. The caller passes a callback which is called on each webhook POST.
|
||||
func newWebhookHandler(t *testing.T, cb func(events *auditv1alpha1.EventList)) http.Handler {
|
||||
// The object passed to cb is of the same type as list.
|
||||
func newWebhookHandler(t *testing.T, list runtime.Object, cb func(events runtime.Object)) http.Handler {
|
||||
s := json.NewSerializer(json.DefaultMetaFactory, audit.Scheme, audit.Scheme, false)
|
||||
return &testWebhookHandler{
|
||||
t: t,
|
||||
list: list,
|
||||
onEvents: cb,
|
||||
serializer: s,
|
||||
}
|
||||
@ -54,7 +58,8 @@ func newWebhookHandler(t *testing.T, cb func(events *auditv1alpha1.EventList)) h
|
||||
type testWebhookHandler struct {
|
||||
t *testing.T
|
||||
|
||||
onEvents func(events *auditv1alpha1.EventList)
|
||||
list runtime.Object
|
||||
onEvents func(events runtime.Object)
|
||||
|
||||
serializer runtime.Serializer
|
||||
}
|
||||
@ -66,15 +71,14 @@ func (t *testWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return fmt.Errorf("read webhook request body: %v", err)
|
||||
}
|
||||
|
||||
obj, _, err := t.serializer.Decode(body, nil, &auditv1alpha1.EventList{})
|
||||
obj, _, err := t.serializer.Decode(body, nil, t.list.DeepCopyObject())
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode request body: %v", err)
|
||||
}
|
||||
list, ok := obj.(*auditv1alpha1.EventList)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected *v1alpha1.EventList got %T", obj)
|
||||
if reflect.TypeOf(obj).Elem() != reflect.TypeOf(t.list).Elem() {
|
||||
return fmt.Errorf("expected %T, got %T", t.list, obj)
|
||||
}
|
||||
t.onEvents(list)
|
||||
t.onEvents(obj)
|
||||
return nil
|
||||
}()
|
||||
|
||||
@ -87,15 +91,15 @@ func (t *testWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func newTestBlockingWebhook(t *testing.T, endpoint string) *blockingBackend {
|
||||
return newWebhook(t, endpoint, ModeBlocking).(*blockingBackend)
|
||||
func newTestBlockingWebhook(t *testing.T, endpoint string, groupVersions []schema.GroupVersion) *blockingBackend {
|
||||
return newWebhook(t, endpoint, ModeBlocking, groupVersions).(*blockingBackend)
|
||||
}
|
||||
|
||||
func newTestBatchWebhook(t *testing.T, endpoint string) *batchBackend {
|
||||
return newWebhook(t, endpoint, ModeBatch).(*batchBackend)
|
||||
func newTestBatchWebhook(t *testing.T, endpoint string, groupVersions []schema.GroupVersion) *batchBackend {
|
||||
return newWebhook(t, endpoint, ModeBatch, groupVersions).(*batchBackend)
|
||||
}
|
||||
|
||||
func newWebhook(t *testing.T, endpoint string, mode string) audit.Backend {
|
||||
func newWebhook(t *testing.T, endpoint string, mode string, groupVersions []schema.GroupVersion) audit.Backend {
|
||||
config := v1.Config{
|
||||
Clusters: []v1.NamedCluster{
|
||||
{Cluster: v1.Cluster{Server: endpoint, InsecureSkipTLSVerify: true}},
|
||||
@ -112,7 +116,7 @@ func newWebhook(t *testing.T, endpoint string, mode string) audit.Backend {
|
||||
// NOTE(ericchiang): Do we need to use a proper serializer?
|
||||
require.NoError(t, stdjson.NewEncoder(f).Encode(config), "writing kubeconfig")
|
||||
|
||||
backend, err := NewBackend(f.Name(), mode)
|
||||
backend, err := NewBackend(f.Name(), mode, groupVersions)
|
||||
require.NoError(t, err, "initializing backend")
|
||||
|
||||
return backend
|
||||
@ -122,12 +126,12 @@ func TestWebhook(t *testing.T) {
|
||||
gotEvents := false
|
||||
defer func() { require.True(t, gotEvents, "no events received") }()
|
||||
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
|
||||
gotEvents = true
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBlockingWebhook(t, s.URL)
|
||||
backend := newTestBlockingWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
|
||||
// Ensure this doesn't return a serialization error.
|
||||
event := &auditinternal.Event{}
|
||||
@ -151,12 +155,12 @@ func TestBatchWebhookMaxEvents(t *testing.T) {
|
||||
}
|
||||
|
||||
got := make(chan int, 2)
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
got <- len(events.Items)
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
|
||||
got <- len(events.(*auditv1beta1.EventList).Items)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL)
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
|
||||
backend.ProcessEvents(events...)
|
||||
|
||||
@ -183,12 +187,12 @@ func TestBatchWebhookStopCh(t *testing.T) {
|
||||
|
||||
expected := len(events)
|
||||
got := make(chan int, 2)
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
got <- len(events.Items)
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
|
||||
got <- len(events.(*auditv1beta1.EventList).Items)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL)
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
backend.ProcessEvents(events...)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
@ -209,12 +213,12 @@ func TestBatchWebhookProcessEventsAfterStop(t *testing.T) {
|
||||
}
|
||||
|
||||
got := make(chan struct{})
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
|
||||
close(got)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL)
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
backend.Run(stopCh)
|
||||
@ -233,13 +237,13 @@ func TestBatchWebhookShutdown(t *testing.T) {
|
||||
got := make(chan struct{})
|
||||
contReqCh := make(chan struct{})
|
||||
shutdownCh := make(chan struct{})
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
|
||||
close(got)
|
||||
<-contReqCh
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL)
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
backend.ProcessEvents(events...)
|
||||
|
||||
go func() {
|
||||
@ -278,12 +282,12 @@ func TestBatchWebhookEmptyBuffer(t *testing.T) {
|
||||
|
||||
expected := len(events)
|
||||
got := make(chan int, 2)
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
got <- len(events.Items)
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
|
||||
got <- len(events.(*auditv1beta1.EventList).Items)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL)
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
timer := make(chan time.Time, 1)
|
||||
@ -311,12 +315,12 @@ func TestBatchBufferFull(t *testing.T) {
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
|
||||
// Do nothing.
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL)
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
|
||||
// Make sure this doesn't block.
|
||||
backend.ProcessEvents(events...)
|
||||
@ -344,7 +348,8 @@ func TestBatchRun(t *testing.T) {
|
||||
close(done)
|
||||
}()
|
||||
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(obj runtime.Object) {
|
||||
events := obj.(*auditv1beta1.EventList)
|
||||
atomic.AddInt64(got, int64(len(events.Items)))
|
||||
wg.Add(-len(events.Items))
|
||||
}))
|
||||
@ -353,7 +358,7 @@ func TestBatchRun(t *testing.T) {
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL)
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
|
||||
// Test the Run codepath. E.g. that the spawned goroutines behave correctly.
|
||||
backend.Run(stopCh)
|
||||
@ -377,8 +382,8 @@ func TestBatchConcurrentRequests(t *testing.T) {
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(len(events))
|
||||
|
||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
||||
wg.Add(-len(events.Items))
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
|
||||
wg.Add(-len(events.(*auditv1beta1.EventList).Items))
|
||||
|
||||
// Since the webhook makes concurrent requests, blocking on the webhook response
|
||||
// shouldn't block the webhook from sending more events.
|
||||
@ -391,7 +396,7 @@ func TestBatchConcurrentRequests(t *testing.T) {
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL)
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
|
||||
backend.Run(stopCh)
|
||||
|
||||
backend.ProcessEvents(events...)
|
||||
|
@ -0,0 +1,290 @@
|
||||
/*
|
||||
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 webhook
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
)
|
||||
|
||||
func TestBatchWebhookMaxEventsV1Alpha1(t *testing.T) {
|
||||
nRest := 10
|
||||
events := make([]*auditinternal.Event, defaultBatchMaxSize+nRest) // greater than max size.
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
|
||||
got := make(chan int, 2)
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
|
||||
got <- len(events.(*auditv1alpha1.EventList).Items)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
|
||||
backend.ProcessEvents(events...)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
timer := make(chan time.Time, 1)
|
||||
|
||||
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
|
||||
require.Equal(t, defaultBatchMaxSize, <-got, "did not get batch max size")
|
||||
|
||||
go func() {
|
||||
waitForEmptyBuffer(backend) // wait for the buffer to empty
|
||||
timer <- time.Now() // Trigger the wait timeout
|
||||
}()
|
||||
|
||||
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
|
||||
require.Equal(t, nRest, <-got, "failed to get the rest of the events")
|
||||
}
|
||||
|
||||
func TestBatchWebhookStopChV1Alpha1(t *testing.T) {
|
||||
events := make([]*auditinternal.Event, 1) // less than max size.
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
|
||||
expected := len(events)
|
||||
got := make(chan int, 2)
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
|
||||
got <- len(events.(*auditv1alpha1.EventList).Items)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
backend.ProcessEvents(events...)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
timer := make(chan time.Time)
|
||||
|
||||
go func() {
|
||||
waitForEmptyBuffer(backend)
|
||||
close(stopCh) // stop channel has stopped
|
||||
}()
|
||||
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
|
||||
require.Equal(t, expected, <-got, "get queued events after timer expires")
|
||||
}
|
||||
|
||||
func TestBatchWebhookProcessEventsAfterStopV1Alpha1(t *testing.T) {
|
||||
events := make([]*auditinternal.Event, 1) // less than max size.
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
|
||||
got := make(chan struct{})
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
|
||||
close(got)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
backend.Run(stopCh)
|
||||
close(stopCh)
|
||||
<-backend.shutdownCh
|
||||
backend.ProcessEvents(events...)
|
||||
assert.Equal(t, 0, len(backend.buffer), "processed events after the backed has been stopped")
|
||||
}
|
||||
|
||||
func TestBatchWebhookShutdownV1Alpha1(t *testing.T) {
|
||||
events := make([]*auditinternal.Event, 1)
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
|
||||
got := make(chan struct{})
|
||||
contReqCh := make(chan struct{})
|
||||
shutdownCh := make(chan struct{})
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
|
||||
close(got)
|
||||
<-contReqCh
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
backend.ProcessEvents(events...)
|
||||
|
||||
go func() {
|
||||
// Assume stopCh was closed.
|
||||
close(backend.buffer)
|
||||
backend.sendBatchEvents(backend.collectLastEvents())
|
||||
}()
|
||||
|
||||
<-got
|
||||
|
||||
go func() {
|
||||
close(backend.shutdownCh)
|
||||
backend.Shutdown()
|
||||
close(shutdownCh)
|
||||
}()
|
||||
|
||||
// Wait for some time in case there's a bug that allows for the Shutdown
|
||||
// method to exit before all requests has been completed.
|
||||
time.Sleep(1 * time.Second)
|
||||
select {
|
||||
case <-shutdownCh:
|
||||
t.Fatal("Backend shut down before all requests finished")
|
||||
default:
|
||||
// Continue.
|
||||
}
|
||||
|
||||
close(contReqCh)
|
||||
<-shutdownCh
|
||||
}
|
||||
|
||||
func TestBatchWebhookEmptyBufferV1Alpha1(t *testing.T) {
|
||||
events := make([]*auditinternal.Event, 1) // less than max size.
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
|
||||
expected := len(events)
|
||||
got := make(chan int, 2)
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
|
||||
got <- len(events.(*auditv1alpha1.EventList).Items)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
timer := make(chan time.Time, 1)
|
||||
|
||||
timer <- time.Now() // Timer is done.
|
||||
|
||||
// Buffer is empty, no events have been queued. This should exit but send no events.
|
||||
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
|
||||
|
||||
// Send additional events after the sendBatchEvents has been called.
|
||||
backend.ProcessEvents(events...)
|
||||
go func() {
|
||||
waitForEmptyBuffer(backend)
|
||||
timer <- time.Now()
|
||||
}()
|
||||
|
||||
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
|
||||
|
||||
// Make sure we didn't get a POST with zero events.
|
||||
require.Equal(t, expected, <-got, "expected one event")
|
||||
}
|
||||
|
||||
func TestBatchBufferFullV1Alpha1(t *testing.T) {
|
||||
events := make([]*auditinternal.Event, defaultBatchBufferSize+1) // More than buffered size
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
|
||||
// Do nothing.
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
|
||||
// Make sure this doesn't block.
|
||||
backend.ProcessEvents(events...)
|
||||
}
|
||||
|
||||
func TestBatchRunV1Alpha1(t *testing.T) {
|
||||
|
||||
// Divisable by max batch size so we don't have to wait for a minute for
|
||||
// the test to finish.
|
||||
events := make([]*auditinternal.Event, defaultBatchMaxSize*3)
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
|
||||
got := new(int64)
|
||||
want := len(events)
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(want)
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
// When the expected number of events have been received, close the channel.
|
||||
close(done)
|
||||
}()
|
||||
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(obj runtime.Object) {
|
||||
events := obj.(*auditv1alpha1.EventList)
|
||||
atomic.AddInt64(got, int64(len(events.Items)))
|
||||
wg.Add(-len(events.Items))
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
|
||||
// Test the Run codepath. E.g. that the spawned goroutines behave correctly.
|
||||
backend.Run(stopCh)
|
||||
|
||||
backend.ProcessEvents(events...)
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
// Received all the events.
|
||||
case <-time.After(2 * time.Minute):
|
||||
t.Errorf("expected %d events got %d", want, atomic.LoadInt64(got))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBatchConcurrentRequestsV1Alpha1(t *testing.T) {
|
||||
events := make([]*auditinternal.Event, defaultBatchBufferSize) // Don't drop events
|
||||
for i := range events {
|
||||
events[i] = &auditinternal.Event{}
|
||||
}
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(len(events))
|
||||
|
||||
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
|
||||
wg.Add(-len(events.(*auditv1alpha1.EventList).Items))
|
||||
|
||||
// Since the webhook makes concurrent requests, blocking on the webhook response
|
||||
// shouldn't block the webhook from sending more events.
|
||||
//
|
||||
// Wait for all responses to be received before sending the response.
|
||||
wg.Wait()
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
|
||||
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
|
||||
backend.Run(stopCh)
|
||||
|
||||
backend.ProcessEvents(events...)
|
||||
// Wait for the webhook to receive all events.
|
||||
wg.Wait()
|
||||
}
|
Loading…
Reference in New Issue
Block a user