84
vendor/k8s.io/apiserver/pkg/audit/context.go
generated
vendored
Normal file
84
vendor/k8s.io/apiserver/pkg/audit/context.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright 2020 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 audit
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
// The key type is unexported to prevent collisions
|
||||
type key int
|
||||
|
||||
const (
|
||||
// auditAnnotationsKey is the context key for the audit annotations.
|
||||
auditAnnotationsKey key = iota
|
||||
)
|
||||
|
||||
// annotations = *[]annotation instead of a map to preserve order of insertions
|
||||
type annotation struct {
|
||||
key, value string
|
||||
}
|
||||
|
||||
// WithAuditAnnotations returns a new context that can store audit annotations
|
||||
// via the AddAuditAnnotation function. This function is meant to be called from
|
||||
// an early request handler to allow all later layers to set audit annotations.
|
||||
// This is required to support flows where handlers that come before WithAudit
|
||||
// (such as WithAuthentication) wish to set audit annotations.
|
||||
func WithAuditAnnotations(parent context.Context) context.Context {
|
||||
// this should never really happen, but prevent double registration of this slice
|
||||
if _, ok := parent.Value(auditAnnotationsKey).(*[]annotation); ok {
|
||||
return parent
|
||||
}
|
||||
|
||||
var annotations []annotation // avoid allocations until we actually need it
|
||||
return genericapirequest.WithValue(parent, auditAnnotationsKey, &annotations)
|
||||
}
|
||||
|
||||
// AddAuditAnnotation sets the audit annotation for the given key, value pair.
|
||||
// It is safe to call at most parts of request flow that come after WithAuditAnnotations.
|
||||
// The notable exception being that this function must not be called via a
|
||||
// defer statement (i.e. after ServeHTTP) in a handler that runs before WithAudit
|
||||
// as at that point the audit event has already been sent to the audit sink.
|
||||
// Handlers that are unaware of their position in the overall request flow should
|
||||
// prefer AddAuditAnnotation over LogAnnotation to avoid dropping annotations.
|
||||
func AddAuditAnnotation(ctx context.Context, key, value string) {
|
||||
// use the audit event directly if we have it
|
||||
if ae := genericapirequest.AuditEventFrom(ctx); ae != nil {
|
||||
LogAnnotation(ae, key, value)
|
||||
return
|
||||
}
|
||||
|
||||
annotations, ok := ctx.Value(auditAnnotationsKey).(*[]annotation)
|
||||
if !ok {
|
||||
return // adding audit annotation is not supported at this call site
|
||||
}
|
||||
|
||||
*annotations = append(*annotations, annotation{key: key, value: value})
|
||||
}
|
||||
|
||||
// This is private to prevent reads/write to the slice from outside of this package.
|
||||
// The audit event should be directly read to get access to the annotations.
|
||||
func auditAnnotationsFrom(ctx context.Context) []annotation {
|
||||
annotations, ok := ctx.Value(auditAnnotationsKey).(*[]annotation)
|
||||
if !ok {
|
||||
return nil // adding audit annotation is not supported at this call site
|
||||
}
|
||||
|
||||
return *annotations
|
||||
}
|
||||
148
vendor/k8s.io/apiserver/pkg/audit/event/attributes.go
generated
vendored
148
vendor/k8s.io/apiserver/pkg/audit/event/attributes.go
generated
vendored
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 event
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
authnv1 "k8s.io/api/authentication/v1"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
authuser "k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
|
||||
var _ authorizer.Attributes = &attributes{}
|
||||
|
||||
// attributes implements the authorizer attributes interface
|
||||
// with event data. This is used for enforced audit backends
|
||||
type attributes struct {
|
||||
event *audit.Event
|
||||
path string
|
||||
}
|
||||
|
||||
// NewAttributes returns a new attributes struct and parsed request uri
|
||||
// if needed
|
||||
func NewAttributes(event *audit.Event) (authorizer.Attributes, error) {
|
||||
a := attributes{
|
||||
event: event,
|
||||
}
|
||||
if event.ObjectRef == nil {
|
||||
u, err := url.ParseRequestURI(a.event.RequestURI)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse url: %v", err)
|
||||
}
|
||||
a.path = u.Path
|
||||
}
|
||||
return &a, nil
|
||||
}
|
||||
|
||||
// GetUser returns the user. This is only used for checking audit policy,
|
||||
// and the audit policy user check is based off the original user,
|
||||
// not the impersonated user.
|
||||
func (a *attributes) GetUser() authuser.Info {
|
||||
return user(a.event.User)
|
||||
}
|
||||
|
||||
// GetVerb returns the verb
|
||||
func (a *attributes) GetVerb() string {
|
||||
return a.event.Verb
|
||||
}
|
||||
|
||||
// IsReadOnly determines if the verb is a read only action
|
||||
func (a *attributes) IsReadOnly() bool {
|
||||
return a.event.Verb == "get" || a.event.Verb == "list" || a.event.Verb == "watch"
|
||||
}
|
||||
|
||||
// GetNamespace returns the object namespace if present
|
||||
func (a *attributes) GetNamespace() string {
|
||||
if a.event.ObjectRef == nil {
|
||||
return ""
|
||||
}
|
||||
return a.event.ObjectRef.Namespace
|
||||
}
|
||||
|
||||
// GetResource returns the object resource if present
|
||||
func (a *attributes) GetResource() string {
|
||||
if a.event.ObjectRef == nil {
|
||||
return ""
|
||||
}
|
||||
return a.event.ObjectRef.Resource
|
||||
}
|
||||
|
||||
// GetSubresource returns the object subresource if present
|
||||
func (a *attributes) GetSubresource() string {
|
||||
if a.event.ObjectRef == nil {
|
||||
return ""
|
||||
}
|
||||
return a.event.ObjectRef.Subresource
|
||||
}
|
||||
|
||||
// GetName returns the object name if present
|
||||
func (a *attributes) GetName() string {
|
||||
if a.event.ObjectRef == nil {
|
||||
return ""
|
||||
}
|
||||
return a.event.ObjectRef.Name
|
||||
}
|
||||
|
||||
// GetAPIGroup returns the object api group if present
|
||||
func (a *attributes) GetAPIGroup() string {
|
||||
if a.event.ObjectRef == nil {
|
||||
return ""
|
||||
}
|
||||
return a.event.ObjectRef.APIGroup
|
||||
}
|
||||
|
||||
// GetAPIVersion returns the object api version if present
|
||||
func (a *attributes) GetAPIVersion() string {
|
||||
if a.event.ObjectRef == nil {
|
||||
return ""
|
||||
}
|
||||
return a.event.ObjectRef.APIVersion
|
||||
}
|
||||
|
||||
// IsResourceRequest determines if the request was acted on a resource
|
||||
func (a *attributes) IsResourceRequest() bool {
|
||||
return a.event.ObjectRef != nil
|
||||
}
|
||||
|
||||
// GetPath returns the path uri accessed
|
||||
func (a *attributes) GetPath() string {
|
||||
return a.path
|
||||
}
|
||||
|
||||
// user represents the event user
|
||||
type user authnv1.UserInfo
|
||||
|
||||
// GetName returns the user name
|
||||
func (u user) GetName() string { return u.Username }
|
||||
|
||||
// GetUID returns the user uid
|
||||
func (u user) GetUID() string { return u.UID }
|
||||
|
||||
// GetGroups returns the user groups
|
||||
func (u user) GetGroups() []string { return u.Groups }
|
||||
|
||||
// GetExtra returns the user extra data
|
||||
func (u user) GetExtra() map[string][]string {
|
||||
m := map[string][]string{}
|
||||
for k, v := range u.Extra {
|
||||
m[k] = []string(v)
|
||||
}
|
||||
return m
|
||||
}
|
||||
13
vendor/k8s.io/apiserver/pkg/audit/metrics.go
generated
vendored
13
vendor/k8s.io/apiserver/pkg/audit/metrics.go
generated
vendored
@@ -17,12 +17,13 @@ limitations under the License.
|
||||
package audit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -31,7 +32,7 @@ const (
|
||||
|
||||
/*
|
||||
* By default, all the following metrics are defined as falling under
|
||||
* ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes)
|
||||
* ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/1209-metrics-stability/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes)
|
||||
*
|
||||
* Promoting the stability level of the metric is a responsibility of the component owner, since it
|
||||
* involves explicitly acknowledging support for the metric across multiple releases, in accordance with
|
||||
@@ -84,13 +85,13 @@ func init() {
|
||||
}
|
||||
|
||||
// ObserveEvent updates the relevant prometheus metrics for the generated audit event.
|
||||
func ObserveEvent() {
|
||||
eventCounter.Inc()
|
||||
func ObserveEvent(ctx context.Context) {
|
||||
eventCounter.WithContext(ctx).Inc()
|
||||
}
|
||||
|
||||
// ObservePolicyLevel updates the relevant prometheus metrics with the audit level for a request.
|
||||
func ObservePolicyLevel(level auditinternal.Level) {
|
||||
levelCounter.WithLabelValues(string(level)).Inc()
|
||||
func ObservePolicyLevel(ctx context.Context, level auditinternal.Level) {
|
||||
levelCounter.WithContext(ctx).WithLabelValues(string(level)).Inc()
|
||||
}
|
||||
|
||||
// HandlePluginError handles an error that occurred in an audit plugin. This method should only be
|
||||
|
||||
54
vendor/k8s.io/apiserver/pkg/audit/policy/dynamic.go
generated
vendored
54
vendor/k8s.io/apiserver/pkg/audit/policy/dynamic.go
generated
vendored
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 policy
|
||||
|
||||
import (
|
||||
"k8s.io/api/auditregistration/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
|
||||
// ConvertDynamicPolicyToInternal constructs an internal policy type from a
|
||||
// v1alpha1 dynamic type
|
||||
func ConvertDynamicPolicyToInternal(p *v1alpha1.Policy) *audit.Policy {
|
||||
stages := make([]audit.Stage, len(p.Stages))
|
||||
for i, stage := range p.Stages {
|
||||
stages[i] = audit.Stage(stage)
|
||||
}
|
||||
return &audit.Policy{
|
||||
Rules: []audit.PolicyRule{
|
||||
{
|
||||
Level: audit.Level(p.Level),
|
||||
},
|
||||
},
|
||||
OmitStages: InvertStages(stages),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDynamicChecker returns a new dynamic policy checker
|
||||
func NewDynamicChecker() Checker {
|
||||
return &dynamicPolicyChecker{}
|
||||
}
|
||||
|
||||
type dynamicPolicyChecker struct{}
|
||||
|
||||
// LevelAndStages returns returns a fixed level of the full event, this is so that the downstream policy
|
||||
// can be applied per sink.
|
||||
// TODO: this needs benchmarking before the API moves to beta to determine the effect this has on the apiserver
|
||||
func (d *dynamicPolicyChecker) LevelAndStages(authorizer.Attributes) (audit.Level, []audit.Stage) {
|
||||
return audit.LevelRequestResponse, []audit.Stage{}
|
||||
}
|
||||
12
vendor/k8s.io/apiserver/pkg/audit/policy/reader.go
generated
vendored
12
vendor/k8s.io/apiserver/pkg/audit/policy/reader.go
generated
vendored
@@ -28,7 +28,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/apis/audit/validation"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -73,10 +73,15 @@ func LoadPolicyFromBytes(policyDef []byte) (*auditinternal.Policy, error) {
|
||||
}
|
||||
|
||||
// Ensure the policy file contained an apiVersion and kind.
|
||||
if !apiGroupVersionSet[schema.GroupVersion{Group: gvk.Group, Version: gvk.Version}] {
|
||||
gv := schema.GroupVersion{Group: gvk.Group, Version: gvk.Version}
|
||||
if !apiGroupVersionSet[gv] {
|
||||
return nil, fmt.Errorf("unknown group version field %v in policy", gvk)
|
||||
}
|
||||
|
||||
if gv != auditv1.SchemeGroupVersion {
|
||||
klog.Warningf("%q is deprecated and will be removed in a future release, use %q instead", gv, auditv1.SchemeGroupVersion)
|
||||
}
|
||||
|
||||
if err := validation.ValidatePolicy(policy); err != nil {
|
||||
return nil, err.ToAggregate()
|
||||
}
|
||||
@@ -85,6 +90,7 @@ func LoadPolicyFromBytes(policyDef []byte) (*auditinternal.Policy, error) {
|
||||
if policyCnt == 0 {
|
||||
return nil, fmt.Errorf("loaded illegal policy with 0 rules")
|
||||
}
|
||||
klog.V(4).Infof("Loaded %d audit policy rules", policyCnt)
|
||||
|
||||
klog.V(4).InfoS("Load audit policy rules success", "policyCnt", policyCnt)
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
10
vendor/k8s.io/apiserver/pkg/audit/request.go
generated
vendored
10
vendor/k8s.io/apiserver/pkg/audit/request.go
generated
vendored
@@ -24,7 +24,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
authnv1 "k8s.io/api/authentication/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
@@ -43,9 +43,9 @@ const (
|
||||
userAgentTruncateSuffix = "...TRUNCATED"
|
||||
)
|
||||
|
||||
func NewEventFromRequest(req *http.Request, level auditinternal.Level, attribs authorizer.Attributes) (*auditinternal.Event, error) {
|
||||
func NewEventFromRequest(req *http.Request, requestReceivedTimestamp time.Time, level auditinternal.Level, attribs authorizer.Attributes) (*auditinternal.Event, error) {
|
||||
ev := &auditinternal.Event{
|
||||
RequestReceivedTimestamp: metav1.NewMicroTime(time.Now()),
|
||||
RequestReceivedTimestamp: metav1.NewMicroTime(requestReceivedTimestamp),
|
||||
Verb: attribs.GetVerb(),
|
||||
RequestURI: req.URL.RequestURI(),
|
||||
UserAgent: maybeTruncateUserAgent(req),
|
||||
@@ -88,6 +88,10 @@ func NewEventFromRequest(req *http.Request, level auditinternal.Level, attribs a
|
||||
}
|
||||
}
|
||||
|
||||
for _, kv := range auditAnnotationsFrom(req.Context()) {
|
||||
LogAnnotation(ev, kv.key, kv.value)
|
||||
}
|
||||
|
||||
return ev, nil
|
||||
}
|
||||
|
||||
|
||||
49
vendor/k8s.io/apiserver/pkg/audit/util/conversion.go
generated
vendored
49
vendor/k8s.io/apiserver/pkg/audit/util/conversion.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 util
|
||||
|
||||
import (
|
||||
"k8s.io/api/auditregistration/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/util/webhook"
|
||||
)
|
||||
|
||||
// HookClientConfigForSink constructs a webhook.ClientConfig using a v1alpha1.AuditSink API object.
|
||||
// webhook.ClientConfig is used to create a HookClient and the purpose of the config struct is to
|
||||
// share that with other packages that need to create a HookClient.
|
||||
func HookClientConfigForSink(a *v1alpha1.AuditSink) webhook.ClientConfig {
|
||||
c := a.Spec.Webhook.ClientConfig
|
||||
ret := webhook.ClientConfig{Name: a.Name, CABundle: c.CABundle}
|
||||
if c.URL != nil {
|
||||
ret.URL = *c.URL
|
||||
}
|
||||
if c.Service != nil {
|
||||
ret.Service = &webhook.ClientConfigService{
|
||||
Name: c.Service.Name,
|
||||
Namespace: c.Service.Namespace,
|
||||
}
|
||||
if c.Service.Port != nil {
|
||||
ret.Service.Port = *c.Service.Port
|
||||
} else {
|
||||
ret.Service.Port = 443
|
||||
}
|
||||
|
||||
if c.Service.Path != nil {
|
||||
ret.Service.Path = *c.Service.Path
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
Reference in New Issue
Block a user