mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-07 02:07:58 +00:00
vendor dependencies
This commit is contained in:
parent
604208ef4f
commit
72abf135d6
1156 changed files with 78178 additions and 105799 deletions
78
vendor/k8s.io/apiserver/plugin/pkg/audit/buffered/buffered.go
generated
vendored
78
vendor/k8s.io/apiserver/plugin/pkg/audit/buffered/buffered.go
generated
vendored
|
|
@ -31,16 +31,6 @@ import (
|
|||
// PluginName is the name reported in error metrics.
|
||||
const PluginName = "buffered"
|
||||
|
||||
const (
|
||||
// Default configuration values for ModeBatch.
|
||||
defaultBatchBufferSize = 10000 // Buffer up to 10000 events before starting discarding.
|
||||
defaultBatchMaxSize = 400 // Only send up to 400 events at a time.
|
||||
defaultBatchMaxWait = 30 * time.Second // Send events at least twice a minute.
|
||||
|
||||
defaultBatchThrottleQPS = 10 // Limit the send rate by 10 QPS.
|
||||
defaultBatchThrottleBurst = 15 // Allow up to 15 QPS burst.
|
||||
)
|
||||
|
||||
// BatchConfig represents batching delegate audit backend configuration.
|
||||
type BatchConfig struct {
|
||||
// BufferSize defines a size of the buffering queue.
|
||||
|
|
@ -57,19 +47,9 @@ type BatchConfig struct {
|
|||
// ThrottleBurst defines the maximum number of requests sent to the delegate backend at the same moment in case
|
||||
// the capacity defined by ThrottleQPS was not utilized.
|
||||
ThrottleBurst int
|
||||
}
|
||||
|
||||
// NewDefaultBatchConfig returns new Config objects populated by default values.
|
||||
func NewDefaultBatchConfig() BatchConfig {
|
||||
return BatchConfig{
|
||||
BufferSize: defaultBatchBufferSize,
|
||||
MaxBatchSize: defaultBatchMaxSize,
|
||||
MaxBatchWait: defaultBatchMaxWait,
|
||||
|
||||
ThrottleEnable: true,
|
||||
ThrottleQPS: defaultBatchThrottleQPS,
|
||||
ThrottleBurst: defaultBatchThrottleBurst,
|
||||
}
|
||||
// Whether the delegate backend should be called asynchronously.
|
||||
AsyncDelegate bool
|
||||
}
|
||||
|
||||
type bufferedBackend struct {
|
||||
|
|
@ -85,6 +65,9 @@ type bufferedBackend struct {
|
|||
// Receiving maxBatchSize events will always trigger sending a batch, regardless of the amount of time passed.
|
||||
maxBatchWait time.Duration
|
||||
|
||||
// Whether the delegate backend should be called asynchronously.
|
||||
asyncDelegate bool
|
||||
|
||||
// Channel to signal that the batching routine has processed all remaining events and exited.
|
||||
// Once `shutdownCh` is closed no new events will be sent to the delegate backend.
|
||||
shutdownCh chan struct{}
|
||||
|
|
@ -113,6 +96,7 @@ func NewBackend(delegate audit.Backend, config BatchConfig) audit.Backend {
|
|||
buffer: make(chan *auditinternal.Event, config.BufferSize),
|
||||
maxBatchSize: config.MaxBatchSize,
|
||||
maxBatchWait: config.MaxBatchWait,
|
||||
asyncDelegate: config.AsyncDelegate,
|
||||
shutdownCh: make(chan struct{}),
|
||||
wg: sync.WaitGroup{},
|
||||
throttle: throttle,
|
||||
|
|
@ -169,8 +153,17 @@ func (b *bufferedBackend) Shutdown() {
|
|||
// b.stopCh is closed, processIncomingEvents stops and closes the buffer.
|
||||
func (b *bufferedBackend) processIncomingEvents(stopCh <-chan struct{}) {
|
||||
defer close(b.buffer)
|
||||
t := time.NewTimer(b.maxBatchWait)
|
||||
defer t.Stop()
|
||||
|
||||
var (
|
||||
maxWaitChan <-chan time.Time
|
||||
maxWaitTimer *time.Timer
|
||||
)
|
||||
// Only use max wait batching if batching is enabled.
|
||||
if b.maxBatchSize > 1 {
|
||||
maxWaitTimer = time.NewTimer(b.maxBatchWait)
|
||||
maxWaitChan = maxWaitTimer.C
|
||||
defer maxWaitTimer.Stop()
|
||||
}
|
||||
|
||||
for {
|
||||
func() {
|
||||
|
|
@ -178,8 +171,10 @@ func (b *bufferedBackend) processIncomingEvents(stopCh <-chan struct{}) {
|
|||
// goroutine can't bring down the main routine.
|
||||
defer runtime.HandleCrash()
|
||||
|
||||
t.Reset(b.maxBatchWait)
|
||||
b.processEvents(b.collectEvents(t.C, stopCh))
|
||||
if b.maxBatchSize > 1 {
|
||||
maxWaitTimer.Reset(b.maxBatchWait)
|
||||
}
|
||||
b.processEvents(b.collectEvents(maxWaitChan, stopCh))
|
||||
}()
|
||||
|
||||
select {
|
||||
|
|
@ -235,18 +230,28 @@ func (b *bufferedBackend) processEvents(events []*auditinternal.Event) {
|
|||
b.throttle.Accept()
|
||||
}
|
||||
|
||||
b.wg.Add(1)
|
||||
go func() {
|
||||
defer b.wg.Done()
|
||||
defer runtime.HandleCrash()
|
||||
if b.asyncDelegate {
|
||||
b.wg.Add(1)
|
||||
go func() {
|
||||
defer b.wg.Done()
|
||||
defer runtime.HandleCrash()
|
||||
|
||||
// Execute the real processing in a goroutine to keep it from blocking.
|
||||
// This lets the batching routine continue draining the queue immediately.
|
||||
b.delegateBackend.ProcessEvents(events...)
|
||||
}()
|
||||
// Execute the real processing in a goroutine to keep it from blocking.
|
||||
// This lets the batching routine continue draining the queue immediately.
|
||||
b.delegateBackend.ProcessEvents(events...)
|
||||
}()
|
||||
} else {
|
||||
func() {
|
||||
defer runtime.HandleCrash()
|
||||
|
||||
// Execute the real processing in a goroutine to keep it from blocking.
|
||||
// This lets the batching routine continue draining the queue immediately.
|
||||
b.delegateBackend.ProcessEvents(events...)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (b *bufferedBackend) ProcessEvents(ev ...*auditinternal.Event) {
|
||||
func (b *bufferedBackend) ProcessEvents(ev ...*auditinternal.Event) bool {
|
||||
// The following mechanism is in place to support the situation when audit
|
||||
// events are still coming after the backend was stopped.
|
||||
var sendErr error
|
||||
|
|
@ -274,9 +279,10 @@ func (b *bufferedBackend) ProcessEvents(ev ...*auditinternal.Event) {
|
|||
case b.buffer <- event:
|
||||
default:
|
||||
sendErr = fmt.Errorf("audit buffer queue blocked")
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *bufferedBackend) String() string {
|
||||
|
|
|
|||
46
vendor/k8s.io/apiserver/plugin/pkg/audit/dynamic/defaults.go
generated
vendored
Normal file
46
vendor/k8s.io/apiserver/plugin/pkg/audit/dynamic/defaults.go
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
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 dynamic
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
bufferedplugin "k8s.io/apiserver/plugin/pkg/audit/buffered"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default configuration values for ModeBatch when applied to a dynamic plugin
|
||||
defaultBatchBufferSize = 5000 // Buffer up to 5000 events before starting discarding.
|
||||
defaultBatchMaxSize = 400 // Only send up to 400 events at a time.
|
||||
defaultBatchMaxWait = 30 * time.Second // Send events at least twice a minute.
|
||||
defaultBatchThrottleQPS = 10 // Limit the send rate by 10 QPS.
|
||||
defaultBatchThrottleBurst = 15 // Allow up to 15 QPS burst.
|
||||
)
|
||||
|
||||
// NewDefaultWebhookBatchConfig returns new Batch Config objects populated by default values
|
||||
// for dynamic webhooks
|
||||
func NewDefaultWebhookBatchConfig() *bufferedplugin.BatchConfig {
|
||||
return &bufferedplugin.BatchConfig{
|
||||
BufferSize: defaultBatchBufferSize,
|
||||
MaxBatchSize: defaultBatchMaxSize,
|
||||
MaxBatchWait: defaultBatchMaxWait,
|
||||
ThrottleEnable: true,
|
||||
ThrottleQPS: defaultBatchThrottleQPS,
|
||||
ThrottleBurst: defaultBatchThrottleBurst,
|
||||
AsyncDelegate: true,
|
||||
}
|
||||
}
|
||||
342
vendor/k8s.io/apiserver/plugin/pkg/audit/dynamic/dynamic.go
generated
vendored
Normal file
342
vendor/k8s.io/apiserver/plugin/pkg/audit/dynamic/dynamic.go
generated
vendored
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
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 dynamic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"k8s.io/klog"
|
||||
|
||||
auditregv1alpha1 "k8s.io/api/auditregistration/v1alpha1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
auditinstall "k8s.io/apiserver/pkg/apis/audit/install"
|
||||
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
webhook "k8s.io/apiserver/pkg/util/webhook"
|
||||
bufferedplugin "k8s.io/apiserver/plugin/pkg/audit/buffered"
|
||||
auditinformer "k8s.io/client-go/informers/auditregistration/v1alpha1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
)
|
||||
|
||||
// PluginName is the name reported in error metrics.
|
||||
const PluginName = "dynamic"
|
||||
|
||||
// Config holds the configuration for the dynamic backend
|
||||
type Config struct {
|
||||
// Informer for the audit sinks
|
||||
Informer auditinformer.AuditSinkInformer
|
||||
// EventConfig holds the configuration for event notifications about the AuditSink API objects
|
||||
EventConfig EventConfig
|
||||
// BufferedConfig is the runtime buffered configuration
|
||||
BufferedConfig *bufferedplugin.BatchConfig
|
||||
// WebhookConfig holds the configuration for outgoing webhooks
|
||||
WebhookConfig WebhookConfig
|
||||
}
|
||||
|
||||
// WebhookConfig holds the configurations for outgoing webhooks
|
||||
type WebhookConfig struct {
|
||||
// AuthInfoResolverWrapper provides the webhook authentication for in-cluster endpoints
|
||||
AuthInfoResolverWrapper webhook.AuthenticationInfoResolverWrapper
|
||||
// ServiceResolver knows how to convert a webhook service reference into an actual location.
|
||||
ServiceResolver webhook.ServiceResolver
|
||||
}
|
||||
|
||||
// EventConfig holds the configurations for sending event notifiations about AuditSink API objects
|
||||
type EventConfig struct {
|
||||
// Sink for emitting events
|
||||
Sink record.EventSink
|
||||
// Source holds the source information about the event emitter
|
||||
Source corev1.EventSource
|
||||
}
|
||||
|
||||
// delegate represents a delegate backend that was created from an audit sink configuration
|
||||
type delegate struct {
|
||||
audit.Backend
|
||||
configuration *auditregv1alpha1.AuditSink
|
||||
stopChan chan struct{}
|
||||
}
|
||||
|
||||
// gracefulShutdown will gracefully shutdown the delegate
|
||||
func (d *delegate) gracefulShutdown() {
|
||||
close(d.stopChan)
|
||||
d.Shutdown()
|
||||
}
|
||||
|
||||
// NewBackend returns a backend that dynamically updates its configuration
|
||||
// based on a shared informer.
|
||||
func NewBackend(c *Config) (audit.Backend, error) {
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
eventBroadcaster.StartLogging(klog.Infof)
|
||||
eventBroadcaster.StartRecordingToSink(c.EventConfig.Sink)
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
err := auditregv1alpha1.AddToScheme(scheme)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
recorder := eventBroadcaster.NewRecorder(scheme, c.EventConfig.Source)
|
||||
|
||||
if c.BufferedConfig == nil {
|
||||
c.BufferedConfig = NewDefaultWebhookBatchConfig()
|
||||
}
|
||||
cm, err := webhook.NewClientManager(auditv1.SchemeGroupVersion, func(s *runtime.Scheme) error {
|
||||
auditinstall.Install(s)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: need a way of injecting authentication before beta
|
||||
authInfoResolver, err := webhook.NewDefaultAuthenticationInfoResolver("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cm.SetAuthenticationInfoResolver(authInfoResolver)
|
||||
cm.SetServiceResolver(c.WebhookConfig.ServiceResolver)
|
||||
cm.SetAuthenticationInfoResolverWrapper(c.WebhookConfig.AuthInfoResolverWrapper)
|
||||
|
||||
manager := &backend{
|
||||
config: c,
|
||||
delegates: atomic.Value{},
|
||||
delegateUpdateMutex: sync.Mutex{},
|
||||
webhookClientManager: cm,
|
||||
recorder: recorder,
|
||||
}
|
||||
manager.delegates.Store(syncedDelegates{})
|
||||
|
||||
c.Informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
manager.addSink(obj.(*auditregv1alpha1.AuditSink))
|
||||
},
|
||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||
manager.updateSink(oldObj.(*auditregv1alpha1.AuditSink), newObj.(*auditregv1alpha1.AuditSink))
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
sink, ok := obj.(*auditregv1alpha1.AuditSink)
|
||||
if !ok {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
klog.V(2).Infof("Couldn't get object from tombstone %#v", obj)
|
||||
return
|
||||
}
|
||||
sink, ok = tombstone.Obj.(*auditregv1alpha1.AuditSink)
|
||||
if !ok {
|
||||
klog.V(2).Infof("Tombstone contained object that is not an AuditSink: %#v", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
manager.deleteSink(sink)
|
||||
},
|
||||
})
|
||||
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
type backend struct {
|
||||
// delegateUpdateMutex holds an update lock on the delegates
|
||||
delegateUpdateMutex sync.Mutex
|
||||
config *Config
|
||||
delegates atomic.Value
|
||||
webhookClientManager webhook.ClientManager
|
||||
recorder record.EventRecorder
|
||||
}
|
||||
|
||||
type syncedDelegates map[types.UID]*delegate
|
||||
|
||||
// Names returns the names of the delegate configurations
|
||||
func (s syncedDelegates) Names() []string {
|
||||
names := []string{}
|
||||
for _, delegate := range s {
|
||||
names = append(names, delegate.configuration.Name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// ProcessEvents proccesses the given events per current delegate map
|
||||
func (b *backend) ProcessEvents(events ...*auditinternal.Event) bool {
|
||||
for _, d := range b.GetDelegates() {
|
||||
d.ProcessEvents(events...)
|
||||
}
|
||||
// Returning true regardless of results, since dynamic audit backends
|
||||
// can never cause apiserver request to fail.
|
||||
return true
|
||||
}
|
||||
|
||||
// Run starts a goroutine that propagates the shutdown signal,
|
||||
// individual delegates are ran as they are created.
|
||||
func (b *backend) Run(stopCh <-chan struct{}) error {
|
||||
go func() {
|
||||
<-stopCh
|
||||
b.stopAllDelegates()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// stopAllDelegates closes the stopChan for every delegate to enable
|
||||
// goroutines to terminate gracefully. This is a helper method to propagate
|
||||
// the primary stopChan to the current delegate map.
|
||||
func (b *backend) stopAllDelegates() {
|
||||
b.delegateUpdateMutex.Lock()
|
||||
for _, d := range b.GetDelegates() {
|
||||
close(d.stopChan)
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown calls the shutdown method on all delegates. The stopChan should
|
||||
// be closed before this is called.
|
||||
func (b *backend) Shutdown() {
|
||||
for _, d := range b.GetDelegates() {
|
||||
d.Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
// GetDelegates retrieves current delegates in a safe manner
|
||||
func (b *backend) GetDelegates() syncedDelegates {
|
||||
return b.delegates.Load().(syncedDelegates)
|
||||
}
|
||||
|
||||
// copyDelegates returns a copied delegate map
|
||||
func (b *backend) copyDelegates() syncedDelegates {
|
||||
c := make(syncedDelegates)
|
||||
for u, s := range b.GetDelegates() {
|
||||
c[u] = s
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// setDelegates sets the current delegates in a safe manner
|
||||
func (b *backend) setDelegates(delegates syncedDelegates) {
|
||||
b.delegates.Store(delegates)
|
||||
}
|
||||
|
||||
// addSink is called by the shared informer when a sink is added
|
||||
func (b *backend) addSink(sink *auditregv1alpha1.AuditSink) {
|
||||
b.delegateUpdateMutex.Lock()
|
||||
defer b.delegateUpdateMutex.Unlock()
|
||||
delegates := b.copyDelegates()
|
||||
if _, ok := delegates[sink.UID]; ok {
|
||||
klog.Errorf("Audit sink %q uid: %s already exists, could not readd", sink.Name, sink.UID)
|
||||
return
|
||||
}
|
||||
d, err := b.createAndStartDelegate(sink)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Could not add audit sink %q: %v", sink.Name, err)
|
||||
klog.Error(msg)
|
||||
b.recorder.Event(sink, corev1.EventTypeWarning, "CreateFailed", msg)
|
||||
return
|
||||
}
|
||||
delegates[sink.UID] = d
|
||||
b.setDelegates(delegates)
|
||||
klog.V(2).Infof("Added audit sink: %s", sink.Name)
|
||||
klog.V(2).Infof("Current audit sinks: %v", delegates.Names())
|
||||
}
|
||||
|
||||
// updateSink is called by the shared informer when a sink is updated.
|
||||
// The new sink is only rebuilt on spec changes. The new sink must not have
|
||||
// the same uid as the previous. The new sink will be started before the old
|
||||
// one is shutdown so no events will be lost
|
||||
func (b *backend) updateSink(oldSink, newSink *auditregv1alpha1.AuditSink) {
|
||||
b.delegateUpdateMutex.Lock()
|
||||
defer b.delegateUpdateMutex.Unlock()
|
||||
delegates := b.copyDelegates()
|
||||
oldDelegate, ok := delegates[oldSink.UID]
|
||||
if !ok {
|
||||
klog.Errorf("Could not update audit sink %q uid: %s, old sink does not exist",
|
||||
oldSink.Name, oldSink.UID)
|
||||
return
|
||||
}
|
||||
|
||||
// check if spec has changed
|
||||
eq := reflect.DeepEqual(oldSink.Spec, newSink.Spec)
|
||||
if eq {
|
||||
delete(delegates, oldSink.UID)
|
||||
delegates[newSink.UID] = oldDelegate
|
||||
b.setDelegates(delegates)
|
||||
} else {
|
||||
d, err := b.createAndStartDelegate(newSink)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Could not update audit sink %q: %v", oldSink.Name, err)
|
||||
klog.Error(msg)
|
||||
b.recorder.Event(newSink, corev1.EventTypeWarning, "UpdateFailed", msg)
|
||||
return
|
||||
}
|
||||
delete(delegates, oldSink.UID)
|
||||
delegates[newSink.UID] = d
|
||||
b.setDelegates(delegates)
|
||||
|
||||
// graceful shutdown in goroutine as to not block
|
||||
go oldDelegate.gracefulShutdown()
|
||||
}
|
||||
|
||||
klog.V(2).Infof("Updated audit sink: %s", newSink.Name)
|
||||
klog.V(2).Infof("Current audit sinks: %v", delegates.Names())
|
||||
}
|
||||
|
||||
// deleteSink is called by the shared informer when a sink is deleted
|
||||
func (b *backend) deleteSink(sink *auditregv1alpha1.AuditSink) {
|
||||
b.delegateUpdateMutex.Lock()
|
||||
defer b.delegateUpdateMutex.Unlock()
|
||||
delegates := b.copyDelegates()
|
||||
delegate, ok := delegates[sink.UID]
|
||||
if !ok {
|
||||
klog.Errorf("Could not delete audit sink %q uid: %s, does not exist", sink.Name, sink.UID)
|
||||
return
|
||||
}
|
||||
delete(delegates, sink.UID)
|
||||
b.setDelegates(delegates)
|
||||
|
||||
// graceful shutdown in goroutine as to not block
|
||||
go delegate.gracefulShutdown()
|
||||
klog.V(2).Infof("Deleted audit sink: %s", sink.Name)
|
||||
klog.V(2).Infof("Current audit sinks: %v", delegates.Names())
|
||||
}
|
||||
|
||||
// createAndStartDelegate will build a delegate from an audit sink configuration and run it
|
||||
func (b *backend) createAndStartDelegate(sink *auditregv1alpha1.AuditSink) (*delegate, error) {
|
||||
f := factory{
|
||||
config: b.config,
|
||||
webhookClientManager: b.webhookClientManager,
|
||||
sink: sink,
|
||||
}
|
||||
delegate, err := f.BuildDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = delegate.Run(delegate.stopChan)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return delegate, nil
|
||||
}
|
||||
|
||||
// String returns a string representation of the backend
|
||||
func (b *backend) String() string {
|
||||
var delegateStrings []string
|
||||
for _, delegate := range b.GetDelegates() {
|
||||
delegateStrings = append(delegateStrings, fmt.Sprintf("%s", delegate))
|
||||
}
|
||||
return fmt.Sprintf("%s[%s]", PluginName, strings.Join(delegateStrings, ","))
|
||||
}
|
||||
93
vendor/k8s.io/apiserver/plugin/pkg/audit/dynamic/enforced/enforced.go
generated
vendored
Normal file
93
vendor/k8s.io/apiserver/plugin/pkg/audit/dynamic/enforced/enforced.go
generated
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
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 enforced
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
ev "k8s.io/apiserver/pkg/audit/event"
|
||||
"k8s.io/apiserver/pkg/audit/policy"
|
||||
)
|
||||
|
||||
// PluginName is the name reported in error metrics.
|
||||
const PluginName = "enforced"
|
||||
|
||||
// Backend filters audit events according to the policy
|
||||
// trimming them as necessary to match the level
|
||||
type Backend struct {
|
||||
policyChecker policy.Checker
|
||||
delegateBackend audit.Backend
|
||||
}
|
||||
|
||||
// NewBackend returns an enforced audit backend that wraps delegate backend.
|
||||
// Enforced backend automatically runs and shuts down the delegate backend.
|
||||
func NewBackend(delegate audit.Backend, p policy.Checker) audit.Backend {
|
||||
return &Backend{
|
||||
policyChecker: p,
|
||||
delegateBackend: delegate,
|
||||
}
|
||||
}
|
||||
|
||||
// Run the delegate backend
|
||||
func (b Backend) Run(stopCh <-chan struct{}) error {
|
||||
return b.delegateBackend.Run(stopCh)
|
||||
}
|
||||
|
||||
// Shutdown the delegate backend
|
||||
func (b Backend) Shutdown() {
|
||||
b.delegateBackend.Shutdown()
|
||||
}
|
||||
|
||||
// ProcessEvents enforces policy on a shallow copy of the given event
|
||||
// dropping any sections that don't conform
|
||||
func (b Backend) ProcessEvents(events ...*auditinternal.Event) bool {
|
||||
for _, event := range events {
|
||||
if event == nil {
|
||||
continue
|
||||
}
|
||||
attr, err := ev.NewAttributes(event)
|
||||
if err != nil {
|
||||
audit.HandlePluginError(PluginName, err, event)
|
||||
continue
|
||||
}
|
||||
level, stages := b.policyChecker.LevelAndStages(attr)
|
||||
if level == auditinternal.LevelNone {
|
||||
continue
|
||||
}
|
||||
// make shallow copy before modifying to satisfy interface definition
|
||||
ev := *event
|
||||
e, err := policy.EnforcePolicy(&ev, level, stages)
|
||||
if err != nil {
|
||||
audit.HandlePluginError(PluginName, err, event)
|
||||
continue
|
||||
}
|
||||
if e == nil {
|
||||
continue
|
||||
}
|
||||
b.delegateBackend.ProcessEvents(e)
|
||||
}
|
||||
// Returning true regardless of results, since dynamic audit backends
|
||||
// can never cause apiserver request to fail.
|
||||
return true
|
||||
}
|
||||
|
||||
// String returns a string representation of the backend
|
||||
func (b Backend) String() string {
|
||||
return fmt.Sprintf("%s<%s>", PluginName, b.delegateBackend)
|
||||
}
|
||||
91
vendor/k8s.io/apiserver/plugin/pkg/audit/dynamic/factory.go
generated
vendored
Normal file
91
vendor/k8s.io/apiserver/plugin/pkg/audit/dynamic/factory.go
generated
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
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 dynamic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
auditregv1alpha1 "k8s.io/api/auditregistration/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/audit/policy"
|
||||
auditutil "k8s.io/apiserver/pkg/audit/util"
|
||||
"k8s.io/apiserver/pkg/util/webhook"
|
||||
bufferedplugin "k8s.io/apiserver/plugin/pkg/audit/buffered"
|
||||
enforcedplugin "k8s.io/apiserver/plugin/pkg/audit/dynamic/enforced"
|
||||
webhookplugin "k8s.io/apiserver/plugin/pkg/audit/webhook"
|
||||
)
|
||||
|
||||
// TODO: find a common place for all the default retry backoffs
|
||||
const retryBackoff = 500 * time.Millisecond
|
||||
|
||||
// factory builds a delegate from an AuditSink
|
||||
type factory struct {
|
||||
config *Config
|
||||
webhookClientManager webhook.ClientManager
|
||||
sink *auditregv1alpha1.AuditSink
|
||||
}
|
||||
|
||||
// BuildDelegate creates a delegate from the AuditSink object
|
||||
func (f *factory) BuildDelegate() (*delegate, error) {
|
||||
backend, err := f.buildWebhookBackend()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
backend = f.applyEnforcedOpts(backend)
|
||||
backend = f.applyBufferedOpts(backend)
|
||||
ch := make(chan struct{})
|
||||
return &delegate{
|
||||
Backend: backend,
|
||||
configuration: f.sink,
|
||||
stopChan: ch,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *factory) buildWebhookBackend() (audit.Backend, error) {
|
||||
hookClient := auditutil.HookClientConfigForSink(f.sink)
|
||||
client, err := f.webhookClientManager.HookClient(hookClient)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create webhook client: %v", err)
|
||||
}
|
||||
backend := webhookplugin.NewDynamicBackend(client, retryBackoff)
|
||||
return backend, nil
|
||||
}
|
||||
|
||||
func (f *factory) applyEnforcedOpts(delegate audit.Backend) audit.Backend {
|
||||
pol := policy.ConvertDynamicPolicyToInternal(&f.sink.Spec.Policy)
|
||||
checker := policy.NewChecker(pol)
|
||||
eb := enforcedplugin.NewBackend(delegate, checker)
|
||||
return eb
|
||||
}
|
||||
|
||||
func (f *factory) applyBufferedOpts(delegate audit.Backend) audit.Backend {
|
||||
bc := f.config.BufferedConfig
|
||||
tc := f.sink.Spec.Webhook.Throttle
|
||||
if tc != nil {
|
||||
bc.ThrottleEnable = true
|
||||
if tc.Burst != nil {
|
||||
bc.ThrottleBurst = int(*tc.Burst)
|
||||
}
|
||||
if tc.QPS != nil {
|
||||
bc.ThrottleQPS = float32(*tc.QPS)
|
||||
}
|
||||
} else {
|
||||
bc.ThrottleEnable = false
|
||||
}
|
||||
return bufferedplugin.NewBackend(delegate, *bc)
|
||||
}
|
||||
14
vendor/k8s.io/apiserver/plugin/pkg/audit/log/backend.go
generated
vendored
14
vendor/k8s.io/apiserver/plugin/pkg/audit/log/backend.go
generated
vendored
|
|
@ -59,13 +59,15 @@ func NewBackend(out io.Writer, format string, groupVersion schema.GroupVersion)
|
|||
}
|
||||
}
|
||||
|
||||
func (b *backend) ProcessEvents(events ...*auditinternal.Event) {
|
||||
func (b *backend) ProcessEvents(events ...*auditinternal.Event) bool {
|
||||
success := true
|
||||
for _, ev := range events {
|
||||
b.logEvent(ev)
|
||||
success = b.logEvent(ev) && success
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func (b *backend) logEvent(ev *auditinternal.Event) {
|
||||
func (b *backend) logEvent(ev *auditinternal.Event) bool {
|
||||
line := ""
|
||||
switch b.format {
|
||||
case FormatLegacy:
|
||||
|
|
@ -74,17 +76,19 @@ func (b *backend) logEvent(ev *auditinternal.Event) {
|
|||
bs, err := runtime.Encode(audit.Codecs.LegacyCodec(b.groupVersion), ev)
|
||||
if err != nil {
|
||||
audit.HandlePluginError(PluginName, err, ev)
|
||||
return
|
||||
return false
|
||||
}
|
||||
line = string(bs[:])
|
||||
default:
|
||||
audit.HandlePluginError(PluginName, fmt.Errorf("log format %q is not in list of known formats (%s)",
|
||||
b.format, strings.Join(AllowedFormats, ",")), ev)
|
||||
return
|
||||
return false
|
||||
}
|
||||
if _, err := fmt.Fprint(b.out, line); err != nil {
|
||||
audit.HandlePluginError(PluginName, err, ev)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *backend) Run(stopCh <-chan struct{}) error {
|
||||
|
|
|
|||
8
vendor/k8s.io/apiserver/plugin/pkg/audit/truncate/truncate.go
generated
vendored
8
vendor/k8s.io/apiserver/plugin/pkg/audit/truncate/truncate.go
generated
vendored
|
|
@ -71,11 +71,12 @@ func NewBackend(delegateBackend audit.Backend, config Config, groupVersion schem
|
|||
}
|
||||
}
|
||||
|
||||
func (b *backend) ProcessEvents(events ...*auditinternal.Event) {
|
||||
func (b *backend) ProcessEvents(events ...*auditinternal.Event) bool {
|
||||
var errors []error
|
||||
var impacted []*auditinternal.Event
|
||||
var batch []*auditinternal.Event
|
||||
var batchSize int64
|
||||
success := true
|
||||
for _, event := range events {
|
||||
size, err := b.calcSize(event)
|
||||
// If event was correctly serialized, but the size is more than allowed
|
||||
|
|
@ -97,7 +98,7 @@ func (b *backend) ProcessEvents(events ...*auditinternal.Event) {
|
|||
}
|
||||
|
||||
if len(batch) > 0 && batchSize+size > b.c.MaxBatchSize {
|
||||
b.delegateBackend.ProcessEvents(batch...)
|
||||
success = b.delegateBackend.ProcessEvents(batch...) && success
|
||||
batch = []*auditinternal.Event{}
|
||||
batchSize = 0
|
||||
}
|
||||
|
|
@ -107,12 +108,13 @@ func (b *backend) ProcessEvents(events ...*auditinternal.Event) {
|
|||
}
|
||||
|
||||
if len(batch) > 0 {
|
||||
b.delegateBackend.ProcessEvents(batch...)
|
||||
success = b.delegateBackend.ProcessEvents(batch...) && success
|
||||
}
|
||||
|
||||
if len(impacted) > 0 {
|
||||
audit.HandlePluginError(PluginName, utilerrors.NewAggregate(errors), impacted...)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// truncate removed request and response objects from the audit events,
|
||||
|
|
|
|||
26
vendor/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go
generated
vendored
26
vendor/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go
generated
vendored
|
|
@ -18,6 +18,7 @@ limitations under the License.
|
|||
package webhook
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
|
@ -47,7 +48,20 @@ func loadWebhook(configFile string, groupVersion schema.GroupVersion, initialBac
|
|||
}
|
||||
|
||||
type backend struct {
|
||||
w *webhook.GenericWebhook
|
||||
w *webhook.GenericWebhook
|
||||
name string
|
||||
}
|
||||
|
||||
// NewDynamicBackend returns an audit backend configured from a REST client that
|
||||
// sends events over HTTP to an external service.
|
||||
func NewDynamicBackend(rc *rest.RESTClient, initialBackoff time.Duration) audit.Backend {
|
||||
return &backend{
|
||||
w: &webhook.GenericWebhook{
|
||||
RestClient: rc,
|
||||
InitialBackoff: initialBackoff,
|
||||
},
|
||||
name: fmt.Sprintf("dynamic_%s", PluginName),
|
||||
}
|
||||
}
|
||||
|
||||
// NewBackend returns an audit backend that sends events over HTTP to an external service.
|
||||
|
|
@ -56,7 +70,7 @@ func NewBackend(kubeConfigFile string, groupVersion schema.GroupVersion, initial
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &backend{w}, nil
|
||||
return &backend{w: w, name: PluginName}, nil
|
||||
}
|
||||
|
||||
func (b *backend) Run(stopCh <-chan struct{}) error {
|
||||
|
|
@ -67,10 +81,12 @@ func (b *backend) Shutdown() {
|
|||
// nothing to do here
|
||||
}
|
||||
|
||||
func (b *backend) ProcessEvents(ev ...*auditinternal.Event) {
|
||||
func (b *backend) ProcessEvents(ev ...*auditinternal.Event) bool {
|
||||
if err := b.processEvents(ev...); err != nil {
|
||||
audit.HandlePluginError(PluginName, err, ev...)
|
||||
audit.HandlePluginError(b.String(), err, ev...)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *backend) processEvents(ev ...*auditinternal.Event) error {
|
||||
|
|
@ -84,5 +100,5 @@ func (b *backend) processEvents(ev ...*auditinternal.Event) error {
|
|||
}
|
||||
|
||||
func (b *backend) String() string {
|
||||
return PluginName
|
||||
return b.name
|
||||
}
|
||||
|
|
|
|||
120
vendor/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go
generated
vendored
120
vendor/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go
generated
vendored
|
|
@ -18,20 +18,19 @@ limitations under the License.
|
|||
package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
authentication "k8s.io/api/authentication/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/cache"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/util/webhook"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -45,56 +44,88 @@ var _ authenticator.Token = (*WebhookTokenAuthenticator)(nil)
|
|||
|
||||
type WebhookTokenAuthenticator struct {
|
||||
tokenReview authenticationclient.TokenReviewInterface
|
||||
responseCache *cache.LRUExpireCache
|
||||
ttl time.Duration
|
||||
initialBackoff time.Duration
|
||||
implicitAuds authenticator.Audiences
|
||||
}
|
||||
|
||||
// NewFromInterface creates a webhook authenticator using the given tokenReview client
|
||||
func NewFromInterface(tokenReview authenticationclient.TokenReviewInterface, ttl time.Duration) (*WebhookTokenAuthenticator, error) {
|
||||
return newWithBackoff(tokenReview, ttl, retryBackoff)
|
||||
// NewFromInterface creates a webhook authenticator using the given tokenReview
|
||||
// client. It is recommend to wrap this authenticator with the token cache
|
||||
// authenticator implemented in
|
||||
// k8s.io/apiserver/pkg/authentication/token/cache.
|
||||
func NewFromInterface(tokenReview authenticationclient.TokenReviewInterface, implicitAuds authenticator.Audiences) (*WebhookTokenAuthenticator, error) {
|
||||
return newWithBackoff(tokenReview, retryBackoff, implicitAuds)
|
||||
}
|
||||
|
||||
// New creates a new WebhookTokenAuthenticator from the provided kubeconfig file.
|
||||
func New(kubeConfigFile string, ttl time.Duration) (*WebhookTokenAuthenticator, error) {
|
||||
// New creates a new WebhookTokenAuthenticator from the provided kubeconfig
|
||||
// file. It is recommend to wrap this authenticator with the token cache
|
||||
// authenticator implemented in
|
||||
// k8s.io/apiserver/pkg/authentication/token/cache.
|
||||
func New(kubeConfigFile string, implicitAuds authenticator.Audiences) (*WebhookTokenAuthenticator, error) {
|
||||
tokenReview, err := tokenReviewInterfaceFromKubeconfig(kubeConfigFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWithBackoff(tokenReview, ttl, retryBackoff)
|
||||
return newWithBackoff(tokenReview, retryBackoff, implicitAuds)
|
||||
}
|
||||
|
||||
// newWithBackoff allows tests to skip the sleep.
|
||||
func newWithBackoff(tokenReview authenticationclient.TokenReviewInterface, ttl, initialBackoff time.Duration) (*WebhookTokenAuthenticator, error) {
|
||||
return &WebhookTokenAuthenticator{tokenReview, cache.NewLRUExpireCache(1024), ttl, initialBackoff}, nil
|
||||
func newWithBackoff(tokenReview authenticationclient.TokenReviewInterface, initialBackoff time.Duration, implicitAuds authenticator.Audiences) (*WebhookTokenAuthenticator, error) {
|
||||
return &WebhookTokenAuthenticator{tokenReview, initialBackoff, implicitAuds}, nil
|
||||
}
|
||||
|
||||
// AuthenticateToken implements the authenticator.Token interface.
|
||||
func (w *WebhookTokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, error) {
|
||||
func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
|
||||
// We take implicit audiences of the API server at WebhookTokenAuthenticator
|
||||
// construction time. The outline of how we validate audience here is:
|
||||
//
|
||||
// * if the ctx is not audience limited, don't do any audience validation.
|
||||
// * if ctx is audience-limited, add the audiences to the tokenreview spec
|
||||
// * if the tokenreview returns with audiences in the status that intersect
|
||||
// with the audiences in the ctx, copy into the response and return success
|
||||
// * if the tokenreview returns without an audience in the status, ensure
|
||||
// the ctx audiences intersect with the implicit audiences, and set the
|
||||
// intersection in the response.
|
||||
// * otherwise return unauthenticated.
|
||||
wantAuds, checkAuds := authenticator.AudiencesFrom(ctx)
|
||||
r := &authentication.TokenReview{
|
||||
Spec: authentication.TokenReviewSpec{Token: token},
|
||||
Spec: authentication.TokenReviewSpec{
|
||||
Token: token,
|
||||
Audiences: wantAuds,
|
||||
},
|
||||
}
|
||||
if entry, ok := w.responseCache.Get(r.Spec); ok {
|
||||
r.Status = entry.(authentication.TokenReviewStatus)
|
||||
} else {
|
||||
var (
|
||||
result *authentication.TokenReview
|
||||
err error
|
||||
)
|
||||
webhook.WithExponentialBackoff(w.initialBackoff, func() error {
|
||||
result, err = w.tokenReview.Create(r)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
// An error here indicates bad configuration or an outage. Log for debugging.
|
||||
glog.Errorf("Failed to make webhook authenticator request: %v", err)
|
||||
return nil, false, err
|
||||
var (
|
||||
result *authentication.TokenReview
|
||||
err error
|
||||
auds authenticator.Audiences
|
||||
)
|
||||
webhook.WithExponentialBackoff(w.initialBackoff, func() error {
|
||||
result, err = w.tokenReview.Create(r)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
// An error here indicates bad configuration or an outage. Log for debugging.
|
||||
klog.Errorf("Failed to make webhook authenticator request: %v", err)
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
if checkAuds {
|
||||
gotAuds := w.implicitAuds
|
||||
if len(result.Status.Audiences) > 0 {
|
||||
gotAuds = result.Status.Audiences
|
||||
}
|
||||
auds = wantAuds.Intersect(gotAuds)
|
||||
if len(auds) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
r.Status = result.Status
|
||||
w.responseCache.Add(r.Spec, result.Status, w.ttl)
|
||||
}
|
||||
|
||||
r.Status = result.Status
|
||||
if !r.Status.Authenticated {
|
||||
return nil, false, nil
|
||||
var err error
|
||||
if len(r.Status.Error) != 0 {
|
||||
err = errors.New(r.Status.Error)
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
var extra map[string][]string
|
||||
|
|
@ -105,11 +136,14 @@ func (w *WebhookTokenAuthenticator) AuthenticateToken(token string) (user.Info,
|
|||
}
|
||||
}
|
||||
|
||||
return &user.DefaultInfo{
|
||||
Name: r.Status.User.Username,
|
||||
UID: r.Status.User.UID,
|
||||
Groups: r.Status.User.Groups,
|
||||
Extra: extra,
|
||||
return &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: r.Status.User.Username,
|
||||
UID: r.Status.User.UID,
|
||||
Groups: r.Status.User.Groups,
|
||||
Extra: extra,
|
||||
},
|
||||
Audiences: auds,
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
|
|
@ -118,8 +152,12 @@ func (w *WebhookTokenAuthenticator) AuthenticateToken(token string) (user.Info,
|
|||
// requests to the exact path specified in the kubeconfig file, so arbitrary non-API servers can be targeted.
|
||||
func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string) (authenticationclient.TokenReviewInterface, error) {
|
||||
localScheme := runtime.NewScheme()
|
||||
scheme.AddToScheme(localScheme)
|
||||
utilruntime.Must(localScheme.SetVersionPriority(groupVersions...))
|
||||
if err := scheme.AddToScheme(localScheme); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := localScheme.SetVersionPriority(groupVersions...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0)
|
||||
if err != nil {
|
||||
|
|
|
|||
18
vendor/k8s.io/apiserver/plugin/pkg/authorizer/webhook/gencerts.sh
generated
vendored
18
vendor/k8s.io/apiserver/plugin/pkg/authorizer/webhook/gencerts.sh
generated
vendored
|
|
@ -17,7 +17,7 @@
|
|||
set -e
|
||||
|
||||
# gencerts.sh generates the certificates for the webhook authz plugin tests.
|
||||
#
|
||||
#
|
||||
# It is not expected to be run often (there is no go generate rule), and mainly
|
||||
# exists for documentation purposes.
|
||||
|
||||
|
|
@ -83,12 +83,12 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was generated using openssl by the gencerts.sh script
|
||||
// and holds raw certificates for the webhook tests.
|
||||
|
||||
package webhook
|
||||
EOF
|
||||
|
||||
echo "// This file was generated using openssl by the gencerts.sh script" >> $outfile
|
||||
echo "// and holds raw certificates for the webhook tests." >> $outfile
|
||||
echo "" >> $outfile
|
||||
echo "package webhook" >> $outfile
|
||||
for file in caKey caCert badCAKey badCACert serverKey serverCert clientKey clientCert; do
|
||||
data=$(cat ${file}.pem)
|
||||
echo "" >> $outfile
|
||||
|
|
@ -96,7 +96,7 @@ for file in caKey caCert badCAKey badCACert serverKey serverCert clientKey clien
|
|||
done
|
||||
|
||||
# Clean up after we're done.
|
||||
rm *.pem
|
||||
rm *.csr
|
||||
rm *.srl
|
||||
rm *.conf
|
||||
rm ./*.pem
|
||||
rm ./*.csr
|
||||
rm ./*.srl
|
||||
rm ./*.conf
|
||||
|
|
|
|||
42
vendor/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go
generated
vendored
42
vendor/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go
generated
vendored
|
|
@ -22,7 +22,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
|
||||
authorization "k8s.io/api/authorization/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -39,7 +39,11 @@ var (
|
|||
groupVersions = []schema.GroupVersion{authorization.SchemeGroupVersion}
|
||||
)
|
||||
|
||||
const retryBackoff = 500 * time.Millisecond
|
||||
const (
|
||||
retryBackoff = 500 * time.Millisecond
|
||||
// The maximum length of requester-controlled attributes to allow caching.
|
||||
maxControlledAttrCacheSize = 10000
|
||||
)
|
||||
|
||||
// Ensure Webhook implements the authorizer.Authorizer interface.
|
||||
var _ authorizer.Authorizer = (*WebhookAuthorizer)(nil)
|
||||
|
|
@ -189,14 +193,16 @@ func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (decision auth
|
|||
})
|
||||
if err != nil {
|
||||
// An error here indicates bad configuration or an outage. Log for debugging.
|
||||
glog.Errorf("Failed to make webhook authorizer request: %v", err)
|
||||
klog.Errorf("Failed to make webhook authorizer request: %v", err)
|
||||
return w.decisionOnError, "", err
|
||||
}
|
||||
r.Status = result.Status
|
||||
if r.Status.Allowed {
|
||||
w.responseCache.Add(string(key), r.Status, w.authorizedTTL)
|
||||
} else {
|
||||
w.responseCache.Add(string(key), r.Status, w.unauthorizedTTL)
|
||||
if shouldCache(attr) {
|
||||
if r.Status.Allowed {
|
||||
w.responseCache.Add(string(key), r.Status, w.authorizedTTL)
|
||||
} else {
|
||||
w.responseCache.Add(string(key), r.Status, w.unauthorizedTTL)
|
||||
}
|
||||
}
|
||||
}
|
||||
switch {
|
||||
|
|
@ -239,8 +245,12 @@ func convertToSARExtra(extra map[string][]string) map[string]authorization.Extra
|
|||
// requests to the exact path specified in the kubeconfig file, so arbitrary non-API servers can be targeted.
|
||||
func subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile string) (authorizationclient.SubjectAccessReviewInterface, error) {
|
||||
localScheme := runtime.NewScheme()
|
||||
scheme.AddToScheme(localScheme)
|
||||
localScheme.SetVersionPriority(groupVersions...)
|
||||
if err := scheme.AddToScheme(localScheme); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := localScheme.SetVersionPriority(groupVersions...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0)
|
||||
if err != nil {
|
||||
|
|
@ -258,3 +268,17 @@ func (t *subjectAccessReviewClient) Create(subjectAccessReview *authorization.Su
|
|||
err := t.w.RestClient.Post().Body(subjectAccessReview).Do().Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// shouldCache determines whether it is safe to cache the given request attributes. If the
|
||||
// requester-controlled attributes are too large, this may be a DoS attempt, so we skip the cache.
|
||||
func shouldCache(attr authorizer.Attributes) bool {
|
||||
controlledAttrSize := int64(len(attr.GetNamespace())) +
|
||||
int64(len(attr.GetVerb())) +
|
||||
int64(len(attr.GetAPIGroup())) +
|
||||
int64(len(attr.GetAPIVersion())) +
|
||||
int64(len(attr.GetResource())) +
|
||||
int64(len(attr.GetSubresource())) +
|
||||
int64(len(attr.GetName())) +
|
||||
int64(len(attr.GetPath()))
|
||||
return controlledAttrSize < maxControlledAttrCacheSize
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue