Merge pull request #1789 from vmware-tanzu/http2

Defensive changes to mitigate potential http2 rapid reset attacks
This commit is contained in:
Ryan Richard
2023-12-06 09:15:07 -08:00
committed by GitHub
4 changed files with 67 additions and 0 deletions
+5
View File
@@ -17,6 +17,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/serializer"
apimachineryversion "k8s.io/apimachinery/pkg/version"
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
"k8s.io/apiserver/pkg/features"
genericapiserver "k8s.io/apiserver/pkg/server"
genericoptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/client-go/rest"
@@ -27,6 +28,7 @@ import (
"go.pinniped.dev/internal/concierge/apiserver"
conciergescheme "go.pinniped.dev/internal/concierge/scheme"
"go.pinniped.dev/internal/config/concierge"
"go.pinniped.dev/internal/config/featuregates"
"go.pinniped.dev/internal/controller/authenticator/authncache"
"go.pinniped.dev/internal/controllerinit"
"go.pinniped.dev/internal/controllermanager"
@@ -103,6 +105,9 @@ func addCommandlineFlagsToCommand(cmd *cobra.Command, app *App) {
// Boot the aggregated API server, which will in turn boot the controllers.
// In practice, the ctx passed in should be one which will be cancelled when the process receives SIGTERM or SIGINT.
func (a *App) runServer(ctx context.Context) error {
// Enable the feature gate from https://github.com/kubernetes/kubernetes/pull/121120.
featuregates.EnableKubeFeatureGate(features.UnauthenticatedHTTP2DOSMitigation)
// Read the server config file.
cfg, err := concierge.FromPath(ctx, a.configPath)
if err != nil {
@@ -0,0 +1,25 @@
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package featuregates
import (
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/component-base/featuregate"
"go.pinniped.dev/internal/plog"
)
func EnableKubeFeatureGate(f featuregate.Feature) {
initialValue := feature.DefaultFeatureGate.Enabled(f)
if err := feature.DefaultMutableFeatureGate.SetFromMap(map[string]bool{string(f): true}); err != nil {
panic(err) // this should never happen as long as a feature gate still exists
}
plog.Always("feature gate status",
"name", f,
"initialEnabledValue", initialValue,
"updatedEnabledValue", feature.DefaultFeatureGate.Enabled(f),
)
}
@@ -0,0 +1,28 @@
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package featuregates
import (
"testing"
"github.com/stretchr/testify/require"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
)
func TestEnableKubeFeatureGate(t *testing.T) {
f := features.UnauthenticatedHTTP2DOSMitigation
// This feature gate is currently disabled by default in the Kubernetes library.
// Assert this as a precondition so if that ever changes during a dependency bump
// we will be forced to take note and decide if any code deserves to change.
require.False(t, feature.DefaultFeatureGate.Enabled(f))
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, f, false)()
require.False(t, feature.DefaultFeatureGate.Enabled(f))
EnableKubeFeatureGate(f)
require.True(t, feature.DefaultFeatureGate.Enabled(f))
}
+9
View File
@@ -28,6 +28,7 @@ import (
apimachineryversion "k8s.io/apimachinery/pkg/version"
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
"k8s.io/apiserver/pkg/features"
genericapiserver "k8s.io/apiserver/pkg/server"
genericoptions "k8s.io/apiserver/pkg/server/options"
k8sinformers "k8s.io/client-go/informers"
@@ -43,6 +44,7 @@ import (
supervisorinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions"
supervisoropenapi "go.pinniped.dev/generated/latest/client/supervisor/openapi"
"go.pinniped.dev/internal/apiserviceref"
"go.pinniped.dev/internal/config/featuregates"
"go.pinniped.dev/internal/config/supervisor"
"go.pinniped.dev/internal/controller/apicerts"
"go.pinniped.dev/internal/controller/supervisorconfig"
@@ -386,6 +388,9 @@ func prepareControllers(
// and start serving the health endpoint and the endpoints of the configured FederationDomains.
// In practice, the ctx passed in should be one which will be cancelled when the process receives SIGTERM or SIGINT.
func runSupervisor(ctx context.Context, podInfo *downward.PodInfo, cfg *supervisor.Config) error { //nolint:funlen
// Enable the feature gate from https://github.com/kubernetes/kubernetes/pull/121120.
featuregates.EnableKubeFeatureGate(features.UnauthenticatedHTTP2DOSMitigation)
serverInstallationNamespace := podInfo.Namespace
clientSecretSupervisorGroupData := groupsuffix.SupervisorAggregatedGroups(*cfg.APIGroupSuffix)
@@ -526,6 +531,10 @@ func runSupervisor(ctx context.Context, podInfo *downward.PodInfo, cfg *supervis
}
c := ptls.Default(nil)
// Remove "h2" from the list for now, until we have a better idea of how to mitigate
// potential http2 rapid reset vulnerabilities. This disables serving requests using http2.
c.NextProtos = []string{"http/1.1"}
c.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
cert := dynamicTLSCertProvider.GetTLSCert(strings.ToLower(info.ServerName))
foundServerNameCert := cert != nil