impersonator: disallow clients from setting the X-Forwarded-For header
Signed-off-by: Monis Khan <mok@vmware.com>
This commit is contained in:
parent
c03fe2d1fe
commit
f519f0cb09
@ -19,6 +19,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/apimachinery/pkg/util/errors"
|
"k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||||
|
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
@ -315,6 +316,12 @@ func newImpersonationReverseProxyFunc(restConfig *rest.Config) (func(*genericapi
|
|||||||
"isUpgradeRequest", isUpgradeRequest,
|
"isUpgradeRequest", isUpgradeRequest,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// do not allow the client to cause log confusion by spoofing this header
|
||||||
|
if len(r.Header.Values("X-Forwarded-For")) > 0 {
|
||||||
|
r = utilnet.CloneRequest(r)
|
||||||
|
r.Header.Del("X-Forwarded-For")
|
||||||
|
}
|
||||||
|
|
||||||
reverseProxy := httputil.NewSingleHostReverseProxy(serverURL)
|
reverseProxy := httputil.NewSingleHostReverseProxy(serverURL)
|
||||||
reverseProxy.Transport = rt
|
reverseProxy.Transport = rt
|
||||||
reverseProxy.FlushInterval = 200 * time.Millisecond // the "watch" verb will not work without this line
|
reverseProxy.FlushInterval = 200 * time.Millisecond // the "watch" verb will not work without this line
|
||||||
|
@ -118,6 +118,40 @@ func TestImpersonator(t *testing.T) {
|
|||||||
"Upgrade": {"spdy/3.1"},
|
"Upgrade": {"spdy/3.1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "happy path ignores forwarded header",
|
||||||
|
clientCert: newClientCert(t, ca, "test-username2", []string{"test-group3", "test-group4"}),
|
||||||
|
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||||
|
clientMutateHeaders: func(header http.Header) {
|
||||||
|
header.Add("X-Forwarded-For", "example.com")
|
||||||
|
},
|
||||||
|
wantKubeAPIServerRequestHeaders: http.Header{
|
||||||
|
"Impersonate-User": {"test-username2"},
|
||||||
|
"Impersonate-Group": {"test-group3", "test-group4", "system:authenticated"},
|
||||||
|
"Authorization": {"Bearer some-service-account-token"},
|
||||||
|
"User-Agent": {"test-agent"},
|
||||||
|
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
|
||||||
|
"Accept-Encoding": {"gzip"},
|
||||||
|
"X-Forwarded-For": {"127.0.0.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy path ignores forwarded header canonicalization",
|
||||||
|
clientCert: newClientCert(t, ca, "test-username2", []string{"test-group3", "test-group4"}),
|
||||||
|
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||||
|
clientMutateHeaders: func(header http.Header) {
|
||||||
|
header.Add("x-FORWARDED-for", "example.com")
|
||||||
|
},
|
||||||
|
wantKubeAPIServerRequestHeaders: http.Header{
|
||||||
|
"Impersonate-User": {"test-username2"},
|
||||||
|
"Impersonate-Group": {"test-group3", "test-group4", "system:authenticated"},
|
||||||
|
"Authorization": {"Bearer some-service-account-token"},
|
||||||
|
"User-Agent": {"test-agent"},
|
||||||
|
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
|
||||||
|
"Accept-Encoding": {"gzip"},
|
||||||
|
"X-Forwarded-For": {"127.0.0.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "user is authenticated but the kube API request returns an error",
|
name: "user is authenticated but the kube API request returns an error",
|
||||||
kubeAPIServerStatusCode: http.StatusNotFound,
|
kubeAPIServerStatusCode: http.StatusNotFound,
|
||||||
|
Loading…
Reference in New Issue
Block a user