rebase: update kubernetes and libraries to v1.22.0 version

Kubernetes v1.22 version has been released and this update
ceph csi dependencies to use the same version.

Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
This commit is contained in:
Humble Chirammal
2021-08-09 12:49:24 +05:30
committed by mergify[bot]
parent e077c1fdf5
commit aa698bc3e1
759 changed files with 61864 additions and 6514 deletions

View File

@ -55,6 +55,10 @@ const (
PatchAuditAnnotationPrefix = "patch.webhook.admission.k8s.io/"
// MutationAuditAnnotationPrefix is a prefix for presisting webhook mutation existence in audit annotation.
MutationAuditAnnotationPrefix = "mutation.webhook.admission.k8s.io/"
// MutationAnnotationFailedOpenKeyPrefix in an annotation indicates
// the mutating webhook failed open when the webhook backend connection
// failed or returned an internal server error.
MutationAuditAnnotationFailedOpenKeyPrefix string = "failed-open." + MutationAuditAnnotationPrefix
)
var encodingjson = json.CaseSensitiveJSONIterator()
@ -134,7 +138,9 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attrib
if reinvokeCtx.IsReinvoke() {
round = 1
}
changed, err := a.callAttrMutatingHook(ctx, hook, invocation, versionedAttr, o, round, i)
annotator := newWebhookAnnotator(versionedAttr, round, i, hook.Name, invocation.Webhook.GetConfigurationName())
changed, err := a.callAttrMutatingHook(ctx, hook, invocation, versionedAttr, annotator, o, round, i)
ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == admissionregistrationv1.Ignore
rejected := false
if err != nil {
@ -168,6 +174,9 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attrib
if callErr, ok := err.(*webhookutil.ErrCallingWebhook); ok {
if ignoreClientCallFailures {
klog.Warningf("Failed calling webhook, failing open %v: %v", hook.Name, callErr)
annotator.addFailedOpenAnnotation()
utilruntime.HandleError(callErr)
select {
@ -198,9 +207,8 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attrib
// note that callAttrMutatingHook updates attr
func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admissionregistrationv1.MutatingWebhook, invocation *generic.WebhookInvocation, attr *generic.VersionedAttributes, o admission.ObjectInterfaces, round, idx int) (bool, error) {
func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admissionregistrationv1.MutatingWebhook, invocation *generic.WebhookInvocation, attr *generic.VersionedAttributes, annotator *webhookAnnotator, o admission.ObjectInterfaces, round, idx int) (bool, error) {
configurationName := invocation.Webhook.GetConfigurationName()
annotator := newWebhookAnnotator(attr, round, idx, h.Name, configurationName)
changed := false
defer func() { annotator.addMutationAnnotation(changed) }()
if attr.Attributes.IsDryRun() {
@ -214,12 +222,12 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss
uid, request, response, err := webhookrequest.CreateAdmissionObjects(attr, invocation)
if err != nil {
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("could not create admission objects: %w", err)}
}
// Make the webhook request
client, err := invocation.Webhook.GetRESTClient(a.cm)
if err != nil {
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("could not get REST client: %w", err)}
}
trace := utiltrace.New("Call mutating webhook",
utiltrace.Field{"configuration", configurationName},
@ -253,13 +261,13 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss
}
if err := r.Do(ctx).Into(response); err != nil {
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("failed to call webhook: %w", err)}
}
trace.Step("Request completed")
result, err := webhookrequest.VerifyAdmissionResponse(uid, true, response)
if err != nil {
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err}
return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("received invalid webhook response: %w", err)}
}
for k, v := range result.AuditAnnotations {
@ -338,20 +346,32 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss
}
type webhookAnnotator struct {
attr *generic.VersionedAttributes
patchAnnotationKey string
mutationAnnotationKey string
webhook string
configuration string
attr *generic.VersionedAttributes
failedOpenAnnotationKey string
patchAnnotationKey string
mutationAnnotationKey string
webhook string
configuration string
}
func newWebhookAnnotator(attr *generic.VersionedAttributes, round, idx int, webhook, configuration string) *webhookAnnotator {
return &webhookAnnotator{
attr: attr,
patchAnnotationKey: fmt.Sprintf("%sround_%d_index_%d", PatchAuditAnnotationPrefix, round, idx),
mutationAnnotationKey: fmt.Sprintf("%sround_%d_index_%d", MutationAuditAnnotationPrefix, round, idx),
webhook: webhook,
configuration: configuration,
attr: attr,
failedOpenAnnotationKey: fmt.Sprintf("%sround_%d_index_%d", MutationAuditAnnotationFailedOpenKeyPrefix, round, idx),
patchAnnotationKey: fmt.Sprintf("%sround_%d_index_%d", PatchAuditAnnotationPrefix, round, idx),
mutationAnnotationKey: fmt.Sprintf("%sround_%d_index_%d", MutationAuditAnnotationPrefix, round, idx),
webhook: webhook,
configuration: configuration,
}
}
func (w *webhookAnnotator) addFailedOpenAnnotation() {
if w.attr == nil || w.attr.Attributes == nil {
return
}
value := w.webhook
if err := w.attr.Attributes.AddAnnotation(w.failedOpenAnnotationKey, value); err != nil {
klog.Warningf("failed to set failed open annotation for mutating webhook key %s to %s: %v", w.failedOpenAnnotationKey, value, err)
}
}

View File

@ -44,6 +44,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&AdmissionConfiguration{},
&EgressSelectorConfiguration{},
&TracingConfiguration{},
)
return nil
}

View File

@ -147,3 +147,23 @@ type TLSConfig struct {
// +optional
ClientCert string
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// TracingConfiguration provides versioned configuration for tracing clients.
type TracingConfiguration struct {
metav1.TypeMeta
// +optional
// Endpoint of the collector that's running on the control-plane node.
// The APIServer uses the egressType ControlPlane when sending data to the collector.
// The syntax is defined in https://github.com/grpc/grpc/blob/master/doc/naming.md.
// Defaults to the otlp grpc default, localhost:4317
// The connection is insecure, and does not currently support TLS.
Endpoint *string
// +optional
// SamplingRatePerMillion is the number of samples to collect per million spans.
// Defaults to 0.
SamplingRatePerMillion *int32
}

View File

@ -18,6 +18,7 @@ limitations under the License.
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/apiserver
// +k8s:defaulter-gen=TypeMeta
// +groupName=apiserver.k8s.io
// +groupName=apiserver.config.k8s.io
// Package v1alpha1 is the v1alpha1 version of the API.
package v1alpha1 // import "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"

View File

@ -23,10 +23,14 @@ import (
)
const GroupName = "apiserver.k8s.io"
const ConfigGroupName = "apiserver.config.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// ConfigSchemeGroupVersion is group version used to register these objects
var ConfigSchemeGroupVersion = schema.GroupVersion{Group: ConfigGroupName, Version: "v1alpha1"}
var (
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
@ -48,6 +52,10 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&AdmissionConfiguration{},
&EgressSelectorConfiguration{},
)
scheme.AddKnownTypes(ConfigSchemeGroupVersion,
&TracingConfiguration{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
metav1.AddToGroupVersion(scheme, ConfigSchemeGroupVersion)
return nil
}

View File

@ -147,3 +147,23 @@ type TLSConfig struct {
// +optional
ClientCert string `json:"clientCert,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// TracingConfiguration provides versioned configuration for tracing clients.
type TracingConfiguration struct {
metav1.TypeMeta `json:",inline"`
// +optional
// Endpoint of the collector that's running on the control-plane node.
// The APIServer uses the egressType ControlPlane when sending data to the collector.
// The syntax is defined in https://github.com/grpc/grpc/blob/master/doc/naming.md.
// Defaults to the otlpgrpc default, localhost:4317
// The connection is insecure, and does not support TLS.
Endpoint *string `json:"endpoint,omitempty" protobuf:"bytes,1,opt,name=endpoint"`
// +optional
// SamplingRatePerMillion is the number of samples to collect per million spans.
// Defaults to 0.
SamplingRatePerMillion *int32 `json:"samplingRatePerMillion,omitempty" protobuf:"varint,2,opt,name=samplingRatePerMillion"`
}

View File

@ -105,6 +105,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*TracingConfiguration)(nil), (*apiserver.TracingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_TracingConfiguration_To_apiserver_TracingConfiguration(a.(*TracingConfiguration), b.(*apiserver.TracingConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*apiserver.TracingConfiguration)(nil), (*TracingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_apiserver_TracingConfiguration_To_v1alpha1_TracingConfiguration(a.(*apiserver.TracingConfiguration), b.(*TracingConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*Transport)(nil), (*apiserver.Transport)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_Transport_To_apiserver_Transport(a.(*Transport), b.(*apiserver.Transport), scope)
}); err != nil {
@ -286,6 +296,28 @@ func Convert_apiserver_TLSConfig_To_v1alpha1_TLSConfig(in *apiserver.TLSConfig,
return autoConvert_apiserver_TLSConfig_To_v1alpha1_TLSConfig(in, out, s)
}
func autoConvert_v1alpha1_TracingConfiguration_To_apiserver_TracingConfiguration(in *TracingConfiguration, out *apiserver.TracingConfiguration, s conversion.Scope) error {
out.Endpoint = (*string)(unsafe.Pointer(in.Endpoint))
out.SamplingRatePerMillion = (*int32)(unsafe.Pointer(in.SamplingRatePerMillion))
return nil
}
// Convert_v1alpha1_TracingConfiguration_To_apiserver_TracingConfiguration is an autogenerated conversion function.
func Convert_v1alpha1_TracingConfiguration_To_apiserver_TracingConfiguration(in *TracingConfiguration, out *apiserver.TracingConfiguration, s conversion.Scope) error {
return autoConvert_v1alpha1_TracingConfiguration_To_apiserver_TracingConfiguration(in, out, s)
}
func autoConvert_apiserver_TracingConfiguration_To_v1alpha1_TracingConfiguration(in *apiserver.TracingConfiguration, out *TracingConfiguration, s conversion.Scope) error {
out.Endpoint = (*string)(unsafe.Pointer(in.Endpoint))
out.SamplingRatePerMillion = (*int32)(unsafe.Pointer(in.SamplingRatePerMillion))
return nil
}
// Convert_apiserver_TracingConfiguration_To_v1alpha1_TracingConfiguration is an autogenerated conversion function.
func Convert_apiserver_TracingConfiguration_To_v1alpha1_TracingConfiguration(in *apiserver.TracingConfiguration, out *TracingConfiguration, s conversion.Scope) error {
return autoConvert_apiserver_TracingConfiguration_To_v1alpha1_TracingConfiguration(in, out, s)
}
func autoConvert_v1alpha1_Transport_To_apiserver_Transport(in *Transport, out *apiserver.Transport, s conversion.Scope) error {
out.TCP = (*apiserver.TCPTransport)(unsafe.Pointer(in.TCP))
out.UDS = (*apiserver.UDSTransport)(unsafe.Pointer(in.UDS))

View File

@ -184,6 +184,41 @@ func (in *TLSConfig) DeepCopy() *TLSConfig {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TracingConfiguration) DeepCopyInto(out *TracingConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Endpoint != nil {
in, out := &in.Endpoint, &out.Endpoint
*out = new(string)
**out = **in
}
if in.SamplingRatePerMillion != nil {
in, out := &in.SamplingRatePerMillion, &out.SamplingRatePerMillion
*out = new(int32)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracingConfiguration.
func (in *TracingConfiguration) DeepCopy() *TracingConfiguration {
if in == nil {
return nil
}
out := new(TracingConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TracingConfiguration) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Transport) DeepCopyInto(out *Transport) {
*out = *in

View File

@ -184,6 +184,41 @@ func (in *TLSConfig) DeepCopy() *TLSConfig {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TracingConfiguration) DeepCopyInto(out *TracingConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Endpoint != nil {
in, out := &in.Endpoint, &out.Endpoint
*out = new(string)
**out = **in
}
if in.SamplingRatePerMillion != nil {
in, out := &in.SamplingRatePerMillion, &out.SamplingRatePerMillion
*out = new(int32)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracingConfiguration.
func (in *TracingConfiguration) DeepCopy() *TracingConfiguration {
if in == nil {
return nil
}
out := new(TracingConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TracingConfiguration) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Transport) DeepCopyInto(out *Transport) {
*out = *in

View File

@ -62,15 +62,15 @@ type Stage string
const (
// The stage for events generated as soon as the audit handler receives the request, and before it
// is delegated down the handler chain.
StageRequestReceived = "RequestReceived"
StageRequestReceived Stage = "RequestReceived"
// The stage for events generated once the response headers are sent, but before the response body
// is sent. This stage is only generated for long-running requests (e.g. watch).
StageResponseStarted = "ResponseStarted"
StageResponseStarted Stage = "ResponseStarted"
// The stage for events generated once the response body has been completed, and no more bytes
// will be sent.
StageResponseComplete = "ResponseComplete"
StageResponseComplete Stage = "ResponseComplete"
// The stage for events generated when a panic occurred.
StagePanic = "Panic"
StagePanic Stage = "Panic"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -55,15 +55,15 @@ type Stage string
const (
// The stage for events generated as soon as the audit handler receives the request, and before it
// is delegated down the handler chain.
StageRequestReceived = "RequestReceived"
StageRequestReceived Stage = "RequestReceived"
// The stage for events generated once the response headers are sent, but before the response body
// is sent. This stage is only generated for long-running requests (e.g. watch).
StageResponseStarted = "ResponseStarted"
StageResponseStarted Stage = "ResponseStarted"
// The stage for events generated once the response body has been completed, and no more bytes
// will be sent.
StageResponseComplete = "ResponseComplete"
StageResponseComplete Stage = "ResponseComplete"
// The stage for events generated when a panic occurred.
StagePanic = "Panic"
StagePanic Stage = "Panic"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -62,15 +62,15 @@ type Stage string
const (
// The stage for events generated as soon as the audit handler receives the request, and before it
// is delegated down the handler chain.
StageRequestReceived = "RequestReceived"
StageRequestReceived Stage = "RequestReceived"
// The stage for events generated once the response headers are sent, but before the response body
// is sent. This stage is only generated for long-running requests (e.g. watch).
StageResponseStarted = "ResponseStarted"
StageResponseStarted Stage = "ResponseStarted"
// The stage for events generated once the response body has been completed, and no more bytes
// will be sent.
StageResponseComplete = "ResponseComplete"
StageResponseComplete Stage = "ResponseComplete"
// The stage for events generated when a panic occurred.
StagePanic = "Panic"
StagePanic Stage = "Panic"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -55,15 +55,15 @@ type Stage string
const (
// The stage for events generated as soon as the audit handler receives the request, and before it
// is delegated down the handler chain.
StageRequestReceived = "RequestReceived"
StageRequestReceived Stage = "RequestReceived"
// The stage for events generated once the response headers are sent, but before the response body
// is sent. This stage is only generated for long-running requests (e.g. watch).
StageResponseStarted = "ResponseStarted"
StageResponseStarted Stage = "ResponseStarted"
// The stage for events generated once the response body has been completed, and no more bytes
// will be sent.
StageResponseComplete = "ResponseComplete"
StageResponseComplete Stage = "ResponseComplete"
// The stage for events generated when a panic occurred.
StagePanic = "Panic"
StagePanic Stage = "Panic"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -60,8 +60,8 @@ func EventString(ev *auditinternal.Event) string {
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 namespace=%q uri=%q response=\"%s\"",
ev.RequestReceivedTimestamp.Format(time.RFC3339Nano), ev.AuditID, ev.Stage, ip, ev.Verb, username, groups, asuser, asgroups, namespace, ev.RequestURI, response)
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 {

View File

@ -32,7 +32,7 @@ const (
/*
* By default, all the following metrics are defined as falling under
* ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/1209-metrics-stability/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes)
* ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/1209-metrics-stability/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

View File

@ -23,9 +23,6 @@ import (
"reflect"
"time"
"github.com/google/uuid"
"k8s.io/klog/v2"
authnv1 "k8s.io/api/authentication/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -36,6 +33,10 @@ import (
auditinternal "k8s.io/apiserver/pkg/apis/audit"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/klog/v2"
"github.com/google/uuid"
)
const (
@ -52,14 +53,11 @@ func NewEventFromRequest(req *http.Request, requestReceivedTimestamp time.Time,
Level: level,
}
// prefer the id from the headers. If not available, create a new one.
// TODO(audit): do we want to forbid the header for non-front-proxy users?
ids := req.Header.Get(auditinternal.HeaderAuditID)
if ids != "" {
ev.AuditID = types.UID(ids)
} else {
ev.AuditID = types.UID(uuid.New().String())
auditID, found := request.AuditIDFrom(req.Context())
if !found {
auditID = types.UID(uuid.New().String())
}
ev.AuditID = auditID
ips := utilnet.SourceIPs(req)
ev.SourceIPs = make([]string, len(ips))
@ -113,7 +111,7 @@ func LogImpersonatedUser(ae *auditinternal.Event, user user.Info) {
// LogRequestObject fills in the request object into an audit event. The passed runtime.Object
// will be converted to the given gv.
func LogRequestObject(ae *auditinternal.Event, obj runtime.Object, gvr schema.GroupVersionResource, subresource string, s runtime.NegotiatedSerializer) {
func LogRequestObject(ae *auditinternal.Event, obj runtime.Object, objGV schema.GroupVersion, gvr schema.GroupVersionResource, subresource string, s runtime.NegotiatedSerializer) {
if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) {
return
}
@ -155,7 +153,7 @@ func LogRequestObject(ae *auditinternal.Event, obj runtime.Object, gvr schema.Gr
// TODO(audit): hook into the serializer to avoid double conversion
var err error
ae.RequestObject, err = encodeObject(obj, gvr.GroupVersion(), s)
ae.RequestObject, err = encodeObject(obj, objGV, s)
if err != nil {
// TODO(audit): add error slice to audit event struct
klog.Warningf("Auditing failed of %v request: %v", reflect.TypeOf(obj).Name(), err)

View File

@ -71,10 +71,10 @@ type Authorizer interface {
Authorize(ctx context.Context, a Attributes) (authorized Decision, reason string, err error)
}
type AuthorizerFunc func(a Attributes) (Decision, string, 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(a)
return f(ctx, a)
}
// RuleResolver provides a mechanism for resolving the list of rules that apply to a given user within a namespace.

View File

@ -0,0 +1,66 @@
/*
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 request
import (
"context"
"net/http"
"k8s.io/apimachinery/pkg/types"
)
type auditIDKeyType int
// auditIDKey is the key to associate the Audit-ID value of a request.
const auditIDKey auditIDKeyType = iota
// WithAuditID returns a copy of the parent context into which the Audit-ID
// associated with the request is set.
//
// If the specified auditID is empty, no value is set and the parent context is returned as is.
func WithAuditID(parent context.Context, auditID types.UID) context.Context {
if auditID == "" {
return parent
}
return WithValue(parent, auditIDKey, auditID)
}
// AuditIDFrom returns the value of the audit ID from the request context.
func AuditIDFrom(ctx context.Context) (types.UID, bool) {
auditID, ok := ctx.Value(auditIDKey).(types.UID)
return auditID, ok
}
// GetAuditIDTruncated returns the audit ID (truncated) associated with a request.
// 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(req *http.Request) string {
auditID, ok := AuditIDFrom(req.Context())
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[0:maxAuditIDLength]
}
return string(auditID)
}

View File

@ -38,12 +38,13 @@ const (
// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
//
// This feature is deprecated, and will be removed in v1.22.
// This feature is deprecated, and will be removed in v1.24.
StreamingProxyRedirects featuregate.Feature = "StreamingProxyRedirects"
// owner: @tallclair
// alpha: v1.12
// beta: v1.14
// deprecated: v1.22
//
// ValidateProxyRedirects controls whether the apiserver should validate that redirects are only
// followed to the same host. Only used if StreamingProxyRedirects is enabled.
@ -95,6 +96,7 @@ const (
// owner: @apelisse, @lavalamp
// alpha: v1.14
// beta: v1.16
// stable: v1.22
//
// Server-side apply. Merging happens on the server.
ServerSideApply featuregate.Feature = "ServerSideApply"
@ -145,6 +147,7 @@ const (
// owner: @liggitt
// beta: v1.19
// GA: v1.22
//
// Allows sending warning headers in API responses.
WarningHeaders featuregate.Feature = "WarningHeaders"
@ -161,6 +164,12 @@ const (
//
// Assigns each kube-apiserver an ID in a cluster.
APIServerIdentity featuregate.Feature = "APIServerIdentity"
// owner: @dashpole
// alpha: v1.22
//
// Add support for distributed tracing in the API Server
APIServerTracing featuregate.Feature = "APIServerTracing"
)
func init() {
@ -171,21 +180,22 @@ func init() {
// To add a new feature, define a key for it above and add it here. The features will be
// available throughout Kubernetes binaries.
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
StreamingProxyRedirects: {Default: true, PreRelease: featuregate.Deprecated},
ValidateProxyRedirects: {Default: true, PreRelease: featuregate.Beta},
StreamingProxyRedirects: {Default: false, PreRelease: featuregate.Deprecated},
ValidateProxyRedirects: {Default: true, PreRelease: featuregate.Deprecated},
AdvancedAuditing: {Default: true, PreRelease: featuregate.GA},
APIResponseCompression: {Default: true, PreRelease: featuregate.Beta},
APIListChunking: {Default: true, PreRelease: featuregate.Beta},
DryRun: {Default: true, PreRelease: featuregate.GA},
RemainingItemCount: {Default: true, PreRelease: featuregate.Beta},
ServerSideApply: {Default: true, PreRelease: featuregate.Beta},
ServerSideApply: {Default: true, PreRelease: featuregate.GA},
StorageVersionHash: {Default: true, PreRelease: featuregate.Beta},
StorageVersionAPI: {Default: false, PreRelease: featuregate.Alpha},
WatchBookmark: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
APIPriorityAndFairness: {Default: true, PreRelease: featuregate.Beta},
RemoveSelfLink: {Default: true, PreRelease: featuregate.Beta},
SelectorIndex: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
WarningHeaders: {Default: true, PreRelease: featuregate.Beta},
WarningHeaders: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
EfficientWatchResumption: {Default: true, PreRelease: featuregate.Beta},
APIServerIdentity: {Default: false, PreRelease: featuregate.Alpha},
APIServerTracing: {Default: false, PreRelease: featuregate.Alpha},
}

View File

@ -54,7 +54,7 @@ type Evaluator interface {
Matches(resourceQuota *corev1.ResourceQuota, item runtime.Object) (bool, error)
// MatchingScopes takes the input specified list of scopes and input object and returns the set of scopes that matches input object.
MatchingScopes(item runtime.Object, scopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error)
// UncoveredQuotaScopes takes the input matched scopes which are limited by configuration and the matched quota scopes. It returns the scopes which are in limited scopes but dont have a corresponding covering quota scope
// UncoveredQuotaScopes takes the input matched scopes which are limited by configuration and the matched quota scopes. It returns the scopes which are in limited scopes but don't have a corresponding covering quota scope
UncoveredQuotaScopes(limitedScopes []corev1.ScopedResourceSelectorRequirement, matchedQuotaScopes []corev1.ScopedResourceSelectorRequirement) ([]corev1.ScopedResourceSelectorRequirement, error)
// MatchingResources takes the input specified list of resources and returns the set of resources evaluator matches.
MatchingResources(input []corev1.ResourceName) []corev1.ResourceName

View File

@ -134,7 +134,7 @@ func tunnelHTTPConnect(proxyConn net.Conn, proxyAddress, addr string) (net.Conn,
type proxier interface {
// proxy returns a connection to addr.
proxy(addr string) (net.Conn, error)
proxy(ctx context.Context, addr string) (net.Conn, error)
}
var _ proxier = &httpConnectProxier{}
@ -144,7 +144,7 @@ type httpConnectProxier struct {
proxyAddress string
}
func (t *httpConnectProxier) proxy(addr string) (net.Conn, error) {
func (t *httpConnectProxier) proxy(ctx context.Context, addr string) (net.Conn, error) {
return tunnelHTTPConnect(t.conn, t.proxyAddress, addr)
}
@ -154,8 +154,8 @@ type grpcProxier struct {
tunnel client.Tunnel
}
func (g *grpcProxier) proxy(addr string) (net.Conn, error) {
return g.tunnel.Dial("tcp", addr)
func (g *grpcProxier) proxy(ctx context.Context, addr string) (net.Conn, error) {
return g.tunnel.DialContext(ctx, "tcp", addr)
}
type proxyServerConnector interface {
@ -203,7 +203,8 @@ func (u *udsGRPCConnector) connect() (proxier, error) {
return c, err
})
tunnel, err := client.CreateSingleUseGrpcTunnel(udsName, dialOption, grpc.WithInsecure())
ctx := context.TODO()
tunnel, err := client.CreateSingleUseGrpcTunnel(ctx, udsName, dialOption, grpc.WithInsecure())
if err != nil {
return nil, err
}
@ -234,7 +235,7 @@ func (d *dialerCreator) createDialer() utilnet.DialFunc {
egressmetrics.Metrics.ObserveDialFailure(d.options.protocol, d.options.transport, egressmetrics.StageConnect)
return nil, err
}
conn, err := proxier.proxy(addr)
conn, err := proxier.proxy(ctx, addr)
if err != nil {
egressmetrics.Metrics.ObserveDialFailure(d.options.protocol, d.options.transport, egressmetrics.StageProxy)
return nil, err

View File

@ -43,12 +43,12 @@ const (
// TODO: make this flexible for non-core resources with alternate naming rules.
maxNameLength = 63
randomLength = 5
maxGeneratedNameLength = maxNameLength - randomLength
MaxGeneratedNameLength = maxNameLength - randomLength
)
func (simpleNameGenerator) GenerateName(base string) string {
if len(base) > maxGeneratedNameLength {
base = base[:maxGeneratedNameLength]
if len(base) > MaxGeneratedNameLength {
base = base[:MaxGeneratedNameLength]
}
return fmt.Sprintf("%s%s", base, utilrand.String(randomLength))
}

View File

@ -25,12 +25,17 @@ import (
"strings"
"time"
"go.opentelemetry.io/otel/trace"
corev1 "k8s.io/api/core/v1"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apiserver/pkg/features"
egressselector "k8s.io/apiserver/pkg/server/egressselector"
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/component-base/traces"
)
// AuthenticationInfoResolverWrapper can be used to inject Dial function to the
@ -41,7 +46,8 @@ type AuthenticationInfoResolverWrapper func(AuthenticationInfoResolver) Authenti
func NewDefaultAuthenticationInfoResolverWrapper(
proxyTransport *http.Transport,
egressSelector *egressselector.EgressSelector,
kubeapiserverClientConfig *rest.Config) AuthenticationInfoResolverWrapper {
kubeapiserverClientConfig *rest.Config,
tp *trace.TracerProvider) AuthenticationInfoResolverWrapper {
webhookAuthResolverWrapper := func(delegate AuthenticationInfoResolver) AuthenticationInfoResolver {
return &AuthenticationInfoResolverDelegator{
@ -53,6 +59,9 @@ func NewDefaultAuthenticationInfoResolverWrapper(
if err != nil {
return nil, err
}
if feature.DefaultFeatureGate.Enabled(features.APIServerTracing) {
ret.Wrap(traces.WrapperFor(tp))
}
if egressSelector != nil {
networkContext := egressselector.ControlPlane.AsNetworkContext()
@ -75,6 +84,9 @@ func NewDefaultAuthenticationInfoResolverWrapper(
if err != nil {
return nil, err
}
if feature.DefaultFeatureGate.Enabled(features.APIServerTracing) {
ret.Wrap(traces.WrapperFor(tp))
}
if egressSelector != nil {
networkContext := egressselector.Cluster.AsNetworkContext()

View File

@ -25,12 +25,13 @@ import (
"net/url"
"strconv"
"github.com/hashicorp/golang-lru"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/util/x509metrics"
"k8s.io/client-go/rest"
"k8s.io/utils/lru"
)
const (
@ -64,10 +65,7 @@ type ClientManager struct {
// NewClientManager creates a clientManager.
func NewClientManager(gvs []schema.GroupVersion, addToSchemaFuncs ...func(s *runtime.Scheme) error) (ClientManager, error) {
cache, err := lru.New(defaultCacheSize)
if err != nil {
return ClientManager{}, err
}
cache := lru.New(defaultCacheSize)
hookScheme := runtime.NewScheme()
for _, addToSchemaFunc := range addToSchemaFuncs {
if err := addToSchemaFunc(hookScheme); err != nil {
@ -148,6 +146,11 @@ func (cm *ClientManager) HookClient(cc ClientConfig) (*rest.RESTClient, error) {
cfg.ContentConfig.NegotiatedSerializer = cm.negotiatedSerializer
cfg.ContentConfig.ContentType = runtime.ContentTypeJSON
// Add a transport wrapper that allows detection of TLS connections to
// servers without SAN extension in their serving certificates
cfg.Wrap(x509metrics.NewMissingSANRoundTripperWrapperConstructor(x509MissingSANCounter))
client, err := rest.UnversionedRESTClientFor(cfg)
if err == nil {
cm.cache.Add(string(cacheKey), client)

View File

@ -35,6 +35,18 @@ extendedKeyUsage = clientAuth, serverAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = 127.0.0.1
DNS.1 = localhost
EOF
cat > server_no_san.conf << EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
EOF
cat > client.conf << EOF
@ -64,6 +76,10 @@ openssl genrsa -out serverKey.pem 2048
openssl req -new -key serverKey.pem -out server.csr -subj "/CN=${CN_BASE}_server" -config server.conf
openssl x509 -req -in server.csr -CA caCert.pem -CAkey caKey.pem -CAcreateserial -out serverCert.pem -days 100000 -extensions v3_req -extfile server.conf
# Create a server certiticate w/o SAN
openssl req -new -key serverKey.pem -out serverNoSAN.csr -subj "/CN=localhost" -config server_no_san.conf
openssl x509 -req -in serverNoSAN.csr -CA caCert.pem -CAkey caKey.pem -CAcreateserial -out serverCertNoSAN.pem -days 100000 -extensions v3_req -extfile server_no_san.conf
# Create a client certiticate
openssl genrsa -out clientKey.pem 2048
openssl req -new -key clientKey.pem -out client.csr -subj "/CN=${CN_BASE}_client" -config client.conf
@ -94,7 +110,7 @@ limitations under the License.
package webhook
EOF
for file in caKey caCert badCAKey badCACert serverKey serverCert clientKey clientCert; do
for file in caKey caCert badCAKey badCACert serverKey serverCert serverCertNoSAN clientKey clientCert; do
data=$(cat ${file}.pem)
echo "" >> $outfile
echo "var $file = []byte(\`$data\`)" >> $outfile

39
vendor/k8s.io/apiserver/pkg/util/webhook/metrics.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
/*
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 webhook
import (
"k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/legacyregistry"
)
var x509MissingSANCounter = metrics.NewCounter(
&metrics.CounterOpts{
Subsystem: "webhooks",
Namespace: "apiserver",
Name: "x509_missing_san_total",
Help: "Counts the number of requests to servers missing SAN extension " +
"in their serving certificate OR the number of connection failures " +
"due to the lack of x509 certificate SAN extension missing " +
"(either/or, based on the runtime environment)",
StabilityLevel: metrics.ALPHA,
},
)
func init() {
legacyregistry.MustRegister(x509MissingSANCounter)
}

View File

@ -28,6 +28,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/serializer"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/util/x509metrics"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
@ -107,6 +108,7 @@ func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFact
clientConfig.ContentConfig.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
clientConfig.Dial = customDial
clientConfig.Wrap(x509metrics.NewMissingSANRoundTripperWrapperConstructor(x509MissingSANCounter))
restClient, err := rest.UnversionedRESTClientFor(clientConfig)
if err != nil {

View File

@ -0,0 +1,92 @@
/*
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 x509metrics
import (
"crypto/x509"
"errors"
"net/http"
"strings"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/component-base/metrics"
)
var _ utilnet.RoundTripperWrapper = &x509MissingSANErrorMetricsRTWrapper{}
type x509MissingSANErrorMetricsRTWrapper struct {
rt http.RoundTripper
counter *metrics.Counter
}
// NewMissingSANRoundTripperWrapperConstructor returns a RoundTripper wrapper that's usable
// within ClientConfig.Wrap that increases the `metricCounter` whenever:
// 1. we get a x509.HostnameError with string `x509: certificate relies on legacy Common Name field`
// which indicates an error caused by the deprecation of Common Name field when veryfing remote
// hostname
// 2. the server certificate in response contains no SAN. This indicates that this binary run
// with the GODEBUG=x509ignoreCN=0 in env
func NewMissingSANRoundTripperWrapperConstructor(metricCounter *metrics.Counter) func(rt http.RoundTripper) http.RoundTripper {
return func(rt http.RoundTripper) http.RoundTripper {
return &x509MissingSANErrorMetricsRTWrapper{
rt: rt,
counter: metricCounter,
}
}
}
func (w *x509MissingSANErrorMetricsRTWrapper) RoundTrip(req *http.Request) (*http.Response, error) {
resp, err := w.rt.RoundTrip(req)
checkForHostnameError(err, w.counter)
checkRespForNoSAN(resp, w.counter)
return resp, err
}
func (w *x509MissingSANErrorMetricsRTWrapper) WrappedRoundTripper() http.RoundTripper {
return w.rt
}
// checkForHostnameError increases the metricCounter when we're running w/o GODEBUG=x509ignoreCN=0
// and the client reports a HostnameError about the legacy CN fields
func checkForHostnameError(err error, metricCounter *metrics.Counter) {
if err != nil && errors.As(err, &x509.HostnameError{}) && strings.Contains(err.Error(), "x509: certificate relies on legacy Common Name field") {
// increase the count of registered failures due to Go 1.15 x509 cert Common Name deprecation
metricCounter.Inc()
}
}
// checkRespForNoSAN increases the metricCounter when the server response contains
// a leaf certificate w/o the SAN extension
func checkRespForNoSAN(resp *http.Response, metricCounter *metrics.Counter) {
if resp != nil && resp.TLS != nil && len(resp.TLS.PeerCertificates) > 0 {
if serverCert := resp.TLS.PeerCertificates[0]; !hasSAN(serverCert) {
metricCounter.Inc()
}
}
}
func hasSAN(c *x509.Certificate) bool {
sanOID := []int{2, 5, 29, 17}
for _, e := range c.Extensions {
if e.Id.Equal(sanOID) {
return true
}
}
return false
}