mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
upgrade advanced audit to v1beta1
This commit is contained in:
parent
da00e92f87
commit
f4e8b8f146
@ -609,6 +609,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/apiserver/v1alpha1
|
||||||
staging/src/k8s.io/apiserver/pkg/apis/audit
|
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/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/audit/validation
|
||||||
staging/src/k8s.io/apiserver/pkg/apis/example
|
staging/src/k8s.io/apiserver/pkg/apis/example
|
||||||
staging/src/k8s.io/apiserver/pkg/apis/example/v1
|
staging/src/k8s.io/apiserver/pkg/apis/example/v1
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apiserver/pkg/apis/audit"
|
"k8s.io/apiserver/pkg/apis/audit"
|
||||||
"k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
"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
|
// 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(
|
if err := announced.NewGroupMetaFactory(
|
||||||
&announced.GroupMetaFactoryArgs{
|
&announced.GroupMetaFactoryArgs{
|
||||||
GroupName: audit.GroupName,
|
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.
|
// Any Kind that is not namespaced must be cluster scoped.
|
||||||
RootScopedKinds: sets.NewString("Event", "Policy"),
|
RootScopedKinds: sets.NewString("Event", "Policy"),
|
||||||
AddInternalObjectsToScheme: audit.AddToScheme,
|
AddInternalObjectsToScheme: audit.AddToScheme,
|
||||||
},
|
},
|
||||||
announced.VersionToSchemeFunc{
|
announced.VersionToSchemeFunc{
|
||||||
|
v1beta1.SchemeGroupVersion.Version: v1beta1.AddToScheme,
|
||||||
v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme,
|
v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme,
|
||||||
},
|
},
|
||||||
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
|
).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)
|
||||||
|
}
|
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"`
|
||||||
|
}
|
@ -23,6 +23,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
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/apis/audit/validation"
|
||||||
"k8s.io/apiserver/pkg/audit"
|
"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)
|
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{}
|
policy := &auditinternal.Policy{}
|
||||||
if err := audit.Scheme.Convert(policyVersioned, policy, nil); err != nil {
|
decoder := audit.Codecs.UniversalDecoder(auditv1beta1.SchemeGroupVersion, auditv1alpha1.SchemeGroupVersion)
|
||||||
return nil, fmt.Errorf("failed converting policy: %v", err)
|
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 {
|
if err := validation.ValidatePolicy(policy); err != nil {
|
||||||
|
@ -24,12 +24,36 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
"k8s.io/apiserver/pkg/apis/audit"
|
"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/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"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:
|
rules:
|
||||||
- level: None
|
- level: None
|
||||||
nonResourceURLs:
|
nonResourceURLs:
|
||||||
@ -66,13 +90,32 @@ var expectedPolicy = &audit.Policy{
|
|||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParser(t *testing.T) {
|
func TestParserV1alpha1(t *testing.T) {
|
||||||
// Create a policy file.
|
// Create a policy file.
|
||||||
f, err := ioutil.TempFile("", "policy.yaml")
|
f, err := ioutil.TempFile("", "policy.yaml")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer os.Remove(f.Name())
|
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, err)
|
||||||
require.NoError(t, f.Close())
|
require.NoError(t, f.Close())
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
"k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||||
|
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Scheme = runtime.NewScheme()
|
var Scheme = runtime.NewScheme()
|
||||||
@ -31,4 +32,5 @@ var Codecs = serializer.NewCodecFactory(Scheme)
|
|||||||
func init() {
|
func init() {
|
||||||
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||||
v1alpha1.AddToScheme(Scheme)
|
v1alpha1.AddToScheme(Scheme)
|
||||||
|
v1beta1.AddToScheme(Scheme)
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
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"
|
||||||
"k8s.io/apiserver/pkg/audit/policy"
|
"k8s.io/apiserver/pkg/audit/policy"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
@ -441,7 +441,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
verb string
|
verb string
|
||||||
auditID string
|
auditID string
|
||||||
handler func(http.ResponseWriter, *http.Request)
|
handler func(http.ResponseWriter, *http.Request)
|
||||||
expected []auditv1alpha1.Event
|
expected []auditv1beta1.Event
|
||||||
respHeader bool
|
respHeader bool
|
||||||
}{
|
}{
|
||||||
// short running requests with read-only verb
|
// short running requests with read-only verb
|
||||||
@ -451,7 +451,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
"GET",
|
"GET",
|
||||||
"",
|
"",
|
||||||
func(http.ResponseWriter, *http.Request) {},
|
func(http.ResponseWriter, *http.Request) {},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "get",
|
Verb: "get",
|
||||||
@ -474,7 +474,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
func(w http.ResponseWriter, req *http.Request) {
|
func(w http.ResponseWriter, req *http.Request) {
|
||||||
w.Write([]byte("foo"))
|
w.Write([]byte("foo"))
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "get",
|
Verb: "get",
|
||||||
@ -497,7 +497,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
func(w http.ResponseWriter, req *http.Request) {
|
func(w http.ResponseWriter, req *http.Request) {
|
||||||
panic("kaboom")
|
panic("kaboom")
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "get",
|
Verb: "get",
|
||||||
@ -519,7 +519,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
"PUT",
|
"PUT",
|
||||||
"",
|
"",
|
||||||
func(http.ResponseWriter, *http.Request) {},
|
func(http.ResponseWriter, *http.Request) {},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "update",
|
Verb: "update",
|
||||||
@ -543,7 +543,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
w.Write([]byte("foo"))
|
w.Write([]byte("foo"))
|
||||||
time.Sleep(delay)
|
time.Sleep(delay)
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "update",
|
Verb: "update",
|
||||||
@ -567,7 +567,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
w.Write([]byte("foo"))
|
w.Write([]byte("foo"))
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "update",
|
Verb: "update",
|
||||||
@ -590,7 +590,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
func(w http.ResponseWriter, req *http.Request) {
|
func(w http.ResponseWriter, req *http.Request) {
|
||||||
panic("kaboom")
|
panic("kaboom")
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "update",
|
Verb: "update",
|
||||||
@ -614,7 +614,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
w.Write([]byte("foo"))
|
w.Write([]byte("foo"))
|
||||||
panic("kaboom")
|
panic("kaboom")
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "update",
|
Verb: "update",
|
||||||
@ -636,7 +636,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
"GET",
|
"GET",
|
||||||
"",
|
"",
|
||||||
func(http.ResponseWriter, *http.Request) {},
|
func(http.ResponseWriter, *http.Request) {},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "watch",
|
Verb: "watch",
|
||||||
@ -665,7 +665,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
func(w http.ResponseWriter, req *http.Request) {
|
func(w http.ResponseWriter, req *http.Request) {
|
||||||
w.Write([]byte("foo"))
|
w.Write([]byte("foo"))
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "watch",
|
Verb: "watch",
|
||||||
@ -694,7 +694,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
func(http.ResponseWriter, *http.Request) {
|
func(http.ResponseWriter, *http.Request) {
|
||||||
time.Sleep(delay)
|
time.Sleep(delay)
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "watch",
|
Verb: "watch",
|
||||||
@ -724,7 +724,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
time.Sleep(delay)
|
time.Sleep(delay)
|
||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "watch",
|
Verb: "watch",
|
||||||
@ -753,7 +753,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
func(w http.ResponseWriter, req *http.Request) {
|
func(w http.ResponseWriter, req *http.Request) {
|
||||||
w.Write([]byte("foo"))
|
w.Write([]byte("foo"))
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "watch",
|
Verb: "watch",
|
||||||
@ -783,7 +783,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
w.Write([]byte("foo"))
|
w.Write([]byte("foo"))
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "watch",
|
Verb: "watch",
|
||||||
@ -812,7 +812,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
func(w http.ResponseWriter, req *http.Request) {
|
func(w http.ResponseWriter, req *http.Request) {
|
||||||
panic("kaboom")
|
panic("kaboom")
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "watch",
|
Verb: "watch",
|
||||||
@ -836,7 +836,7 @@ func TestAuditJson(t *testing.T) {
|
|||||||
w.Write([]byte("foo"))
|
w.Write([]byte("foo"))
|
||||||
panic("kaboom")
|
panic("kaboom")
|
||||||
},
|
},
|
||||||
[]auditv1alpha1.Event{
|
[]auditv1beta1.Event{
|
||||||
{
|
{
|
||||||
Stage: auditinternal.StageRequestReceived,
|
Stage: auditinternal.StageRequestReceived,
|
||||||
Verb: "watch",
|
Verb: "watch",
|
||||||
@ -892,8 +892,8 @@ func TestAuditJson(t *testing.T) {
|
|||||||
expectedID := types.UID("")
|
expectedID := types.UID("")
|
||||||
for i, expect := range test.expected {
|
for i, expect := range test.expected {
|
||||||
// decode events back to check json elements.
|
// decode events back to check json elements.
|
||||||
event := &auditv1alpha1.Event{}
|
event := &auditv1beta1.Event{}
|
||||||
decoder := audit.Codecs.UniversalDecoder(auditv1alpha1.SchemeGroupVersion)
|
decoder := audit.Codecs.UniversalDecoder(auditv1beta1.SchemeGroupVersion)
|
||||||
if err := runtime.DecodeInto(decoder, []byte(line[i]), event); err != nil {
|
if err := runtime.DecodeInto(decoder, []byte(line[i]), event); err != nil {
|
||||||
t.Errorf("failed decoding line %s: %v", line[i], err)
|
t.Errorf("failed decoding line %s: %v", line[i], err)
|
||||||
continue
|
continue
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -66,7 +66,8 @@ func (b *backend) logEvent(ev *auditinternal.Event) {
|
|||||||
case FormatLegacy:
|
case FormatLegacy:
|
||||||
line = audit.EventString(ev) + "\n"
|
line = audit.EventString(ev) + "\n"
|
||||||
case FormatJson:
|
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 {
|
if err != nil {
|
||||||
audit.HandlePluginError("log", err, ev)
|
audit.HandlePluginError("log", err, ev)
|
||||||
return
|
return
|
||||||
|
@ -32,7 +32,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/runtime"
|
"k8s.io/apimachinery/pkg/util/runtime"
|
||||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||||
"k8s.io/apiserver/pkg/apis/audit/install"
|
"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/audit"
|
||||||
"k8s.io/apiserver/pkg/util/webhook"
|
"k8s.io/apiserver/pkg/util/webhook"
|
||||||
)
|
)
|
||||||
@ -87,8 +87,9 @@ var (
|
|||||||
//
|
//
|
||||||
// Can we make these passable to NewGenericWebhook?
|
// Can we make these passable to NewGenericWebhook?
|
||||||
groupFactoryRegistry = make(announced.APIGroupFactoryRegistry)
|
groupFactoryRegistry = make(announced.APIGroupFactoryRegistry)
|
||||||
groupVersions = []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion}
|
// TODO(audit): figure out a general way to let the client choose their preferred version
|
||||||
registry = registered.NewOrDie("")
|
groupVersions = []schema.GroupVersion{auditv1beta1.SchemeGroupVersion}
|
||||||
|
registry = registered.NewOrDie("")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -35,14 +35,14 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
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"
|
||||||
"k8s.io/client-go/tools/clientcmd/api/v1"
|
"k8s.io/client-go/tools/clientcmd/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// newWebhookHandler returns a handler which recieves webhook events and decodes the
|
// 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.
|
// 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 {
|
func newWebhookHandler(t *testing.T, cb func(events *auditv1beta1.EventList)) http.Handler {
|
||||||
s := json.NewSerializer(json.DefaultMetaFactory, audit.Scheme, audit.Scheme, false)
|
s := json.NewSerializer(json.DefaultMetaFactory, audit.Scheme, audit.Scheme, false)
|
||||||
return &testWebhookHandler{
|
return &testWebhookHandler{
|
||||||
t: t,
|
t: t,
|
||||||
@ -54,7 +54,7 @@ func newWebhookHandler(t *testing.T, cb func(events *auditv1alpha1.EventList)) h
|
|||||||
type testWebhookHandler struct {
|
type testWebhookHandler struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
|
|
||||||
onEvents func(events *auditv1alpha1.EventList)
|
onEvents func(events *auditv1beta1.EventList)
|
||||||
|
|
||||||
serializer runtime.Serializer
|
serializer runtime.Serializer
|
||||||
}
|
}
|
||||||
@ -66,13 +66,13 @@ func (t *testWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return fmt.Errorf("read webhook request body: %v", err)
|
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, &auditv1beta1.EventList{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("decode request body: %v", err)
|
return fmt.Errorf("decode request body: %v", err)
|
||||||
}
|
}
|
||||||
list, ok := obj.(*auditv1alpha1.EventList)
|
list, ok := obj.(*auditv1beta1.EventList)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("expected *v1alpha1.EventList got %T", obj)
|
return fmt.Errorf("expected *v1beta1.EventList got %T", obj)
|
||||||
}
|
}
|
||||||
t.onEvents(list)
|
t.onEvents(list)
|
||||||
return nil
|
return nil
|
||||||
@ -122,7 +122,7 @@ func TestWebhook(t *testing.T) {
|
|||||||
gotEvents := false
|
gotEvents := false
|
||||||
defer func() { require.True(t, gotEvents, "no events received") }()
|
defer func() { require.True(t, gotEvents, "no events received") }()
|
||||||
|
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
gotEvents = true
|
gotEvents = true
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
@ -151,7 +151,7 @@ func TestBatchWebhookMaxEvents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
got := make(chan int, 2)
|
got := make(chan int, 2)
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
got <- len(events.Items)
|
got <- len(events.Items)
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
@ -183,7 +183,7 @@ func TestBatchWebhookStopCh(t *testing.T) {
|
|||||||
|
|
||||||
expected := len(events)
|
expected := len(events)
|
||||||
got := make(chan int, 2)
|
got := make(chan int, 2)
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
got <- len(events.Items)
|
got <- len(events.Items)
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
@ -209,7 +209,7 @@ func TestBatchWebhookProcessEventsAfterStop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
got := make(chan struct{})
|
got := make(chan struct{})
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
close(got)
|
close(got)
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
@ -233,7 +233,7 @@ func TestBatchWebhookShutdown(t *testing.T) {
|
|||||||
got := make(chan struct{})
|
got := make(chan struct{})
|
||||||
contReqCh := make(chan struct{})
|
contReqCh := make(chan struct{})
|
||||||
shutdownCh := make(chan struct{})
|
shutdownCh := make(chan struct{})
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
close(got)
|
close(got)
|
||||||
<-contReqCh
|
<-contReqCh
|
||||||
}))
|
}))
|
||||||
@ -278,7 +278,7 @@ func TestBatchWebhookEmptyBuffer(t *testing.T) {
|
|||||||
|
|
||||||
expected := len(events)
|
expected := len(events)
|
||||||
got := make(chan int, 2)
|
got := make(chan int, 2)
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
got <- len(events.Items)
|
got <- len(events.Items)
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
@ -311,7 +311,7 @@ func TestBatchBufferFull(t *testing.T) {
|
|||||||
for i := range events {
|
for i := range events {
|
||||||
events[i] = &auditinternal.Event{}
|
events[i] = &auditinternal.Event{}
|
||||||
}
|
}
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
@ -344,7 +344,7 @@ func TestBatchRun(t *testing.T) {
|
|||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
atomic.AddInt64(got, int64(len(events.Items)))
|
atomic.AddInt64(got, int64(len(events.Items)))
|
||||||
wg.Add(-len(events.Items))
|
wg.Add(-len(events.Items))
|
||||||
}))
|
}))
|
||||||
@ -377,7 +377,7 @@ func TestBatchConcurrentRequests(t *testing.T) {
|
|||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
wg.Add(len(events))
|
wg.Add(len(events))
|
||||||
|
|
||||||
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) {
|
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1beta1.EventList) {
|
||||||
wg.Add(-len(events.Items))
|
wg.Add(-len(events.Items))
|
||||||
|
|
||||||
// Since the webhook makes concurrent requests, blocking on the webhook response
|
// Since the webhook makes concurrent requests, blocking on the webhook response
|
||||||
|
Loading…
Reference in New Issue
Block a user