Update tests to handle RemoteRequestHeaderUID

Signed-off-by: Monis Khan <mok@microsoft.com>
This commit is contained in:
Monis Khan
2024-12-04 16:04:36 -05:00
parent a051b067cd
commit 779d76176a
8 changed files with 206 additions and 42 deletions

View File

@@ -30,11 +30,14 @@ import (
"k8s.io/apimachinery/pkg/util/dump" "k8s.io/apimachinery/pkg/util/dump"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/authentication/request/headerrequest" "k8s.io/apiserver/pkg/authentication/request/headerrequest"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/server/dynamiccertificates" "k8s.io/apiserver/pkg/server/dynamiccertificates"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/fake"
corev1listers "k8s.io/client-go/listers/core/v1" corev1listers "k8s.io/client-go/listers/core/v1"
clienttesting "k8s.io/client-go/testing" clienttesting "k8s.io/client-go/testing"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
featuregatetesting "k8s.io/component-base/featuregate/testing"
) )
var ( var (
@@ -95,6 +98,7 @@ func TestWriteClientCAs(t *testing.T) {
preexistingObjs []runtime.Object preexistingObjs []runtime.Object
expectedConfigMaps map[string]*corev1.ConfigMap expectedConfigMaps map[string]*corev1.ConfigMap
expectCreate bool expectCreate bool
uidGate bool
}{ }{
{ {
name: "basic", name: "basic",
@@ -107,6 +111,32 @@ func TestWriteClientCAs(t *testing.T) {
RequestHeaderCA: anotherRandomCAProvider, RequestHeaderCA: anotherRandomCAProvider,
RequestHeaderAllowedNames: headerrequest.StaticStringSlice{"first", "second"}, RequestHeaderAllowedNames: headerrequest.StaticStringSlice{"first", "second"},
}, },
expectedConfigMaps: map[string]*corev1.ConfigMap{
"extension-apiserver-authentication": {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{
"client-ca-file": string(someRandomCA),
"requestheader-username-headers": `["alfa","bravo","charlie"]`,
"requestheader-group-headers": `["delta"]`,
"requestheader-extra-headers-prefix": `["echo","foxtrot"]`,
"requestheader-client-ca-file": string(anotherRandomCA),
"requestheader-allowed-names": `["first","second"]`,
},
},
},
expectCreate: true,
},
{
name: "basic with feature gate",
clusterAuthInfo: ClusterAuthenticationInfo{
ClientCA: someRandomCAProvider,
RequestHeaderUsernameHeaders: headerrequest.StaticStringSlice{"alfa", "bravo", "charlie"},
RequestHeaderUIDHeaders: headerrequest.StaticStringSlice{"golf", "hotel", "india"},
RequestHeaderGroupHeaders: headerrequest.StaticStringSlice{"delta"},
RequestHeaderExtraHeaderPrefixes: headerrequest.StaticStringSlice{"echo", "foxtrot"},
RequestHeaderCA: anotherRandomCAProvider,
RequestHeaderAllowedNames: headerrequest.StaticStringSlice{"first", "second"},
},
expectedConfigMaps: map[string]*corev1.ConfigMap{ expectedConfigMaps: map[string]*corev1.ConfigMap{
"extension-apiserver-authentication": { "extension-apiserver-authentication": {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
@@ -122,6 +152,7 @@ func TestWriteClientCAs(t *testing.T) {
}, },
}, },
expectCreate: true, expectCreate: true,
uidGate: true,
}, },
{ {
name: "skip extension-apiserver-authentication", name: "skip extension-apiserver-authentication",
@@ -134,7 +165,6 @@ func TestWriteClientCAs(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{ Data: map[string]string{
"requestheader-username-headers": `[]`, "requestheader-username-headers": `[]`,
"requestheader-uid-headers": `[]`,
"requestheader-group-headers": `[]`, "requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`, "requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA), "requestheader-client-ca-file": string(anotherRandomCA),
@@ -169,7 +199,6 @@ func TestWriteClientCAs(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{ Data: map[string]string{
"requestheader-username-headers": `[]`, "requestheader-username-headers": `[]`,
"requestheader-uid-headers": `[]`,
"requestheader-group-headers": `[]`, "requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`, "requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA), "requestheader-client-ca-file": string(anotherRandomCA),
@@ -205,7 +234,6 @@ func TestWriteClientCAs(t *testing.T) {
name: "overwrite extension-apiserver-authentication requestheader", name: "overwrite extension-apiserver-authentication requestheader",
clusterAuthInfo: ClusterAuthenticationInfo{ clusterAuthInfo: ClusterAuthenticationInfo{
RequestHeaderUsernameHeaders: headerrequest.StaticStringSlice{}, RequestHeaderUsernameHeaders: headerrequest.StaticStringSlice{},
RequestHeaderUIDHeaders: headerrequest.StaticStringSlice{},
RequestHeaderGroupHeaders: headerrequest.StaticStringSlice{}, RequestHeaderGroupHeaders: headerrequest.StaticStringSlice{},
RequestHeaderExtraHeaderPrefixes: headerrequest.StaticStringSlice{}, RequestHeaderExtraHeaderPrefixes: headerrequest.StaticStringSlice{},
RequestHeaderCA: anotherRandomCAProvider, RequestHeaderCA: anotherRandomCAProvider,
@@ -216,7 +244,6 @@ func TestWriteClientCAs(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{ Data: map[string]string{
"requestheader-username-headers": `[]`, "requestheader-username-headers": `[]`,
"requestheader-uid-headers": `[]`,
"requestheader-group-headers": `[]`, "requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`, "requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(someRandomCA), "requestheader-client-ca-file": string(someRandomCA),
@@ -229,7 +256,6 @@ func TestWriteClientCAs(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{ Data: map[string]string{
"requestheader-username-headers": `[]`, "requestheader-username-headers": `[]`,
"requestheader-uid-headers": `[]`,
"requestheader-group-headers": `[]`, "requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`, "requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(someRandomCA) + string(anotherRandomCA), "requestheader-client-ca-file": string(someRandomCA) + string(anotherRandomCA),
@@ -260,7 +286,6 @@ func TestWriteClientCAs(t *testing.T) {
name: "skip on no change", name: "skip on no change",
clusterAuthInfo: ClusterAuthenticationInfo{ clusterAuthInfo: ClusterAuthenticationInfo{
RequestHeaderUsernameHeaders: headerrequest.StaticStringSlice{}, RequestHeaderUsernameHeaders: headerrequest.StaticStringSlice{},
RequestHeaderUIDHeaders: headerrequest.StaticStringSlice{},
RequestHeaderGroupHeaders: headerrequest.StaticStringSlice{}, RequestHeaderGroupHeaders: headerrequest.StaticStringSlice{},
RequestHeaderExtraHeaderPrefixes: headerrequest.StaticStringSlice{}, RequestHeaderExtraHeaderPrefixes: headerrequest.StaticStringSlice{},
RequestHeaderCA: anotherRandomCAProvider, RequestHeaderCA: anotherRandomCAProvider,
@@ -271,7 +296,6 @@ func TestWriteClientCAs(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{ Data: map[string]string{
"requestheader-username-headers": `[]`, "requestheader-username-headers": `[]`,
"requestheader-uid-headers": `[]`,
"requestheader-group-headers": `[]`, "requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`, "requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA), "requestheader-client-ca-file": string(anotherRandomCA),
@@ -282,10 +306,126 @@ func TestWriteClientCAs(t *testing.T) {
expectedConfigMaps: map[string]*corev1.ConfigMap{}, expectedConfigMaps: map[string]*corev1.ConfigMap{},
expectCreate: false, expectCreate: false,
}, },
{
name: "drop uid without feature gate",
clusterAuthInfo: ClusterAuthenticationInfo{
RequestHeaderUsernameHeaders: headerrequest.StaticStringSlice{},
RequestHeaderUIDHeaders: headerrequest.StaticStringSlice{"panda"},
RequestHeaderGroupHeaders: headerrequest.StaticStringSlice{},
RequestHeaderExtraHeaderPrefixes: headerrequest.StaticStringSlice{},
RequestHeaderCA: anotherRandomCAProvider,
RequestHeaderAllowedNames: headerrequest.StaticStringSlice{},
},
preexistingObjs: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{
"requestheader-username-headers": `[]`,
"requestheader-uid-headers": `["snorlax"]`,
"requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA),
"requestheader-allowed-names": `[]`,
},
},
},
expectedConfigMaps: map[string]*corev1.ConfigMap{
"extension-apiserver-authentication": {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{
"requestheader-username-headers": `[]`,
"requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA),
"requestheader-allowed-names": `[]`,
},
},
},
expectCreate: false,
},
{
name: "add uid with feature gate",
clusterAuthInfo: ClusterAuthenticationInfo{
RequestHeaderUsernameHeaders: headerrequest.StaticStringSlice{},
RequestHeaderUIDHeaders: headerrequest.StaticStringSlice{"panda"},
RequestHeaderGroupHeaders: headerrequest.StaticStringSlice{},
RequestHeaderExtraHeaderPrefixes: headerrequest.StaticStringSlice{},
RequestHeaderCA: anotherRandomCAProvider,
RequestHeaderAllowedNames: headerrequest.StaticStringSlice{},
},
preexistingObjs: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{
"requestheader-username-headers": `[]`,
"requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA),
"requestheader-allowed-names": `[]`,
},
},
},
expectedConfigMaps: map[string]*corev1.ConfigMap{
"extension-apiserver-authentication": {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{
"requestheader-username-headers": `[]`,
"requestheader-uid-headers": `["panda"]`,
"requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA),
"requestheader-allowed-names": `[]`,
},
},
},
expectCreate: false,
uidGate: true,
},
{
name: "append uid with feature gate",
clusterAuthInfo: ClusterAuthenticationInfo{
RequestHeaderUsernameHeaders: headerrequest.StaticStringSlice{},
RequestHeaderUIDHeaders: headerrequest.StaticStringSlice{"panda"},
RequestHeaderGroupHeaders: headerrequest.StaticStringSlice{},
RequestHeaderExtraHeaderPrefixes: headerrequest.StaticStringSlice{},
RequestHeaderCA: anotherRandomCAProvider,
RequestHeaderAllowedNames: headerrequest.StaticStringSlice{},
},
preexistingObjs: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{
"requestheader-username-headers": `[]`,
"requestheader-uid-headers": `["snorlax"]`,
"requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA),
"requestheader-allowed-names": `[]`,
},
},
},
expectedConfigMaps: map[string]*corev1.ConfigMap{
"extension-apiserver-authentication": {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{
"requestheader-username-headers": `[]`,
"requestheader-uid-headers": `["snorlax","panda"]`,
"requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA),
"requestheader-allowed-names": `[]`,
},
},
},
expectCreate: false,
uidGate: true,
},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RemoteRequestHeaderUID, test.uidGate)
client := fake.NewSimpleClientset(test.preexistingObjs...) client := fake.NewSimpleClientset(test.preexistingObjs...)
configMapIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) configMapIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
for _, obj := range test.preexistingObjs { for _, obj := range test.preexistingObjs {
@@ -341,7 +481,6 @@ func TestWriteConfigMapDeleted(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "extension-apiserver-authentication"},
Data: map[string]string{ Data: map[string]string{
"requestheader-username-headers": `[]`, "requestheader-username-headers": `[]`,
"requestheader-uid-headers": `[]`,
"requestheader-group-headers": `[]`, "requestheader-group-headers": `[]`,
"requestheader-extra-headers-prefix": `[]`, "requestheader-extra-headers-prefix": `[]`,
"requestheader-client-ca-file": string(anotherRandomCA), "requestheader-client-ca-file": string(anotherRandomCA),

View File

@@ -99,7 +99,7 @@ func SetFeatureGateEmulationVersionDuringTest(tb TB, gate featuregate.FeatureGat
detectParallelOverrideCleanup := detectParallelOverrideEmulationVersion(tb, ver) detectParallelOverrideCleanup := detectParallelOverrideEmulationVersion(tb, ver)
originalEmuVer := gate.(featuregate.MutableVersionedFeatureGate).EmulationVersion() originalEmuVer := gate.(featuregate.MutableVersionedFeatureGate).EmulationVersion()
if err := gate.(featuregate.MutableVersionedFeatureGate).SetEmulationVersion(ver); err != nil { if err := gate.(featuregate.MutableVersionedFeatureGate).SetEmulationVersion(ver); err != nil {
tb.Fatalf("failed to set emulation version to %s during test", ver.String()) tb.Fatalf("failed to set emulation version to %s during test: %v", ver.String(), err)
} }
tb.Cleanup(func() { tb.Cleanup(func() {
tb.Helper() tb.Helper()

View File

@@ -35,35 +35,33 @@ import (
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"k8s.io/apiserver/pkg/audit"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/server/dynamiccertificates"
"k8s.io/client-go/transport"
"golang.org/x/net/websocket"
"go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/sdk/trace/tracetest"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"golang.org/x/net/websocket"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
utilnet "k8s.io/apimachinery/pkg/util/net" utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/proxy" "k8s.io/apimachinery/pkg/util/proxy"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/audit"
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/endpoints/filters" "k8s.io/apiserver/pkg/endpoints/filters"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/server/dynamiccertificates"
"k8s.io/apiserver/pkg/server/egressselector" "k8s.io/apiserver/pkg/server/egressselector"
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
utilflowcontrol "k8s.io/apiserver/pkg/util/flowcontrol" utilflowcontrol "k8s.io/apiserver/pkg/util/flowcontrol"
apiserverproxyutil "k8s.io/apiserver/pkg/util/proxy" apiserverproxyutil "k8s.io/apiserver/pkg/util/proxy"
"k8s.io/client-go/transport"
"k8s.io/component-base/featuregate" "k8s.io/component-base/featuregate"
featuregatetesting "k8s.io/component-base/featuregate/testing" featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/component-base/metrics" "k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/legacyregistry" "k8s.io/component-base/metrics/legacyregistry"
apiregistration "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" apiregistration "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
"k8s.io/utils/pointer"
"k8s.io/utils/ptr" "k8s.io/utils/ptr"
) )
@@ -145,7 +143,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
}, },
@@ -168,7 +166,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
InsecureSkipTLSVerify: true, InsecureSkipTLSVerify: true,
@@ -201,7 +199,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
InsecureSkipTLSVerify: true, InsecureSkipTLSVerify: true,
@@ -236,7 +234,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
CABundle: testCACrt, CABundle: testCACrt,
@@ -269,7 +267,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
CABundle: testCACrt, CABundle: testCACrt,
@@ -304,7 +302,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
CABundle: testCACrt, CABundle: testCACrt,
@@ -328,7 +326,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Name: "bad-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "bad-service", Namespace: "test-ns", Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
CABundle: testCACrt, CABundle: testCACrt,
@@ -351,7 +349,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
}, },
@@ -373,7 +371,7 @@ func TestProxyHandler(t *testing.T) {
apiService: &apiregistration.APIService{ apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
CABundle: testCACrt, CABundle: testCACrt,
@@ -511,6 +509,8 @@ func newBrokenDialerAndSelector() (*mockEgressDialer, *egressselector.EgressSele
} }
func TestProxyUpgrade(t *testing.T) { func TestProxyUpgrade(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RemoteRequestHeaderUID, true)
upgradeUser := "upgradeUser" upgradeUser := "upgradeUser"
upgradeUID := "upgradeUser-UID" upgradeUID := "upgradeUser-UID"
testcases := map[string]struct { testcases := map[string]struct {
@@ -525,7 +525,7 @@ func TestProxyUpgrade(t *testing.T) {
CABundle: testCACrt, CABundle: testCACrt,
Group: "mygroup", Group: "mygroup",
Version: "v1", Version: "v1",
Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: ptr.To[int32](443)},
}, },
Status: apiregistration.APIServiceStatus{ Status: apiregistration.APIServiceStatus{
Conditions: []apiregistration.APIServiceCondition{ Conditions: []apiregistration.APIServiceCondition{
@@ -542,7 +542,7 @@ func TestProxyUpgrade(t *testing.T) {
InsecureSkipTLSVerify: true, InsecureSkipTLSVerify: true,
Group: "mygroup", Group: "mygroup",
Version: "v1", Version: "v1",
Service: &apiregistration.ServiceReference{Name: "invalid-service", Namespace: "invalid-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "invalid-service", Namespace: "invalid-ns", Port: ptr.To[int32](443)},
}, },
Status: apiregistration.APIServiceStatus{ Status: apiregistration.APIServiceStatus{
Conditions: []apiregistration.APIServiceCondition{ Conditions: []apiregistration.APIServiceCondition{
@@ -559,7 +559,7 @@ func TestProxyUpgrade(t *testing.T) {
CABundle: testCACrt, CABundle: testCACrt,
Group: "mygroup", Group: "mygroup",
Version: "v1", Version: "v1",
Service: &apiregistration.ServiceReference{Name: "invalid-service", Namespace: "invalid-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "invalid-service", Namespace: "invalid-ns", Port: ptr.To[int32](443)},
}, },
Status: apiregistration.APIServiceStatus{ Status: apiregistration.APIServiceStatus{
Conditions: []apiregistration.APIServiceCondition{ Conditions: []apiregistration.APIServiceCondition{
@@ -576,7 +576,7 @@ func TestProxyUpgrade(t *testing.T) {
CABundle: testCACrt, CABundle: testCACrt,
Group: "mygroup", Group: "mygroup",
Version: "v1", Version: "v1",
Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: ptr.To[int32](443)},
}, },
Status: apiregistration.APIServiceStatus{ Status: apiregistration.APIServiceStatus{
Conditions: []apiregistration.APIServiceCondition{ Conditions: []apiregistration.APIServiceCondition{
@@ -594,7 +594,7 @@ func TestProxyUpgrade(t *testing.T) {
CABundle: testCACrt, CABundle: testCACrt,
Group: "mygroup", Group: "mygroup",
Version: "v1", Version: "v1",
Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: ptr.To[int32](443)},
}, },
Status: apiregistration.APIServiceStatus{ Status: apiregistration.APIServiceStatus{
Conditions: []apiregistration.APIServiceCondition{ Conditions: []apiregistration.APIServiceCondition{
@@ -1075,7 +1075,7 @@ func TestProxyCertReload(t *testing.T) {
apiService := &apiregistration.APIService{ apiService := &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
Spec: apiregistration.APIServiceSpec{ Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{Name: "test-service2", Namespace: "test-ns", Port: pointer.Int32Ptr(443)}, Service: &apiregistration.ServiceReference{Name: "test-service2", Namespace: "test-ns", Port: ptr.To[int32](443)},
Group: "foo", Group: "foo",
Version: "v1", Version: "v1",
CABundle: backendCaCertificate(), // used to validate backendCertificate() CABundle: backendCaCertificate(), // used to validate backendCertificate()

View File

@@ -27,7 +27,7 @@ import (
func main() { func main() {
ctx := genericapiserver.SetupSignalContext() ctx := genericapiserver.SetupSignalContext()
options := server.NewWardleServerOptions(os.Stdout, os.Stderr) options := server.NewWardleServerOptions(os.Stdout, os.Stderr)
cmd := server.NewCommandStartWardleServer(ctx, options) cmd := server.NewCommandStartWardleServer(ctx, options, false)
code := cli.Run(cmd) code := cli.Run(cmd)
os.Exit(code) os.Exit(code)
} }

View File

@@ -90,12 +90,15 @@ func NewWardleServerOptions(out, errOut io.Writer) *WardleServerOptions {
// NewCommandStartWardleServer provides a CLI handler for 'start master' command // NewCommandStartWardleServer provides a CLI handler for 'start master' command
// with a default WardleServerOptions. // with a default WardleServerOptions.
func NewCommandStartWardleServer(ctx context.Context, defaults *WardleServerOptions) *cobra.Command { func NewCommandStartWardleServer(ctx context.Context, defaults *WardleServerOptions, skipDefaultComponentGlobalsRegistrySet bool) *cobra.Command {
o := *defaults o := *defaults
cmd := &cobra.Command{ cmd := &cobra.Command{
Short: "Launch a wardle API server", Short: "Launch a wardle API server",
Long: "Launch a wardle API server", Long: "Launch a wardle API server",
PersistentPreRunE: func(*cobra.Command, []string) error { PersistentPreRunE: func(*cobra.Command, []string) error {
if skipDefaultComponentGlobalsRegistrySet {
return nil
}
return featuregate.DefaultComponentGlobalsRegistry.Set() return featuregate.DefaultComponentGlobalsRegistry.Set()
}, },
RunE: func(c *cobra.Command, args []string) error { RunE: func(c *cobra.Command, args []string) error {

View File

@@ -1058,6 +1058,12 @@
lockToDefault: true lockToDefault: true
preRelease: GA preRelease: GA
version: "1.29" version: "1.29"
- name: RemoteRequestHeaderUID
versionedSpecs:
- default: false
lockToDefault: false
preRelease: Alpha
version: "1.32"
- name: ResilientWatchCacheInitialization - name: ResilientWatchCacheInitialization
versionedSpecs: versionedSpecs:
- default: true - default: true

View File

@@ -27,11 +27,14 @@ import (
authnv1 "k8s.io/api/authentication/v1" authnv1 "k8s.io/api/authentication/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/features"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
"k8s.io/client-go/util/keyutil" "k8s.io/client-go/util/keyutil"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options" "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
"k8s.io/kubernetes/test/integration/framework" "k8s.io/kubernetes/test/integration/framework"
testutils "k8s.io/kubernetes/test/utils" testutils "k8s.io/kubernetes/test/utils"
@@ -39,6 +42,8 @@ import (
) )
func TestAuthnToKAS(t *testing.T) { func TestAuthnToKAS(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RemoteRequestHeaderUID, true)
tCtx := ktesting.Init(t) tCtx := ktesting.Init(t)
frontProxyCA, frontProxyClient, frontProxyKey, err := newTestCAWithClient( frontProxyCA, frontProxyClient, frontProxyKey, err := newTestCAWithClient(

View File

@@ -45,8 +45,10 @@ import (
"k8s.io/apiserver/pkg/authentication/serviceaccount" "k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/server/dynamiccertificates" "k8s.io/apiserver/pkg/server/dynamiccertificates"
genericapiserveroptions "k8s.io/apiserver/pkg/server/options" genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
utilfeature "k8s.io/apiserver/pkg/util/feature"
client "k8s.io/client-go/kubernetes" client "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
@@ -54,6 +56,7 @@ import (
"k8s.io/client-go/transport" "k8s.io/client-go/transport"
"k8s.io/client-go/util/cert" "k8s.io/client-go/util/cert"
"k8s.io/component-base/featuregate" "k8s.io/component-base/featuregate"
featuregatetesting "k8s.io/component-base/featuregate/testing"
utilversion "k8s.io/component-base/version" utilversion "k8s.io/component-base/version"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
@@ -260,6 +263,7 @@ func TestFrontProxyConfig(t *testing.T) {
testFrontProxyConfig(t, false) testFrontProxyConfig(t, false)
}) })
t.Run("WithUID", func(t *testing.T) { t.Run("WithUID", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RemoteRequestHeaderUID, true)
testFrontProxyConfig(t, true) testFrontProxyConfig(t, true)
}) })
} }
@@ -282,7 +286,7 @@ func testFrontProxyConfig(t *testing.T, withUID bool) {
kubeBinaryVersion := sampleserver.WardleVersionToKubeVersion(version.MustParse(wardleBinaryVersion)).String() kubeBinaryVersion := sampleserver.WardleVersionToKubeVersion(version.MustParse(wardleBinaryVersion)).String()
// start up the KAS and prepare the options for the wardle API server // start up the KAS and prepare the options for the wardle API server
testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, kubeBinaryVersion, wardleBinaryVersion, extraKASFlags) testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, kubeBinaryVersion, wardleBinaryVersion, extraKASFlags, withUID)
kubeConfig := getKubeConfig(testKAS) kubeConfig := getKubeConfig(testKAS)
// create the SA that we will use to query the aggregated API // create the SA that we will use to query the aggregated API
@@ -337,12 +341,12 @@ func testFrontProxyConfig(t *testing.T, withUID bool) {
transport.WrapperFunc(func(rt http.RoundTripper) http.RoundTripper { transport.WrapperFunc(func(rt http.RoundTripper) http.RoundTripper {
return roundTripperFunc(func(req *http.Request) (*http.Response, error) { return roundTripperFunc(func(req *http.Request) (*http.Response, error) {
gotUser, ok := genericapirequest.UserFrom(req.Context()) gotUser, ok := genericapirequest.UserFrom(req.Context())
if !ok || gotUser.GetName() == "system:anonymous" { if !ok {
return nil, fmt.Errorf("got an unauthenticated request") return nil, fmt.Errorf("got an unauthenticated request")
} }
// this is likely the KAS checking the OpenAPI endpoints // this is likely the KAS checking the OpenAPI endpoints
if gotUser.GetName() == "system:anonymous" || gotUser.GetName() == "system:aggregator" { if gotUser.GetName() == "system:anonymous" || gotUser.GetName() == "system:aggregator" || gotUser.GetName() == "system:kube-aggregator" {
return rt.RoundTrip(req) return rt.RoundTrip(req)
} }
@@ -368,7 +372,7 @@ func testFrontProxyConfig(t *testing.T, withUID bool) {
wardleCertDir, _ := os.MkdirTemp("", "test-integration-wardle-server") wardleCertDir, _ := os.MkdirTemp("", "test-integration-wardle-server")
defer os.RemoveAll(wardleCertDir) defer os.RemoveAll(wardleCertDir)
runPreparedWardleServer(ctx, t, wardleOptions, wardleCertDir, wardlePort, false, true, wardleBinaryVersion, kubeConfig) runPreparedWardleServer(ctx, t, wardleOptions, wardleCertDir, wardlePort, false, true, wardleBinaryVersion, kubeConfig, withUID)
waitForWardleAPIServiceReady(ctx, t, kubeConfig, wardleCertDir, testNamespace) waitForWardleAPIServiceReady(ctx, t, kubeConfig, wardleCertDir, testNamespace)
// get the wardle API client using our SA token // get the wardle API client using our SA token
@@ -401,13 +405,13 @@ func testAggregatedAPIServer(t *testing.T, setWardleFeatureGate, banFlunder bool
// each wardle binary is bundled with a specific kube binary. // each wardle binary is bundled with a specific kube binary.
kubeBinaryVersion := sampleserver.WardleVersionToKubeVersion(version.MustParse(wardleBinaryVersion)).String() kubeBinaryVersion := sampleserver.WardleVersionToKubeVersion(version.MustParse(wardleBinaryVersion)).String()
testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, kubeBinaryVersion, wardleBinaryVersion, nil) testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, kubeBinaryVersion, wardleBinaryVersion, nil, false)
kubeClientConfig := getKubeConfig(testKAS) kubeClientConfig := getKubeConfig(testKAS)
wardleCertDir, _ := os.MkdirTemp("", "test-integration-wardle-server") wardleCertDir, _ := os.MkdirTemp("", "test-integration-wardle-server")
defer os.RemoveAll(wardleCertDir) defer os.RemoveAll(wardleCertDir)
directWardleClientConfig := runPreparedWardleServer(ctx, t, wardleOptions, wardleCertDir, wardlePort, setWardleFeatureGate, banFlunder, wardleEmulationVersion, kubeClientConfig) directWardleClientConfig := runPreparedWardleServer(ctx, t, wardleOptions, wardleCertDir, wardlePort, setWardleFeatureGate, banFlunder, wardleEmulationVersion, kubeClientConfig, false)
// now we're finally ready to test. These are what's run by default now // now we're finally ready to test. These are what's run by default now
wardleDirectClient := client.NewForConfigOrDie(directWardleClientConfig) wardleDirectClient := client.NewForConfigOrDie(directWardleClientConfig)
@@ -681,7 +685,7 @@ func TestAggregatedAPIServerRejectRedirectResponse(t *testing.T) {
} }
} }
func prepareAggregatedWardleAPIServer(ctx context.Context, t *testing.T, namespace, kubebinaryVersion, wardleBinaryVersion string, kubeAPIServerFlags []string) (*kastesting.TestServer, *sampleserver.WardleServerOptions, int) { func prepareAggregatedWardleAPIServer(ctx context.Context, t *testing.T, namespace, kubebinaryVersion, wardleBinaryVersion string, kubeAPIServerFlags []string, withUID bool) (*kastesting.TestServer, *sampleserver.WardleServerOptions, int) {
// makes the kube-apiserver very responsive. it's normally a minute // makes the kube-apiserver very responsive. it's normally a minute
dynamiccertificates.FileRefreshDuration = 1 * time.Second dynamiccertificates.FileRefreshDuration = 1 * time.Second
@@ -693,6 +697,11 @@ func prepareAggregatedWardleAPIServer(ctx context.Context, t *testing.T, namespa
// endpoints cannot have loopback IPs so we need to override the resolver itself // endpoints cannot have loopback IPs so we need to override the resolver itself
t.Cleanup(app.SetServiceResolverForTests(staticURLServiceResolver(fmt.Sprintf("https://127.0.0.1:%d", wardlePort)))) t.Cleanup(app.SetServiceResolverForTests(staticURLServiceResolver(fmt.Sprintf("https://127.0.0.1:%d", wardlePort))))
// TODO figure out how to actually make BinaryVersion/EmulationVersion work with Wardle and KAS at the same time when Alpha FG are being set
if withUID {
kubebinaryVersion = ""
}
testServer := kastesting.StartTestServerOrDie(t, testServer := kastesting.StartTestServerOrDie(t,
&kastesting.TestServerInstanceOptions{ &kastesting.TestServerInstanceOptions{
EnableCertAuth: true, EnableCertAuth: true,
@@ -751,6 +760,7 @@ func runPreparedWardleServer(
banFlunder bool, banFlunder bool,
emulationVersion string, emulationVersion string,
kubeConfig *rest.Config, kubeConfig *rest.Config,
withUID bool,
) *rest.Config { ) *rest.Config {
// start the wardle server to prove we can aggregate it // start the wardle server to prove we can aggregate it
@@ -769,7 +779,8 @@ func runPreparedWardleServer(
if flunderBanningFeatureGate { if flunderBanningFeatureGate {
args = append(args, "--feature-gates", fmt.Sprintf("wardle:BanFlunder=%v", banFlunder)) args = append(args, "--feature-gates", fmt.Sprintf("wardle:BanFlunder=%v", banFlunder))
} }
wardleCmd := sampleserver.NewCommandStartWardleServer(ctx, wardleOptions) // TODO figure out how to actually make BinaryVersion/EmulationVersion work with Wardle and KAS at the same time when Alpha FG are being set
wardleCmd := sampleserver.NewCommandStartWardleServer(ctx, wardleOptions, withUID)
wardleCmd.SetArgs(args) wardleCmd.SetArgs(args)
if err := wardleCmd.Execute(); err != nil { if err := wardleCmd.Execute(); err != nil {
t.Error(err) t.Error(err)