Bump sigs.k8s.io/controller-runtime to v0.14.4 (#5507)
* Bump sigs.k8s.io/controller-runtime to v0.14.4 * Update gofmt
This commit is contained in:
78
vendor/k8s.io/apiserver/pkg/server/config.go
generated
vendored
78
vendor/k8s.io/apiserver/pkg/server/config.go
generated
vendored
@@ -17,9 +17,13 @@ limitations under the License.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
goruntime "runtime"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
@@ -30,11 +34,12 @@ import (
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/google/uuid"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
@@ -45,9 +50,8 @@ import (
|
||||
authenticatorunion "k8s.io/apiserver/pkg/authentication/request/union"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
||||
authorizerunion "k8s.io/apiserver/pkg/authorization/union"
|
||||
"k8s.io/apiserver/pkg/endpoints/discovery"
|
||||
discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
|
||||
"k8s.io/apiserver/pkg/endpoints/filterlatency"
|
||||
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
|
||||
apiopenapi "k8s.io/apiserver/pkg/endpoints/openapi"
|
||||
@@ -67,6 +71,9 @@ import (
|
||||
"k8s.io/client-go/informers"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/component-base/logs"
|
||||
"k8s.io/component-base/metrics/features"
|
||||
"k8s.io/component-base/metrics/prometheus/slis"
|
||||
"k8s.io/component-base/tracing"
|
||||
"k8s.io/klog/v2"
|
||||
openapicommon "k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
@@ -120,6 +127,7 @@ type Config struct {
|
||||
EnableIndex bool
|
||||
EnableProfiling bool
|
||||
EnableDiscovery bool
|
||||
|
||||
// Requires generic profiling enabled
|
||||
EnableContentionProfiling bool
|
||||
EnableMetrics bool
|
||||
@@ -139,7 +147,7 @@ type Config struct {
|
||||
ExternalAddress string
|
||||
|
||||
// TracerProvider can provide a tracer, which records spans for distributed tracing.
|
||||
TracerProvider oteltrace.TracerProvider
|
||||
TracerProvider tracing.TracerProvider
|
||||
|
||||
//===========================================================================
|
||||
// Fields you probably don't care about changing
|
||||
@@ -257,6 +265,9 @@ type Config struct {
|
||||
|
||||
// StorageVersionManager holds the storage versions of the API resources installed by this server.
|
||||
StorageVersionManager storageversion.Manager
|
||||
|
||||
// AggregatedDiscoveryGroupManager serves /apis in an aggregated form.
|
||||
AggregatedDiscoveryGroupManager discoveryendpoint.ResourceManager
|
||||
}
|
||||
|
||||
type RecommendedConfig struct {
|
||||
@@ -317,12 +328,22 @@ type AuthorizationInfo struct {
|
||||
Authorizer authorizer.Authorizer
|
||||
}
|
||||
|
||||
func init() {
|
||||
utilruntime.Must(features.AddFeatureGates(utilfeature.DefaultMutableFeatureGate))
|
||||
}
|
||||
|
||||
// NewConfig returns a Config struct with the default values
|
||||
func NewConfig(codecs serializer.CodecFactory) *Config {
|
||||
defaultHealthChecks := []healthz.HealthChecker{healthz.PingHealthz, healthz.LogHealthz}
|
||||
var id string
|
||||
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerIdentity) {
|
||||
id = "kube-apiserver-" + uuid.New().String()
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
klog.Fatalf("error getting hostname for apiserver identity: %v", err)
|
||||
}
|
||||
|
||||
hash := sha256.Sum256([]byte(hostname))
|
||||
id = "kube-apiserver-" + strings.ToLower(base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(hash[:16]))
|
||||
}
|
||||
lifecycleSignals := newLifecycleSignals()
|
||||
|
||||
@@ -359,7 +380,7 @@ func NewConfig(codecs serializer.CodecFactory) *Config {
|
||||
// A request body might be encoded in json, and is converted to
|
||||
// proto when persisted in etcd, so we allow 2x as the largest request
|
||||
// body size to be accepted and decoded in a write request.
|
||||
// If this constant is changed, maxRequestSizeBytes in apiextensions-apiserver/third_party/forked/celopenapi/model/schemas.go
|
||||
// If this constant is changed, DefaultMaxRequestSizeBytes in k8s.io/apiserver/pkg/cel/limits.go
|
||||
// should be changed to reflect the new value, if the two haven't
|
||||
// been wired together already somehow.
|
||||
MaxRequestBodyBytes: int64(3 * 1024 * 1024),
|
||||
@@ -372,7 +393,7 @@ func NewConfig(codecs serializer.CodecFactory) *Config {
|
||||
|
||||
APIServerID: id,
|
||||
StorageVersionManager: storageversion.NewDefaultManager(),
|
||||
TracerProvider: oteltrace.NewNoopTracerProvider(),
|
||||
TracerProvider: tracing.NewNoopTracerProvider(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -662,6 +683,14 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
|
||||
muxAndDiscoveryCompleteSignals: map[string]<-chan struct{}{},
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.AggregatedDiscoveryEndpoint) {
|
||||
manager := c.AggregatedDiscoveryGroupManager
|
||||
if manager == nil {
|
||||
manager = discoveryendpoint.NewResourceManager()
|
||||
}
|
||||
s.AggregatedDiscoveryGroupManager = manager
|
||||
s.AggregatedLegacyDiscoveryGroupManager = discoveryendpoint.NewResourceManager()
|
||||
}
|
||||
for {
|
||||
if c.JSONPatchMaxCopyBytes <= 0 {
|
||||
break
|
||||
@@ -782,6 +811,11 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
|
||||
}
|
||||
s.AddHealthChecks(delegateCheck)
|
||||
}
|
||||
s.RegisterDestroyFunc(func() {
|
||||
if err := c.Config.TracerProvider.Shutdown(context.Background()); err != nil {
|
||||
klog.Errorf("failed to shut down tracer provider: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
s.listedPathProvider = routes.ListedPathProviders{s.listedPathProvider, delegationTarget}
|
||||
|
||||
@@ -808,7 +842,7 @@ func BuildHandlerChainWithStorageVersionPrecondition(apiHandler http.Handler, c
|
||||
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
||||
handler := filterlatency.TrackCompleted(apiHandler)
|
||||
handler = genericapifilters.WithAuthorization(handler, c.Authorization.Authorizer, c.Serializer)
|
||||
handler = filterlatency.TrackStarted(handler, "authorization")
|
||||
handler = filterlatency.TrackStarted(handler, c.TracerProvider, "authorization")
|
||||
|
||||
if c.FlowControl != nil {
|
||||
workEstimatorCfg := flowcontrolrequest.DefaultWorkEstimatorConfig()
|
||||
@@ -816,18 +850,18 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
||||
c.StorageObjectCountTracker.Get, c.FlowControl.GetInterestedWatchCount, workEstimatorCfg)
|
||||
handler = filterlatency.TrackCompleted(handler)
|
||||
handler = genericfilters.WithPriorityAndFairness(handler, c.LongRunningFunc, c.FlowControl, requestWorkEstimator)
|
||||
handler = filterlatency.TrackStarted(handler, "priorityandfairness")
|
||||
handler = filterlatency.TrackStarted(handler, c.TracerProvider, "priorityandfairness")
|
||||
} else {
|
||||
handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc)
|
||||
}
|
||||
|
||||
handler = filterlatency.TrackCompleted(handler)
|
||||
handler = genericapifilters.WithImpersonation(handler, c.Authorization.Authorizer, c.Serializer)
|
||||
handler = filterlatency.TrackStarted(handler, "impersonation")
|
||||
handler = filterlatency.TrackStarted(handler, c.TracerProvider, "impersonation")
|
||||
|
||||
handler = filterlatency.TrackCompleted(handler)
|
||||
handler = genericapifilters.WithAudit(handler, c.AuditBackend, c.AuditPolicyRuleEvaluator, c.LongRunningFunc)
|
||||
handler = filterlatency.TrackStarted(handler, "audit")
|
||||
handler = filterlatency.TrackStarted(handler, c.TracerProvider, "audit")
|
||||
|
||||
failedHandler := genericapifilters.Unauthorized(c.Serializer)
|
||||
failedHandler = genericapifilters.WithFailedAuthenticationAudit(failedHandler, c.AuditBackend, c.AuditPolicyRuleEvaluator)
|
||||
@@ -835,7 +869,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
||||
failedHandler = filterlatency.TrackCompleted(failedHandler)
|
||||
handler = filterlatency.TrackCompleted(handler)
|
||||
handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences)
|
||||
handler = filterlatency.TrackStarted(handler, "authentication")
|
||||
handler = filterlatency.TrackStarted(handler, c.TracerProvider, "authentication")
|
||||
|
||||
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true")
|
||||
|
||||
@@ -849,7 +883,6 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
||||
if c.SecureServing != nil && !c.SecureServing.DisableHTTP2 && c.GoawayChance > 0 {
|
||||
handler = genericfilters.WithProbabilisticGoaway(handler, c.GoawayChance)
|
||||
}
|
||||
handler = genericapifilters.WithAuditAnnotations(handler, c.AuditBackend, c.AuditPolicyRuleEvaluator)
|
||||
handler = genericapifilters.WithWarningRecorder(handler)
|
||||
handler = genericapifilters.WithCacheControl(handler)
|
||||
handler = genericfilters.WithHSTS(handler, c.HSTSDirectives)
|
||||
@@ -865,7 +898,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
||||
handler = genericapifilters.WithRequestReceivedTimestamp(handler)
|
||||
handler = genericapifilters.WithMuxAndDiscoveryComplete(handler, c.lifecycleSignals.MuxAndDiscoveryComplete.Signaled())
|
||||
handler = genericfilters.WithPanicRecovery(handler, c.RequestInfoResolver)
|
||||
handler = genericapifilters.WithAuditID(handler)
|
||||
handler = genericapifilters.WithAuditInit(handler)
|
||||
return handler
|
||||
}
|
||||
|
||||
@@ -881,18 +914,30 @@ func installAPI(s *GenericAPIServer, c *Config) {
|
||||
// so far, only logging related endpoints are considered valid to add for these debug flags.
|
||||
routes.DebugFlags{}.Install(s.Handler.NonGoRestfulMux, "v", routes.StringFlagPutHandler(logs.GlogSetter))
|
||||
}
|
||||
|
||||
if c.EnableMetrics {
|
||||
if c.EnableProfiling {
|
||||
routes.MetricsWithReset{}.Install(s.Handler.NonGoRestfulMux)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ComponentSLIs) {
|
||||
slis.SLIMetricsWithReset{}.Install(s.Handler.NonGoRestfulMux)
|
||||
}
|
||||
} else {
|
||||
routes.DefaultMetrics{}.Install(s.Handler.NonGoRestfulMux)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ComponentSLIs) {
|
||||
slis.SLIMetrics{}.Install(s.Handler.NonGoRestfulMux)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
routes.Version{Version: c.Version}.Install(s.Handler.GoRestfulContainer)
|
||||
|
||||
if c.EnableDiscovery {
|
||||
s.Handler.GoRestfulContainer.Add(s.DiscoveryGroupManager.WebService())
|
||||
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.AggregatedDiscoveryEndpoint) {
|
||||
wrapped := discoveryendpoint.WrapAggregatedDiscoveryToHandler(s.DiscoveryGroupManager, s.AggregatedDiscoveryGroupManager)
|
||||
s.Handler.GoRestfulContainer.Add(wrapped.GenerateWebService("/apis", metav1.APIGroupList{}))
|
||||
} else {
|
||||
s.Handler.GoRestfulContainer.Add(s.DiscoveryGroupManager.WebService())
|
||||
}
|
||||
}
|
||||
if c.FlowControl != nil && utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIPriorityAndFairness) {
|
||||
c.FlowControl.Install(s.Handler.NonGoRestfulMux)
|
||||
@@ -957,7 +1002,4 @@ func AuthorizeClientBearerToken(loopback *restclient.Config, authn *Authenticati
|
||||
|
||||
tokenAuthenticator := authenticatorfactory.NewFromTokens(tokens, authn.APIAudiences)
|
||||
authn.Authenticator = authenticatorunion.New(tokenAuthenticator, authn.Authenticator)
|
||||
|
||||
tokenAuthorizer := authorizerfactory.NewPrivilegedGroups(user.SystemPrivilegedGroup)
|
||||
authz.Authorizer = authorizerunion.New(tokenAuthorizer, authz.Authorizer)
|
||||
}
|
||||
|
||||
4
vendor/k8s.io/apiserver/pkg/server/deleted_kinds.go
generated
vendored
4
vendor/k8s.io/apiserver/pkg/server/deleted_kinds.go
generated
vendored
@@ -54,7 +54,9 @@ type ResourceExpirationEvaluator interface {
|
||||
}
|
||||
|
||||
func NewResourceExpirationEvaluator(currentVersion apimachineryversion.Info) (ResourceExpirationEvaluator, error) {
|
||||
ret := &resourceExpirationEvaluator{}
|
||||
ret := &resourceExpirationEvaluator{
|
||||
strictRemovedHandlingInAlpha: false,
|
||||
}
|
||||
if len(currentVersion.Major) > 0 {
|
||||
currentMajor64, err := strconv.ParseInt(currentVersion.Major, 10, 32)
|
||||
if err != nil {
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_cafile_content.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_cafile_content.go
generated
vendored
@@ -204,7 +204,7 @@ func (c *DynamicFileCAContent) watchCAFile(stopCh <-chan struct{}) error {
|
||||
func (c *DynamicFileCAContent) handleWatchEvent(e fsnotify.Event, w *fsnotify.Watcher) error {
|
||||
// This should be executed after restarting the watch (if applicable) to ensure no file event will be missing.
|
||||
defer c.queue.Add(workItemKey)
|
||||
if e.Op&(fsnotify.Remove|fsnotify.Rename) == 0 {
|
||||
if !e.Has(fsnotify.Remove) && !e.Has(fsnotify.Rename) {
|
||||
return nil
|
||||
}
|
||||
if err := w.Remove(c.filename); err != nil {
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_serving_content.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_serving_content.go
generated
vendored
@@ -185,7 +185,7 @@ func (c *DynamicCertKeyPairContent) watchCertKeyFile(stopCh <-chan struct{}) err
|
||||
func (c *DynamicCertKeyPairContent) handleWatchEvent(e fsnotify.Event, w *fsnotify.Watcher) error {
|
||||
// This should be executed after restarting the watch (if applicable) to ensure no file event will be missing.
|
||||
defer c.queue.Add(workItemKey)
|
||||
if e.Op&(fsnotify.Remove|fsnotify.Rename) == 0 {
|
||||
if !e.Has(fsnotify.Remove) && !e.Has(fsnotify.Rename) {
|
||||
return nil
|
||||
}
|
||||
if err := w.Remove(e.Name); err != nil {
|
||||
|
||||
16
vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector.go
generated
vendored
16
vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector.go
generated
vendored
@@ -29,19 +29,25 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
egressmetrics "k8s.io/apiserver/pkg/server/egressselector/metrics"
|
||||
compbasemetrics "k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/tracing"
|
||||
"k8s.io/klog/v2"
|
||||
utiltrace "k8s.io/utils/trace"
|
||||
client "sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client"
|
||||
)
|
||||
|
||||
var directDialer utilnet.DialFunc = http.DefaultTransport.(*http.Transport).DialContext
|
||||
|
||||
func init() {
|
||||
client.Metrics.RegisterMetrics(compbasemetrics.NewKubeRegistry().Registerer())
|
||||
}
|
||||
|
||||
// EgressSelector is the map of network context type to context dialer, for network egress.
|
||||
type EgressSelector struct {
|
||||
egressToDialer map[EgressType]utilnet.DialFunc
|
||||
@@ -216,6 +222,9 @@ func (u *udsGRPCConnector) connect(_ context.Context) (proxier, error) {
|
||||
// See https://github.com/kubernetes-sigs/apiserver-network-proxy/issues/357.
|
||||
tunnelCtx := context.TODO()
|
||||
tunnel, err := client.CreateSingleUseGrpcTunnel(tunnelCtx, udsName, dialOption,
|
||||
grpc.WithBlock(),
|
||||
grpc.WithReturnConnectionError(),
|
||||
grpc.WithTimeout(30*time.Second), // matches http.DefaultTransport dial timeout
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -239,9 +248,10 @@ func (d *dialerCreator) createDialer() utilnet.DialFunc {
|
||||
return directDialer
|
||||
}
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
trace := utiltrace.New(fmt.Sprintf("Proxy via %s protocol over %s", d.options.protocol, d.options.transport), utiltrace.Field{Key: "address", Value: addr})
|
||||
defer trace.LogIfLong(500 * time.Millisecond)
|
||||
ctx, span := tracing.Start(ctx, fmt.Sprintf("Proxy via %s protocol over %s", d.options.protocol, d.options.transport), attribute.String("address", addr))
|
||||
defer span.End(500 * time.Millisecond)
|
||||
start := egressmetrics.Metrics.Clock().Now()
|
||||
egressmetrics.Metrics.ObserveDialStart(d.options.protocol, d.options.transport)
|
||||
proxier, err := d.connector.connect(ctx)
|
||||
if err != nil {
|
||||
egressmetrics.Metrics.ObserveDialFailure(d.options.protocol, d.options.transport, egressmetrics.StageConnect)
|
||||
|
||||
21
vendor/k8s.io/apiserver/pkg/server/egressselector/metrics/metrics.go
generated
vendored
21
vendor/k8s.io/apiserver/pkg/server/egressselector/metrics/metrics.go
generated
vendored
@@ -53,12 +53,24 @@ var (
|
||||
// DialMetrics instruments dials to proxy server with prometheus metrics.
|
||||
type DialMetrics struct {
|
||||
clock clock.Clock
|
||||
starts *metrics.CounterVec
|
||||
latencies *metrics.HistogramVec
|
||||
failures *metrics.CounterVec
|
||||
}
|
||||
|
||||
// newDialMetrics create a new DialMetrics, configured with default metric names.
|
||||
func newDialMetrics() *DialMetrics {
|
||||
starts := metrics.NewCounterVec(
|
||||
&metrics.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "dial_start_total",
|
||||
Help: "Dial starts, labeled by the protocol (http-connect or grpc) and transport (tcp or uds).",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"protocol", "transport"},
|
||||
)
|
||||
|
||||
latencies := metrics.NewHistogramVec(
|
||||
&metrics.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
@@ -82,9 +94,10 @@ func newDialMetrics() *DialMetrics {
|
||||
[]string{"protocol", "transport", "stage"},
|
||||
)
|
||||
|
||||
legacyregistry.MustRegister(starts)
|
||||
legacyregistry.MustRegister(latencies)
|
||||
legacyregistry.MustRegister(failures)
|
||||
return &DialMetrics{latencies: latencies, failures: failures, clock: clock.RealClock{}}
|
||||
return &DialMetrics{starts: starts, latencies: latencies, failures: failures, clock: clock.RealClock{}}
|
||||
}
|
||||
|
||||
// Clock returns the clock.
|
||||
@@ -99,10 +112,16 @@ func (m *DialMetrics) SetClock(c clock.Clock) {
|
||||
|
||||
// Reset resets the metrics.
|
||||
func (m *DialMetrics) Reset() {
|
||||
m.starts.Reset()
|
||||
m.latencies.Reset()
|
||||
m.failures.Reset()
|
||||
}
|
||||
|
||||
// ObserveDialStart records the start of a dial attempt, labeled by protocol, transport.
|
||||
func (m *DialMetrics) ObserveDialStart(protocol, transport string) {
|
||||
m.starts.WithLabelValues(protocol, transport).Inc()
|
||||
}
|
||||
|
||||
// ObserveDialLatency records the latency of a dial, labeled by protocol, transport.
|
||||
func (m *DialMetrics) ObserveDialLatency(elapsed time.Duration, protocol, transport string) {
|
||||
m.latencies.WithLabelValues(protocol, transport).Observe(elapsed.Seconds())
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/server/filters/priority-and-fairness.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/filters/priority-and-fairness.go
generated
vendored
@@ -25,7 +25,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
flowcontrol "k8s.io/api/flowcontrol/v1beta2"
|
||||
flowcontrol "k8s.io/api/flowcontrol/v1beta3"
|
||||
apitypes "k8s.io/apimachinery/pkg/types"
|
||||
epmetrics "k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
|
||||
5
vendor/k8s.io/apiserver/pkg/server/filters/timeout.go
generated
vendored
5
vendor/k8s.io/apiserver/pkg/server/filters/timeout.go
generated
vendored
@@ -31,6 +31,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/endpoints/responsewriter"
|
||||
"k8s.io/apiserver/pkg/server/httplog"
|
||||
)
|
||||
|
||||
// WithTimeoutForNonLongRunningRequests times out non-long-running requests after the time given by timeout.
|
||||
@@ -141,7 +142,9 @@ func (t *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
utilruntime.HandleError(err)
|
||||
}()
|
||||
}()
|
||||
|
||||
httplog.SetStacktracePredicate(r.Context(), func(status int) bool {
|
||||
return false
|
||||
})
|
||||
defer postTimeoutFn()
|
||||
tw.timeout(err)
|
||||
}
|
||||
|
||||
5
vendor/k8s.io/apiserver/pkg/server/filters/wrap.go
generated
vendored
5
vendor/k8s.io/apiserver/pkg/server/filters/wrap.go
generated
vendored
@@ -21,6 +21,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/server/httplog"
|
||||
@@ -50,11 +51,11 @@ func WithPanicRecovery(handler http.Handler, resolver request.RequestInfoResolve
|
||||
// This call can have different handlers, but the default chain rate limits. Call it after the metrics are updated
|
||||
// in case the rate limit delays it. If you outrun the rate for this one timed out requests, something has gone
|
||||
// seriously wrong with your server, but generally having a logging signal for timeouts is useful.
|
||||
runtime.HandleError(fmt.Errorf("timeout or abort while handling: method=%v URI=%q audit-ID=%q", req.Method, req.RequestURI, request.GetAuditIDTruncated(req.Context())))
|
||||
runtime.HandleError(fmt.Errorf("timeout or abort while handling: method=%v URI=%q audit-ID=%q", req.Method, req.RequestURI, audit.GetAuditIDTruncated(req.Context())))
|
||||
return
|
||||
}
|
||||
http.Error(w, "This request caused apiserver to panic. Look in the logs for details.", http.StatusInternalServerError)
|
||||
klog.ErrorS(nil, "apiserver panic'd", "method", req.Method, "URI", req.RequestURI, "audit-ID", request.GetAuditIDTruncated(req.Context()))
|
||||
klog.ErrorS(nil, "apiserver panic'd", "method", req.Method, "URI", req.RequestURI, "audit-ID", audit.GetAuditIDTruncated(req.Context()))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
118
vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
generated
vendored
118
vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
generated
vendored
@@ -26,6 +26,7 @@ import (
|
||||
|
||||
systemd "github.com/coreos/go-systemd/v22/daemon"
|
||||
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -39,6 +40,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
genericapi "k8s.io/apiserver/pkg/endpoints"
|
||||
"k8s.io/apiserver/pkg/endpoints/discovery"
|
||||
discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
@@ -137,9 +139,15 @@ type GenericAPIServer struct {
|
||||
// listedPathProvider is a lister which provides the set of paths to show at /
|
||||
listedPathProvider routes.ListedPathProvider
|
||||
|
||||
// DiscoveryGroupManager serves /apis
|
||||
// DiscoveryGroupManager serves /apis in an unaggregated form.
|
||||
DiscoveryGroupManager discovery.GroupManager
|
||||
|
||||
// AggregatedDiscoveryGroupManager serves /apis in an aggregated form.
|
||||
AggregatedDiscoveryGroupManager discoveryendpoint.ResourceManager
|
||||
|
||||
// AggregatedLegacyDiscoveryGroupManager serves /api in an aggregated form.
|
||||
AggregatedLegacyDiscoveryGroupManager discoveryendpoint.ResourceManager
|
||||
|
||||
// Enable swagger and/or OpenAPI if these configs are non-nil.
|
||||
openAPIConfig *openapicommon.Config
|
||||
|
||||
@@ -418,44 +426,40 @@ func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
|
||||
// or the secure port cannot be listened on initially.
|
||||
// This is the diagram of what channels/signals are dependent on each other:
|
||||
//
|
||||
// stopCh
|
||||
// |
|
||||
// ---------------------------------------------------------
|
||||
// | |
|
||||
// ShutdownInitiated (shutdownInitiatedCh) |
|
||||
// | |
|
||||
//
|
||||
// (ShutdownDelayDuration) (PreShutdownHooks)
|
||||
//
|
||||
// | |
|
||||
// AfterShutdownDelayDuration (delayedStopCh) PreShutdownHooksStopped (preShutdownHooksHasStoppedCh)
|
||||
// | |
|
||||
// |-------------------------------------------------------|
|
||||
// |
|
||||
// |
|
||||
// NotAcceptingNewRequest (notAcceptingNewRequestCh)
|
||||
// |
|
||||
// |
|
||||
// |---------------------------------------------------------|
|
||||
// | | | |
|
||||
// [without [with | |
|
||||
//
|
||||
// ShutdownSendRetryAfter] ShutdownSendRetryAfter] | |
|
||||
//
|
||||
// | | | |
|
||||
// | ---------------| |
|
||||
// | | |
|
||||
// | (HandlerChainWaitGroup::Wait) |
|
||||
// | | |
|
||||
// | InFlightRequestsDrained (drainedCh) |
|
||||
// | | |
|
||||
// ----------------------------------------|-----------------|
|
||||
// | |
|
||||
// stopHttpServerCh (AuditBackend::Shutdown())
|
||||
// |
|
||||
// listenerStoppedCh
|
||||
// |
|
||||
// HTTPServerStoppedListening (httpServerStoppedListeningCh)
|
||||
// | stopCh
|
||||
// | |
|
||||
// | ---------------------------------------------------------
|
||||
// | | |
|
||||
// | ShutdownInitiated (shutdownInitiatedCh) |
|
||||
// | | |
|
||||
// | (ShutdownDelayDuration) (PreShutdownHooks)
|
||||
// | | |
|
||||
// | AfterShutdownDelayDuration (delayedStopCh) PreShutdownHooksStopped (preShutdownHooksHasStoppedCh)
|
||||
// | | |
|
||||
// | |-------------------------------------------------------|
|
||||
// | |
|
||||
// | |
|
||||
// | NotAcceptingNewRequest (notAcceptingNewRequestCh)
|
||||
// | |
|
||||
// | |
|
||||
// | |---------------------------------------------------------|
|
||||
// | | | | |
|
||||
// | [without [with | |
|
||||
// | ShutdownSendRetryAfter] ShutdownSendRetryAfter] | |
|
||||
// | | | | |
|
||||
// | | ---------------| |
|
||||
// | | | |
|
||||
// | | (HandlerChainWaitGroup::Wait) |
|
||||
// | | | |
|
||||
// | | InFlightRequestsDrained (drainedCh) |
|
||||
// | | | |
|
||||
// | ----------------------------------------|-----------------|
|
||||
// | | |
|
||||
// | stopHttpServerCh (AuditBackend::Shutdown())
|
||||
// | |
|
||||
// | listenerStoppedCh
|
||||
// | |
|
||||
// | HTTPServerStoppedListening (httpServerStoppedListeningCh)
|
||||
func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
|
||||
delayedStopCh := s.lifecycleSignals.AfterShutdownDelayDuration
|
||||
shutdownInitiatedCh := s.lifecycleSignals.ShutdownInitiated
|
||||
@@ -666,7 +670,7 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
|
||||
}
|
||||
apiGroupVersion.OpenAPIModels = openAPIModels
|
||||
|
||||
if openAPIModels != nil && utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
||||
if openAPIModels != nil {
|
||||
typeConverter, err := fieldmanager.NewTypeConverter(openAPIModels, false)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -676,11 +680,35 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
|
||||
|
||||
apiGroupVersion.MaxRequestBodyBytes = s.maxRequestBodyBytes
|
||||
|
||||
r, err := apiGroupVersion.InstallREST(s.Handler.GoRestfulContainer)
|
||||
discoveryAPIResources, r, err := apiGroupVersion.InstallREST(s.Handler.GoRestfulContainer)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to setup API %v: %v", apiGroupInfo, err)
|
||||
}
|
||||
resourceInfos = append(resourceInfos, r...)
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.AggregatedDiscoveryEndpoint) {
|
||||
// Aggregated discovery only aggregates resources under /apis
|
||||
if apiPrefix == APIGroupPrefix {
|
||||
s.AggregatedDiscoveryGroupManager.AddGroupVersion(
|
||||
groupVersion.Group,
|
||||
apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Version: groupVersion.Version,
|
||||
Resources: discoveryAPIResources,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
// There is only one group version for legacy resources, priority can be defaulted to 0.
|
||||
s.AggregatedLegacyDiscoveryGroupManager.AddGroupVersion(
|
||||
groupVersion.Group,
|
||||
apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Version: groupVersion.Version,
|
||||
Resources: discoveryAPIResources,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
s.RegisterDestroyFunc(apiGroupInfo.destroyStorage)
|
||||
@@ -715,7 +743,13 @@ func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo
|
||||
|
||||
// Install the version handler.
|
||||
// Add a handler at /<apiPrefix> to enumerate the supported api versions.
|
||||
s.Handler.GoRestfulContainer.Add(discovery.NewLegacyRootAPIHandler(s.discoveryAddresses, s.Serializer, apiPrefix).WebService())
|
||||
legacyRootAPIHandler := discovery.NewLegacyRootAPIHandler(s.discoveryAddresses, s.Serializer, apiPrefix)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.AggregatedDiscoveryEndpoint) {
|
||||
wrapped := discoveryendpoint.WrapAggregatedDiscoveryToHandler(legacyRootAPIHandler, s.AggregatedLegacyDiscoveryGroupManager)
|
||||
s.Handler.GoRestfulContainer.Add(wrapped.GenerateWebService("/api", metav1.APIVersions{}))
|
||||
} else {
|
||||
s.Handler.GoRestfulContainer.Add(legacyRootAPIHandler.WebService())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
6
vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go
generated
vendored
6
vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go
generated
vendored
@@ -18,6 +18,7 @@ package healthz
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
@@ -30,6 +31,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
"k8s.io/apiserver/pkg/server/httplog"
|
||||
"k8s.io/component-base/metrics/prometheus/slis"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
@@ -237,6 +239,7 @@ func handleRootHealth(name string, firstTimeHealthy func(), checks ...HealthChec
|
||||
continue
|
||||
}
|
||||
if err := check.Check(r); err != nil {
|
||||
slis.ObserveHealthcheck(context.Background(), check.Name(), name, slis.Error)
|
||||
// don't include the error since this endpoint is public. If someone wants more detail
|
||||
// they should have explicit permission to the detailed checks.
|
||||
fmt.Fprintf(&individualCheckOutput, "[-]%s failed: reason withheld\n", check.Name())
|
||||
@@ -244,12 +247,13 @@ func handleRootHealth(name string, firstTimeHealthy func(), checks ...HealthChec
|
||||
fmt.Fprintf(&failedVerboseLogOutput, "[-]%s failed: %v\n", check.Name(), err)
|
||||
failedChecks = append(failedChecks, check.Name())
|
||||
} else {
|
||||
slis.ObserveHealthcheck(context.Background(), check.Name(), name, slis.Success)
|
||||
fmt.Fprintf(&individualCheckOutput, "[+]%s ok\n", check.Name())
|
||||
}
|
||||
}
|
||||
if excluded.Len() > 0 {
|
||||
fmt.Fprintf(&individualCheckOutput, "warn: some health checks cannot be excluded: no matches for %s\n", formatQuoted(excluded.List()...))
|
||||
klog.Warningf("cannot exclude some health checks, no health checks are installed matching %s",
|
||||
klog.V(6).Infof("cannot exclude some health checks, no health checks are installed matching %s",
|
||||
formatQuoted(excluded.List()...))
|
||||
}
|
||||
// always be verbose on failure
|
||||
|
||||
4
vendor/k8s.io/apiserver/pkg/server/hooks.go
generated
vendored
4
vendor/k8s.io/apiserver/pkg/server/hooks.go
generated
vendored
@@ -233,13 +233,13 @@ func (h postStartHookHealthz) Name() string {
|
||||
return h.name
|
||||
}
|
||||
|
||||
var hookNotFinished = errors.New("not finished")
|
||||
var errHookNotFinished = errors.New("not finished")
|
||||
|
||||
func (h postStartHookHealthz) Check(req *http.Request) error {
|
||||
select {
|
||||
case <-h.done:
|
||||
return nil
|
||||
default:
|
||||
return hookNotFinished
|
||||
return errHookNotFinished
|
||||
}
|
||||
}
|
||||
|
||||
20
vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go
generated
vendored
20
vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go
generated
vendored
@@ -27,6 +27,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/endpoints/responsewriter"
|
||||
@@ -59,7 +60,7 @@ type respLogger struct {
|
||||
statusRecorded bool
|
||||
status int
|
||||
statusStack string
|
||||
// mutex is used when accessing addedInfo and addedKeyValuePairs.
|
||||
// mutex is used when accessing addedInfo, addedKeyValuePairs and logStacktracePred.
|
||||
// They can be modified by other goroutine when logging happens (in case of request timeout)
|
||||
mutex sync.Mutex
|
||||
addedInfo strings.Builder
|
||||
@@ -181,6 +182,8 @@ func Unlogged(req *http.Request, w http.ResponseWriter) http.ResponseWriter {
|
||||
// StacktraceWhen sets the stacktrace logging predicate, which decides when to log a stacktrace.
|
||||
// There's a default, so you don't need to call this unless you don't like the default.
|
||||
func (rl *respLogger) StacktraceWhen(pred StacktracePred) *respLogger {
|
||||
rl.mutex.Lock()
|
||||
defer rl.mutex.Unlock()
|
||||
rl.logStacktracePred = pred
|
||||
return rl
|
||||
}
|
||||
@@ -239,17 +242,8 @@ func SetStacktracePredicate(ctx context.Context, pred StacktracePred) {
|
||||
// Log is intended to be called once at the end of your request handler, via defer
|
||||
func (rl *respLogger) Log() {
|
||||
latency := time.Since(rl.startTime)
|
||||
auditID := request.GetAuditIDTruncated(rl.req.Context())
|
||||
|
||||
verb := rl.req.Method
|
||||
if requestInfo, ok := request.RequestInfoFrom(rl.req.Context()); ok {
|
||||
// If we can find a requestInfo, we can get a scope, and then
|
||||
// we can convert GETs to LISTs when needed.
|
||||
scope := metrics.CleanScope(requestInfo)
|
||||
verb = metrics.CanonicalVerb(strings.ToUpper(verb), scope)
|
||||
}
|
||||
// mark APPLY requests and WATCH requests correctly.
|
||||
verb = metrics.CleanVerb(verb, rl.req)
|
||||
auditID := audit.GetAuditIDTruncated(rl.req.Context())
|
||||
verb := metrics.NormalizedVerb(rl.req)
|
||||
|
||||
keysAndValues := []interface{}{
|
||||
"verb", verb,
|
||||
@@ -316,6 +310,8 @@ func (rl *respLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
}
|
||||
|
||||
func (rl *respLogger) recordStatus(status int) {
|
||||
rl.mutex.Lock()
|
||||
defer rl.mutex.Unlock()
|
||||
rl.status = status
|
||||
rl.statusRecorded = true
|
||||
if rl.logStacktracePred(status) {
|
||||
|
||||
10
vendor/k8s.io/apiserver/pkg/server/options/admission.go
generated
vendored
10
vendor/k8s.io/apiserver/pkg/server/options/admission.go
generated
vendored
@@ -29,12 +29,14 @@ import (
|
||||
"k8s.io/apiserver/pkg/admission/initializer"
|
||||
admissionmetrics "k8s.io/apiserver/pkg/admission/metrics"
|
||||
"k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
|
||||
"k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy"
|
||||
mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating"
|
||||
validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating"
|
||||
apiserverapi "k8s.io/apiserver/pkg/apis/apiserver"
|
||||
apiserverapiv1 "k8s.io/apiserver/pkg/apis/apiserver/v1"
|
||||
apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
@@ -85,7 +87,7 @@ func NewAdmissionOptions() *AdmissionOptions {
|
||||
// admission plugins. The apiserver always runs the validating ones
|
||||
// after all the mutating ones, so their relative order in this list
|
||||
// doesn't matter.
|
||||
RecommendedPluginOrder: []string{lifecycle.PluginName, mutatingwebhook.PluginName, validatingwebhook.PluginName},
|
||||
RecommendedPluginOrder: []string{lifecycle.PluginName, mutatingwebhook.PluginName, validatingadmissionpolicy.PluginName, validatingwebhook.PluginName},
|
||||
DefaultOffPlugins: sets.NewString(),
|
||||
}
|
||||
server.RegisterAllAdmissionPlugins(options.Plugins)
|
||||
@@ -145,7 +147,11 @@ func (a *AdmissionOptions) ApplyTo(
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genericInitializer := initializer.New(clientset, informers, c.Authorization.Authorizer, features, c.DrainedNotify())
|
||||
dynamicClient, err := dynamic.NewForConfig(kubeAPIServerClientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genericInitializer := initializer.New(clientset, dynamicClient, informers, c.Authorization.Authorizer, features, c.DrainedNotify())
|
||||
initializersChain := admission.PluginInitializers{genericInitializer}
|
||||
initializersChain = append(initializersChain, pluginInitializers...)
|
||||
|
||||
|
||||
5
vendor/k8s.io/apiserver/pkg/server/options/authentication.go
generated
vendored
5
vendor/k8s.io/apiserver/pkg/server/options/authentication.go
generated
vendored
@@ -202,6 +202,9 @@ type DelegatingAuthenticationOptions struct {
|
||||
|
||||
// CustomRoundTripperFn allows for specifying a middleware function for custom HTTP behaviour for the authentication webhook client.
|
||||
CustomRoundTripperFn transport.WrapperFunc
|
||||
|
||||
// DisableAnonymous gives user an option to disable Anonymous authentication.
|
||||
DisableAnonymous bool
|
||||
}
|
||||
|
||||
func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions {
|
||||
@@ -283,7 +286,7 @@ func (s *DelegatingAuthenticationOptions) ApplyTo(authenticationInfo *server.Aut
|
||||
}
|
||||
|
||||
cfg := authenticatorfactory.DelegatingAuthenticatorConfig{
|
||||
Anonymous: true,
|
||||
Anonymous: !s.DisableAnonymous,
|
||||
CacheTTL: s.CacheTTL,
|
||||
WebhookRetryBackoff: s.WebhookRetryBackoff,
|
||||
TokenAccessReviewTimeout: s.TokenRequestTimeout,
|
||||
|
||||
43
vendor/k8s.io/apiserver/pkg/server/options/deprecated_insecure_serving.go
generated
vendored
43
vendor/k8s.io/apiserver/pkg/server/options/deprecated_insecure_serving.go
generated
vendored
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// DeprecatedInsecureServingOptions are for creating an unauthenticated, unauthorized, insecure port.
|
||||
@@ -125,45 +124,3 @@ func (s *DeprecatedInsecureServingOptions) ApplyTo(c **server.DeprecatedInsecure
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithLoopback adds loopback functionality to the serving options.
|
||||
func (o *DeprecatedInsecureServingOptions) WithLoopback() *DeprecatedInsecureServingOptionsWithLoopback {
|
||||
return &DeprecatedInsecureServingOptionsWithLoopback{o}
|
||||
}
|
||||
|
||||
// DeprecatedInsecureServingOptionsWithLoopback adds loopback functionality to the DeprecatedInsecureServingOptions.
|
||||
// DEPRECATED: all insecure serving options will be removed in a future version, however note that
|
||||
// there are security concerns over how health checks can work here - see e.g. #43784
|
||||
type DeprecatedInsecureServingOptionsWithLoopback struct {
|
||||
*DeprecatedInsecureServingOptions
|
||||
}
|
||||
|
||||
// ApplyTo fills up serving information in the server configuration.
|
||||
func (s *DeprecatedInsecureServingOptionsWithLoopback) ApplyTo(insecureServingInfo **server.DeprecatedInsecureServingInfo, loopbackClientConfig **rest.Config) error {
|
||||
if s == nil || s.DeprecatedInsecureServingOptions == nil || insecureServingInfo == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := s.DeprecatedInsecureServingOptions.ApplyTo(insecureServingInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if *insecureServingInfo == nil || loopbackClientConfig == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
secureLoopbackClientConfig, err := (*insecureServingInfo).NewLoopbackClientConfig()
|
||||
switch {
|
||||
// if we failed and there's no fallback loopback client config, we need to fail
|
||||
case err != nil && *loopbackClientConfig == nil:
|
||||
return err
|
||||
|
||||
// if we failed, but we already have a fallback loopback client config (usually insecure), allow it
|
||||
case err != nil && *loopbackClientConfig != nil:
|
||||
|
||||
default:
|
||||
*loopbackClientConfig = secureLoopbackClientConfig
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
595
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go
generated
vendored
595
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go
generated
vendored
@@ -20,20 +20,23 @@ import (
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
apiserverconfig "k8s.io/apiserver/pkg/apis/config"
|
||||
apiserverconfigv1 "k8s.io/apiserver/pkg/apis/config/v1"
|
||||
"k8s.io/apiserver/pkg/apis/config/validation"
|
||||
@@ -58,6 +61,7 @@ const (
|
||||
kmsPluginHealthzPositiveTTL = 20 * time.Second
|
||||
kmsAPIVersionV1 = "v1"
|
||||
kmsAPIVersionV2 = "v2"
|
||||
kmsReloadHealthCheckName = "kms-providers"
|
||||
)
|
||||
|
||||
type kmsPluginHealthzResponse struct {
|
||||
@@ -66,122 +70,158 @@ type kmsPluginHealthzResponse struct {
|
||||
}
|
||||
|
||||
type kmsPluginProbe struct {
|
||||
name string
|
||||
ttl time.Duration
|
||||
envelope.Service
|
||||
name string
|
||||
ttl time.Duration
|
||||
service envelope.Service
|
||||
lastResponse *kmsPluginHealthzResponse
|
||||
l *sync.Mutex
|
||||
}
|
||||
|
||||
type kmsv2PluginProbe struct {
|
||||
name string
|
||||
ttl time.Duration
|
||||
envelopekmsv2.Service
|
||||
name string
|
||||
ttl time.Duration
|
||||
service envelopekmsv2.Service
|
||||
lastResponse *kmsPluginHealthzResponse
|
||||
l *sync.Mutex
|
||||
}
|
||||
|
||||
type kmsHealthChecker []healthz.HealthChecker
|
||||
|
||||
func (k kmsHealthChecker) Name() string {
|
||||
return kmsReloadHealthCheckName
|
||||
}
|
||||
|
||||
func (k kmsHealthChecker) Check(req *http.Request) error {
|
||||
var errs []error
|
||||
|
||||
for i := range k {
|
||||
checker := k[i]
|
||||
if err := checker.Check(req); err != nil {
|
||||
errs = append(errs, fmt.Errorf("%s: %w", checker.Name(), err))
|
||||
}
|
||||
}
|
||||
|
||||
return utilerrors.Reduce(utilerrors.NewAggregate(errs))
|
||||
}
|
||||
|
||||
func (h *kmsPluginProbe) toHealthzCheck(idx int) healthz.HealthChecker {
|
||||
return healthz.NamedCheck(fmt.Sprintf("kms-provider-%d", idx), func(r *http.Request) error {
|
||||
return h.Check()
|
||||
return h.check()
|
||||
})
|
||||
}
|
||||
|
||||
func (p *kmsv2PluginProbe) toHealthzCheck(idx int) healthz.HealthChecker {
|
||||
func (h *kmsv2PluginProbe) toHealthzCheck(idx int) healthz.HealthChecker {
|
||||
return healthz.NamedCheck(fmt.Sprintf("kms-provider-%d", idx), func(r *http.Request) error {
|
||||
return p.Check()
|
||||
return h.check(r.Context())
|
||||
})
|
||||
}
|
||||
|
||||
// GetKMSPluginHealthzCheckers extracts KMSPluginProbes from the EncryptionConfig.
|
||||
func GetKMSPluginHealthzCheckers(filepath string) ([]healthz.HealthChecker, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening encryption provider configuration file %q: %v", filepath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
// EncryptionConfiguration represents the parsed and normalized encryption configuration for the apiserver.
|
||||
type EncryptionConfiguration struct {
|
||||
// Transformers is a list of value.Transformer that will be used to encrypt and decrypt data.
|
||||
Transformers map[schema.GroupResource]value.Transformer
|
||||
|
||||
var result []healthz.HealthChecker
|
||||
probes, err := getKMSPluginProbes(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, p := range probes {
|
||||
probe := p
|
||||
switch t := probe.(type) {
|
||||
case *kmsPluginProbe:
|
||||
result = append(result, t.toHealthzCheck(i))
|
||||
case *kmsv2PluginProbe:
|
||||
result = append(result, t.toHealthzCheck(i))
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported KMS plugin type: %T", t)
|
||||
}
|
||||
}
|
||||
// HealthChecks is a list of healthz.HealthChecker that will be used to check the health of the encryption providers.
|
||||
HealthChecks []healthz.HealthChecker
|
||||
|
||||
return result, nil
|
||||
// EncryptionFileContentHash is the hash of the encryption config file.
|
||||
EncryptionFileContentHash string
|
||||
|
||||
// KMSCloseGracePeriod is the duration we will wait before closing old transformers.
|
||||
// We wait for any in-flight requests to finish by using the duration which is longer than their timeout.
|
||||
KMSCloseGracePeriod time.Duration
|
||||
}
|
||||
|
||||
func getKMSPluginProbes(reader io.Reader) ([]interface{}, error) {
|
||||
var result []interface{}
|
||||
|
||||
configFileContents, err := ioutil.ReadAll(reader)
|
||||
// LoadEncryptionConfig parses and validates the encryption config specified by filepath.
|
||||
// It may launch multiple go routines whose lifecycle is controlled by stopCh.
|
||||
// If reload is true, or KMS v2 plugins are used with no KMS v1 plugins, the returned slice of health checkers will always be of length 1.
|
||||
func LoadEncryptionConfig(filepath string, reload bool, stopCh <-chan struct{}) (*EncryptionConfiguration, error) {
|
||||
config, contentHash, err := loadConfig(filepath, reload)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read content of encryption provider configuration: %v", err)
|
||||
return nil, fmt.Errorf("error while parsing file: %w", err)
|
||||
}
|
||||
|
||||
config, err := loadConfig(configFileContents)
|
||||
transformers, kmsHealthChecks, kmsUsed, err := getTransformerOverridesAndKMSPluginHealthzCheckers(config, stopCh)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing encryption provider configuration: %v", err)
|
||||
return nil, fmt.Errorf("error while building transformers: %w", err)
|
||||
}
|
||||
|
||||
for _, r := range config.Resources {
|
||||
for _, p := range r.Providers {
|
||||
if p.KMS != nil {
|
||||
switch p.KMS.APIVersion {
|
||||
case kmsAPIVersionV1:
|
||||
s, err := envelope.NewGRPCService(p.KMS.Endpoint, p.KMS.Timeout.Duration)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not configure KMSv1-Plugin's probe %q, error: %v", p.KMS.Name, err)
|
||||
}
|
||||
|
||||
result = append(result, &kmsPluginProbe{
|
||||
name: p.KMS.Name,
|
||||
ttl: kmsPluginHealthzNegativeTTL,
|
||||
Service: s,
|
||||
l: &sync.Mutex{},
|
||||
lastResponse: &kmsPluginHealthzResponse{},
|
||||
})
|
||||
|
||||
case kmsAPIVersionV2:
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.KMSv2) {
|
||||
return nil, fmt.Errorf("could not configure KMSv2-Plugin's probe %q, KMSv2 feature is not enabled", p.KMS.Name)
|
||||
}
|
||||
|
||||
s, err := envelopekmsv2.NewGRPCService(p.KMS.Endpoint, p.KMS.Timeout.Duration)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not configure KMSv2-Plugin's probe %q, error: %v", p.KMS.Name, err)
|
||||
}
|
||||
|
||||
result = append(result, &kmsv2PluginProbe{
|
||||
name: p.KMS.Name,
|
||||
ttl: kmsPluginHealthzNegativeTTL,
|
||||
Service: s,
|
||||
l: &sync.Mutex{},
|
||||
lastResponse: &kmsPluginHealthzResponse{},
|
||||
})
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("could not configure KMS Plugin's probe %q, unsupported KMS API version %q", p.KMS.Name, p.KMS.APIVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
if reload || (kmsUsed.v2Used && !kmsUsed.v1Used) {
|
||||
kmsHealthChecks = []healthz.HealthChecker{kmsHealthChecker(kmsHealthChecks)}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
// KMSTimeout is the duration we will wait before closing old transformers.
|
||||
// The way we calculate is as follows:
|
||||
// 1. Sum all timeouts across all KMS plugins. (check kmsPrefixTransformer for differences between v1 and v2)
|
||||
// 2. Multiply that by 2 (to allow for some buffer)
|
||||
// The reason we sum all timeout is because kmsHealthChecker() will run all health checks serially
|
||||
return &EncryptionConfiguration{
|
||||
Transformers: transformers,
|
||||
HealthChecks: kmsHealthChecks,
|
||||
EncryptionFileContentHash: contentHash,
|
||||
KMSCloseGracePeriod: 2 * kmsUsed.kmsTimeoutSum,
|
||||
}, err
|
||||
}
|
||||
|
||||
// Check encrypts and decrypts test data against KMS-Plugin's gRPC endpoint.
|
||||
func (h *kmsPluginProbe) Check() error {
|
||||
func getTransformerOverridesAndKMSPluginHealthzCheckers(config *apiserverconfig.EncryptionConfiguration, stopCh <-chan struct{}) (map[schema.GroupResource]value.Transformer, []healthz.HealthChecker, *kmsState, error) {
|
||||
var kmsHealthChecks []healthz.HealthChecker
|
||||
transformers, probes, kmsUsed, err := getTransformerOverridesAndKMSPluginProbes(config, stopCh)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
for i := range probes {
|
||||
probe := probes[i]
|
||||
kmsHealthChecks = append(kmsHealthChecks, probe.toHealthzCheck(i))
|
||||
}
|
||||
|
||||
return transformers, kmsHealthChecks, kmsUsed, nil
|
||||
}
|
||||
|
||||
type healthChecker interface {
|
||||
toHealthzCheck(idx int) healthz.HealthChecker
|
||||
}
|
||||
|
||||
func getTransformerOverridesAndKMSPluginProbes(config *apiserverconfig.EncryptionConfiguration, stopCh <-chan struct{}) (map[schema.GroupResource]value.Transformer, []healthChecker, *kmsState, error) {
|
||||
resourceToPrefixTransformer := map[schema.GroupResource][]value.PrefixTransformer{}
|
||||
var probes []healthChecker
|
||||
var kmsUsed kmsState
|
||||
|
||||
// For each entry in the configuration
|
||||
for _, resourceConfig := range config.Resources {
|
||||
resourceConfig := resourceConfig
|
||||
|
||||
transformers, p, used, err := prefixTransformersAndProbes(resourceConfig, stopCh)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
kmsUsed.v1Used = kmsUsed.v1Used || used.v1Used
|
||||
kmsUsed.v2Used = kmsUsed.v2Used || used.v2Used
|
||||
|
||||
kmsUsed.kmsTimeoutSum += used.kmsTimeoutSum
|
||||
|
||||
// For each resource, create a list of providers to use
|
||||
for _, resource := range resourceConfig.Resources {
|
||||
resource := resource
|
||||
gr := schema.ParseGroupResource(resource)
|
||||
resourceToPrefixTransformer[gr] = append(
|
||||
resourceToPrefixTransformer[gr], transformers...)
|
||||
}
|
||||
|
||||
probes = append(probes, p...)
|
||||
}
|
||||
|
||||
transformers := make(map[schema.GroupResource]value.Transformer, len(resourceToPrefixTransformer))
|
||||
for gr, transList := range resourceToPrefixTransformer {
|
||||
gr := gr
|
||||
transList := transList
|
||||
transformers[gr] = value.NewPrefixTransformers(fmt.Errorf("no matching prefix found"), transList...)
|
||||
}
|
||||
|
||||
return transformers, probes, &kmsUsed, nil
|
||||
}
|
||||
|
||||
// check encrypts and decrypts test data against KMS-Plugin's gRPC endpoint.
|
||||
func (h *kmsPluginProbe) check() error {
|
||||
h.l.Lock()
|
||||
defer h.l.Unlock()
|
||||
|
||||
@@ -189,17 +229,17 @@ func (h *kmsPluginProbe) Check() error {
|
||||
return h.lastResponse.err
|
||||
}
|
||||
|
||||
p, err := h.Service.Encrypt([]byte("ping"))
|
||||
p, err := h.service.Encrypt([]byte("ping"))
|
||||
if err != nil {
|
||||
h.lastResponse = &kmsPluginHealthzResponse{err: err, received: time.Now()}
|
||||
h.ttl = kmsPluginHealthzNegativeTTL
|
||||
return fmt.Errorf("failed to perform encrypt section of the healthz check for KMS Provider %s, error: %v", h.name, err)
|
||||
return fmt.Errorf("failed to perform encrypt section of the healthz check for KMS Provider %s, error: %w", h.name, err)
|
||||
}
|
||||
|
||||
if _, err := h.Service.Decrypt(p); err != nil {
|
||||
if _, err := h.service.Decrypt(p); err != nil {
|
||||
h.lastResponse = &kmsPluginHealthzResponse{err: err, received: time.Now()}
|
||||
h.ttl = kmsPluginHealthzNegativeTTL
|
||||
return fmt.Errorf("failed to perform decrypt section of the healthz check for KMS Provider %s, error: %v", h.name, err)
|
||||
return fmt.Errorf("failed to perform decrypt section of the healthz check for KMS Provider %s, error: %w", h.name, err)
|
||||
}
|
||||
|
||||
h.lastResponse = &kmsPluginHealthzResponse{err: nil, received: time.Now()}
|
||||
@@ -207,8 +247,8 @@ func (h *kmsPluginProbe) Check() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check gets the healthz status of the KMSv2-Plugin using the Status() method.
|
||||
func (h *kmsv2PluginProbe) Check() error {
|
||||
// check gets the healthz status of the KMSv2-Plugin using the Status() method.
|
||||
func (h *kmsv2PluginProbe) check(ctx context.Context) error {
|
||||
h.l.Lock()
|
||||
defer h.l.Unlock()
|
||||
|
||||
@@ -216,12 +256,11 @@ func (h *kmsv2PluginProbe) Check() error {
|
||||
return h.lastResponse.err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
p, err := h.Service.Status(ctx)
|
||||
p, err := h.service.Status(ctx)
|
||||
if err != nil {
|
||||
h.lastResponse = &kmsPluginHealthzResponse{err: err, received: time.Now()}
|
||||
h.ttl = kmsPluginHealthzNegativeTTL
|
||||
return fmt.Errorf("failed to perform status section of the healthz check for KMS Provider %s, error: %v", h.name, err)
|
||||
return fmt.Errorf("failed to perform status section of the healthz check for KMS Provider %s, error: %w", h.name, err)
|
||||
}
|
||||
|
||||
if err := isKMSv2ProviderHealthy(h.name, p); err != nil {
|
||||
@@ -249,139 +288,97 @@ func isKMSv2ProviderHealthy(name string, response *envelopekmsv2.StatusResponse)
|
||||
}
|
||||
|
||||
if err := utilerrors.Reduce(utilerrors.NewAggregate(errs)); err != nil {
|
||||
return fmt.Errorf("kmsv2 Provider %s is not healthy, error: %v", name, err)
|
||||
return fmt.Errorf("kmsv2 Provider %s is not healthy, error: %w", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTransformerOverrides returns the transformer overrides by reading and parsing the encryption provider configuration file
|
||||
func GetTransformerOverrides(filepath string) (map[schema.GroupResource]value.Transformer, error) {
|
||||
// loadConfig parses the encryption configuration file at filepath and returns the parsed config and hash of the file.
|
||||
func loadConfig(filepath string, reload bool) (*apiserverconfig.EncryptionConfiguration, string, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening encryption provider configuration file %q: %v", filepath, err)
|
||||
return nil, "", fmt.Errorf("error opening encryption provider configuration file %q: %w", filepath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
result, err := parseEncryptionConfiguration(f)
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing encryption provider configuration file %q: %v", filepath, err)
|
||||
return nil, "", fmt.Errorf("could not read contents: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func parseEncryptionConfiguration(f io.Reader) (map[schema.GroupResource]value.Transformer, error) {
|
||||
configFileContents, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read contents: %v", err)
|
||||
if len(data) == 0 {
|
||||
return nil, "", fmt.Errorf("encryption provider configuration file %q is empty", filepath)
|
||||
}
|
||||
|
||||
config, err := loadConfig(configFileContents)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing file: %v", err)
|
||||
}
|
||||
|
||||
resourceToPrefixTransformer := map[schema.GroupResource][]value.PrefixTransformer{}
|
||||
|
||||
// For each entry in the configuration
|
||||
for _, resourceConfig := range config.Resources {
|
||||
transformers, err := prefixTransformers(&resourceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// For each resource, create a list of providers to use
|
||||
for _, resource := range resourceConfig.Resources {
|
||||
gr := schema.ParseGroupResource(resource)
|
||||
resourceToPrefixTransformer[gr] = append(
|
||||
resourceToPrefixTransformer[gr], transformers...)
|
||||
}
|
||||
}
|
||||
|
||||
result := map[schema.GroupResource]value.Transformer{}
|
||||
for gr, transList := range resourceToPrefixTransformer {
|
||||
result[gr] = value.NewMutableTransformer(value.NewPrefixTransformers(fmt.Errorf("no matching prefix found"), transList...))
|
||||
}
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
func loadConfig(data []byte) (*apiserverconfig.EncryptionConfiguration, error) {
|
||||
scheme := runtime.NewScheme()
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
apiserverconfig.AddToScheme(scheme)
|
||||
apiserverconfigv1.AddToScheme(scheme)
|
||||
utilruntime.Must(apiserverconfig.AddToScheme(scheme))
|
||||
utilruntime.Must(apiserverconfigv1.AddToScheme(scheme))
|
||||
|
||||
configObj, gvk, err := codecs.UniversalDecoder().Decode(data, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
config, ok := configObj.(*apiserverconfig.EncryptionConfiguration)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("got unexpected config type: %v", gvk)
|
||||
return nil, "", fmt.Errorf("got unexpected config type: %v", gvk)
|
||||
}
|
||||
|
||||
return config, validation.ValidateEncryptionConfiguration(config).ToAggregate()
|
||||
return config, computeEncryptionConfigHash(data), validation.ValidateEncryptionConfiguration(config, reload).ToAggregate()
|
||||
}
|
||||
|
||||
var (
|
||||
// The factory to create kms service. This is to make writing test easier.
|
||||
envelopeServiceFactory = envelope.NewGRPCService
|
||||
func prefixTransformersAndProbes(config apiserverconfig.ResourceConfiguration, stopCh <-chan struct{}) ([]value.PrefixTransformer, []healthChecker, *kmsState, error) {
|
||||
var transformers []value.PrefixTransformer
|
||||
var probes []healthChecker
|
||||
var kmsUsed kmsState
|
||||
|
||||
// The factory to create kmsv2 service.
|
||||
envelopeKMSv2ServiceFactory = envelopekmsv2.NewGRPCService
|
||||
)
|
||||
|
||||
func prefixTransformers(config *apiserverconfig.ResourceConfiguration) ([]value.PrefixTransformer, error) {
|
||||
var result []value.PrefixTransformer
|
||||
for _, provider := range config.Providers {
|
||||
provider := provider
|
||||
var (
|
||||
transformer value.PrefixTransformer
|
||||
err error
|
||||
transformer value.PrefixTransformer
|
||||
transformerErr error
|
||||
probe healthChecker
|
||||
used *kmsState
|
||||
)
|
||||
|
||||
switch {
|
||||
case provider.AESGCM != nil:
|
||||
transformer, err = aesPrefixTransformer(provider.AESGCM, aestransformer.NewGCMTransformer, aesGCMTransformerPrefixV1)
|
||||
case provider.AESCBC != nil:
|
||||
transformer, err = aesPrefixTransformer(provider.AESCBC, aestransformer.NewCBCTransformer, aesCBCTransformerPrefixV1)
|
||||
case provider.Secretbox != nil:
|
||||
transformer, err = secretboxPrefixTransformer(provider.Secretbox)
|
||||
case provider.KMS != nil:
|
||||
switch provider.KMS.APIVersion {
|
||||
case kmsAPIVersionV1:
|
||||
var envelopeService envelope.Service
|
||||
if envelopeService, err = envelopeServiceFactory(provider.KMS.Endpoint, provider.KMS.Timeout.Duration); err != nil {
|
||||
return nil, fmt.Errorf("could not configure KMS plugin %q, error: %v", provider.KMS.Name, err)
|
||||
}
|
||||
transformer, err = envelopePrefixTransformer(provider.KMS, envelopeService, kmsTransformerPrefixV1)
|
||||
case kmsAPIVersionV2:
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.KMSv2) {
|
||||
return nil, fmt.Errorf("could not configure KMSv2 plugin %q, KMSv2 feature is not enabled", provider.KMS.Name)
|
||||
}
|
||||
transformer, transformerErr = aesPrefixTransformer(provider.AESGCM, aestransformer.NewGCMTransformer, aesGCMTransformerPrefixV1)
|
||||
|
||||
var envelopeService envelopekmsv2.Service
|
||||
if envelopeService, err = envelopeKMSv2ServiceFactory(provider.KMS.Endpoint, provider.KMS.Timeout.Duration); err != nil {
|
||||
return nil, fmt.Errorf("could not configure KMSv2 plugin %q, error: %v", provider.KMS.Name, err)
|
||||
}
|
||||
transformer, err = envelopekmsv2PrefixTransformer(provider.KMS, envelopeService, kmsTransformerPrefixV2)
|
||||
default:
|
||||
return nil, fmt.Errorf("could not configure KMS plugin %q, unsupported KMS API version %q", provider.KMS.Name, provider.KMS.APIVersion)
|
||||
case provider.AESCBC != nil:
|
||||
transformer, transformerErr = aesPrefixTransformer(provider.AESCBC, aestransformer.NewCBCTransformer, aesCBCTransformerPrefixV1)
|
||||
|
||||
case provider.Secretbox != nil:
|
||||
transformer, transformerErr = secretboxPrefixTransformer(provider.Secretbox)
|
||||
|
||||
case provider.KMS != nil:
|
||||
transformer, probe, used, transformerErr = kmsPrefixTransformer(provider.KMS, stopCh)
|
||||
if transformerErr == nil {
|
||||
probes = append(probes, probe)
|
||||
kmsUsed.v1Used = kmsUsed.v1Used || used.v1Used
|
||||
kmsUsed.v2Used = kmsUsed.v2Used || used.v2Used
|
||||
|
||||
// calculate the maximum timeout for all KMS providers
|
||||
kmsUsed.kmsTimeoutSum += used.kmsTimeoutSum
|
||||
}
|
||||
|
||||
case provider.Identity != nil:
|
||||
transformer = value.PrefixTransformer{
|
||||
Transformer: identity.NewEncryptCheckTransformer(),
|
||||
Prefix: []byte{},
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, errors.New("provider does not contain any of the expected providers: KMS, AESGCM, AESCBC, Secretbox, Identity")
|
||||
return nil, nil, nil, errors.New("provider does not contain any of the expected providers: KMS, AESGCM, AESCBC, Secretbox, Identity")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
if transformerErr != nil {
|
||||
return nil, nil, nil, transformerErr
|
||||
}
|
||||
result = append(result, transformer)
|
||||
|
||||
transformers = append(transformers, transformer)
|
||||
}
|
||||
return result, nil
|
||||
|
||||
return transformers, probes, &kmsUsed, nil
|
||||
}
|
||||
|
||||
type blockTransformerFunc func(cipher.Block) value.Transformer
|
||||
@@ -393,6 +390,7 @@ func aesPrefixTransformer(config *apiserverconfig.AESConfiguration, fn blockTran
|
||||
return result, fmt.Errorf("aes provider has no valid keys")
|
||||
}
|
||||
for _, key := range config.Keys {
|
||||
key := key
|
||||
if key.Name == "" {
|
||||
return result, fmt.Errorf("key with invalid name provided")
|
||||
}
|
||||
@@ -404,6 +402,7 @@ func aesPrefixTransformer(config *apiserverconfig.AESConfiguration, fn blockTran
|
||||
keyTransformers := []value.PrefixTransformer{}
|
||||
|
||||
for _, keyData := range config.Keys {
|
||||
keyData := keyData
|
||||
key, err := base64.StdEncoding.DecodeString(keyData.Secret)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("could not obtain secret for named key %s: %s", keyData.Name, err)
|
||||
@@ -440,6 +439,7 @@ func secretboxPrefixTransformer(config *apiserverconfig.SecretboxConfiguration)
|
||||
return result, fmt.Errorf("secretbox provider has no valid keys")
|
||||
}
|
||||
for _, key := range config.Keys {
|
||||
key := key
|
||||
if key.Name == "" {
|
||||
return result, fmt.Errorf("key with invalid name provided")
|
||||
}
|
||||
@@ -451,6 +451,7 @@ func secretboxPrefixTransformer(config *apiserverconfig.SecretboxConfiguration)
|
||||
keyTransformers := []value.PrefixTransformer{}
|
||||
|
||||
for _, keyData := range config.Keys {
|
||||
keyData := keyData
|
||||
key, err := base64.StdEncoding.DecodeString(keyData.Secret)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("could not obtain secret for named key %s: %s", keyData.Name, err)
|
||||
@@ -483,7 +484,82 @@ func secretboxPrefixTransformer(config *apiserverconfig.SecretboxConfiguration)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func envelopePrefixTransformer(config *apiserverconfig.KMSConfiguration, envelopeService envelope.Service, prefix string) (value.PrefixTransformer, error) {
|
||||
var (
|
||||
// The factory to create kms service. This is to make writing test easier.
|
||||
envelopeServiceFactory = envelope.NewGRPCService
|
||||
|
||||
// The factory to create kmsv2 service. Exported for integration tests.
|
||||
EnvelopeKMSv2ServiceFactory = envelopekmsv2.NewGRPCService
|
||||
)
|
||||
|
||||
type kmsState struct {
|
||||
v1Used, v2Used bool
|
||||
kmsTimeoutSum time.Duration
|
||||
}
|
||||
|
||||
func kmsPrefixTransformer(config *apiserverconfig.KMSConfiguration, stopCh <-chan struct{}) (value.PrefixTransformer, healthChecker, *kmsState, error) {
|
||||
// we ignore the cancel func because this context should only be canceled when stopCh is closed
|
||||
ctx, _ := wait.ContextForChannel(stopCh)
|
||||
|
||||
kmsName := config.Name
|
||||
switch config.APIVersion {
|
||||
case kmsAPIVersionV1:
|
||||
envelopeService, err := envelopeServiceFactory(ctx, config.Endpoint, config.Timeout.Duration)
|
||||
if err != nil {
|
||||
return value.PrefixTransformer{}, nil, nil, fmt.Errorf("could not configure KMSv1-Plugin's probe %q, error: %w", kmsName, err)
|
||||
}
|
||||
|
||||
probe := &kmsPluginProbe{
|
||||
name: kmsName,
|
||||
ttl: kmsPluginHealthzNegativeTTL,
|
||||
service: envelopeService,
|
||||
l: &sync.Mutex{},
|
||||
lastResponse: &kmsPluginHealthzResponse{},
|
||||
}
|
||||
|
||||
transformer := envelopePrefixTransformer(config, envelopeService, kmsTransformerPrefixV1)
|
||||
|
||||
return transformer, probe, &kmsState{
|
||||
v1Used: true,
|
||||
// for v1 we will do encrypt and decrypt for health check. Since these are serial operations, we will double the timeout.
|
||||
kmsTimeoutSum: 2 * config.Timeout.Duration,
|
||||
}, nil
|
||||
|
||||
case kmsAPIVersionV2:
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.KMSv2) {
|
||||
return value.PrefixTransformer{}, nil, nil, fmt.Errorf("could not configure KMSv2 plugin %q, KMSv2 feature is not enabled", kmsName)
|
||||
}
|
||||
|
||||
envelopeService, err := EnvelopeKMSv2ServiceFactory(ctx, config.Endpoint, config.Timeout.Duration)
|
||||
if err != nil {
|
||||
return value.PrefixTransformer{}, nil, nil, fmt.Errorf("could not configure KMSv2-Plugin's probe %q, error: %w", kmsName, err)
|
||||
}
|
||||
|
||||
probe := &kmsv2PluginProbe{
|
||||
name: kmsName,
|
||||
ttl: kmsPluginHealthzNegativeTTL,
|
||||
service: envelopeService,
|
||||
l: &sync.Mutex{},
|
||||
lastResponse: &kmsPluginHealthzResponse{},
|
||||
}
|
||||
|
||||
// using AES-GCM by default for encrypting data with KMSv2
|
||||
transformer := value.PrefixTransformer{
|
||||
Transformer: envelopekmsv2.NewEnvelopeTransformer(envelopeService, int(*config.CacheSize), aestransformer.NewGCMTransformer),
|
||||
Prefix: []byte(kmsTransformerPrefixV2 + kmsName + ":"),
|
||||
}
|
||||
|
||||
return transformer, probe, &kmsState{
|
||||
v2Used: true,
|
||||
kmsTimeoutSum: config.Timeout.Duration,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return value.PrefixTransformer{}, nil, nil, fmt.Errorf("could not configure KMS plugin %q, unsupported KMS API version %q", kmsName, config.APIVersion)
|
||||
}
|
||||
}
|
||||
|
||||
func envelopePrefixTransformer(config *apiserverconfig.KMSConfiguration, envelopeService envelope.Service, prefix string) value.PrefixTransformer {
|
||||
baseTransformerFunc := func(block cipher.Block) value.Transformer {
|
||||
// v1.24: write using AES-CBC only but support reads via AES-CBC and AES-GCM (so we can move to AES-GCM)
|
||||
// v1.25: write using AES-GCM only but support reads via AES-GCM and fallback to AES-CBC for backwards compatibility
|
||||
@@ -492,33 +568,18 @@ func envelopePrefixTransformer(config *apiserverconfig.KMSConfiguration, envelop
|
||||
return unionTransformers{aestransformer.NewGCMTransformer(block), aestransformer.NewCBCTransformer(block)}
|
||||
}
|
||||
|
||||
envelopeTransformer, err := envelope.NewEnvelopeTransformer(envelopeService, int(*config.CacheSize), baseTransformerFunc)
|
||||
if err != nil {
|
||||
return value.PrefixTransformer{}, err
|
||||
}
|
||||
return value.PrefixTransformer{
|
||||
Transformer: envelopeTransformer,
|
||||
Transformer: envelope.NewEnvelopeTransformer(envelopeService, int(*config.CacheSize), baseTransformerFunc),
|
||||
Prefix: []byte(prefix + config.Name + ":"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func envelopekmsv2PrefixTransformer(config *apiserverconfig.KMSConfiguration, envelopeService envelopekmsv2.Service, prefix string) (value.PrefixTransformer, error) {
|
||||
// using AES-GCM by default for encrypting data with KMSv2
|
||||
envelopeTransformer, err := envelopekmsv2.NewEnvelopeTransformer(envelopeService, int(*config.CacheSize), aestransformer.NewGCMTransformer)
|
||||
if err != nil {
|
||||
return value.PrefixTransformer{}, err
|
||||
}
|
||||
return value.PrefixTransformer{
|
||||
Transformer: envelopeTransformer,
|
||||
Prefix: []byte(prefix + config.Name + ":"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type unionTransformers []value.Transformer
|
||||
|
||||
func (u unionTransformers) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) (out []byte, stale bool, err error) {
|
||||
var errs []error
|
||||
for i, transformer := range u {
|
||||
for i := range u {
|
||||
transformer := u[i]
|
||||
result, stale, err := transformer.TransformFromStorage(ctx, data, dataCtx)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
@@ -537,3 +598,133 @@ func (u unionTransformers) TransformFromStorage(ctx context.Context, data []byte
|
||||
func (u unionTransformers) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) (out []byte, err error) {
|
||||
return u[0].TransformToStorage(ctx, data, dataCtx)
|
||||
}
|
||||
|
||||
// computeEncryptionConfigHash returns the expected hash for an encryption config file that has been loaded as bytes.
|
||||
// We use a hash instead of the raw file contents when tracking changes to avoid holding any encryption keys in memory outside of their associated transformers.
|
||||
// This hash must be used in-memory and not externalized to the process because it has no cross-release stability guarantees.
|
||||
func computeEncryptionConfigHash(data []byte) string {
|
||||
return fmt.Sprintf("%x", sha256.Sum256(data))
|
||||
}
|
||||
|
||||
var _ healthz.HealthChecker = &DynamicTransformers{}
|
||||
|
||||
// DynamicTransformers holds transformers that may be dynamically updated via a single external actor, likely a controller.
|
||||
// This struct must avoid locks (even read write locks) as it is inline to all calls to storage.
|
||||
type DynamicTransformers struct {
|
||||
transformTracker *atomic.Value
|
||||
}
|
||||
|
||||
type transformTracker struct {
|
||||
transformerOverrides map[schema.GroupResource]value.Transformer
|
||||
kmsPluginHealthzCheck healthz.HealthChecker
|
||||
closeTransformers context.CancelFunc
|
||||
kmsCloseGracePeriod time.Duration
|
||||
}
|
||||
|
||||
// NewDynamicTransformers returns transformers, health checks for kms providers and an ability to close transformers.
|
||||
func NewDynamicTransformers(
|
||||
transformerOverrides map[schema.GroupResource]value.Transformer,
|
||||
kmsPluginHealthzCheck healthz.HealthChecker,
|
||||
closeTransformers context.CancelFunc,
|
||||
kmsCloseGracePeriod time.Duration,
|
||||
) *DynamicTransformers {
|
||||
dynamicTransformers := &DynamicTransformers{
|
||||
transformTracker: &atomic.Value{},
|
||||
}
|
||||
|
||||
tracker := &transformTracker{
|
||||
transformerOverrides: transformerOverrides,
|
||||
kmsPluginHealthzCheck: kmsPluginHealthzCheck,
|
||||
closeTransformers: closeTransformers,
|
||||
kmsCloseGracePeriod: kmsCloseGracePeriod,
|
||||
}
|
||||
dynamicTransformers.transformTracker.Store(tracker)
|
||||
|
||||
return dynamicTransformers
|
||||
}
|
||||
|
||||
// Check implements healthz.HealthChecker
|
||||
func (d *DynamicTransformers) Check(req *http.Request) error {
|
||||
return d.transformTracker.Load().(*transformTracker).kmsPluginHealthzCheck.Check(req)
|
||||
}
|
||||
|
||||
// Name implements healthz.HealthChecker
|
||||
func (d *DynamicTransformers) Name() string {
|
||||
return kmsReloadHealthCheckName
|
||||
}
|
||||
|
||||
// TransformerForResource returns the transformer for the given resource.
|
||||
func (d *DynamicTransformers) TransformerForResource(resource schema.GroupResource) value.Transformer {
|
||||
return &resourceTransformer{
|
||||
resource: resource,
|
||||
transformTracker: d.transformTracker,
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets the transformer overrides. This method is not go routine safe and must only be called by the same, single caller throughout the lifetime of this object.
|
||||
func (d *DynamicTransformers) Set(
|
||||
transformerOverrides map[schema.GroupResource]value.Transformer,
|
||||
closeTransformers context.CancelFunc,
|
||||
kmsPluginHealthzCheck healthz.HealthChecker,
|
||||
kmsCloseGracePeriod time.Duration,
|
||||
) {
|
||||
// store new values
|
||||
newTransformTracker := &transformTracker{
|
||||
transformerOverrides: transformerOverrides,
|
||||
closeTransformers: closeTransformers,
|
||||
kmsPluginHealthzCheck: kmsPluginHealthzCheck,
|
||||
kmsCloseGracePeriod: kmsCloseGracePeriod,
|
||||
}
|
||||
|
||||
// update new transformer overrides
|
||||
oldTransformTracker := d.transformTracker.Swap(newTransformTracker).(*transformTracker)
|
||||
|
||||
// close old transformers once we wait for grpc request to finish any in-flight requests.
|
||||
// by the time we spawn this go routine, the new transformers have already been set and will be used for new requests.
|
||||
// if the server starts shutting down during sleep duration then the transformers will correctly closed early because their lifetime is tied to the api-server drain notifier.
|
||||
go func() {
|
||||
time.Sleep(oldTransformTracker.kmsCloseGracePeriod)
|
||||
oldTransformTracker.closeTransformers()
|
||||
}()
|
||||
}
|
||||
|
||||
var _ value.Transformer = &resourceTransformer{}
|
||||
|
||||
type resourceTransformer struct {
|
||||
resource schema.GroupResource
|
||||
transformTracker *atomic.Value
|
||||
}
|
||||
|
||||
func (r *resourceTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) {
|
||||
return r.transformer().TransformFromStorage(ctx, data, dataCtx)
|
||||
}
|
||||
|
||||
func (r *resourceTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) {
|
||||
return r.transformer().TransformToStorage(ctx, data, dataCtx)
|
||||
}
|
||||
|
||||
func (r *resourceTransformer) transformer() value.Transformer {
|
||||
transformer := r.transformTracker.Load().(*transformTracker).transformerOverrides[r.resource]
|
||||
if transformer == nil {
|
||||
return identity.NewEncryptCheckTransformer()
|
||||
}
|
||||
return transformer
|
||||
}
|
||||
|
||||
type ResourceTransformers interface {
|
||||
TransformerForResource(resource schema.GroupResource) value.Transformer
|
||||
}
|
||||
|
||||
var _ ResourceTransformers = &DynamicTransformers{}
|
||||
var _ ResourceTransformers = &StaticTransformers{}
|
||||
|
||||
type StaticTransformers map[schema.GroupResource]value.Transformer
|
||||
|
||||
// StaticTransformers
|
||||
func (s StaticTransformers) TransformerForResource(resource schema.GroupResource) value.Transformer {
|
||||
transformer := s[resource]
|
||||
if transformer == nil {
|
||||
return identity.NewEncryptCheckTransformer()
|
||||
}
|
||||
return transformer
|
||||
}
|
||||
|
||||
265
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/controller/controller.go
generated
vendored
Normal file
265
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/controller/controller.go
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
Copyright 2022 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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
"k8s.io/apiserver/pkg/server/options/encryptionconfig"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// workqueueKey is the dummy key used to process change in encryption config file.
|
||||
const workqueueKey = "key"
|
||||
|
||||
// DynamicKMSEncryptionConfigContent which can dynamically handle changes in encryption config file.
|
||||
type DynamicKMSEncryptionConfigContent struct {
|
||||
name string
|
||||
|
||||
// filePath is the path of the file to read.
|
||||
filePath string
|
||||
|
||||
// lastLoadedEncryptionConfigHash stores last successfully read encryption config file content.
|
||||
lastLoadedEncryptionConfigHash string
|
||||
|
||||
// queue for processing changes in encryption config file.
|
||||
queue workqueue.RateLimitingInterface
|
||||
|
||||
// dynamicTransformers updates the transformers when encryption config file changes.
|
||||
dynamicTransformers *encryptionconfig.DynamicTransformers
|
||||
|
||||
// stopCh used here is a lifecycle signal of genericapiserver already drained while shutting down.
|
||||
stopCh <-chan struct{}
|
||||
}
|
||||
|
||||
// NewDynamicKMSEncryptionConfiguration returns controller that dynamically reacts to changes in encryption config file.
|
||||
func NewDynamicKMSEncryptionConfiguration(
|
||||
name, filePath string,
|
||||
dynamicTransformers *encryptionconfig.DynamicTransformers,
|
||||
configContentHash string,
|
||||
stopCh <-chan struct{},
|
||||
) *DynamicKMSEncryptionConfigContent {
|
||||
encryptionConfig := &DynamicKMSEncryptionConfigContent{
|
||||
name: name,
|
||||
filePath: filePath,
|
||||
lastLoadedEncryptionConfigHash: configContentHash,
|
||||
dynamicTransformers: dynamicTransformers,
|
||||
stopCh: stopCh,
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("%s-hot-reload", name)),
|
||||
}
|
||||
encryptionConfig.queue.Add(workqueueKey)
|
||||
|
||||
return encryptionConfig
|
||||
}
|
||||
|
||||
// Run starts the controller and blocks until stopCh is closed.
|
||||
func (d *DynamicKMSEncryptionConfigContent) Run(ctx context.Context) {
|
||||
defer utilruntime.HandleCrash()
|
||||
defer d.queue.ShutDown()
|
||||
|
||||
klog.InfoS("Starting controller", "name", d.name)
|
||||
defer klog.InfoS("Shutting down controller", "name", d.name)
|
||||
|
||||
// start worker for processing content
|
||||
go wait.Until(d.runWorker, time.Second, ctx.Done())
|
||||
|
||||
// start the loop that watches the encryption config file until stopCh is closed.
|
||||
go wait.Until(func() {
|
||||
if err := d.watchEncryptionConfigFile(ctx.Done()); err != nil {
|
||||
// if there is an error while setting up or handling the watches, this will ensure that we will process the config file.
|
||||
defer d.queue.Add(workqueueKey)
|
||||
klog.ErrorS(err, "Failed to watch encryption config file, will retry later")
|
||||
}
|
||||
}, time.Second, ctx.Done())
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func (d *DynamicKMSEncryptionConfigContent) watchEncryptionConfigFile(stopCh <-chan struct{}) error {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating fsnotify watcher: %w", err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
if err = watcher.Add(d.filePath); err != nil {
|
||||
return fmt.Errorf("error adding watch for file %s: %w", d.filePath, err)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
if err := d.handleWatchEvent(event, watcher); err != nil {
|
||||
return err
|
||||
}
|
||||
case err := <-watcher.Errors:
|
||||
return fmt.Errorf("received fsnotify error: %w", err)
|
||||
case <-stopCh:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DynamicKMSEncryptionConfigContent) handleWatchEvent(event fsnotify.Event, watcher *fsnotify.Watcher) error {
|
||||
// This should be executed after restarting the watch (if applicable) to ensure no file event will be missing.
|
||||
defer d.queue.Add(workqueueKey)
|
||||
|
||||
// return if file has not been removed or renamed.
|
||||
if event.Op&(fsnotify.Remove|fsnotify.Rename) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := watcher.Remove(d.filePath); err != nil {
|
||||
klog.V(2).InfoS("Failed to remove file watch, it may have been deleted", "file", d.filePath, "err", err)
|
||||
}
|
||||
if err := watcher.Add(d.filePath); err != nil {
|
||||
return fmt.Errorf("error adding watch for file %s: %w", d.filePath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// runWorker to process file content
|
||||
func (d *DynamicKMSEncryptionConfigContent) runWorker() {
|
||||
for d.processNextWorkItem() {
|
||||
}
|
||||
}
|
||||
|
||||
// processNextWorkItem processes file content when there is a message in the queue.
|
||||
func (d *DynamicKMSEncryptionConfigContent) processNextWorkItem() bool {
|
||||
// key here is dummy item in the queue to trigger file content processing.
|
||||
key, quit := d.queue.Get()
|
||||
if quit {
|
||||
return false
|
||||
}
|
||||
defer d.queue.Done(key)
|
||||
|
||||
var (
|
||||
updatedEffectiveConfig bool
|
||||
err error
|
||||
encryptionConfiguration *encryptionconfig.EncryptionConfiguration
|
||||
configChanged bool
|
||||
)
|
||||
|
||||
// get context to close the new transformers.
|
||||
ctx, closeTransformers := wait.ContextForChannel(d.stopCh)
|
||||
|
||||
defer func() {
|
||||
// TODO: increment success metric when updatedEffectiveConfig=true
|
||||
|
||||
if !updatedEffectiveConfig {
|
||||
// avoid leaking if we're not using the newly constructed transformers (due to an error or them not being changed)
|
||||
closeTransformers()
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: increment failure metric
|
||||
utilruntime.HandleError(fmt.Errorf("error processing encryption config file %s: %v", d.filePath, err))
|
||||
// add dummy item back to the queue to trigger file content processing.
|
||||
d.queue.AddRateLimited(key)
|
||||
}
|
||||
}()
|
||||
|
||||
encryptionConfiguration, configChanged, err = d.processEncryptionConfig(ctx)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
if !configChanged {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(encryptionConfiguration.HealthChecks) != 1 {
|
||||
err = fmt.Errorf("unexpected number of healthz checks: %d. Should have only one", len(encryptionConfiguration.HealthChecks))
|
||||
return true
|
||||
}
|
||||
// get healthz checks for all new KMS plugins.
|
||||
if err = d.validateNewTransformersHealth(ctx, encryptionConfiguration.HealthChecks[0], encryptionConfiguration.KMSCloseGracePeriod); err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// update transformers.
|
||||
// when reload=true there must always be one healthz check.
|
||||
d.dynamicTransformers.Set(
|
||||
encryptionConfiguration.Transformers,
|
||||
closeTransformers,
|
||||
encryptionConfiguration.HealthChecks[0],
|
||||
encryptionConfiguration.KMSCloseGracePeriod,
|
||||
)
|
||||
|
||||
// update local copy of recent config content once update is successful.
|
||||
d.lastLoadedEncryptionConfigHash = encryptionConfiguration.EncryptionFileContentHash
|
||||
klog.V(2).InfoS("Loaded new kms encryption config content", "name", d.name)
|
||||
|
||||
updatedEffectiveConfig = true
|
||||
return true
|
||||
}
|
||||
|
||||
// loadEncryptionConfig processes the next set of content from the file.
|
||||
func (d *DynamicKMSEncryptionConfigContent) processEncryptionConfig(ctx context.Context) (
|
||||
encryptionConfiguration *encryptionconfig.EncryptionConfiguration,
|
||||
configChanged bool,
|
||||
err error,
|
||||
) {
|
||||
// this code path will only execute if reload=true. So passing true explicitly.
|
||||
encryptionConfiguration, err = encryptionconfig.LoadEncryptionConfig(d.filePath, true, ctx.Done())
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// check if encryptionConfig is different from the current. Do nothing if they are the same.
|
||||
if encryptionConfiguration.EncryptionFileContentHash == d.lastLoadedEncryptionConfigHash {
|
||||
klog.V(4).InfoS("Encryption config has not changed", "name", d.name)
|
||||
return nil, false, nil
|
||||
}
|
||||
return encryptionConfiguration, true, nil
|
||||
}
|
||||
|
||||
func (d *DynamicKMSEncryptionConfigContent) validateNewTransformersHealth(
|
||||
ctx context.Context,
|
||||
kmsPluginHealthzCheck healthz.HealthChecker,
|
||||
kmsPluginCloseGracePeriod time.Duration,
|
||||
) error {
|
||||
// test if new transformers are healthy
|
||||
var healthCheckError error
|
||||
|
||||
if kmsPluginCloseGracePeriod < 10*time.Second {
|
||||
kmsPluginCloseGracePeriod = 10 * time.Second
|
||||
}
|
||||
|
||||
pollErr := wait.PollImmediate(100*time.Millisecond, kmsPluginCloseGracePeriod, func() (bool, error) {
|
||||
// create a fake http get request to health check endpoint
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("/healthz/%s", kmsPluginHealthzCheck.Name()), nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
healthCheckError = kmsPluginHealthzCheck.Check(req)
|
||||
return healthCheckError == nil, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
return fmt.Errorf("health check for new transformers failed, polling error %v: %w", pollErr, healthCheckError)
|
||||
}
|
||||
klog.V(2).InfoS("Health check succeeded")
|
||||
return nil
|
||||
}
|
||||
255
vendor/k8s.io/apiserver/pkg/server/options/etcd.go
generated
vendored
255
vendor/k8s.io/apiserver/pkg/server/options/etcd.go
generated
vendored
@@ -27,23 +27,26 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
"k8s.io/apiserver/pkg/server/options/encryptionconfig"
|
||||
kmsconfigcontroller "k8s.io/apiserver/pkg/server/options/encryptionconfig/controller"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
storagefactory "k8s.io/apiserver/pkg/storage/storagebackend/factory"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
flowcontrolrequest "k8s.io/apiserver/pkg/util/flowcontrol/request"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
type EtcdOptions struct {
|
||||
// The value of Paging on StorageConfig will be overridden by the
|
||||
// calculated feature gate value.
|
||||
StorageConfig storagebackend.Config
|
||||
EncryptionProviderConfigFilepath string
|
||||
StorageConfig storagebackend.Config
|
||||
EncryptionProviderConfigFilepath string
|
||||
EncryptionProviderConfigAutomaticReload bool
|
||||
|
||||
EtcdServersOverrides []string
|
||||
|
||||
@@ -59,6 +62,15 @@ type EtcdOptions struct {
|
||||
DefaultWatchCacheSize int
|
||||
// WatchCacheSizes represents override to a given resource
|
||||
WatchCacheSizes []string
|
||||
|
||||
// complete guards fields that must be initialized via Complete before the Apply methods can be used.
|
||||
complete bool
|
||||
resourceTransformers encryptionconfig.ResourceTransformers
|
||||
kmsPluginHealthzChecks []healthz.HealthChecker
|
||||
|
||||
// SkipHealthEndpoints, when true, causes the Apply methods to not set up health endpoints.
|
||||
// This allows multiple invocations of the Apply methods without duplication of said endpoints.
|
||||
SkipHealthEndpoints bool
|
||||
}
|
||||
|
||||
var storageTypes = sets.NewString(
|
||||
@@ -107,10 +119,14 @@ func (s *EtcdOptions) Validate() []error {
|
||||
|
||||
}
|
||||
|
||||
if len(s.EncryptionProviderConfigFilepath) == 0 && s.EncryptionProviderConfigAutomaticReload {
|
||||
allErrors = append(allErrors, fmt.Errorf("--encryption-provider-config-automatic-reload must be set with --encryption-provider-config"))
|
||||
}
|
||||
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// AddEtcdFlags adds flags related to etcd storage for a specific APIServer to the specified FlagSet
|
||||
// AddFlags adds flags related to etcd storage for a specific APIServer to the specified FlagSet
|
||||
func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if s == nil {
|
||||
return
|
||||
@@ -123,7 +139,8 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
|
||||
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
|
||||
"The media type to use to store objects in storage. "+
|
||||
"Some resources or storage backends may only support a specific media type and will ignore this setting.")
|
||||
"Some resources or storage backends may only support a specific media type and will ignore this setting. "+
|
||||
"Supported media types: [application/json, application/yaml, application/vnd.kubernetes.protobuf]")
|
||||
fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
|
||||
"Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.")
|
||||
|
||||
@@ -171,6 +188,10 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVar(&s.EncryptionProviderConfigFilepath, "encryption-provider-config", s.EncryptionProviderConfigFilepath,
|
||||
"The file containing configuration for encryption providers to be used for storing secrets in etcd")
|
||||
|
||||
fs.BoolVar(&s.EncryptionProviderConfigAutomaticReload, "encryption-provider-config-automatic-reload", s.EncryptionProviderConfigAutomaticReload,
|
||||
"Determines if the file set by --encryption-provider-config should be automatically reloaded if the disk contents change. "+
|
||||
"Setting this to true disables the ability to uniquely identify distinct KMS plugins via the API server healthz endpoints.")
|
||||
|
||||
fs.DurationVar(&s.StorageConfig.CompactionInterval, "etcd-compaction-interval", s.StorageConfig.CompactionInterval,
|
||||
"The interval of compaction requests. If 0, the compaction request from apiserver is disabled.")
|
||||
|
||||
@@ -190,39 +211,114 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
"The time in seconds that each lease is reused. A lower value could avoid large number of objects reusing the same lease. Notice that a too small value may cause performance problems at storage layer.")
|
||||
}
|
||||
|
||||
// Complete must be called exactly once before using any of the Apply methods. It is responsible for setting
|
||||
// up objects that must be created once and reused across multiple invocations such as storage transformers.
|
||||
// This method mutates the receiver (EtcdOptions). It must never mutate the inputs.
|
||||
func (s *EtcdOptions) Complete(
|
||||
storageObjectCountTracker flowcontrolrequest.StorageObjectCountTracker,
|
||||
stopCh <-chan struct{},
|
||||
addPostStartHook func(name string, hook server.PostStartHookFunc) error,
|
||||
) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.complete {
|
||||
return fmt.Errorf("EtcdOptions.Complete called more than once")
|
||||
}
|
||||
|
||||
if len(s.EncryptionProviderConfigFilepath) != 0 {
|
||||
ctxTransformers, closeTransformers := wait.ContextForChannel(stopCh)
|
||||
ctxServer, _ := wait.ContextForChannel(stopCh) // explicitly ignore cancel here because we do not own the server's lifecycle
|
||||
|
||||
encryptionConfiguration, err := encryptionconfig.LoadEncryptionConfig(s.EncryptionProviderConfigFilepath, s.EncryptionProviderConfigAutomaticReload, ctxTransformers.Done())
|
||||
if err != nil {
|
||||
// in case of error, we want to close partially initialized (if any) transformers
|
||||
closeTransformers()
|
||||
return err
|
||||
}
|
||||
|
||||
// enable kms hot reload controller only if the config file is set to be automatically reloaded
|
||||
if s.EncryptionProviderConfigAutomaticReload {
|
||||
// with reload=true we will always have 1 health check
|
||||
if len(encryptionConfiguration.HealthChecks) != 1 {
|
||||
// in case of error, we want to close partially initialized (if any) transformers
|
||||
closeTransformers()
|
||||
return fmt.Errorf("failed to start kms encryption config hot reload controller. only 1 health check should be available when reload is enabled")
|
||||
}
|
||||
|
||||
dynamicTransformers := encryptionconfig.NewDynamicTransformers(encryptionConfiguration.Transformers, encryptionConfiguration.HealthChecks[0], closeTransformers, encryptionConfiguration.KMSCloseGracePeriod)
|
||||
|
||||
s.resourceTransformers = dynamicTransformers
|
||||
s.kmsPluginHealthzChecks = []healthz.HealthChecker{dynamicTransformers}
|
||||
|
||||
// add post start hook to start hot reload controller
|
||||
// adding this hook here will ensure that it gets configured exactly once
|
||||
err = addPostStartHook(
|
||||
"start-encryption-provider-config-automatic-reload",
|
||||
func(hookContext server.PostStartHookContext) error {
|
||||
kmsConfigController := kmsconfigcontroller.NewDynamicKMSEncryptionConfiguration(
|
||||
"kms-encryption-config",
|
||||
s.EncryptionProviderConfigFilepath,
|
||||
dynamicTransformers,
|
||||
encryptionConfiguration.EncryptionFileContentHash,
|
||||
ctxServer.Done(),
|
||||
)
|
||||
|
||||
go kmsConfigController.Run(ctxServer)
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
// in case of error, we want to close partially initialized (if any) transformers
|
||||
closeTransformers()
|
||||
return fmt.Errorf("failed to add post start hook for kms encryption config hot reload controller: %w", err)
|
||||
}
|
||||
} else {
|
||||
s.resourceTransformers = encryptionconfig.StaticTransformers(encryptionConfiguration.Transformers)
|
||||
s.kmsPluginHealthzChecks = encryptionConfiguration.HealthChecks
|
||||
}
|
||||
}
|
||||
|
||||
s.StorageConfig.StorageObjectCountTracker = storageObjectCountTracker
|
||||
|
||||
s.complete = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyTo mutates the provided server.Config. It must never mutate the receiver (EtcdOptions).
|
||||
func (s *EtcdOptions) ApplyTo(c *server.Config) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
if err := s.addEtcdHealthEndpoint(c); err != nil {
|
||||
return err
|
||||
|
||||
return s.ApplyWithStorageFactoryTo(&SimpleStorageFactory{StorageConfig: s.StorageConfig}, c)
|
||||
}
|
||||
|
||||
// ApplyWithStorageFactoryTo mutates the provided server.Config. It must never mutate the receiver (EtcdOptions).
|
||||
func (s *EtcdOptions) ApplyWithStorageFactoryTo(factory serverstorage.StorageFactory, c *server.Config) error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
transformerOverrides := make(map[schema.GroupResource]value.Transformer)
|
||||
if len(s.EncryptionProviderConfigFilepath) > 0 {
|
||||
var err error
|
||||
transformerOverrides, err = encryptionconfig.GetTransformerOverrides(s.EncryptionProviderConfigFilepath)
|
||||
if err != nil {
|
||||
|
||||
if !s.complete {
|
||||
return fmt.Errorf("EtcdOptions.Apply called without completion")
|
||||
}
|
||||
|
||||
if !s.SkipHealthEndpoints {
|
||||
if err := s.addEtcdHealthEndpoint(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// use the StorageObjectCountTracker interface instance from server.Config
|
||||
s.StorageConfig.StorageObjectCountTracker = c.StorageObjectCountTracker
|
||||
|
||||
c.RESTOptionsGetter = &SimpleRestOptionsFactory{
|
||||
Options: *s,
|
||||
TransformerOverrides: transformerOverrides,
|
||||
if s.resourceTransformers != nil {
|
||||
factory = &transformerStorageFactory{
|
||||
delegate: factory,
|
||||
resourceTransformers: s.resourceTransformers,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *EtcdOptions) ApplyWithStorageFactoryTo(factory serverstorage.StorageFactory, c *server.Config) error {
|
||||
if err := s.addEtcdHealthEndpoint(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// use the StorageObjectCountTracker interface instance from server.Config
|
||||
s.StorageConfig.StorageObjectCountTracker = c.StorageObjectCountTracker
|
||||
|
||||
c.RESTOptionsGetter = &StorageFactoryRestOptionsFactory{Options: *s, StorageFactory: factory}
|
||||
return nil
|
||||
@@ -245,57 +341,11 @@ func (s *EtcdOptions) addEtcdHealthEndpoint(c *server.Config) error {
|
||||
return readyCheck()
|
||||
}))
|
||||
|
||||
if s.EncryptionProviderConfigFilepath != "" {
|
||||
kmsPluginHealthzChecks, err := encryptionconfig.GetKMSPluginHealthzCheckers(s.EncryptionProviderConfigFilepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.AddHealthChecks(kmsPluginHealthzChecks...)
|
||||
}
|
||||
c.AddHealthChecks(s.kmsPluginHealthzChecks...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type SimpleRestOptionsFactory struct {
|
||||
Options EtcdOptions
|
||||
TransformerOverrides map[schema.GroupResource]value.Transformer
|
||||
}
|
||||
|
||||
func (f *SimpleRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
|
||||
ret := generic.RESTOptions{
|
||||
StorageConfig: f.Options.StorageConfig.ForResource(resource),
|
||||
Decorator: generic.UndecoratedStorage,
|
||||
EnableGarbageCollection: f.Options.EnableGarbageCollection,
|
||||
DeleteCollectionWorkers: f.Options.DeleteCollectionWorkers,
|
||||
ResourcePrefix: resource.Group + "/" + resource.Resource,
|
||||
CountMetricPollPeriod: f.Options.StorageConfig.CountMetricPollPeriod,
|
||||
StorageObjectCountTracker: f.Options.StorageConfig.StorageObjectCountTracker,
|
||||
}
|
||||
if f.TransformerOverrides != nil {
|
||||
if transformer, ok := f.TransformerOverrides[resource]; ok {
|
||||
ret.StorageConfig.Transformer = transformer
|
||||
}
|
||||
}
|
||||
if f.Options.EnableWatchCache {
|
||||
sizes, err := ParseWatchCacheSizes(f.Options.WatchCacheSizes)
|
||||
if err != nil {
|
||||
return generic.RESTOptions{}, err
|
||||
}
|
||||
size, ok := sizes[resource]
|
||||
if ok && size > 0 {
|
||||
klog.Warningf("Dropping watch-cache-size for %v - watchCache size is now dynamic", resource)
|
||||
}
|
||||
if ok && size <= 0 {
|
||||
klog.V(3).InfoS("Not using watch cache", "resource", resource)
|
||||
ret.Decorator = generic.UndecoratedStorage
|
||||
} else {
|
||||
klog.V(3).InfoS("Using watch cache", "resource", resource)
|
||||
ret.Decorator = genericregistry.StorageWithCacher()
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type StorageFactoryRestOptionsFactory struct {
|
||||
Options EtcdOptions
|
||||
StorageFactory serverstorage.StorageFactory
|
||||
@@ -316,6 +366,7 @@ func (f *StorageFactoryRestOptionsFactory) GetRESTOptions(resource schema.GroupR
|
||||
CountMetricPollPeriod: f.Options.StorageConfig.CountMetricPollPeriod,
|
||||
StorageObjectCountTracker: f.Options.StorageConfig.StorageObjectCountTracker,
|
||||
}
|
||||
|
||||
if f.Options.EnableWatchCache {
|
||||
sizes, err := ParseWatchCacheSizes(f.Options.WatchCacheSizes)
|
||||
if err != nil {
|
||||
@@ -326,8 +377,10 @@ func (f *StorageFactoryRestOptionsFactory) GetRESTOptions(resource schema.GroupR
|
||||
klog.Warningf("Dropping watch-cache-size for %v - watchCache size is now dynamic", resource)
|
||||
}
|
||||
if ok && size <= 0 {
|
||||
klog.V(3).InfoS("Not using watch cache", "resource", resource)
|
||||
ret.Decorator = generic.UndecoratedStorage
|
||||
} else {
|
||||
klog.V(3).InfoS("Using watch cache", "resource", resource)
|
||||
ret.Decorator = genericregistry.StorageWithCacher()
|
||||
}
|
||||
}
|
||||
@@ -369,3 +422,55 @@ func WriteWatchCacheSizes(watchCacheSizes map[schema.GroupResource]int) ([]strin
|
||||
}
|
||||
return cacheSizes, nil
|
||||
}
|
||||
|
||||
var _ serverstorage.StorageFactory = &SimpleStorageFactory{}
|
||||
|
||||
// SimpleStorageFactory provides a StorageFactory implementation that should be used when different
|
||||
// resources essentially share the same storage config (as defined by the given storagebackend.Config).
|
||||
// It assumes the resources are stored at a path that is purely based on the schema.GroupResource.
|
||||
// Users that need flexibility and per resource overrides should use DefaultStorageFactory instead.
|
||||
type SimpleStorageFactory struct {
|
||||
StorageConfig storagebackend.Config
|
||||
}
|
||||
|
||||
func (s *SimpleStorageFactory) NewConfig(resource schema.GroupResource) (*storagebackend.ConfigForResource, error) {
|
||||
return s.StorageConfig.ForResource(resource), nil
|
||||
}
|
||||
|
||||
func (s *SimpleStorageFactory) ResourcePrefix(resource schema.GroupResource) string {
|
||||
return resource.Group + "/" + resource.Resource
|
||||
}
|
||||
|
||||
func (s *SimpleStorageFactory) Backends() []serverstorage.Backend {
|
||||
// nothing should ever call this method but we still provide a functional implementation
|
||||
return serverstorage.Backends(s.StorageConfig)
|
||||
}
|
||||
|
||||
var _ serverstorage.StorageFactory = &transformerStorageFactory{}
|
||||
|
||||
type transformerStorageFactory struct {
|
||||
delegate serverstorage.StorageFactory
|
||||
resourceTransformers encryptionconfig.ResourceTransformers
|
||||
}
|
||||
|
||||
func (t *transformerStorageFactory) NewConfig(resource schema.GroupResource) (*storagebackend.ConfigForResource, error) {
|
||||
config, err := t.delegate.NewConfig(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configCopy := *config
|
||||
resourceConfig := configCopy.Config
|
||||
resourceConfig.Transformer = t.resourceTransformers.TransformerForResource(resource)
|
||||
configCopy.Config = resourceConfig
|
||||
|
||||
return &configCopy, nil
|
||||
}
|
||||
|
||||
func (t *transformerStorageFactory) ResourcePrefix(resource schema.GroupResource) string {
|
||||
return t.delegate.ResourcePrefix(resource)
|
||||
}
|
||||
|
||||
func (t *transformerStorageFactory) Backends() []serverstorage.Backend {
|
||||
return t.delegate.Backends()
|
||||
}
|
||||
|
||||
5
vendor/k8s.io/apiserver/pkg/server/options/recommended.go
generated
vendored
5
vendor/k8s.io/apiserver/pkg/server/options/recommended.go
generated
vendored
@@ -101,6 +101,9 @@ func (o *RecommendedOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
// ApplyTo adds RecommendedOptions to the server configuration.
|
||||
// pluginInitializers can be empty, it is only need for additional initializers.
|
||||
func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig) error {
|
||||
if err := o.Etcd.Complete(config.Config.StorageObjectCountTracker, config.Config.DrainedNotify(), config.Config.AddPostStartHook); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.Etcd.ApplyTo(&config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -141,7 +144,7 @@ func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig) error {
|
||||
}
|
||||
config.FlowControl = utilflowcontrol.New(
|
||||
config.SharedInformerFactory,
|
||||
kubernetes.NewForConfigOrDie(config.ClientConfig).FlowcontrolV1beta2(),
|
||||
kubernetes.NewForConfigOrDie(config.ClientConfig).FlowcontrolV1beta3(),
|
||||
config.MaxRequestsInFlight+config.MaxMutatingRequestsInFlight,
|
||||
config.RequestTimeout/4,
|
||||
)
|
||||
|
||||
1
vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
generated
vendored
1
vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
generated
vendored
@@ -208,6 +208,7 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
||||
deprecatedMasterServiceNamespace := metav1.NamespaceDefault
|
||||
fs.StringVar(&deprecatedMasterServiceNamespace, "master-service-namespace", deprecatedMasterServiceNamespace, ""+
|
||||
"DEPRECATED: the namespace from which the Kubernetes master services should be injected into pods.")
|
||||
fs.MarkDeprecated("master-service-namespace", "This flag will be removed in v1.27")
|
||||
|
||||
fs.IntVar(&s.MaxRequestsInFlight, "max-requests-inflight", s.MaxRequestsInFlight, ""+
|
||||
"This and --max-mutating-requests-inflight are summed to determine the server's total concurrency limit "+
|
||||
|
||||
15
vendor/k8s.io/apiserver/pkg/server/options/tracing.go
generated
vendored
15
vendor/k8s.io/apiserver/pkg/server/options/tracing.go
generated
vendored
@@ -23,9 +23,9 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpgrpc"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"go.opentelemetry.io/otel/semconv"
|
||||
"go.opentelemetry.io/otel/semconv/v1.12.0"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -93,7 +93,7 @@ func (o *TracingOptions) ApplyTo(es *egressselector.EgressSelector, c *server.Co
|
||||
return fmt.Errorf("failed to validate tracing configuration: %v", errs.ToAggregate())
|
||||
}
|
||||
|
||||
opts := []otlpgrpc.Option{}
|
||||
opts := []otlptracegrpc.Option{}
|
||||
if es != nil {
|
||||
// Only use the egressselector dialer if egressselector is enabled.
|
||||
// Endpoint is on the "ControlPlane" network
|
||||
@@ -101,11 +101,12 @@ func (o *TracingOptions) ApplyTo(es *egressselector.EgressSelector, c *server.Co
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
otelDialer := func(ctx context.Context, addr string) (net.Conn, error) {
|
||||
return egressDialer(ctx, "tcp", addr)
|
||||
if egressDialer != nil {
|
||||
otelDialer := func(ctx context.Context, addr string) (net.Conn, error) {
|
||||
return egressDialer(ctx, "tcp", addr)
|
||||
}
|
||||
opts = append(opts, otlptracegrpc.WithDialOption(grpc.WithContextDialer(otelDialer)))
|
||||
}
|
||||
opts = append(opts, otlpgrpc.WithDialOption(grpc.WithContextDialer(otelDialer)))
|
||||
}
|
||||
|
||||
resourceOpts := []resource.Option{
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/server/plugins.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/plugins.go
generated
vendored
@@ -20,6 +20,7 @@ package server
|
||||
import (
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
|
||||
"k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy"
|
||||
mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating"
|
||||
validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating"
|
||||
)
|
||||
@@ -29,4 +30,5 @@ func RegisterAllAdmissionPlugins(plugins *admission.Plugins) {
|
||||
lifecycle.Register(plugins)
|
||||
validatingwebhook.Register(plugins)
|
||||
mutatingwebhook.Register(plugins)
|
||||
validatingadmissionpolicy.Register(plugins)
|
||||
}
|
||||
|
||||
9
vendor/k8s.io/apiserver/pkg/server/storage/storage_codec.go
generated
vendored
9
vendor/k8s.io/apiserver/pkg/server/storage/storage_codec.go
generated
vendored
@@ -46,9 +46,14 @@ func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, runtime.GroupVersi
|
||||
return nil, nil, fmt.Errorf("%q is not a valid mime-type", opts.StorageMediaType)
|
||||
}
|
||||
|
||||
serializer, ok := runtime.SerializerInfoForMediaType(opts.StorageSerializer.SupportedMediaTypes(), mediaType)
|
||||
supportedMediaTypes := opts.StorageSerializer.SupportedMediaTypes()
|
||||
serializer, ok := runtime.SerializerInfoForMediaType(supportedMediaTypes, mediaType)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("unable to find serializer for %q", mediaType)
|
||||
supportedMediaTypeList := make([]string, len(supportedMediaTypes))
|
||||
for i, mediaType := range supportedMediaTypes {
|
||||
supportedMediaTypeList[i] = mediaType.MediaType
|
||||
}
|
||||
return nil, nil, fmt.Errorf("unable to find serializer for %q, supported media types: %v", mediaType, supportedMediaTypeList)
|
||||
}
|
||||
|
||||
s := serializer.Serializer
|
||||
|
||||
36
vendor/k8s.io/apiserver/pkg/server/storage/storage_factory.go
generated
vendored
36
vendor/k8s.io/apiserver/pkg/server/storage/storage_factory.go
generated
vendored
@@ -29,7 +29,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
)
|
||||
|
||||
@@ -112,8 +111,6 @@ type groupResourceOverrides struct {
|
||||
// decoderDecoratorFn is optional and may wrap the provided decoders (can add new decoders). The order of
|
||||
// returned decoders will be priority for attempt to decode.
|
||||
decoderDecoratorFn func([]runtime.Decoder) []runtime.Decoder
|
||||
// transformer is optional and shall encrypt that resource at rest.
|
||||
transformer value.Transformer
|
||||
// disablePaging will prevent paging on the provided resource.
|
||||
disablePaging bool
|
||||
}
|
||||
@@ -139,9 +136,6 @@ func (o groupResourceOverrides) Apply(config *storagebackend.Config, options *St
|
||||
if o.decoderDecoratorFn != nil {
|
||||
options.DecoderDecoratorFn = o.decoderDecoratorFn
|
||||
}
|
||||
if o.transformer != nil {
|
||||
config.Transformer = o.transformer
|
||||
}
|
||||
if o.disablePaging {
|
||||
config.Paging = false
|
||||
}
|
||||
@@ -210,12 +204,6 @@ func (s *DefaultStorageFactory) SetSerializer(groupResource schema.GroupResource
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
|
||||
func (s *DefaultStorageFactory) SetTransformer(groupResource schema.GroupResource, transformer value.Transformer) {
|
||||
overrides := s.Overrides[groupResource]
|
||||
overrides.transformer = transformer
|
||||
s.Overrides[groupResource] = overrides
|
||||
}
|
||||
|
||||
// AddCohabitatingResources links resources together the order of the slice matters! its the priority order of lookup for finding a storage location
|
||||
func (s *DefaultStorageFactory) AddCohabitatingResources(groupResources ...schema.GroupResource) {
|
||||
for _, groupResource := range groupResources {
|
||||
@@ -291,25 +279,35 @@ func (s *DefaultStorageFactory) NewConfig(groupResource schema.GroupResource) (*
|
||||
// Backends returns all backends for all registered storage destinations.
|
||||
// Used for getting all instances for health validations.
|
||||
func (s *DefaultStorageFactory) Backends() []Backend {
|
||||
servers := sets.NewString(s.StorageConfig.Transport.ServerList...)
|
||||
return backends(s.StorageConfig, s.Overrides)
|
||||
}
|
||||
|
||||
for _, overrides := range s.Overrides {
|
||||
// Backends returns all backends for all registered storage destinations.
|
||||
// Used for getting all instances for health validations.
|
||||
func Backends(storageConfig storagebackend.Config) []Backend {
|
||||
return backends(storageConfig, nil)
|
||||
}
|
||||
|
||||
func backends(storageConfig storagebackend.Config, grOverrides map[schema.GroupResource]groupResourceOverrides) []Backend {
|
||||
servers := sets.NewString(storageConfig.Transport.ServerList...)
|
||||
|
||||
for _, overrides := range grOverrides {
|
||||
servers.Insert(overrides.etcdLocation...)
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
if len(s.StorageConfig.Transport.CertFile) > 0 && len(s.StorageConfig.Transport.KeyFile) > 0 {
|
||||
cert, err := tls.LoadX509KeyPair(s.StorageConfig.Transport.CertFile, s.StorageConfig.Transport.KeyFile)
|
||||
if len(storageConfig.Transport.CertFile) > 0 && len(storageConfig.Transport.KeyFile) > 0 {
|
||||
cert, err := tls.LoadX509KeyPair(storageConfig.Transport.CertFile, storageConfig.Transport.KeyFile)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to load key pair while getting backends: %s", err)
|
||||
} else {
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
}
|
||||
if len(s.StorageConfig.Transport.TrustedCAFile) > 0 {
|
||||
if caCert, err := ioutil.ReadFile(s.StorageConfig.Transport.TrustedCAFile); err != nil {
|
||||
if len(storageConfig.Transport.TrustedCAFile) > 0 {
|
||||
if caCert, err := ioutil.ReadFile(storageConfig.Transport.TrustedCAFile); err != nil {
|
||||
klog.Errorf("failed to read ca file while getting backends: %s", err)
|
||||
} else {
|
||||
caPool := x509.NewCertPool()
|
||||
@@ -324,7 +322,7 @@ func (s *DefaultStorageFactory) Backends() []Backend {
|
||||
backends = append(backends, Backend{
|
||||
Server: server,
|
||||
// We can't share TLSConfig across different backends to avoid races.
|
||||
// For more details see: http://pr.k8s.io/59338
|
||||
// For more details see: https://pr.k8s.io/59338
|
||||
TLSConfig: tlsConfig.Clone(),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user