mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
build: move e2e dependencies into e2e/go.mod
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
15da101b1b
commit
bec6090996
8
e2e/vendor/k8s.io/apiserver/pkg/audit/OWNERS
generated
vendored
Normal file
8
e2e/vendor/k8s.io/apiserver/pkg/audit/OWNERS
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- sig-auth-audit-approvers
|
||||
reviewers:
|
||||
- sig-auth-audit-reviewers
|
||||
labels:
|
||||
- sig/auth
|
188
e2e/vendor/k8s.io/apiserver/pkg/audit/context.go
generated
vendored
Normal file
188
e2e/vendor/k8s.io/apiserver/pkg/audit/context.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
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"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// The key type is unexported to prevent collisions
|
||||
type key int
|
||||
|
||||
// auditKey is the context key for storing the audit context that is being
|
||||
// captured and the evaluated policy that applies to the given request.
|
||||
const auditKey key = iota
|
||||
|
||||
// AuditContext holds the information for constructing the audit events for the current request.
|
||||
type AuditContext struct {
|
||||
// RequestAuditConfig is the audit configuration that applies to the request
|
||||
RequestAuditConfig RequestAuditConfig
|
||||
|
||||
// Event is the audit Event object that is being captured to be written in
|
||||
// the API audit log.
|
||||
Event auditinternal.Event
|
||||
|
||||
// annotationMutex guards event.Annotations
|
||||
annotationMutex sync.Mutex
|
||||
}
|
||||
|
||||
// Enabled checks whether auditing is enabled for this audit context.
|
||||
func (ac *AuditContext) Enabled() bool {
|
||||
// Note: An unset Level should be considered Enabled, so that request data (e.g. annotations)
|
||||
// can still be captured before the audit policy is evaluated.
|
||||
return ac != nil && ac.RequestAuditConfig.Level != auditinternal.LevelNone
|
||||
}
|
||||
|
||||
// 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) {
|
||||
ac := AuditContextFrom(ctx)
|
||||
if !ac.Enabled() {
|
||||
return
|
||||
}
|
||||
|
||||
ac.annotationMutex.Lock()
|
||||
defer ac.annotationMutex.Unlock()
|
||||
|
||||
addAuditAnnotationLocked(ac, key, value)
|
||||
}
|
||||
|
||||
// AddAuditAnnotations is a bulk version of AddAuditAnnotation. Refer to AddAuditAnnotation for
|
||||
// restrictions on when this can be called.
|
||||
// keysAndValues are the key-value pairs to add, and must have an even number of items.
|
||||
func AddAuditAnnotations(ctx context.Context, keysAndValues ...string) {
|
||||
ac := AuditContextFrom(ctx)
|
||||
if !ac.Enabled() {
|
||||
return
|
||||
}
|
||||
|
||||
ac.annotationMutex.Lock()
|
||||
defer ac.annotationMutex.Unlock()
|
||||
|
||||
if len(keysAndValues)%2 != 0 {
|
||||
klog.Errorf("Dropping mismatched audit annotation %q", keysAndValues[len(keysAndValues)-1])
|
||||
}
|
||||
for i := 0; i < len(keysAndValues); i += 2 {
|
||||
addAuditAnnotationLocked(ac, keysAndValues[i], keysAndValues[i+1])
|
||||
}
|
||||
}
|
||||
|
||||
// AddAuditAnnotationsMap is a bulk version of AddAuditAnnotation. Refer to AddAuditAnnotation for
|
||||
// restrictions on when this can be called.
|
||||
func AddAuditAnnotationsMap(ctx context.Context, annotations map[string]string) {
|
||||
ac := AuditContextFrom(ctx)
|
||||
if !ac.Enabled() {
|
||||
return
|
||||
}
|
||||
|
||||
ac.annotationMutex.Lock()
|
||||
defer ac.annotationMutex.Unlock()
|
||||
|
||||
for k, v := range annotations {
|
||||
addAuditAnnotationLocked(ac, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// addAuditAnnotationLocked records the audit annotation on the event.
|
||||
func addAuditAnnotationLocked(ac *AuditContext, key, value string) {
|
||||
ae := &ac.Event
|
||||
|
||||
if ae.Annotations == nil {
|
||||
ae.Annotations = make(map[string]string)
|
||||
}
|
||||
if v, ok := ae.Annotations[key]; ok && v != value {
|
||||
klog.Warningf("Failed to set annotations[%q] to %q for audit:%q, it has already been set to %q", key, value, ae.AuditID, ae.Annotations[key])
|
||||
return
|
||||
}
|
||||
ae.Annotations[key] = value
|
||||
}
|
||||
|
||||
// WithAuditContext returns a new context that stores the AuditContext.
|
||||
func WithAuditContext(parent context.Context) context.Context {
|
||||
if AuditContextFrom(parent) != nil {
|
||||
return parent // Avoid double registering.
|
||||
}
|
||||
|
||||
return genericapirequest.WithValue(parent, auditKey, &AuditContext{})
|
||||
}
|
||||
|
||||
// AuditEventFrom returns the audit event struct on the ctx
|
||||
func AuditEventFrom(ctx context.Context) *auditinternal.Event {
|
||||
if ac := AuditContextFrom(ctx); ac.Enabled() {
|
||||
return &ac.Event
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AuditContextFrom returns the pair of the audit configuration object
|
||||
// that applies to the given request and the audit event that is going to
|
||||
// be written to the API audit log.
|
||||
func AuditContextFrom(ctx context.Context) *AuditContext {
|
||||
ev, _ := ctx.Value(auditKey).(*AuditContext)
|
||||
return ev
|
||||
}
|
||||
|
||||
// WithAuditID sets the AuditID on the AuditContext. The AuditContext must already be present in the
|
||||
// request context. If the specified auditID is empty, no value is set.
|
||||
func WithAuditID(ctx context.Context, auditID types.UID) {
|
||||
if auditID == "" {
|
||||
return
|
||||
}
|
||||
if ac := AuditContextFrom(ctx); ac != nil {
|
||||
ac.Event.AuditID = auditID
|
||||
}
|
||||
}
|
||||
|
||||
// AuditIDFrom returns the value of the audit ID from the request context, along with whether
|
||||
// auditing is enabled.
|
||||
func AuditIDFrom(ctx context.Context) (types.UID, bool) {
|
||||
if ac := AuditContextFrom(ctx); ac != nil {
|
||||
return ac.Event.AuditID, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// GetAuditIDTruncated returns the audit ID (truncated) from the request context.
|
||||
// If the length of the Audit-ID value exceeds the limit, we truncate it to keep
|
||||
// the first N (maxAuditIDLength) characters.
|
||||
// This is intended to be used in logging only.
|
||||
func GetAuditIDTruncated(ctx context.Context) string {
|
||||
auditID, ok := AuditIDFrom(ctx)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
// if the user has specified a very long audit ID then we will use the first N characters
|
||||
// Note: assuming Audit-ID header is in ASCII
|
||||
const maxAuditIDLength = 64
|
||||
if len(auditID) > maxAuditIDLength {
|
||||
auditID = auditID[:maxAuditIDLength]
|
||||
}
|
||||
|
||||
return string(auditID)
|
||||
}
|
45
e2e/vendor/k8s.io/apiserver/pkg/audit/evaluator.go
generated
vendored
Normal file
45
e2e/vendor/k8s.io/apiserver/pkg/audit/evaluator.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2021 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 (
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
|
||||
// RequestAuditConfig is the evaluated audit configuration that is applicable to
|
||||
// a given request. PolicyRuleEvaluator evaluates the audit policy against the
|
||||
// authorizer attributes and returns a RequestAuditConfig that applies to the request.
|
||||
type RequestAuditConfig struct {
|
||||
// Level at which the request is being audited at
|
||||
Level audit.Level
|
||||
|
||||
// OmitStages is the stages that need to be omitted from being audited.
|
||||
OmitStages []audit.Stage
|
||||
|
||||
// OmitManagedFields indicates whether to omit the managed fields of the request
|
||||
// and response bodies from being written to the API audit log.
|
||||
OmitManagedFields bool
|
||||
}
|
||||
|
||||
// PolicyRuleEvaluator exposes methods for evaluating the policy rules.
|
||||
type PolicyRuleEvaluator interface {
|
||||
// EvaluatePolicyRule evaluates the audit policy of the apiserver against
|
||||
// the given authorizer attributes and returns the audit configuration that
|
||||
// is applicable to the given equest.
|
||||
EvaluatePolicyRule(authorizer.Attributes) RequestAuditConfig
|
||||
}
|
73
e2e/vendor/k8s.io/apiserver/pkg/audit/format.go
generated
vendored
Normal file
73
e2e/vendor/k8s.io/apiserver/pkg/audit/format.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
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 audit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
)
|
||||
|
||||
// EventString creates a 1-line text representation of an audit event, using a subset of the
|
||||
// information in the event struct.
|
||||
func EventString(ev *auditinternal.Event) string {
|
||||
username := "<none>"
|
||||
groups := "<none>"
|
||||
if len(ev.User.Username) > 0 {
|
||||
username = ev.User.Username
|
||||
if len(ev.User.Groups) > 0 {
|
||||
groups = auditStringSlice(ev.User.Groups)
|
||||
}
|
||||
}
|
||||
asuser := "<self>"
|
||||
asgroups := "<lookup>"
|
||||
if ev.ImpersonatedUser != nil {
|
||||
asuser = ev.ImpersonatedUser.Username
|
||||
if ev.ImpersonatedUser.Groups != nil {
|
||||
asgroups = auditStringSlice(ev.ImpersonatedUser.Groups)
|
||||
}
|
||||
}
|
||||
|
||||
namespace := "<none>"
|
||||
if ev.ObjectRef != nil && len(ev.ObjectRef.Namespace) != 0 {
|
||||
namespace = ev.ObjectRef.Namespace
|
||||
}
|
||||
|
||||
response := "<deferred>"
|
||||
if ev.ResponseStatus != nil {
|
||||
response = strconv.Itoa(int(ev.ResponseStatus.Code))
|
||||
}
|
||||
|
||||
ip := "<unknown>"
|
||||
if len(ev.SourceIPs) > 0 {
|
||||
ip = ev.SourceIPs[0]
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s AUDIT: id=%q stage=%q ip=%q method=%q user=%q groups=%q as=%q asgroups=%q user-agent=%q namespace=%q uri=%q response=\"%s\"",
|
||||
ev.RequestReceivedTimestamp.Format(time.RFC3339Nano), ev.AuditID, ev.Stage, ip, ev.Verb, username, groups, asuser, asgroups, ev.UserAgent, namespace, ev.RequestURI, response)
|
||||
}
|
||||
|
||||
func auditStringSlice(inList []string) string {
|
||||
quotedElements := make([]string, len(inList))
|
||||
for i, in := range inList {
|
||||
quotedElements[i] = fmt.Sprintf("%q", in)
|
||||
}
|
||||
return strings.Join(quotedElements, ",")
|
||||
}
|
111
e2e/vendor/k8s.io/apiserver/pkg/audit/metrics.go
generated
vendored
Normal file
111
e2e/vendor/k8s.io/apiserver/pkg/audit/metrics.go
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
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 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/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
subsystem = "apiserver_audit"
|
||||
)
|
||||
|
||||
/*
|
||||
* By default, all the following metrics are defined as falling under
|
||||
* ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/1209-metrics-stability/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
|
||||
* the metric stability policy.
|
||||
*/
|
||||
var (
|
||||
eventCounter = metrics.NewCounter(
|
||||
&metrics.CounterOpts{
|
||||
Subsystem: subsystem,
|
||||
Name: "event_total",
|
||||
Help: "Counter of audit events generated and sent to the audit backend.",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
})
|
||||
errorCounter = metrics.NewCounterVec(
|
||||
&metrics.CounterOpts{
|
||||
Subsystem: subsystem,
|
||||
Name: "error_total",
|
||||
Help: "Counter of audit events that failed to be audited properly. " +
|
||||
"Plugin identifies the plugin affected by the error.",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"plugin"},
|
||||
)
|
||||
levelCounter = metrics.NewCounterVec(
|
||||
&metrics.CounterOpts{
|
||||
Subsystem: subsystem,
|
||||
Name: "level_total",
|
||||
Help: "Counter of policy levels for audit events (1 per request).",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"level"},
|
||||
)
|
||||
|
||||
ApiserverAuditDroppedCounter = metrics.NewCounter(
|
||||
&metrics.CounterOpts{
|
||||
Subsystem: subsystem,
|
||||
Name: "requests_rejected_total",
|
||||
Help: "Counter of apiserver requests rejected due to an error " +
|
||||
"in audit logging backend.",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
func init() {
|
||||
legacyregistry.MustRegister(eventCounter)
|
||||
legacyregistry.MustRegister(errorCounter)
|
||||
legacyregistry.MustRegister(levelCounter)
|
||||
legacyregistry.MustRegister(ApiserverAuditDroppedCounter)
|
||||
}
|
||||
|
||||
// ObserveEvent updates the relevant prometheus metrics for the generated audit event.
|
||||
func ObserveEvent(ctx context.Context) {
|
||||
eventCounter.WithContext(ctx).Inc()
|
||||
}
|
||||
|
||||
// ObservePolicyLevel updates the relevant prometheus metrics with the audit level for a request.
|
||||
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
|
||||
// used if the error may have prevented the audit event from being properly recorded. The events are
|
||||
// logged to the debug log.
|
||||
func HandlePluginError(plugin string, err error, impacted ...*auditinternal.Event) {
|
||||
// Count the error.
|
||||
errorCounter.WithLabelValues(plugin).Add(float64(len(impacted)))
|
||||
|
||||
// Log the audit events to the debug log.
|
||||
msg := fmt.Sprintf("Error in audit plugin '%s' affecting %d audit events: %v\nImpacted events:\n",
|
||||
plugin, len(impacted), err)
|
||||
for _, ev := range impacted {
|
||||
msg = msg + EventString(ev) + "\n"
|
||||
}
|
||||
klog.Error(msg)
|
||||
}
|
239
e2e/vendor/k8s.io/apiserver/pkg/audit/policy/checker.go
generated
vendored
Normal file
239
e2e/vendor/k8s.io/apiserver/pkg/audit/policy/checker.go
generated
vendored
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
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 policy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
auditinternal "k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultAuditLevel is the default level to audit at, if no policy rules are matched.
|
||||
DefaultAuditLevel = audit.LevelNone
|
||||
)
|
||||
|
||||
// NewPolicyRuleEvaluator creates a new policy rule evaluator.
|
||||
func NewPolicyRuleEvaluator(policy *audit.Policy) auditinternal.PolicyRuleEvaluator {
|
||||
for i, rule := range policy.Rules {
|
||||
policy.Rules[i].OmitStages = unionStages(policy.OmitStages, rule.OmitStages)
|
||||
}
|
||||
return &policyRuleEvaluator{*policy}
|
||||
}
|
||||
|
||||
func unionStages(stageLists ...[]audit.Stage) []audit.Stage {
|
||||
m := make(map[audit.Stage]bool)
|
||||
for _, sl := range stageLists {
|
||||
for _, s := range sl {
|
||||
m[s] = true
|
||||
}
|
||||
}
|
||||
result := make([]audit.Stage, 0, len(m))
|
||||
for key := range m {
|
||||
result = append(result, key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NewFakePolicyRuleEvaluator creates a fake policy rule evaluator that returns
|
||||
// a constant level for all requests (for testing).
|
||||
func NewFakePolicyRuleEvaluator(level audit.Level, stage []audit.Stage) auditinternal.PolicyRuleEvaluator {
|
||||
return &fakePolicyRuleEvaluator{level, stage}
|
||||
}
|
||||
|
||||
type policyRuleEvaluator struct {
|
||||
audit.Policy
|
||||
}
|
||||
|
||||
func (p *policyRuleEvaluator) EvaluatePolicyRule(attrs authorizer.Attributes) auditinternal.RequestAuditConfig {
|
||||
for _, rule := range p.Rules {
|
||||
if ruleMatches(&rule, attrs) {
|
||||
return auditinternal.RequestAuditConfig{
|
||||
Level: rule.Level,
|
||||
OmitStages: rule.OmitStages,
|
||||
OmitManagedFields: isOmitManagedFields(&rule, p.OmitManagedFields),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return auditinternal.RequestAuditConfig{
|
||||
Level: DefaultAuditLevel,
|
||||
OmitStages: p.OmitStages,
|
||||
OmitManagedFields: p.OmitManagedFields,
|
||||
}
|
||||
}
|
||||
|
||||
// isOmitManagedFields returns whether to omit managed fields from the request
|
||||
// and response bodies from being written to the API audit log.
|
||||
// If a user specifies OmitManagedFields inside a policy rule, that overrides
|
||||
// the global policy default in Policy.OmitManagedFields.
|
||||
func isOmitManagedFields(policyRule *audit.PolicyRule, policyDefault bool) bool {
|
||||
if policyRule.OmitManagedFields == nil {
|
||||
return policyDefault
|
||||
}
|
||||
|
||||
return *policyRule.OmitManagedFields
|
||||
}
|
||||
|
||||
// Check whether the rule matches the request attrs.
|
||||
func ruleMatches(r *audit.PolicyRule, attrs authorizer.Attributes) bool {
|
||||
user := attrs.GetUser()
|
||||
if len(r.Users) > 0 {
|
||||
if user == nil || !hasString(r.Users, user.GetName()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(r.UserGroups) > 0 {
|
||||
if user == nil {
|
||||
return false
|
||||
}
|
||||
matched := false
|
||||
for _, group := range user.GetGroups() {
|
||||
if hasString(r.UserGroups, group) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(r.Verbs) > 0 {
|
||||
if !hasString(r.Verbs, attrs.GetVerb()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.Namespaces) > 0 || len(r.Resources) > 0 {
|
||||
return ruleMatchesResource(r, attrs)
|
||||
}
|
||||
|
||||
if len(r.NonResourceURLs) > 0 {
|
||||
return ruleMatchesNonResource(r, attrs)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Check whether the rule's non-resource URLs match the request attrs.
|
||||
func ruleMatchesNonResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool {
|
||||
if attrs.IsResourceRequest() {
|
||||
return false
|
||||
}
|
||||
|
||||
path := attrs.GetPath()
|
||||
for _, spec := range r.NonResourceURLs {
|
||||
if pathMatches(path, spec) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Check whether the path matches the path specification.
|
||||
func pathMatches(path, spec string) bool {
|
||||
// Allow wildcard match
|
||||
if spec == "*" {
|
||||
return true
|
||||
}
|
||||
// Allow exact match
|
||||
if spec == path {
|
||||
return true
|
||||
}
|
||||
// Allow a trailing * subpath match
|
||||
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Check whether the rule's resource fields match the request attrs.
|
||||
func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool {
|
||||
if !attrs.IsResourceRequest() {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(r.Namespaces) > 0 {
|
||||
if !hasString(r.Namespaces, attrs.GetNamespace()) { // Non-namespaced resources use the empty string.
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(r.Resources) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
apiGroup := attrs.GetAPIGroup()
|
||||
resource := attrs.GetResource()
|
||||
subresource := attrs.GetSubresource()
|
||||
combinedResource := resource
|
||||
// If subresource, the resource in the policy must match "(resource)/(subresource)"
|
||||
if subresource != "" {
|
||||
combinedResource = resource + "/" + subresource
|
||||
}
|
||||
|
||||
name := attrs.GetName()
|
||||
|
||||
for _, gr := range r.Resources {
|
||||
if gr.Group == apiGroup {
|
||||
if len(gr.Resources) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, res := range gr.Resources {
|
||||
if len(gr.ResourceNames) == 0 || hasString(gr.ResourceNames, name) {
|
||||
// match "*"
|
||||
if res == combinedResource || res == "*" {
|
||||
return true
|
||||
}
|
||||
// match "*/subresource"
|
||||
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimPrefix(res, "*/") {
|
||||
return true
|
||||
}
|
||||
// match "resource/*"
|
||||
if strings.HasSuffix(res, "/*") && resource == strings.TrimSuffix(res, "/*") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Utility function to check whether a string slice contains a string.
|
||||
func hasString(slice []string, value string) bool {
|
||||
for _, s := range slice {
|
||||
if s == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type fakePolicyRuleEvaluator struct {
|
||||
level audit.Level
|
||||
stage []audit.Stage
|
||||
}
|
||||
|
||||
func (f *fakePolicyRuleEvaluator) EvaluatePolicyRule(_ authorizer.Attributes) auditinternal.RequestAuditConfig {
|
||||
return auditinternal.RequestAuditConfig{
|
||||
Level: f.level,
|
||||
OmitStages: f.stage,
|
||||
}
|
||||
}
|
101
e2e/vendor/k8s.io/apiserver/pkg/audit/policy/reader.go
generated
vendored
Normal file
101
e2e/vendor/k8s.io/apiserver/pkg/audit/policy/reader.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
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 policy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
|
||||
"k8s.io/apiserver/pkg/apis/audit/validation"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
apiGroupVersions = []schema.GroupVersion{
|
||||
auditv1.SchemeGroupVersion,
|
||||
}
|
||||
apiGroupVersionSet = map[schema.GroupVersion]bool{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
for _, gv := range apiGroupVersions {
|
||||
apiGroupVersionSet[gv] = true
|
||||
}
|
||||
}
|
||||
|
||||
func LoadPolicyFromFile(filePath string) (*auditinternal.Policy, error) {
|
||||
if filePath == "" {
|
||||
return nil, fmt.Errorf("file path not specified")
|
||||
}
|
||||
policyDef, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file path %q: %+v", filePath, err)
|
||||
}
|
||||
|
||||
ret, err := LoadPolicyFromBytes(policyDef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%v: from file %v", err.Error(), filePath)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func LoadPolicyFromBytes(policyDef []byte) (*auditinternal.Policy, error) {
|
||||
policy := &auditinternal.Policy{}
|
||||
strictDecoder := serializer.NewCodecFactory(audit.Scheme, serializer.EnableStrict).UniversalDecoder()
|
||||
|
||||
// Try strict decoding first.
|
||||
_, gvk, err := strictDecoder.Decode(policyDef, nil, policy)
|
||||
if err != nil {
|
||||
if !runtime.IsStrictDecodingError(err) {
|
||||
return nil, fmt.Errorf("failed decoding: %w", err)
|
||||
}
|
||||
var (
|
||||
lenientDecoder = audit.Codecs.UniversalDecoder(apiGroupVersions...)
|
||||
lenientErr error
|
||||
)
|
||||
_, gvk, lenientErr = lenientDecoder.Decode(policyDef, nil, policy)
|
||||
if lenientErr != nil {
|
||||
return nil, fmt.Errorf("failed lenient decoding: %w", lenientErr)
|
||||
}
|
||||
klog.Warningf("Audit policy contains errors, falling back to lenient decoding: %v", err)
|
||||
}
|
||||
|
||||
// Ensure the policy file contained an apiVersion and kind.
|
||||
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 err := validation.ValidatePolicy(policy); err != nil {
|
||||
return nil, err.ToAggregate()
|
||||
}
|
||||
|
||||
policyCnt := len(policy.Rules)
|
||||
if policyCnt == 0 {
|
||||
return nil, fmt.Errorf("loaded illegal policy with 0 rules")
|
||||
}
|
||||
|
||||
klog.V(4).InfoS("Load audit policy rules success", "policyCnt", policyCnt)
|
||||
return policy, nil
|
||||
}
|
68
e2e/vendor/k8s.io/apiserver/pkg/audit/policy/util.go
generated
vendored
Normal file
68
e2e/vendor/k8s.io/apiserver/pkg/audit/policy/util.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
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/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
)
|
||||
|
||||
// AllStages returns all possible stages
|
||||
func AllStages() sets.String {
|
||||
return sets.NewString(
|
||||
string(audit.StageRequestReceived),
|
||||
string(audit.StageResponseStarted),
|
||||
string(audit.StageResponseComplete),
|
||||
string(audit.StagePanic),
|
||||
)
|
||||
}
|
||||
|
||||
// AllLevels returns all possible levels
|
||||
func AllLevels() sets.String {
|
||||
return sets.NewString(
|
||||
string(audit.LevelNone),
|
||||
string(audit.LevelMetadata),
|
||||
string(audit.LevelRequest),
|
||||
string(audit.LevelRequestResponse),
|
||||
)
|
||||
}
|
||||
|
||||
// InvertStages subtracts the given array of stages from all stages
|
||||
func InvertStages(stages []audit.Stage) []audit.Stage {
|
||||
s := ConvertStagesToStrings(stages)
|
||||
a := AllStages()
|
||||
a.Delete(s...)
|
||||
return ConvertStringSetToStages(a)
|
||||
}
|
||||
|
||||
// ConvertStagesToStrings converts an array of stages to a string array
|
||||
func ConvertStagesToStrings(stages []audit.Stage) []string {
|
||||
s := make([]string, len(stages))
|
||||
for i, stage := range stages {
|
||||
s[i] = string(stage)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ConvertStringSetToStages converts a string set to an array of stages
|
||||
func ConvertStringSetToStages(set sets.String) []audit.Stage {
|
||||
stages := make([]audit.Stage, len(set))
|
||||
for i, stage := range set.List() {
|
||||
stages[i] = audit.Stage(stage)
|
||||
}
|
||||
return stages
|
||||
}
|
312
e2e/vendor/k8s.io/apiserver/pkg/audit/request.go
generated
vendored
Normal file
312
e2e/vendor/k8s.io/apiserver/pkg/audit/request.go
generated
vendored
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
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 audit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
authnv1 "k8s.io/api/authentication/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
maxUserAgentLength = 1024
|
||||
userAgentTruncateSuffix = "...TRUNCATED"
|
||||
)
|
||||
|
||||
func LogRequestMetadata(ctx context.Context, req *http.Request, requestReceivedTimestamp time.Time, level auditinternal.Level, attribs authorizer.Attributes) {
|
||||
ac := AuditContextFrom(ctx)
|
||||
if !ac.Enabled() {
|
||||
return
|
||||
}
|
||||
ev := &ac.Event
|
||||
|
||||
ev.RequestReceivedTimestamp = metav1.NewMicroTime(requestReceivedTimestamp)
|
||||
ev.Verb = attribs.GetVerb()
|
||||
ev.RequestURI = req.URL.RequestURI()
|
||||
ev.UserAgent = maybeTruncateUserAgent(req)
|
||||
ev.Level = level
|
||||
|
||||
ips := utilnet.SourceIPs(req)
|
||||
ev.SourceIPs = make([]string, len(ips))
|
||||
for i := range ips {
|
||||
ev.SourceIPs[i] = ips[i].String()
|
||||
}
|
||||
|
||||
if user := attribs.GetUser(); user != nil {
|
||||
ev.User.Username = user.GetName()
|
||||
ev.User.Extra = map[string]authnv1.ExtraValue{}
|
||||
for k, v := range user.GetExtra() {
|
||||
ev.User.Extra[k] = authnv1.ExtraValue(v)
|
||||
}
|
||||
ev.User.Groups = user.GetGroups()
|
||||
ev.User.UID = user.GetUID()
|
||||
}
|
||||
|
||||
if attribs.IsResourceRequest() {
|
||||
ev.ObjectRef = &auditinternal.ObjectReference{
|
||||
Namespace: attribs.GetNamespace(),
|
||||
Name: attribs.GetName(),
|
||||
Resource: attribs.GetResource(),
|
||||
Subresource: attribs.GetSubresource(),
|
||||
APIGroup: attribs.GetAPIGroup(),
|
||||
APIVersion: attribs.GetAPIVersion(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LogImpersonatedUser fills in the impersonated user attributes into an audit event.
|
||||
func LogImpersonatedUser(ae *auditinternal.Event, user user.Info) {
|
||||
if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) {
|
||||
return
|
||||
}
|
||||
ae.ImpersonatedUser = &authnv1.UserInfo{
|
||||
Username: user.GetName(),
|
||||
}
|
||||
ae.ImpersonatedUser.Groups = user.GetGroups()
|
||||
ae.ImpersonatedUser.UID = user.GetUID()
|
||||
ae.ImpersonatedUser.Extra = map[string]authnv1.ExtraValue{}
|
||||
for k, v := range user.GetExtra() {
|
||||
ae.ImpersonatedUser.Extra[k] = authnv1.ExtraValue(v)
|
||||
}
|
||||
}
|
||||
|
||||
// LogRequestObject fills in the request object into an audit event. The passed runtime.Object
|
||||
// will be converted to the given gv.
|
||||
func LogRequestObject(ctx context.Context, obj runtime.Object, objGV schema.GroupVersion, gvr schema.GroupVersionResource, subresource string, s runtime.NegotiatedSerializer) {
|
||||
ae := AuditEventFrom(ctx)
|
||||
if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) {
|
||||
return
|
||||
}
|
||||
|
||||
// complete ObjectRef
|
||||
if ae.ObjectRef == nil {
|
||||
ae.ObjectRef = &auditinternal.ObjectReference{}
|
||||
}
|
||||
|
||||
// meta.Accessor is more general than ObjectMetaAccessor, but if it fails, we can just skip setting these bits
|
||||
if meta, err := meta.Accessor(obj); err == nil {
|
||||
if len(ae.ObjectRef.Namespace) == 0 {
|
||||
ae.ObjectRef.Namespace = meta.GetNamespace()
|
||||
}
|
||||
if len(ae.ObjectRef.Name) == 0 {
|
||||
ae.ObjectRef.Name = meta.GetName()
|
||||
}
|
||||
if len(ae.ObjectRef.UID) == 0 {
|
||||
ae.ObjectRef.UID = meta.GetUID()
|
||||
}
|
||||
if len(ae.ObjectRef.ResourceVersion) == 0 {
|
||||
ae.ObjectRef.ResourceVersion = meta.GetResourceVersion()
|
||||
}
|
||||
}
|
||||
if len(ae.ObjectRef.APIVersion) == 0 {
|
||||
ae.ObjectRef.APIGroup = gvr.Group
|
||||
ae.ObjectRef.APIVersion = gvr.Version
|
||||
}
|
||||
if len(ae.ObjectRef.Resource) == 0 {
|
||||
ae.ObjectRef.Resource = gvr.Resource
|
||||
}
|
||||
if len(ae.ObjectRef.Subresource) == 0 {
|
||||
ae.ObjectRef.Subresource = subresource
|
||||
}
|
||||
|
||||
if ae.Level.Less(auditinternal.LevelRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
if shouldOmitManagedFields(ctx) {
|
||||
copy, ok, err := copyWithoutManagedFields(obj)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "Error while dropping managed fields from the request", "auditID", ae.AuditID)
|
||||
}
|
||||
if ok {
|
||||
obj = copy
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(audit): hook into the serializer to avoid double conversion
|
||||
var err error
|
||||
ae.RequestObject, err = encodeObject(obj, objGV, s)
|
||||
if err != nil {
|
||||
// TODO(audit): add error slice to audit event struct
|
||||
klog.ErrorS(err, "Encoding failed of request object", "auditID", ae.AuditID, "gvr", gvr.String(), "obj", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// LogRequestPatch fills in the given patch as the request object into an audit event.
|
||||
func LogRequestPatch(ctx context.Context, patch []byte) {
|
||||
ae := AuditEventFrom(ctx)
|
||||
if ae == nil || ae.Level.Less(auditinternal.LevelRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
ae.RequestObject = &runtime.Unknown{
|
||||
Raw: patch,
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
}
|
||||
|
||||
// LogResponseObject fills in the response object into an audit event. The passed runtime.Object
|
||||
// will be converted to the given gv.
|
||||
func LogResponseObject(ctx context.Context, obj runtime.Object, gv schema.GroupVersion, s runtime.NegotiatedSerializer) {
|
||||
ae := AuditEventFrom(ctx)
|
||||
if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) {
|
||||
return
|
||||
}
|
||||
if status, ok := obj.(*metav1.Status); ok {
|
||||
// selectively copy the bounded fields.
|
||||
ae.ResponseStatus = &metav1.Status{
|
||||
Status: status.Status,
|
||||
Message: status.Message,
|
||||
Reason: status.Reason,
|
||||
Details: status.Details,
|
||||
Code: status.Code,
|
||||
}
|
||||
}
|
||||
|
||||
if ae.Level.Less(auditinternal.LevelRequestResponse) {
|
||||
return
|
||||
}
|
||||
|
||||
if shouldOmitManagedFields(ctx) {
|
||||
copy, ok, err := copyWithoutManagedFields(obj)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "Error while dropping managed fields from the response", "auditID", ae.AuditID)
|
||||
}
|
||||
if ok {
|
||||
obj = copy
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(audit): hook into the serializer to avoid double conversion
|
||||
var err error
|
||||
ae.ResponseObject, err = encodeObject(obj, gv, s)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "Encoding failed of response object", "auditID", ae.AuditID, "obj", obj)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeObject(obj runtime.Object, gv schema.GroupVersion, serializer runtime.NegotiatedSerializer) (*runtime.Unknown, error) {
|
||||
const mediaType = runtime.ContentTypeJSON
|
||||
info, ok := runtime.SerializerInfoForMediaType(serializer.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to locate encoder -- %q is not a supported media type", mediaType)
|
||||
}
|
||||
|
||||
enc := serializer.EncoderForVersion(info.Serializer, gv)
|
||||
var buf bytes.Buffer
|
||||
if err := enc.Encode(obj, &buf); err != nil {
|
||||
return nil, fmt.Errorf("encoding failed: %v", err)
|
||||
}
|
||||
|
||||
return &runtime.Unknown{
|
||||
Raw: buf.Bytes(),
|
||||
ContentType: mediaType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// truncate User-Agent if too long, otherwise return it directly.
|
||||
func maybeTruncateUserAgent(req *http.Request) string {
|
||||
ua := req.UserAgent()
|
||||
if len(ua) > maxUserAgentLength {
|
||||
ua = ua[:maxUserAgentLength] + userAgentTruncateSuffix
|
||||
}
|
||||
|
||||
return ua
|
||||
}
|
||||
|
||||
// copyWithoutManagedFields will make a deep copy of the specified object and
|
||||
// will discard the managed fields from the copy.
|
||||
// The specified object is expected to be a meta.Object or a "list".
|
||||
// The specified object obj is treated as readonly and hence not mutated.
|
||||
// On return, an error is set if the function runs into any error while
|
||||
// removing the managed fields, the boolean value is true if the copy has
|
||||
// been made successfully, otherwise false.
|
||||
func copyWithoutManagedFields(obj runtime.Object) (runtime.Object, bool, error) {
|
||||
isAccessor := true
|
||||
if _, err := meta.Accessor(obj); err != nil {
|
||||
isAccessor = false
|
||||
}
|
||||
isList := meta.IsListType(obj)
|
||||
_, isTable := obj.(*metav1.Table)
|
||||
if !isAccessor && !isList && !isTable {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
// TODO a deep copy isn't really needed here, figure out how we can reliably
|
||||
// use shallow copy here to omit the manageFields.
|
||||
copy := obj.DeepCopyObject()
|
||||
|
||||
if isAccessor {
|
||||
if err := removeManagedFields(copy); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if isList {
|
||||
if err := meta.EachListItem(copy, removeManagedFields); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if isTable {
|
||||
table := copy.(*metav1.Table)
|
||||
for i := range table.Rows {
|
||||
rowObj := table.Rows[i].Object
|
||||
if err := removeManagedFields(rowObj.Object); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return copy, true, nil
|
||||
}
|
||||
|
||||
func removeManagedFields(obj runtime.Object) error {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetManagedFields(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldOmitManagedFields(ctx context.Context) bool {
|
||||
if auditContext := AuditContextFrom(ctx); auditContext != nil {
|
||||
return auditContext.RequestAuditConfig.OmitManagedFields
|
||||
}
|
||||
|
||||
// If we can't decide, return false to maintain current behavior which is
|
||||
// to retain the manage fields in the audit.
|
||||
return false
|
||||
}
|
38
e2e/vendor/k8s.io/apiserver/pkg/audit/scheme.go
generated
vendored
Normal file
38
e2e/vendor/k8s.io/apiserver/pkg/audit/scheme.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// TODO: Delete this file if we generate a clientset.
|
||||
package audit
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1"
|
||||
)
|
||||
|
||||
var Scheme = runtime.NewScheme()
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
|
||||
func init() {
|
||||
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||
utilruntime.Must(v1.AddToScheme(Scheme))
|
||||
utilruntime.Must(auditinternal.AddToScheme(Scheme))
|
||||
utilruntime.Must(Scheme.SetVersionPriority(v1.SchemeGroupVersion))
|
||||
}
|
46
e2e/vendor/k8s.io/apiserver/pkg/audit/types.go
generated
vendored
Normal file
46
e2e/vendor/k8s.io/apiserver/pkg/audit/types.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
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 audit
|
||||
|
||||
import (
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
)
|
||||
|
||||
type Sink interface {
|
||||
// ProcessEvents handles events. Per audit ID it might be that ProcessEvents is called up to three times.
|
||||
// Errors might be logged by the sink itself. If an error should be fatal, leading to an internal
|
||||
// error, ProcessEvents is supposed to panic. The event must not be mutated and is reused by the caller
|
||||
// after the call returns, i.e. the sink has to make a deepcopy to keep a copy around if necessary.
|
||||
// Returns true on success, may return false on error.
|
||||
ProcessEvents(events ...*auditinternal.Event) bool
|
||||
}
|
||||
|
||||
type Backend interface {
|
||||
Sink
|
||||
|
||||
// Run will initialize the backend. It must not block, but may run go routines in the background. If
|
||||
// stopCh is closed, it is supposed to stop them. Run will be called before the first call to ProcessEvents.
|
||||
Run(stopCh <-chan struct{}) error
|
||||
|
||||
// Shutdown will synchronously shut down the backend while making sure that all pending
|
||||
// events are delivered. It can be assumed that this method is called after
|
||||
// the stopCh channel passed to the Run method has been closed.
|
||||
Shutdown()
|
||||
|
||||
// Returns the backend PluginName.
|
||||
String() string
|
||||
}
|
71
e2e/vendor/k8s.io/apiserver/pkg/audit/union.go
generated
vendored
Normal file
71
e2e/vendor/k8s.io/apiserver/pkg/audit/union.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
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 audit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
)
|
||||
|
||||
// Union returns an audit Backend which logs events to a set of backends. The returned
|
||||
// Sink implementation blocks in turn for each call to ProcessEvents.
|
||||
func Union(backends ...Backend) Backend {
|
||||
if len(backends) == 1 {
|
||||
return backends[0]
|
||||
}
|
||||
return union{backends}
|
||||
}
|
||||
|
||||
type union struct {
|
||||
backends []Backend
|
||||
}
|
||||
|
||||
func (u union) ProcessEvents(events ...*auditinternal.Event) bool {
|
||||
success := true
|
||||
for _, backend := range u.backends {
|
||||
success = backend.ProcessEvents(events...) && success
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func (u union) Run(stopCh <-chan struct{}) error {
|
||||
var funcs []func() error
|
||||
for _, backend := range u.backends {
|
||||
backend := backend
|
||||
funcs = append(funcs, func() error {
|
||||
return backend.Run(stopCh)
|
||||
})
|
||||
}
|
||||
return errors.AggregateGoroutines(funcs...)
|
||||
}
|
||||
|
||||
func (u union) Shutdown() {
|
||||
for _, backend := range u.backends {
|
||||
backend.Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
func (u union) String() string {
|
||||
var backendStrings []string
|
||||
for _, backend := range u.backends {
|
||||
backendStrings = append(backendStrings, fmt.Sprintf("%s", backend))
|
||||
}
|
||||
return fmt.Sprintf("union[%s]", strings.Join(backendStrings, ","))
|
||||
}
|
Reference in New Issue
Block a user