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
184
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizer/interfaces.go
generated
vendored
Normal file
184
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizer/interfaces.go
generated
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
Copyright 2014 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 authorizer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
// Attributes is an interface used by an Authorizer to get information about a request
|
||||
// that is used to make an authorization decision.
|
||||
type Attributes interface {
|
||||
// GetUser returns the user.Info object to authorize
|
||||
GetUser() user.Info
|
||||
|
||||
// GetVerb returns the kube verb associated with API requests (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy),
|
||||
// or the lowercased HTTP verb associated with non-API requests (this includes get, put, post, patch, and delete)
|
||||
GetVerb() string
|
||||
|
||||
// When IsReadOnly() == true, the request has no side effects, other than
|
||||
// caching, logging, and other incidentals.
|
||||
IsReadOnly() bool
|
||||
|
||||
// The namespace of the object, if a request is for a REST object.
|
||||
GetNamespace() string
|
||||
|
||||
// The kind of object, if a request is for a REST object.
|
||||
GetResource() string
|
||||
|
||||
// GetSubresource returns the subresource being requested, if present
|
||||
GetSubresource() string
|
||||
|
||||
// GetName returns the name of the object as parsed off the request. This will not be present for all request types, but
|
||||
// will be present for: get, update, delete
|
||||
GetName() string
|
||||
|
||||
// The group of the resource, if a request is for a REST object.
|
||||
GetAPIGroup() string
|
||||
|
||||
// GetAPIVersion returns the version of the group requested, if a request is for a REST object.
|
||||
GetAPIVersion() string
|
||||
|
||||
// IsResourceRequest returns true for requests to API resources, like /api/v1/nodes,
|
||||
// and false for non-resource endpoints like /api, /healthz
|
||||
IsResourceRequest() bool
|
||||
|
||||
// GetPath returns the path of the request
|
||||
GetPath() string
|
||||
|
||||
// ParseFieldSelector is lazy, thread-safe, and stores the parsed result and error.
|
||||
// It returns an error if the field selector cannot be parsed.
|
||||
// The returned requirements must be treated as readonly and not modified.
|
||||
GetFieldSelector() (fields.Requirements, error)
|
||||
|
||||
// ParseLabelSelector is lazy, thread-safe, and stores the parsed result and error.
|
||||
// It returns an error if the label selector cannot be parsed.
|
||||
// The returned requirements must be treated as readonly and not modified.
|
||||
GetLabelSelector() (labels.Requirements, error)
|
||||
}
|
||||
|
||||
// Authorizer makes an authorization decision based on information gained by making
|
||||
// zero or more calls to methods of the Attributes interface. It returns nil when an action is
|
||||
// authorized, otherwise it returns an error.
|
||||
type Authorizer interface {
|
||||
Authorize(ctx context.Context, a Attributes) (authorized Decision, reason string, err error)
|
||||
}
|
||||
|
||||
type AuthorizerFunc func(ctx context.Context, a Attributes) (Decision, string, error)
|
||||
|
||||
func (f AuthorizerFunc) Authorize(ctx context.Context, a Attributes) (Decision, string, error) {
|
||||
return f(ctx, a)
|
||||
}
|
||||
|
||||
// RuleResolver provides a mechanism for resolving the list of rules that apply to a given user within a namespace.
|
||||
type RuleResolver interface {
|
||||
// RulesFor get the list of cluster wide rules, the list of rules in the specific namespace, incomplete status and errors.
|
||||
RulesFor(ctx context.Context, user user.Info, namespace string) ([]ResourceRuleInfo, []NonResourceRuleInfo, bool, error)
|
||||
}
|
||||
|
||||
// RequestAttributesGetter provides a function that extracts Attributes from an http.Request
|
||||
type RequestAttributesGetter interface {
|
||||
GetRequestAttributes(user.Info, *http.Request) Attributes
|
||||
}
|
||||
|
||||
// AttributesRecord implements Attributes interface.
|
||||
type AttributesRecord struct {
|
||||
User user.Info
|
||||
Verb string
|
||||
Namespace string
|
||||
APIGroup string
|
||||
APIVersion string
|
||||
Resource string
|
||||
Subresource string
|
||||
Name string
|
||||
ResourceRequest bool
|
||||
Path string
|
||||
|
||||
FieldSelectorRequirements fields.Requirements
|
||||
FieldSelectorParsingErr error
|
||||
LabelSelectorRequirements labels.Requirements
|
||||
LabelSelectorParsingErr error
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetUser() user.Info {
|
||||
return a.User
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetVerb() string {
|
||||
return a.Verb
|
||||
}
|
||||
|
||||
func (a AttributesRecord) IsReadOnly() bool {
|
||||
return a.Verb == "get" || a.Verb == "list" || a.Verb == "watch"
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetNamespace() string {
|
||||
return a.Namespace
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetResource() string {
|
||||
return a.Resource
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetSubresource() string {
|
||||
return a.Subresource
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetName() string {
|
||||
return a.Name
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetAPIGroup() string {
|
||||
return a.APIGroup
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetAPIVersion() string {
|
||||
return a.APIVersion
|
||||
}
|
||||
|
||||
func (a AttributesRecord) IsResourceRequest() bool {
|
||||
return a.ResourceRequest
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetPath() string {
|
||||
return a.Path
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetFieldSelector() (fields.Requirements, error) {
|
||||
return a.FieldSelectorRequirements, a.FieldSelectorParsingErr
|
||||
}
|
||||
|
||||
func (a AttributesRecord) GetLabelSelector() (labels.Requirements, error) {
|
||||
return a.LabelSelectorRequirements, a.LabelSelectorParsingErr
|
||||
}
|
||||
|
||||
type Decision int
|
||||
|
||||
const (
|
||||
// DecisionDeny means that an authorizer decided to deny the action.
|
||||
DecisionDeny Decision = iota
|
||||
// DecisionAllow means that an authorizer decided to allow the action.
|
||||
DecisionAllow
|
||||
// DecisionNoOpinion means that an authorizer has no opinion on whether
|
||||
// to allow or deny an action.
|
||||
DecisionNoOpinion
|
||||
)
|
73
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizer/rule.go
generated
vendored
Normal file
73
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizer/rule.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 authorizer
|
||||
|
||||
type ResourceRuleInfo interface {
|
||||
// GetVerbs returns a list of kubernetes resource API verbs.
|
||||
GetVerbs() []string
|
||||
// GetAPIGroups return the names of the APIGroup that contains the resources.
|
||||
GetAPIGroups() []string
|
||||
// GetResources return a list of resources the rule applies to.
|
||||
GetResources() []string
|
||||
// GetResourceNames return a white list of names that the rule applies to.
|
||||
GetResourceNames() []string
|
||||
}
|
||||
|
||||
// DefaultResourceRuleInfo holds information that describes a rule for the resource
|
||||
type DefaultResourceRuleInfo struct {
|
||||
Verbs []string
|
||||
APIGroups []string
|
||||
Resources []string
|
||||
ResourceNames []string
|
||||
}
|
||||
|
||||
func (i *DefaultResourceRuleInfo) GetVerbs() []string {
|
||||
return i.Verbs
|
||||
}
|
||||
|
||||
func (i *DefaultResourceRuleInfo) GetAPIGroups() []string {
|
||||
return i.APIGroups
|
||||
}
|
||||
|
||||
func (i *DefaultResourceRuleInfo) GetResources() []string {
|
||||
return i.Resources
|
||||
}
|
||||
|
||||
func (i *DefaultResourceRuleInfo) GetResourceNames() []string {
|
||||
return i.ResourceNames
|
||||
}
|
||||
|
||||
type NonResourceRuleInfo interface {
|
||||
// GetVerbs returns a list of kubernetes resource API verbs.
|
||||
GetVerbs() []string
|
||||
// GetNonResourceURLs return a set of partial urls that a user should have access to.
|
||||
GetNonResourceURLs() []string
|
||||
}
|
||||
|
||||
// DefaultNonResourceRuleInfo holds information that describes a rule for the non-resource
|
||||
type DefaultNonResourceRuleInfo struct {
|
||||
Verbs []string
|
||||
NonResourceURLs []string
|
||||
}
|
||||
|
||||
func (i *DefaultNonResourceRuleInfo) GetVerbs() []string {
|
||||
return i.Verbs
|
||||
}
|
||||
|
||||
func (i *DefaultNonResourceRuleInfo) GetNonResourceURLs() []string {
|
||||
return i.NonResourceURLs
|
||||
}
|
95
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin.go
generated
vendored
Normal file
95
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2016 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 authorizerfactory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
|
||||
// alwaysAllowAuthorizer is an implementation of authorizer.Attributes
|
||||
// which always says yes to an authorization request.
|
||||
// It is useful in tests and when using kubernetes in an open manner.
|
||||
type alwaysAllowAuthorizer struct{}
|
||||
|
||||
func (alwaysAllowAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
func (alwaysAllowAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
return []authorizer.ResourceRuleInfo{
|
||||
&authorizer.DefaultResourceRuleInfo{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"*"},
|
||||
},
|
||||
}, []authorizer.NonResourceRuleInfo{
|
||||
&authorizer.DefaultNonResourceRuleInfo{
|
||||
Verbs: []string{"*"},
|
||||
NonResourceURLs: []string{"*"},
|
||||
},
|
||||
}, false, nil
|
||||
}
|
||||
|
||||
func NewAlwaysAllowAuthorizer() *alwaysAllowAuthorizer {
|
||||
return new(alwaysAllowAuthorizer)
|
||||
}
|
||||
|
||||
// alwaysDenyAuthorizer is an implementation of authorizer.Attributes
|
||||
// which always says no to an authorization request.
|
||||
// It is useful in unit tests to force an operation to be forbidden.
|
||||
type alwaysDenyAuthorizer struct{}
|
||||
|
||||
func (alwaysDenyAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) {
|
||||
return authorizer.DecisionNoOpinion, "Everything is forbidden.", nil
|
||||
}
|
||||
|
||||
func (alwaysDenyAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
return []authorizer.ResourceRuleInfo{}, []authorizer.NonResourceRuleInfo{}, false, nil
|
||||
}
|
||||
|
||||
func NewAlwaysDenyAuthorizer() *alwaysDenyAuthorizer {
|
||||
return new(alwaysDenyAuthorizer)
|
||||
}
|
||||
|
||||
type privilegedGroupAuthorizer struct {
|
||||
groups []string
|
||||
}
|
||||
|
||||
func (r *privilegedGroupAuthorizer) Authorize(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
if attr.GetUser() == nil {
|
||||
return authorizer.DecisionNoOpinion, "Error", errors.New("no user on request.")
|
||||
}
|
||||
for _, attr_group := range attr.GetUser().GetGroups() {
|
||||
for _, priv_group := range r.groups {
|
||||
if priv_group == attr_group {
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}
|
||||
|
||||
// NewPrivilegedGroups is for use in loopback scenarios
|
||||
func NewPrivilegedGroups(groups ...string) *privilegedGroupAuthorizer {
|
||||
return &privilegedGroupAuthorizer{
|
||||
groups: groups,
|
||||
}
|
||||
}
|
69
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/delegating.go
generated
vendored
Normal file
69
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/delegating.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 2016 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 authorizerfactory
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
authorizationcel "k8s.io/apiserver/pkg/authorization/cel"
|
||||
"k8s.io/apiserver/plugin/pkg/authorizer/webhook"
|
||||
authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1"
|
||||
)
|
||||
|
||||
// DelegatingAuthorizerConfig is the minimal configuration needed to create an authorizer
|
||||
// built to delegate authorization to a kube API server
|
||||
type DelegatingAuthorizerConfig struct {
|
||||
SubjectAccessReviewClient authorizationclient.AuthorizationV1Interface
|
||||
|
||||
// Compiler is the CEL compiler to use for evaluating policies. If nil, a default compiler will be used.
|
||||
Compiler authorizationcel.Compiler
|
||||
|
||||
// AllowCacheTTL is the length of time that a successful authorization response will be cached
|
||||
AllowCacheTTL time.Duration
|
||||
|
||||
// DenyCacheTTL is the length of time that an unsuccessful authorization response will be cached.
|
||||
// You generally want more responsive, "deny, try again" flows.
|
||||
DenyCacheTTL time.Duration
|
||||
|
||||
// WebhookRetryBackoff specifies the backoff parameters for the authorization webhook retry logic.
|
||||
// This allows us to configure the sleep time at each iteration and the maximum number of retries allowed
|
||||
// before we fail the webhook call in order to limit the fan out that ensues when the system is degraded.
|
||||
WebhookRetryBackoff *wait.Backoff
|
||||
}
|
||||
|
||||
func (c DelegatingAuthorizerConfig) New() (authorizer.Authorizer, error) {
|
||||
if c.WebhookRetryBackoff == nil {
|
||||
return nil, errors.New("retry backoff parameters for delegating authorization webhook has not been specified")
|
||||
}
|
||||
compiler := c.Compiler
|
||||
if compiler == nil {
|
||||
compiler = authorizationcel.NewDefaultCompiler()
|
||||
}
|
||||
|
||||
return webhook.NewFromInterface(
|
||||
c.SubjectAccessReviewClient,
|
||||
c.AllowCacheTTL,
|
||||
c.DenyCacheTTL,
|
||||
*c.WebhookRetryBackoff,
|
||||
authorizer.DecisionNoOpinion,
|
||||
NewDelegatingAuthorizerMetrics(),
|
||||
compiler,
|
||||
)
|
||||
}
|
82
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/metrics.go
generated
vendored
Normal file
82
e2e/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/metrics.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
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 authorizerfactory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
celmetrics "k8s.io/apiserver/pkg/authorization/cel"
|
||||
webhookmetrics "k8s.io/apiserver/plugin/pkg/authorizer/webhook/metrics"
|
||||
compbasemetrics "k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
)
|
||||
|
||||
var registerMetrics sync.Once
|
||||
|
||||
// RegisterMetrics registers authorizer metrics.
|
||||
func RegisterMetrics() {
|
||||
registerMetrics.Do(func() {
|
||||
legacyregistry.MustRegister(requestTotal)
|
||||
legacyregistry.MustRegister(requestLatency)
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
requestTotal = compbasemetrics.NewCounterVec(
|
||||
&compbasemetrics.CounterOpts{
|
||||
Name: "apiserver_delegated_authz_request_total",
|
||||
Help: "Number of HTTP requests partitioned by status code.",
|
||||
StabilityLevel: compbasemetrics.ALPHA,
|
||||
},
|
||||
[]string{"code"},
|
||||
)
|
||||
|
||||
requestLatency = compbasemetrics.NewHistogramVec(
|
||||
&compbasemetrics.HistogramOpts{
|
||||
Name: "apiserver_delegated_authz_request_duration_seconds",
|
||||
Help: "Request latency in seconds. Broken down by status code.",
|
||||
Buckets: []float64{0.25, 0.5, 0.7, 1, 1.5, 3, 5, 10},
|
||||
StabilityLevel: compbasemetrics.ALPHA,
|
||||
},
|
||||
[]string{"code"},
|
||||
)
|
||||
)
|
||||
|
||||
var _ = webhookmetrics.AuthorizerMetrics(delegatingAuthorizerMetrics{})
|
||||
|
||||
type delegatingAuthorizerMetrics struct {
|
||||
// no-op for webhook metrics for now, delegating authorization reports original total/latency metrics
|
||||
webhookmetrics.NoopWebhookMetrics
|
||||
// no-op for matchCondition metrics for now, delegating authorization doesn't configure match conditions
|
||||
celmetrics.NoopMatcherMetrics
|
||||
}
|
||||
|
||||
func NewDelegatingAuthorizerMetrics() delegatingAuthorizerMetrics {
|
||||
RegisterMetrics()
|
||||
return delegatingAuthorizerMetrics{}
|
||||
}
|
||||
|
||||
// RecordRequestTotal increments the total number of requests for the delegated authorization.
|
||||
func (delegatingAuthorizerMetrics) RecordRequestTotal(ctx context.Context, code string) {
|
||||
requestTotal.WithContext(ctx).WithLabelValues(code).Add(1)
|
||||
}
|
||||
|
||||
// RecordRequestLatency measures request latency in seconds for the delegated authorization. Broken down by status code.
|
||||
func (delegatingAuthorizerMetrics) RecordRequestLatency(ctx context.Context, code string, latency float64) {
|
||||
requestLatency.WithContext(ctx).WithLabelValues(code).Observe(latency)
|
||||
}
|
336
e2e/vendor/k8s.io/apiserver/pkg/authorization/cel/compile.go
generated
vendored
Normal file
336
e2e/vendor/k8s.io/apiserver/pkg/authorization/cel/compile.go
generated
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
/*
|
||||
Copyright 2023 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 cel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
celast "github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
authorizationv1 "k8s.io/api/authorization/v1"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||
"k8s.io/apiserver/pkg/cel/environment"
|
||||
genericfeatures "k8s.io/apiserver/pkg/features"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
)
|
||||
|
||||
const (
|
||||
subjectAccessReviewRequestVarName = "request"
|
||||
|
||||
fieldSelectorVarName = "fieldSelector"
|
||||
labelSelectorVarName = "labelSelector"
|
||||
)
|
||||
|
||||
// CompilationResult represents a compiled authorization cel expression.
|
||||
type CompilationResult struct {
|
||||
Program cel.Program
|
||||
ExpressionAccessor ExpressionAccessor
|
||||
|
||||
// These track if a given expression uses fieldSelector and labelSelector,
|
||||
// so construction of data passed to the CEL expression can be optimized if those fields are unused.
|
||||
UsesFieldSelector bool
|
||||
UsesLabelSelector bool
|
||||
}
|
||||
|
||||
// EvaluationResult contains the minimal required fields and metadata of a cel evaluation
|
||||
type EvaluationResult struct {
|
||||
EvalResult ref.Val
|
||||
ExpressionAccessor ExpressionAccessor
|
||||
}
|
||||
|
||||
// Compiler is an interface for compiling CEL expressions with the desired environment mode.
|
||||
type Compiler interface {
|
||||
CompileCELExpression(expressionAccessor ExpressionAccessor) (CompilationResult, error)
|
||||
}
|
||||
|
||||
type compiler struct {
|
||||
envSet *environment.EnvSet
|
||||
}
|
||||
|
||||
// NewDefaultCompiler returns a new Compiler following the default compatibility version.
|
||||
// Note: the compiler construction depends on feature gates and the compatibility version to be initialized.
|
||||
func NewDefaultCompiler() Compiler {
|
||||
return NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
||||
}
|
||||
|
||||
// NewCompiler returns a new Compiler.
|
||||
func NewCompiler(env *environment.EnvSet) Compiler {
|
||||
return &compiler{
|
||||
envSet: mustBuildEnv(env),
|
||||
}
|
||||
}
|
||||
|
||||
func (c compiler) CompileCELExpression(expressionAccessor ExpressionAccessor) (CompilationResult, error) {
|
||||
resultError := func(errorString string, errType apiservercel.ErrorType) (CompilationResult, error) {
|
||||
err := &apiservercel.Error{
|
||||
Type: errType,
|
||||
Detail: errorString,
|
||||
}
|
||||
return CompilationResult{
|
||||
ExpressionAccessor: expressionAccessor,
|
||||
}, err
|
||||
}
|
||||
env, err := c.envSet.Env(environment.StoredExpressions)
|
||||
if err != nil {
|
||||
return resultError(fmt.Sprintf("unexpected error loading CEL environment: %v", err), apiservercel.ErrorTypeInternal)
|
||||
}
|
||||
ast, issues := env.Compile(expressionAccessor.GetExpression())
|
||||
if issues != nil {
|
||||
return resultError("compilation failed: "+issues.String(), apiservercel.ErrorTypeInvalid)
|
||||
}
|
||||
found := false
|
||||
returnTypes := expressionAccessor.ReturnTypes()
|
||||
for _, returnType := range returnTypes {
|
||||
if ast.OutputType() == returnType {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
var reason string
|
||||
if len(returnTypes) == 1 {
|
||||
reason = fmt.Sprintf("must evaluate to %v but got %v", returnTypes[0].String(), ast.OutputType())
|
||||
} else {
|
||||
reason = fmt.Sprintf("must evaluate to one of %v", returnTypes)
|
||||
}
|
||||
|
||||
return resultError(reason, apiservercel.ErrorTypeInvalid)
|
||||
}
|
||||
checkedExpr, err := cel.AstToCheckedExpr(ast)
|
||||
if err != nil {
|
||||
// should be impossible since env.Compile returned no issues
|
||||
return resultError("unexpected compilation error: "+err.Error(), apiservercel.ErrorTypeInternal)
|
||||
}
|
||||
celAST, err := celast.ToAST(checkedExpr)
|
||||
if err != nil {
|
||||
// should be impossible since env.Compile returned no issues
|
||||
return resultError("unexpected compilation error: "+err.Error(), apiservercel.ErrorTypeInternal)
|
||||
}
|
||||
|
||||
var usesFieldSelector, usesLabelSelector bool
|
||||
celast.PreOrderVisit(celast.NavigateAST(celAST), celast.NewExprVisitor(func(e celast.Expr) {
|
||||
// we already know we use both, no need to inspect more
|
||||
if usesFieldSelector && usesLabelSelector {
|
||||
return
|
||||
}
|
||||
|
||||
var fieldName string
|
||||
switch e.Kind() {
|
||||
case celast.SelectKind:
|
||||
// simple select (.fieldSelector / .labelSelector)
|
||||
fieldName = e.AsSelect().FieldName()
|
||||
case celast.CallKind:
|
||||
// optional select (.?fieldSelector / .?labelSelector)
|
||||
if e.AsCall().FunctionName() != operators.OptSelect {
|
||||
return
|
||||
}
|
||||
args := e.AsCall().Args()
|
||||
// args[0] is the receiver (what comes before the `.?`), args[1] is the field name being optionally selected (what comes after the `.?`)
|
||||
if len(args) != 2 || args[1].Kind() != celast.LiteralKind || args[1].AsLiteral().Type() != cel.StringType {
|
||||
return
|
||||
}
|
||||
fieldName, _ = args[1].AsLiteral().Value().(string)
|
||||
}
|
||||
|
||||
switch fieldName {
|
||||
case fieldSelectorVarName:
|
||||
usesFieldSelector = true
|
||||
case labelSelectorVarName:
|
||||
usesLabelSelector = true
|
||||
}
|
||||
}))
|
||||
|
||||
prog, err := env.Program(ast)
|
||||
if err != nil {
|
||||
return resultError("program instantiation failed: "+err.Error(), apiservercel.ErrorTypeInternal)
|
||||
}
|
||||
return CompilationResult{
|
||||
Program: prog,
|
||||
ExpressionAccessor: expressionAccessor,
|
||||
UsesFieldSelector: usesFieldSelector,
|
||||
UsesLabelSelector: usesLabelSelector,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func mustBuildEnv(baseEnv *environment.EnvSet) *environment.EnvSet {
|
||||
field := func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField {
|
||||
return apiservercel.NewDeclField(name, declType, required, nil, nil)
|
||||
}
|
||||
fields := func(fields ...*apiservercel.DeclField) map[string]*apiservercel.DeclField {
|
||||
result := make(map[string]*apiservercel.DeclField, len(fields))
|
||||
for _, f := range fields {
|
||||
result[f.Name] = f
|
||||
}
|
||||
return result
|
||||
}
|
||||
subjectAccessReviewSpecRequestType := buildRequestType(field, fields)
|
||||
extended, err := baseEnv.Extend(
|
||||
environment.VersionedOptions{
|
||||
// we record this as 1.0 since it was available in the
|
||||
// first version that supported this feature
|
||||
IntroducedVersion: version.MajorMinor(1, 0),
|
||||
EnvOptions: []cel.EnvOption{
|
||||
cel.Variable(subjectAccessReviewRequestVarName, subjectAccessReviewSpecRequestType.CelType()),
|
||||
},
|
||||
DeclTypes: []*apiservercel.DeclType{
|
||||
subjectAccessReviewSpecRequestType,
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("environment misconfigured: %v", err))
|
||||
}
|
||||
|
||||
return extended
|
||||
}
|
||||
|
||||
// buildRequestType generates a DeclType for SubjectAccessReviewSpec.
|
||||
// if attributes are added here, also add to convertObjectToUnstructured.
|
||||
func buildRequestType(field func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField, fields func(fields ...*apiservercel.DeclField) map[string]*apiservercel.DeclField) *apiservercel.DeclType {
|
||||
resourceAttributesType := buildResourceAttributesType(field, fields)
|
||||
nonResourceAttributesType := buildNonResourceAttributesType(field, fields)
|
||||
return apiservercel.NewObjectType("kubernetes.SubjectAccessReviewSpec", fields(
|
||||
field("resourceAttributes", resourceAttributesType, false),
|
||||
field("nonResourceAttributes", nonResourceAttributesType, false),
|
||||
field("user", apiservercel.StringType, false),
|
||||
field("groups", apiservercel.NewListType(apiservercel.StringType, -1), false),
|
||||
field("extra", apiservercel.NewMapType(apiservercel.StringType, apiservercel.NewListType(apiservercel.StringType, -1), -1), false),
|
||||
field("uid", apiservercel.StringType, false),
|
||||
))
|
||||
}
|
||||
|
||||
// buildResourceAttributesType generates a DeclType for ResourceAttributes.
|
||||
// if attributes are added here, also add to convertObjectToUnstructured.
|
||||
func buildResourceAttributesType(field func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField, fields func(fields ...*apiservercel.DeclField) map[string]*apiservercel.DeclField) *apiservercel.DeclType {
|
||||
resourceAttributesFields := []*apiservercel.DeclField{
|
||||
field("namespace", apiservercel.StringType, false),
|
||||
field("verb", apiservercel.StringType, false),
|
||||
field("group", apiservercel.StringType, false),
|
||||
field("version", apiservercel.StringType, false),
|
||||
field("resource", apiservercel.StringType, false),
|
||||
field("subresource", apiservercel.StringType, false),
|
||||
field("name", apiservercel.StringType, false),
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.AuthorizeWithSelectors) {
|
||||
resourceAttributesFields = append(resourceAttributesFields, field("fieldSelector", buildFieldSelectorType(field, fields), false))
|
||||
resourceAttributesFields = append(resourceAttributesFields, field("labelSelector", buildLabelSelectorType(field, fields), false))
|
||||
}
|
||||
return apiservercel.NewObjectType("kubernetes.ResourceAttributes", fields(resourceAttributesFields...))
|
||||
}
|
||||
|
||||
func buildFieldSelectorType(field func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField, fields func(fields ...*apiservercel.DeclField) map[string]*apiservercel.DeclField) *apiservercel.DeclType {
|
||||
return apiservercel.NewObjectType("kubernetes.FieldSelectorAttributes", fields(
|
||||
field("rawSelector", apiservercel.StringType, false),
|
||||
field("requirements", apiservercel.NewListType(buildSelectorRequirementType(field, fields), -1), false),
|
||||
))
|
||||
}
|
||||
|
||||
func buildLabelSelectorType(field func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField, fields func(fields ...*apiservercel.DeclField) map[string]*apiservercel.DeclField) *apiservercel.DeclType {
|
||||
return apiservercel.NewObjectType("kubernetes.LabelSelectorAttributes", fields(
|
||||
field("rawSelector", apiservercel.StringType, false),
|
||||
field("requirements", apiservercel.NewListType(buildSelectorRequirementType(field, fields), -1), false),
|
||||
))
|
||||
}
|
||||
|
||||
func buildSelectorRequirementType(field func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField, fields func(fields ...*apiservercel.DeclField) map[string]*apiservercel.DeclField) *apiservercel.DeclType {
|
||||
return apiservercel.NewObjectType("kubernetes.SelectorRequirement", fields(
|
||||
field("key", apiservercel.StringType, false),
|
||||
field("operator", apiservercel.StringType, false),
|
||||
field("values", apiservercel.NewListType(apiservercel.StringType, -1), false),
|
||||
))
|
||||
}
|
||||
|
||||
// buildNonResourceAttributesType generates a DeclType for NonResourceAttributes.
|
||||
// if attributes are added here, also add to convertObjectToUnstructured.
|
||||
func buildNonResourceAttributesType(field func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField, fields func(fields ...*apiservercel.DeclField) map[string]*apiservercel.DeclField) *apiservercel.DeclType {
|
||||
return apiservercel.NewObjectType("kubernetes.NonResourceAttributes", fields(
|
||||
field("path", apiservercel.StringType, false),
|
||||
field("verb", apiservercel.StringType, false),
|
||||
))
|
||||
}
|
||||
|
||||
func convertObjectToUnstructured(obj *authorizationv1.SubjectAccessReviewSpec, includeFieldSelector, includeLabelSelector bool) map[string]interface{} {
|
||||
// Construct version containing every SubjectAccessReview user and string attribute field, even omitempty ones, for evaluation by CEL
|
||||
extra := obj.Extra
|
||||
if extra == nil {
|
||||
extra = map[string]authorizationv1.ExtraValue{}
|
||||
}
|
||||
ret := map[string]interface{}{
|
||||
"user": obj.User,
|
||||
"groups": obj.Groups,
|
||||
"uid": string(obj.UID),
|
||||
"extra": extra,
|
||||
}
|
||||
if obj.ResourceAttributes != nil {
|
||||
resourceAttributes := map[string]interface{}{
|
||||
"namespace": obj.ResourceAttributes.Namespace,
|
||||
"verb": obj.ResourceAttributes.Verb,
|
||||
"group": obj.ResourceAttributes.Group,
|
||||
"version": obj.ResourceAttributes.Version,
|
||||
"resource": obj.ResourceAttributes.Resource,
|
||||
"subresource": obj.ResourceAttributes.Subresource,
|
||||
"name": obj.ResourceAttributes.Name,
|
||||
}
|
||||
|
||||
if includeFieldSelector && obj.ResourceAttributes.FieldSelector != nil {
|
||||
if len(obj.ResourceAttributes.FieldSelector.Requirements) > 0 {
|
||||
requirements := make([]map[string]interface{}, 0, len(obj.ResourceAttributes.FieldSelector.Requirements))
|
||||
for _, r := range obj.ResourceAttributes.FieldSelector.Requirements {
|
||||
requirements = append(requirements, map[string]interface{}{
|
||||
"key": r.Key,
|
||||
"operator": r.Operator,
|
||||
"values": r.Values,
|
||||
})
|
||||
}
|
||||
resourceAttributes[fieldSelectorVarName] = map[string]interface{}{"requirements": requirements}
|
||||
}
|
||||
if len(obj.ResourceAttributes.FieldSelector.RawSelector) > 0 {
|
||||
resourceAttributes[fieldSelectorVarName] = map[string]interface{}{"rawSelector": obj.ResourceAttributes.FieldSelector.RawSelector}
|
||||
}
|
||||
}
|
||||
|
||||
if includeLabelSelector && obj.ResourceAttributes.LabelSelector != nil {
|
||||
if len(obj.ResourceAttributes.LabelSelector.Requirements) > 0 {
|
||||
requirements := make([]map[string]interface{}, 0, len(obj.ResourceAttributes.LabelSelector.Requirements))
|
||||
for _, r := range obj.ResourceAttributes.LabelSelector.Requirements {
|
||||
requirements = append(requirements, map[string]interface{}{
|
||||
"key": r.Key,
|
||||
"operator": r.Operator,
|
||||
"values": r.Values,
|
||||
})
|
||||
}
|
||||
resourceAttributes[labelSelectorVarName] = map[string]interface{}{"requirements": requirements}
|
||||
}
|
||||
if len(obj.ResourceAttributes.LabelSelector.RawSelector) > 0 {
|
||||
resourceAttributes[labelSelectorVarName] = map[string]interface{}{"rawSelector": obj.ResourceAttributes.LabelSelector.RawSelector}
|
||||
}
|
||||
}
|
||||
|
||||
ret["resourceAttributes"] = resourceAttributes
|
||||
}
|
||||
if obj.NonResourceAttributes != nil {
|
||||
ret["nonResourceAttributes"] = map[string]string{
|
||||
"verb": obj.NonResourceAttributes.Verb,
|
||||
"path": obj.NonResourceAttributes.Path,
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
41
e2e/vendor/k8s.io/apiserver/pkg/authorization/cel/interface.go
generated
vendored
Normal file
41
e2e/vendor/k8s.io/apiserver/pkg/authorization/cel/interface.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2023 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 cel
|
||||
|
||||
import (
|
||||
celgo "github.com/google/cel-go/cel"
|
||||
)
|
||||
|
||||
type ExpressionAccessor interface {
|
||||
GetExpression() string
|
||||
ReturnTypes() []*celgo.Type
|
||||
}
|
||||
|
||||
var _ ExpressionAccessor = &SubjectAccessReviewMatchCondition{}
|
||||
|
||||
// SubjectAccessReviewMatchCondition is a CEL expression that maps a SubjectAccessReview request to a list of values.
|
||||
type SubjectAccessReviewMatchCondition struct {
|
||||
Expression string
|
||||
}
|
||||
|
||||
func (v *SubjectAccessReviewMatchCondition) GetExpression() string {
|
||||
return v.Expression
|
||||
}
|
||||
|
||||
func (v *SubjectAccessReviewMatchCondition) ReturnTypes() []*celgo.Type {
|
||||
return []*celgo.Type{celgo.BoolType}
|
||||
}
|
91
e2e/vendor/k8s.io/apiserver/pkg/authorization/cel/matcher.go
generated
vendored
Normal file
91
e2e/vendor/k8s.io/apiserver/pkg/authorization/cel/matcher.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2023 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 cel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
celgo "github.com/google/cel-go/cel"
|
||||
|
||||
authorizationv1 "k8s.io/api/authorization/v1"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
)
|
||||
|
||||
type CELMatcher struct {
|
||||
CompilationResults []CompilationResult
|
||||
|
||||
// These track if any expressions use fieldSelector and labelSelector,
|
||||
// so construction of data passed to the CEL expression can be optimized if those fields are unused.
|
||||
UsesLabelSelector bool
|
||||
UsesFieldSelector bool
|
||||
|
||||
// These are optional fields which can be populated if metrics reporting is desired
|
||||
Metrics MatcherMetrics
|
||||
AuthorizerType string
|
||||
AuthorizerName string
|
||||
}
|
||||
|
||||
// eval evaluates the given SubjectAccessReview against all cel matchCondition expression
|
||||
func (c *CELMatcher) Eval(ctx context.Context, r *authorizationv1.SubjectAccessReview) (bool, error) {
|
||||
var evalErrors []error
|
||||
|
||||
metrics := c.Metrics
|
||||
if metrics == nil {
|
||||
metrics = NoopMatcherMetrics{}
|
||||
}
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
metrics.RecordAuthorizationMatchConditionEvaluation(ctx, c.AuthorizerType, c.AuthorizerName, time.Since(start))
|
||||
if len(evalErrors) > 0 {
|
||||
metrics.RecordAuthorizationMatchConditionEvaluationFailure(ctx, c.AuthorizerType, c.AuthorizerName)
|
||||
}
|
||||
}()
|
||||
|
||||
va := map[string]interface{}{
|
||||
"request": convertObjectToUnstructured(&r.Spec, c.UsesFieldSelector, c.UsesLabelSelector),
|
||||
}
|
||||
for _, compilationResult := range c.CompilationResults {
|
||||
evalResult, _, err := compilationResult.Program.ContextEval(ctx, va)
|
||||
if err != nil {
|
||||
evalErrors = append(evalErrors, fmt.Errorf("cel evaluation error: expression '%v' resulted in error: %w", compilationResult.ExpressionAccessor.GetExpression(), err))
|
||||
continue
|
||||
}
|
||||
if evalResult.Type() != celgo.BoolType {
|
||||
evalErrors = append(evalErrors, fmt.Errorf("cel evaluation error: expression '%v' eval result type should be bool but got %W", compilationResult.ExpressionAccessor.GetExpression(), evalResult.Type()))
|
||||
continue
|
||||
}
|
||||
match, ok := evalResult.Value().(bool)
|
||||
if !ok {
|
||||
evalErrors = append(evalErrors, fmt.Errorf("cel evaluation error: expression '%v' eval result value should be bool but got %W", compilationResult.ExpressionAccessor.GetExpression(), evalResult.Value()))
|
||||
continue
|
||||
}
|
||||
// If at least one matchCondition successfully evaluates to FALSE,
|
||||
// return early
|
||||
if !match {
|
||||
metrics.RecordAuthorizationMatchConditionExclusion(ctx, c.AuthorizerType, c.AuthorizerName)
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
// if there is any error, return
|
||||
if len(evalErrors) > 0 {
|
||||
return false, utilerrors.NewAggregate(evalErrors)
|
||||
}
|
||||
// return ALL matchConditions evaluate to TRUE successfully without error
|
||||
return true, nil
|
||||
}
|
120
e2e/vendor/k8s.io/apiserver/pkg/authorization/cel/metrics.go
generated
vendored
Normal file
120
e2e/vendor/k8s.io/apiserver/pkg/authorization/cel/metrics.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2024 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 cel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
)
|
||||
|
||||
// MatcherMetrics defines methods for reporting matchCondition metrics
|
||||
type MatcherMetrics interface {
|
||||
// RecordAuthorizationMatchConditionEvaluation records the total time taken to evaluate matchConditions for an Authorize() call to the given authorizer
|
||||
RecordAuthorizationMatchConditionEvaluation(ctx context.Context, authorizerType, authorizerName string, elapsed time.Duration)
|
||||
// RecordAuthorizationMatchConditionEvaluationFailure increments if any evaluation error was encountered evaluating matchConditions for an Authorize() call to the given authorizer
|
||||
RecordAuthorizationMatchConditionEvaluationFailure(ctx context.Context, authorizerType, authorizerName string)
|
||||
// RecordAuthorizationMatchConditionExclusion records increments when at least one matchCondition evaluates to false and excludes an Authorize() call to the given authorizer
|
||||
RecordAuthorizationMatchConditionExclusion(ctx context.Context, authorizerType, authorizerName string)
|
||||
}
|
||||
|
||||
type NoopMatcherMetrics struct{}
|
||||
|
||||
func (NoopMatcherMetrics) RecordAuthorizationMatchConditionEvaluation(ctx context.Context, authorizerType, authorizerName string, elapsed time.Duration) {
|
||||
}
|
||||
func (NoopMatcherMetrics) RecordAuthorizationMatchConditionEvaluationFailure(ctx context.Context, authorizerType, authorizerName string) {
|
||||
}
|
||||
func (NoopMatcherMetrics) RecordAuthorizationMatchConditionExclusion(ctx context.Context, authorizerType, authorizerName string) {
|
||||
}
|
||||
|
||||
type matcherMetrics struct{}
|
||||
|
||||
func NewMatcherMetrics() MatcherMetrics {
|
||||
RegisterMetrics()
|
||||
return matcherMetrics{}
|
||||
}
|
||||
|
||||
const (
|
||||
namespace = "apiserver"
|
||||
subsystem = "authorization"
|
||||
)
|
||||
|
||||
var (
|
||||
authorizationMatchConditionEvaluationErrorsTotal = metrics.NewCounterVec(
|
||||
&metrics.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "match_condition_evaluation_errors_total",
|
||||
Help: "Total number of errors when an authorization webhook encounters a match condition error split by authorizer type and name.",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"type", "name"},
|
||||
)
|
||||
authorizationMatchConditionExclusionsTotal = metrics.NewCounterVec(
|
||||
&metrics.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "match_condition_exclusions_total",
|
||||
Help: "Total number of exclusions when an authorization webhook is skipped because match conditions exclude it.",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"type", "name"},
|
||||
)
|
||||
authorizationMatchConditionEvaluationSeconds = metrics.NewHistogramVec(
|
||||
&metrics.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "match_condition_evaluation_seconds",
|
||||
Help: "Authorization match condition evaluation time in seconds, split by authorizer type and name.",
|
||||
Buckets: []float64{0.001, 0.005, 0.01, 0.025, 0.1, 0.2, 0.25},
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"type", "name"},
|
||||
)
|
||||
)
|
||||
|
||||
var registerMetrics sync.Once
|
||||
|
||||
func RegisterMetrics() {
|
||||
registerMetrics.Do(func() {
|
||||
legacyregistry.MustRegister(authorizationMatchConditionEvaluationErrorsTotal)
|
||||
legacyregistry.MustRegister(authorizationMatchConditionExclusionsTotal)
|
||||
legacyregistry.MustRegister(authorizationMatchConditionEvaluationSeconds)
|
||||
})
|
||||
}
|
||||
|
||||
func ResetMetricsForTest() {
|
||||
authorizationMatchConditionEvaluationErrorsTotal.Reset()
|
||||
authorizationMatchConditionExclusionsTotal.Reset()
|
||||
authorizationMatchConditionEvaluationSeconds.Reset()
|
||||
}
|
||||
|
||||
func (matcherMetrics) RecordAuthorizationMatchConditionEvaluationFailure(ctx context.Context, authorizerType, authorizerName string) {
|
||||
authorizationMatchConditionEvaluationErrorsTotal.WithContext(ctx).WithLabelValues(authorizerType, authorizerName).Inc()
|
||||
}
|
||||
|
||||
func (matcherMetrics) RecordAuthorizationMatchConditionExclusion(ctx context.Context, authorizerType, authorizerName string) {
|
||||
authorizationMatchConditionExclusionsTotal.WithContext(ctx).WithLabelValues(authorizerType, authorizerName).Inc()
|
||||
}
|
||||
|
||||
func (matcherMetrics) RecordAuthorizationMatchConditionEvaluation(ctx context.Context, authorizerType, authorizerName string, elapsed time.Duration) {
|
||||
elapsedSeconds := elapsed.Seconds()
|
||||
authorizationMatchConditionEvaluationSeconds.WithContext(ctx).WithLabelValues(authorizerType, authorizerName).Observe(elapsedSeconds)
|
||||
}
|
18
e2e/vendor/k8s.io/apiserver/pkg/authorization/path/doc.go
generated
vendored
Normal file
18
e2e/vendor/k8s.io/apiserver/pkg/authorization/path/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
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 path contains an authorizer that allows certain paths and path prefixes.
|
||||
package path // import "k8s.io/apiserver/pkg/authorization/path"
|
68
e2e/vendor/k8s.io/apiserver/pkg/authorization/path/path.go
generated
vendored
Normal file
68
e2e/vendor/k8s.io/apiserver/pkg/authorization/path/path.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 path
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
|
||||
// NewAuthorizer returns an authorizer which accepts a given set of paths.
|
||||
// Each path is either a fully matching path or it ends in * in case a prefix match is done. A leading / is optional.
|
||||
func NewAuthorizer(alwaysAllowPaths []string) (authorizer.Authorizer, error) {
|
||||
var prefixes []string
|
||||
paths := sets.NewString()
|
||||
for _, p := range alwaysAllowPaths {
|
||||
p = strings.TrimPrefix(p, "/")
|
||||
if len(p) == 0 {
|
||||
// matches "/"
|
||||
paths.Insert(p)
|
||||
continue
|
||||
}
|
||||
if strings.ContainsRune(p[:len(p)-1], '*') {
|
||||
return nil, fmt.Errorf("only trailing * allowed in %q", p)
|
||||
}
|
||||
if strings.HasSuffix(p, "*") {
|
||||
prefixes = append(prefixes, p[:len(p)-1])
|
||||
} else {
|
||||
paths.Insert(p)
|
||||
}
|
||||
}
|
||||
|
||||
return authorizer.AuthorizerFunc(func(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
if a.IsResourceRequest() {
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}
|
||||
|
||||
pth := strings.TrimPrefix(a.GetPath(), "/")
|
||||
if paths.Has(pth) {
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
for _, prefix := range prefixes {
|
||||
if strings.HasPrefix(pth, prefix) {
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
}
|
||||
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}), nil
|
||||
}
|
106
e2e/vendor/k8s.io/apiserver/pkg/authorization/union/union.go
generated
vendored
Normal file
106
e2e/vendor/k8s.io/apiserver/pkg/authorization/union/union.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright 2014 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 union implements an authorizer that combines multiple subauthorizer.
|
||||
// The union authorizer iterates over each subauthorizer and returns the first
|
||||
// decision that is either an Allow decision or a Deny decision. If a
|
||||
// subauthorizer returns a NoOpinion, then the union authorizer moves onto the
|
||||
// next authorizer or, if the subauthorizer was the last authorizer, returns
|
||||
// NoOpinion as the aggregate decision. I.e. union authorizer creates an
|
||||
// aggregate decision and supports short-circuit allows and denies from
|
||||
// subauthorizers.
|
||||
package union
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
)
|
||||
|
||||
// unionAuthzHandler authorizer against a chain of authorizer.Authorizer
|
||||
type unionAuthzHandler []authorizer.Authorizer
|
||||
|
||||
// New returns an authorizer that authorizes against a chain of authorizer.Authorizer objects
|
||||
func New(authorizationHandlers ...authorizer.Authorizer) authorizer.Authorizer {
|
||||
return unionAuthzHandler(authorizationHandlers)
|
||||
}
|
||||
|
||||
// Authorizes against a chain of authorizer.Authorizer objects and returns nil if successful and returns error if unsuccessful
|
||||
func (authzHandler unionAuthzHandler) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
var (
|
||||
errlist []error
|
||||
reasonlist []string
|
||||
)
|
||||
|
||||
for _, currAuthzHandler := range authzHandler {
|
||||
decision, reason, err := currAuthzHandler.Authorize(ctx, a)
|
||||
|
||||
if err != nil {
|
||||
errlist = append(errlist, err)
|
||||
}
|
||||
if len(reason) != 0 {
|
||||
reasonlist = append(reasonlist, reason)
|
||||
}
|
||||
switch decision {
|
||||
case authorizer.DecisionAllow, authorizer.DecisionDeny:
|
||||
return decision, reason, err
|
||||
case authorizer.DecisionNoOpinion:
|
||||
// continue to the next authorizer
|
||||
}
|
||||
}
|
||||
|
||||
return authorizer.DecisionNoOpinion, strings.Join(reasonlist, "\n"), utilerrors.NewAggregate(errlist)
|
||||
}
|
||||
|
||||
// unionAuthzRulesHandler authorizer against a chain of authorizer.RuleResolver
|
||||
type unionAuthzRulesHandler []authorizer.RuleResolver
|
||||
|
||||
// NewRuleResolvers returns an authorizer that authorizes against a chain of authorizer.Authorizer objects
|
||||
func NewRuleResolvers(authorizationHandlers ...authorizer.RuleResolver) authorizer.RuleResolver {
|
||||
return unionAuthzRulesHandler(authorizationHandlers)
|
||||
}
|
||||
|
||||
// RulesFor against a chain of authorizer.RuleResolver objects and returns nil if successful and returns error if unsuccessful
|
||||
func (authzHandler unionAuthzRulesHandler) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
var (
|
||||
errList []error
|
||||
resourceRulesList []authorizer.ResourceRuleInfo
|
||||
nonResourceRulesList []authorizer.NonResourceRuleInfo
|
||||
)
|
||||
incompleteStatus := false
|
||||
|
||||
for _, currAuthzHandler := range authzHandler {
|
||||
resourceRules, nonResourceRules, incomplete, err := currAuthzHandler.RulesFor(ctx, user, namespace)
|
||||
|
||||
if incomplete {
|
||||
incompleteStatus = true
|
||||
}
|
||||
if err != nil {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
if len(resourceRules) > 0 {
|
||||
resourceRulesList = append(resourceRulesList, resourceRules...)
|
||||
}
|
||||
if len(nonResourceRules) > 0 {
|
||||
nonResourceRulesList = append(nonResourceRulesList, nonResourceRules...)
|
||||
}
|
||||
}
|
||||
|
||||
return resourceRulesList, nonResourceRulesList, incompleteStatus, utilerrors.NewAggregate(errList)
|
||||
}
|
Reference in New Issue
Block a user