mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	featuregate UID in RequestHeader authenticator
This commit is contained in:
		@@ -35,7 +35,9 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"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"
 | 
				
			||||||
	corev1informers "k8s.io/client-go/informers/core/v1"
 | 
						corev1informers "k8s.io/client-go/informers/core/v1"
 | 
				
			||||||
	"k8s.io/client-go/kubernetes"
 | 
						"k8s.io/client-go/kubernetes"
 | 
				
			||||||
	corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
 | 
						corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
 | 
				
			||||||
@@ -262,10 +264,13 @@ func getConfigMapDataFor(authenticationInfo ClusterAuthenticationInfo) (map[stri
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if utilfeature.DefaultFeatureGate.Enabled(features.RemoteRequestHeaderUID) && len(authenticationInfo.RequestHeaderUIDHeaders.Value()) > 0 {
 | 
				
			||||||
			data["requestheader-uid-headers"], err = jsonSerializeStringSlice(authenticationInfo.RequestHeaderUIDHeaders.Value())
 | 
								data["requestheader-uid-headers"], err = jsonSerializeStringSlice(authenticationInfo.RequestHeaderUIDHeaders.Value())
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		data["requestheader-group-headers"], err = jsonSerializeStringSlice(authenticationInfo.RequestHeaderGroupHeaders.Value())
 | 
							data["requestheader-group-headers"], err = jsonSerializeStringSlice(authenticationInfo.RequestHeaderGroupHeaders.Value())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
@@ -305,10 +310,13 @@ func getClusterAuthenticationInfoFor(data map[string]string) (ClusterAuthenticat
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return ClusterAuthenticationInfo{}, err
 | 
							return ClusterAuthenticationInfo{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if utilfeature.DefaultFeatureGate.Enabled(features.RemoteRequestHeaderUID) {
 | 
				
			||||||
		ret.RequestHeaderUIDHeaders, err = jsonDeserializeStringSlice(data["requestheader-uid-headers"])
 | 
							ret.RequestHeaderUIDHeaders, err = jsonDeserializeStringSlice(data["requestheader-uid-headers"])
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return ClusterAuthenticationInfo{}, err
 | 
								return ClusterAuthenticationInfo{}, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if caBundle := data["requestheader-client-ca-file"]; len(caBundle) > 0 {
 | 
						if caBundle := data["requestheader-client-ca-file"]; len(caBundle) > 0 {
 | 
				
			||||||
		ret.RequestHeaderCA, err = dynamiccertificates.NewStaticCAContent("existing", []byte(caBundle))
 | 
							ret.RequestHeaderCA, err = dynamiccertificates.NewStaticCAContent("existing", []byte(caBundle))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -306,6 +306,10 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
 | 
				
			|||||||
		{Version: version.MustParse("1.29"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
 | 
							{Version: version.MustParse("1.29"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						genericfeatures.RemoteRequestHeaderUID: {
 | 
				
			||||||
 | 
							{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	genericfeatures.ResilientWatchCacheInitialization: {
 | 
						genericfeatures.ResilientWatchCacheInitialization: {
 | 
				
			||||||
		{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
 | 
							{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -149,6 +149,13 @@ const (
 | 
				
			|||||||
	// to a chunking list request.
 | 
						// to a chunking list request.
 | 
				
			||||||
	RemainingItemCount featuregate.Feature = "RemainingItemCount"
 | 
						RemainingItemCount featuregate.Feature = "RemainingItemCount"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// owner: @stlaz
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Enable kube-apiserver to accept UIDs via request header authentication.
 | 
				
			||||||
 | 
						// This will also make the kube-apiserver's API aggregator add UIDs via standard
 | 
				
			||||||
 | 
						// headers when forwarding requests to the servers serving the aggregated API.
 | 
				
			||||||
 | 
						RemoteRequestHeaderUID featuregate.Feature = "RemoteRequestHeaderUID"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// owner: @wojtek-t
 | 
						// owner: @wojtek-t
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	// Enables resilient watchcache initialization to avoid controlplane
 | 
						// Enables resilient watchcache initialization to avoid controlplane
 | 
				
			||||||
@@ -359,6 +366,10 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
 | 
				
			|||||||
		{Version: version.MustParse("1.29"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
 | 
							{Version: version.MustParse("1.29"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RemoteRequestHeaderUID: {
 | 
				
			||||||
 | 
							{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ResilientWatchCacheInitialization: {
 | 
						ResilientWatchCacheInitialization: {
 | 
				
			||||||
		{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
 | 
							{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,8 +29,10 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/apis/apiserver"
 | 
						"k8s.io/apiserver/pkg/apis/apiserver"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
 | 
						"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/authentication/request/headerrequest"
 | 
						"k8s.io/apiserver/pkg/authentication/request/headerrequest"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/features"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server"
 | 
						"k8s.io/apiserver/pkg/server"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server/dynamiccertificates"
 | 
						"k8s.io/apiserver/pkg/server/dynamiccertificates"
 | 
				
			||||||
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/client-go/kubernetes"
 | 
						"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"
 | 
				
			||||||
@@ -68,9 +70,6 @@ func (s *RequestHeaderAuthenticationOptions) Validate() []error {
 | 
				
			|||||||
	if err := checkForWhiteSpaceOnly("requestheader-username-headers", s.UsernameHeaders...); err != nil {
 | 
						if err := checkForWhiteSpaceOnly("requestheader-username-headers", s.UsernameHeaders...); err != nil {
 | 
				
			||||||
		allErrors = append(allErrors, err)
 | 
							allErrors = append(allErrors, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := checkForWhiteSpaceOnly("requestheader-uid-headers", s.UIDHeaders...); err != nil {
 | 
					 | 
				
			||||||
		allErrors = append(allErrors, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := checkForWhiteSpaceOnly("requestheader-group-headers", s.GroupHeaders...); err != nil {
 | 
						if err := checkForWhiteSpaceOnly("requestheader-group-headers", s.GroupHeaders...); err != nil {
 | 
				
			||||||
		allErrors = append(allErrors, err)
 | 
							allErrors = append(allErrors, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -84,10 +83,6 @@ func (s *RequestHeaderAuthenticationOptions) Validate() []error {
 | 
				
			|||||||
	if len(s.UsernameHeaders) > 0 && !caseInsensitiveHas(s.UsernameHeaders, "X-Remote-User") {
 | 
						if len(s.UsernameHeaders) > 0 && !caseInsensitiveHas(s.UsernameHeaders, "X-Remote-User") {
 | 
				
			||||||
		klog.Warningf("--requestheader-username-headers is set without specifying the standard X-Remote-User header - API aggregation will not work")
 | 
							klog.Warningf("--requestheader-username-headers is set without specifying the standard X-Remote-User header - API aggregation will not work")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(s.UIDHeaders) > 0 && !caseInsensitiveHas(s.UIDHeaders, "X-Remote-Uid") {
 | 
					 | 
				
			||||||
		// this was added later and so we are able to error out
 | 
					 | 
				
			||||||
		allErrors = append(allErrors, fmt.Errorf("--requestheader-uid-headers is set without specifying the standard X-Remote-Uid header - API aggregation will not work"))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(s.GroupHeaders) > 0 && !caseInsensitiveHas(s.GroupHeaders, "X-Remote-Group") {
 | 
						if len(s.GroupHeaders) > 0 && !caseInsensitiveHas(s.GroupHeaders, "X-Remote-Group") {
 | 
				
			||||||
		klog.Warningf("--requestheader-group-headers is set without specifying the standard X-Remote-Group header - API aggregation will not work")
 | 
							klog.Warningf("--requestheader-group-headers is set without specifying the standard X-Remote-Group header - API aggregation will not work")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -95,6 +90,20 @@ func (s *RequestHeaderAuthenticationOptions) Validate() []error {
 | 
				
			|||||||
		klog.Warningf("--requestheader-extra-headers-prefix is set without specifying the standard X-Remote-Extra- header prefix - API aggregation will not work")
 | 
							klog.Warningf("--requestheader-extra-headers-prefix is set without specifying the standard X-Remote-Extra- header prefix - API aggregation will not work")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !utilfeature.DefaultFeatureGate.Enabled(features.RemoteRequestHeaderUID) {
 | 
				
			||||||
 | 
							if len(s.UIDHeaders) > 0 {
 | 
				
			||||||
 | 
								allErrors = append(allErrors, fmt.Errorf("--requestheader-uid-headers requires the %q feature to be enabled", features.RemoteRequestHeaderUID))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if err := checkForWhiteSpaceOnly("requestheader-uid-headers", s.UIDHeaders...); err != nil {
 | 
				
			||||||
 | 
								allErrors = append(allErrors, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(s.UIDHeaders) > 0 && !caseInsensitiveHas(s.UIDHeaders, "X-Remote-Uid") {
 | 
				
			||||||
 | 
								// this was added later and so we are able to error out
 | 
				
			||||||
 | 
								allErrors = append(allErrors, fmt.Errorf("--requestheader-uid-headers is set without specifying the standard X-Remote-Uid header - API aggregation will not work"))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return allErrors
 | 
						return allErrors
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -126,7 +135,7 @@ func (s *RequestHeaderAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
 | 
				
			|||||||
		"List of request headers to inspect for usernames. X-Remote-User is common.")
 | 
							"List of request headers to inspect for usernames. X-Remote-User is common.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fs.StringSliceVar(&s.UIDHeaders, "requestheader-uid-headers", s.UIDHeaders, ""+
 | 
						fs.StringSliceVar(&s.UIDHeaders, "requestheader-uid-headers", s.UIDHeaders, ""+
 | 
				
			||||||
		"List of request headers to inspect for UIDs. X-Remote-Uid is suggested.")
 | 
							"List of request headers to inspect for UIDs. X-Remote-Uid is suggested. Requires the RemoteRequestHeaderUID feature to be enabled.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fs.StringSliceVar(&s.GroupHeaders, "requestheader-group-headers", s.GroupHeaders, ""+
 | 
						fs.StringSliceVar(&s.GroupHeaders, "requestheader-group-headers", s.GroupHeaders, ""+
 | 
				
			||||||
		"List of request headers to inspect for groups. X-Remote-Group is suggested.")
 | 
							"List of request headers to inspect for groups. X-Remote-Group is suggested.")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -159,7 +159,12 @@ func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | 
				
			|||||||
	proxyRoundTripper := handlingInfo.proxyRoundTripper
 | 
						proxyRoundTripper := handlingInfo.proxyRoundTripper
 | 
				
			||||||
	upgrade := httpstream.IsUpgradeRequest(req)
 | 
						upgrade := httpstream.IsUpgradeRequest(req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), user.GetUID(), user.GetGroups(), user.GetExtra(), proxyRoundTripper)
 | 
						var userUID string
 | 
				
			||||||
 | 
						if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.RemoteRequestHeaderUID) {
 | 
				
			||||||
 | 
							userUID = user.GetUID()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), userUID, user.GetGroups(), user.GetExtra(), proxyRoundTripper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) && !upgrade {
 | 
						if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) && !upgrade {
 | 
				
			||||||
		tracingWrapper := tracing.WrapperFor(r.tracerProvider)
 | 
							tracingWrapper := tracing.WrapperFor(r.tracerProvider)
 | 
				
			||||||
@@ -170,7 +175,7 @@ func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | 
				
			|||||||
	// NOT use the proxyRoundTripper.  It's a direct dial that bypasses the proxyRoundTripper.  This means that we have to
 | 
						// NOT use the proxyRoundTripper.  It's a direct dial that bypasses the proxyRoundTripper.  This means that we have to
 | 
				
			||||||
	// attach the "correct" user headers to the request ahead of time.
 | 
						// attach the "correct" user headers to the request ahead of time.
 | 
				
			||||||
	if upgrade {
 | 
						if upgrade {
 | 
				
			||||||
		transport.SetAuthProxyHeaders(newReq, user.GetName(), user.GetUID(), user.GetGroups(), user.GetExtra())
 | 
							transport.SetAuthProxyHeaders(newReq, user.GetName(), userUID, user.GetGroups(), user.GetExtra())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handler := proxy.NewUpgradeAwareHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w})
 | 
						handler := proxy.NewUpgradeAwareHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,9 @@ import (
 | 
				
			|||||||
	"sync/atomic"
 | 
						"sync/atomic"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/google/go-cmp/cmp"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/audit"
 | 
						"k8s.io/apiserver/pkg/audit"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/features"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server/dynamiccertificates"
 | 
						"k8s.io/apiserver/pkg/server/dynamiccertificates"
 | 
				
			||||||
	"k8s.io/client-go/transport"
 | 
						"k8s.io/client-go/transport"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,8 +55,11 @@ import (
 | 
				
			|||||||
	"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/server/egressselector"
 | 
						"k8s.io/apiserver/pkg/server/egressselector"
 | 
				
			||||||
 | 
						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/component-base/featuregate"
 | 
				
			||||||
 | 
						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"
 | 
				
			||||||
@@ -130,6 +135,8 @@ func TestProxyHandler(t *testing.T) {
 | 
				
			|||||||
		expectedBody       string
 | 
							expectedBody       string
 | 
				
			||||||
		expectedCalled     bool
 | 
							expectedCalled     bool
 | 
				
			||||||
		expectedHeaders    map[string][]string
 | 
							expectedHeaders    map[string][]string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							enableFeatureGates []featuregate.Feature
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		"no target": {
 | 
							"no target": {
 | 
				
			||||||
			expectedStatusCode: http.StatusNotFound,
 | 
								expectedStatusCode: http.StatusNotFound,
 | 
				
			||||||
@@ -174,6 +181,40 @@ func TestProxyHandler(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			expectedStatusCode: http.StatusOK,
 | 
								expectedStatusCode: http.StatusOK,
 | 
				
			||||||
			expectedCalled:     true,
 | 
								expectedCalled:     true,
 | 
				
			||||||
 | 
								expectedHeaders: map[string][]string{
 | 
				
			||||||
 | 
									"X-Forwarded-Proto": {"https"},
 | 
				
			||||||
 | 
									"X-Forwarded-Uri":   {"/request/path"},
 | 
				
			||||||
 | 
									"X-Forwarded-For":   {"127.0.0.1"},
 | 
				
			||||||
 | 
									"X-Remote-User":     {"username"},
 | 
				
			||||||
 | 
									"User-Agent":        {"Go-http-client/1.1"},
 | 
				
			||||||
 | 
									"Accept-Encoding":   {"gzip"},
 | 
				
			||||||
 | 
									"X-Remote-Group":    {"one", "two"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"[RemoteRequestHeaderUID] proxy with user, insecure": {
 | 
				
			||||||
 | 
								user: &user.DefaultInfo{
 | 
				
			||||||
 | 
									Name:   "username",
 | 
				
			||||||
 | 
									UID:    "6b60d791-1af9-4513-92e5-e4252a1e0a78",
 | 
				
			||||||
 | 
									Groups: []string{"one", "two"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								path: "/request/path",
 | 
				
			||||||
 | 
								apiService: &apiregistration.APIService{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
 | 
				
			||||||
 | 
									Spec: apiregistration.APIServiceSpec{
 | 
				
			||||||
 | 
										Service:               &apiregistration.ServiceReference{Port: pointer.Int32Ptr(443)},
 | 
				
			||||||
 | 
										Group:                 "foo",
 | 
				
			||||||
 | 
										Version:               "v1",
 | 
				
			||||||
 | 
										InsecureSkipTLSVerify: true,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: apiregistration.APIServiceStatus{
 | 
				
			||||||
 | 
										Conditions: []apiregistration.APIServiceCondition{
 | 
				
			||||||
 | 
											{Type: apiregistration.Available, Status: apiregistration.ConditionTrue},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								enableFeatureGates: []featuregate.Feature{features.RemoteRequestHeaderUID},
 | 
				
			||||||
 | 
								expectedStatusCode: http.StatusOK,
 | 
				
			||||||
 | 
								expectedCalled:     true,
 | 
				
			||||||
			expectedHeaders: map[string][]string{
 | 
								expectedHeaders: map[string][]string{
 | 
				
			||||||
				"X-Forwarded-Proto": {"https"},
 | 
									"X-Forwarded-Proto": {"https"},
 | 
				
			||||||
				"X-Forwarded-Uri":   {"/request/path"},
 | 
									"X-Forwarded-Uri":   {"/request/path"},
 | 
				
			||||||
@@ -208,6 +249,40 @@ func TestProxyHandler(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			expectedStatusCode: http.StatusOK,
 | 
								expectedStatusCode: http.StatusOK,
 | 
				
			||||||
			expectedCalled:     true,
 | 
								expectedCalled:     true,
 | 
				
			||||||
 | 
								expectedHeaders: map[string][]string{
 | 
				
			||||||
 | 
									"X-Forwarded-Proto": {"https"},
 | 
				
			||||||
 | 
									"X-Forwarded-Uri":   {"/request/path"},
 | 
				
			||||||
 | 
									"X-Forwarded-For":   {"127.0.0.1"},
 | 
				
			||||||
 | 
									"X-Remote-User":     {"username"},
 | 
				
			||||||
 | 
									"User-Agent":        {"Go-http-client/1.1"},
 | 
				
			||||||
 | 
									"Accept-Encoding":   {"gzip"},
 | 
				
			||||||
 | 
									"X-Remote-Group":    {"one", "two"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"[RemoteRequestHeaderUID] proxy with user, cabundle": {
 | 
				
			||||||
 | 
								user: &user.DefaultInfo{
 | 
				
			||||||
 | 
									Name:   "username",
 | 
				
			||||||
 | 
									UID:    "6b60d791-1af9-4513-92e5-e4252a1e0a78",
 | 
				
			||||||
 | 
									Groups: []string{"one", "two"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								path: "/request/path",
 | 
				
			||||||
 | 
								apiService: &apiregistration.APIService{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"},
 | 
				
			||||||
 | 
									Spec: apiregistration.APIServiceSpec{
 | 
				
			||||||
 | 
										Service:  &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns", Port: pointer.Int32Ptr(443)},
 | 
				
			||||||
 | 
										Group:    "foo",
 | 
				
			||||||
 | 
										Version:  "v1",
 | 
				
			||||||
 | 
										CABundle: testCACrt,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: apiregistration.APIServiceStatus{
 | 
				
			||||||
 | 
										Conditions: []apiregistration.APIServiceCondition{
 | 
				
			||||||
 | 
											{Type: apiregistration.Available, Status: apiregistration.ConditionTrue},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								enableFeatureGates: []featuregate.Feature{features.RemoteRequestHeaderUID},
 | 
				
			||||||
 | 
								expectedStatusCode: http.StatusOK,
 | 
				
			||||||
 | 
								expectedCalled:     true,
 | 
				
			||||||
			expectedHeaders: map[string][]string{
 | 
								expectedHeaders: map[string][]string{
 | 
				
			||||||
				"X-Forwarded-Proto": {"https"},
 | 
									"X-Forwarded-Proto": {"https"},
 | 
				
			||||||
				"X-Forwarded-Uri":   {"/request/path"},
 | 
									"X-Forwarded-Uri":   {"/request/path"},
 | 
				
			||||||
@@ -320,7 +395,11 @@ func TestProxyHandler(t *testing.T) {
 | 
				
			|||||||
		target.Reset()
 | 
							target.Reset()
 | 
				
			||||||
		legacyregistry.Reset()
 | 
							legacyregistry.Reset()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		func() {
 | 
							t.Run(name, func(t *testing.T) {
 | 
				
			||||||
 | 
								for _, f := range tc.enableFeatureGates {
 | 
				
			||||||
 | 
									featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, f, true)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			targetServer := httptest.NewUnstartedServer(target)
 | 
								targetServer := httptest.NewUnstartedServer(target)
 | 
				
			||||||
			serviceCert := tc.serviceCertOverride
 | 
								serviceCert := tc.serviceCertOverride
 | 
				
			||||||
			if serviceCert == nil {
 | 
								if serviceCert == nil {
 | 
				
			||||||
@@ -354,37 +433,37 @@ func TestProxyHandler(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			resp, err := http.Get(server.URL + tc.path)
 | 
								resp, err := http.Get(server.URL + tc.path)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Errorf("%s: %v", name, err)
 | 
									t.Errorf("%v", err)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if e, a := tc.expectedStatusCode, resp.StatusCode; e != a {
 | 
								if e, a := tc.expectedStatusCode, resp.StatusCode; e != a {
 | 
				
			||||||
				body, _ := httputil.DumpResponse(resp, true)
 | 
									body, _ := httputil.DumpResponse(resp, true)
 | 
				
			||||||
				t.Logf("%s: %v", name, string(body))
 | 
									t.Logf("%v", string(body))
 | 
				
			||||||
				t.Errorf("%s: expected %v, got %v", name, e, a)
 | 
									t.Errorf("expected %v, got %v", e, a)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			bytes, err := io.ReadAll(resp.Body)
 | 
								bytes, err := io.ReadAll(resp.Body)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Errorf("%s: %v", name, err)
 | 
									t.Errorf("%v", err)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if !strings.Contains(string(bytes), tc.expectedBody) {
 | 
								if !strings.Contains(string(bytes), tc.expectedBody) {
 | 
				
			||||||
				t.Errorf("%s: expected %q, got %q", name, tc.expectedBody, string(bytes))
 | 
									t.Errorf("expected %q, got %q", tc.expectedBody, string(bytes))
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if e, a := tc.expectedCalled, target.called; e != a {
 | 
								if e, a := tc.expectedCalled, target.called; e != a {
 | 
				
			||||||
				t.Errorf("%s: expected %v, got %v", name, e, a)
 | 
									t.Errorf("expected %v, got %v", e, a)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// this varies every test
 | 
								// this varies every test
 | 
				
			||||||
			delete(target.headers, "X-Forwarded-Host")
 | 
								delete(target.headers, "X-Forwarded-Host")
 | 
				
			||||||
			if e, a := tc.expectedHeaders, target.headers; !reflect.DeepEqual(e, a) {
 | 
								if e, a := tc.expectedHeaders, target.headers; !reflect.DeepEqual(e, a) {
 | 
				
			||||||
				t.Errorf("%s: expected %v, got %v", name, e, a)
 | 
									t.Errorf("expected != got %v", cmp.Diff(e, a))
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if e, a := targetServer.Listener.Addr().String(), target.host; tc.expectedCalled && !reflect.DeepEqual(e, a) {
 | 
								if e, a := targetServer.Listener.Addr().String(), target.host; tc.expectedCalled && !reflect.DeepEqual(e, a) {
 | 
				
			||||||
				t.Errorf("%s: expected %v, got %v", name, e, a)
 | 
									t.Errorf("expected %v, got %v", e, a)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -397,7 +476,7 @@ func TestProxyHandler(t *testing.T) {
 | 
				
			|||||||
					t.Errorf("expected the x509_missing_san_total to be 1, but it's %d", errorCounter)
 | 
										t.Errorf("expected the x509_missing_san_total to be 1, but it's %d", errorCounter)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user