Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions pkg/features/kcp_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ const (
WorkspaceAuthentication featuregate.Feature = "WorkspaceAuthentication"
)

// Re-export upstream feature gates used by kcp server logic so callers import
// only this package instead of mixing kcp and upstream feature imports.
// Mirrored from k8s.io/apiserver/pkg/features.
const (
// StorageVersionAPI enables the storage version API (alpha since k8s 1.20, off by default).
// When enabled in kcp, WithStorageVersionPrecondition is applied in the handler chain to
// block write requests to resources whose storage versions have not yet converged across
// all kcp shards during a rolling upgrade.
// See: https://github.com/kcp-dev/kubernetes/pull/185
StorageVersionAPI = genericfeatures.StorageVersionAPI
)

// DefaultFeatureGate exposes the upstream feature gate, but with our gate setting applied.
var DefaultFeatureGate = utilfeature.DefaultFeatureGate

Expand Down Expand Up @@ -141,6 +153,11 @@ var defaultVersionedGenericControlPlaneFeatureGates = map[featuregate.Feature]fe
WorkspaceAuthentication: {
{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
},
// StorageVersionAPI mirrors the upstream k8s gate; kcp keeps it Alpha/off-by-default.
// Must be listed here so kcp's feature gate machinery tracks it and exposes it via --feature-gates.
genericfeatures.StorageVersionAPI: {
{Version: version.MustParse("1.20"), Default: false, PreRelease: featuregate.Alpha},
},
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:
genericfeatures.APIResponseCompression: {
Expand Down
18 changes: 18 additions & 0 deletions pkg/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,14 @@ func NewConfig(ctx context.Context, opts kcpserveroptions.CompletedOptions) (*Co
// preHandlerChainMux is called before the actual handler chain. Note that BuildHandlerChainFunc below
// is called multiple times, but only one of the handler chain will actually be used. Hence, we wrap it
// to give handlers below one mux.Handle func to call.
//
// NOTE: kcp fully replaces BuildHandlerChainFunc here, which means any handler chain customization
// done earlier in the setup pipeline (e.g. genericConfig.BuildHandlerChainFunc =
// genericapiserver.BuildHandlerChainWithStorageVersionPrecondition in CreateAggregatorConfig when
// StorageVersionAPI + APIServerIdentity feature gates are enabled) is overwritten and never applied.
// WithStorageVersionPrecondition is therefore applied explicitly below, gated behind the
// StorageVersionAPI feature gate (alpha, off by default) to match upstream k8s behaviour.
// See: https://github.com/kcp-dev/kubernetes/pull/185
c.preHandlerChainMux = &handlerChainMuxes{}
c.GenericConfig.BuildHandlerChainFunc = func(apiHandler http.Handler, genericConfig *genericapiserver.Config) (secure http.Handler) {
apiHandler = openapiv3.WithOpenAPIv3(apiHandler, c.openAPIv3ServiceCache) // will be initialized further down after apiextensions-apiserver
Expand All @@ -461,6 +469,16 @@ func NewConfig(ctx context.Context, opts kcpserveroptions.CompletedOptions) (*Co
apiHandler = authorization.WithSubjectAccessReviewAuditAnnotations(apiHandler)
apiHandler = authorization.WithDeepSubjectAccessReview(apiHandler)

// WithStorageVersionPrecondition blocks write requests to resources whose storage versions
// have not yet converged across all kcp shards during a rolling upgrade. It must wrap the
// API handler before the authz chain runs, and relies on WithRequestInfo
// (in DefaultBuildHandlerChainFromStartToBeforeImpersonation below) being present in the
// outer chain at request time.
// Gated behind StorageVersionAPI (alpha, off by default) to match upstream k8s behaviour.
if kcpfeatures.DefaultFeatureGate.Enabled(kcpfeatures.StorageVersionAPI) {
apiHandler = filters.WithStorageVersionPrecondition(apiHandler, genericConfig.StorageVersionManager, genericConfig.Serializer)
}

// The following ensures that only the default main api handler chain executes authorizers which log audit messages.
// All other invocations of the same authorizer chain still work but do not produce audit log entries.
// This compromises audit log size and information overflow vs. having audit reasons for the main api handler only.
Expand Down