Skip to content

Commit 474db72

Browse files
jindijamieenj
authored andcommitted
Add an option for aggregator
1 parent cd37983 commit 474db72

File tree

7 files changed

+132
-8
lines changed

7 files changed

+132
-8
lines changed

Diff for: cmd/kube-apiserver/app/aggregator.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,11 @@ func createAggregatorConfig(
111111
SharedInformerFactory: externalInformers,
112112
},
113113
ExtraConfig: aggregatorapiserver.ExtraConfig{
114-
ProxyClientCertFile: commandOptions.ProxyClientCertFile,
115-
ProxyClientKeyFile: commandOptions.ProxyClientKeyFile,
116-
ServiceResolver: serviceResolver,
117-
ProxyTransport: proxyTransport,
114+
ProxyClientCertFile: commandOptions.ProxyClientCertFile,
115+
ProxyClientKeyFile: commandOptions.ProxyClientKeyFile,
116+
ServiceResolver: serviceResolver,
117+
ProxyTransport: proxyTransport,
118+
RejectForwardingRedirects: commandOptions.AggregatorRejectForwardingRedirects,
118119
},
119120
}
120121

Diff for: cmd/kube-apiserver/app/options/options.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ type ServerRunOptions struct {
7676
ProxyClientCertFile string
7777
ProxyClientKeyFile string
7878

79-
EnableAggregatorRouting bool
79+
EnableAggregatorRouting bool
80+
AggregatorRejectForwardingRedirects bool
8081

8182
MasterCount int
8283
EndpointReconcilerType string
@@ -132,7 +133,8 @@ func NewServerRunOptions() *ServerRunOptions {
132133
},
133134
HTTPTimeout: time.Duration(5) * time.Second,
134135
},
135-
ServiceNodePortRange: kubeoptions.DefaultServiceNodePortRange,
136+
ServiceNodePortRange: kubeoptions.DefaultServiceNodePortRange,
137+
AggregatorRejectForwardingRedirects: true,
136138
}
137139

138140
// Overwrite the default for storage data format.
@@ -244,6 +246,9 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) {
244246
fs.BoolVar(&s.EnableAggregatorRouting, "enable-aggregator-routing", s.EnableAggregatorRouting,
245247
"Turns on aggregator routing requests to endpoints IP rather than cluster IP.")
246248

249+
fs.BoolVar(&s.AggregatorRejectForwardingRedirects, "aggregator-reject-forwarding-redirect", s.AggregatorRejectForwardingRedirects,
250+
"Aggregator reject forwarding redirect response back to client.")
251+
247252
fs.StringVar(&s.ServiceAccountSigningKeyFile, "service-account-signing-key-file", s.ServiceAccountSigningKeyFile, ""+
248253
"Path to the file that contains the current private key of the service account token issuer. The issuer will sign issued ID tokens with this private key.")
249254

Diff for: cmd/kube-apiserver/app/options/options_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,9 @@ func TestAddFlags(t *testing.T) {
318318
Traces: &apiserveroptions.TracingOptions{
319319
ConfigFile: "/var/run/kubernetes/tracing_config.yaml",
320320
},
321-
IdentityLeaseDurationSeconds: 3600,
322-
IdentityLeaseRenewIntervalSeconds: 10,
321+
IdentityLeaseDurationSeconds: 3600,
322+
IdentityLeaseRenewIntervalSeconds: 10,
323+
AggregatorRejectForwardingRedirects: true,
323324
}
324325

325326
if !reflect.DeepEqual(expected, s) {

Diff for: staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go

+27
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ type UpgradeAwareHandler struct {
8383
MaxBytesPerSec int64
8484
// Responder is passed errors that occur while setting up proxying.
8585
Responder ErrorResponder
86+
// Reject to forward redirect response
87+
RejectForwardingRedirects bool
8688
}
8789

8890
const defaultFlushInterval = 200 * time.Millisecond
@@ -257,6 +259,31 @@ func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request
257259
proxy.Transport = h.Transport
258260
proxy.FlushInterval = h.FlushInterval
259261
proxy.ErrorLog = log.New(noSuppressPanicError{}, "", log.LstdFlags)
262+
if h.RejectForwardingRedirects {
263+
oldModifyResponse := proxy.ModifyResponse
264+
proxy.ModifyResponse = func(response *http.Response) error {
265+
code := response.StatusCode
266+
if code >= 300 && code <= 399 {
267+
// close the original response
268+
response.Body.Close()
269+
msg := "the backend attempted to redirect this request, which is not permitted"
270+
// replace the response
271+
*response = http.Response{
272+
StatusCode: http.StatusBadGateway,
273+
Status: fmt.Sprintf("%d %s", response.StatusCode, http.StatusText(response.StatusCode)),
274+
Body: io.NopCloser(strings.NewReader(msg)),
275+
ContentLength: int64(len(msg)),
276+
}
277+
} else {
278+
if oldModifyResponse != nil {
279+
if err := oldModifyResponse(response); err != nil {
280+
return err
281+
}
282+
}
283+
}
284+
return nil
285+
}
286+
}
260287
if h.Responder != nil {
261288
// if an optional error interceptor/responder was provided wire it
262289
// the custom responder might be used for providing a unified error reporting

Diff for: staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware_test.go

+77
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,83 @@ func TestProxyUpgradeErrorResponse(t *testing.T) {
704704
}
705705
}
706706

707+
func TestRejectForwardingRedirectsOption(t *testing.T) {
708+
originalBody := []byte(`some data`)
709+
testCases := []struct {
710+
name string
711+
rejectForwardingRedirects bool
712+
serverStatusCode int
713+
expectStatusCode int
714+
expectBody []byte
715+
}{
716+
{
717+
name: "reject redirection enabled in proxy, backend server sending 200 response",
718+
rejectForwardingRedirects: true,
719+
serverStatusCode: 200,
720+
expectStatusCode: 200,
721+
expectBody: originalBody,
722+
},
723+
{
724+
name: "reject redirection enabled in proxy, backend server sending 301 response",
725+
rejectForwardingRedirects: true,
726+
serverStatusCode: 301,
727+
expectStatusCode: 502,
728+
expectBody: []byte(`the backend attempted to redirect this request, which is not permitted`),
729+
},
730+
{
731+
name: "reject redirection disabled in proxy, backend server sending 200 response",
732+
rejectForwardingRedirects: false,
733+
serverStatusCode: 200,
734+
expectStatusCode: 200,
735+
expectBody: originalBody,
736+
},
737+
{
738+
name: "reject redirection disabled in proxy, backend server sending 301 response",
739+
rejectForwardingRedirects: false,
740+
serverStatusCode: 301,
741+
expectStatusCode: 301,
742+
expectBody: originalBody,
743+
},
744+
}
745+
for _, tc := range testCases {
746+
t.Run(tc.name, func(t *testing.T) {
747+
// Set up a backend server
748+
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
749+
w.WriteHeader(tc.serverStatusCode)
750+
w.Write(originalBody)
751+
}))
752+
defer backendServer.Close()
753+
backendServerURL, _ := url.Parse(backendServer.URL)
754+
755+
// Set up a proxy pointing to the backend
756+
proxyHandler := NewUpgradeAwareHandler(backendServerURL, nil, false, false, &fakeResponder{t: t})
757+
proxyHandler.RejectForwardingRedirects = tc.rejectForwardingRedirects
758+
proxy := httptest.NewServer(proxyHandler)
759+
defer proxy.Close()
760+
proxyURL, _ := url.Parse(proxy.URL)
761+
762+
conn, err := net.Dial("tcp", proxyURL.Host)
763+
require.NoError(t, err)
764+
bufferedReader := bufio.NewReader(conn)
765+
766+
req, _ := http.NewRequest("GET", proxyURL.String(), nil)
767+
require.NoError(t, req.Write(conn))
768+
// Verify we get the correct response and message body content
769+
resp, err := http.ReadResponse(bufferedReader, nil)
770+
require.NoError(t, err)
771+
assert.Equal(t, tc.expectStatusCode, resp.StatusCode)
772+
data, err := ioutil.ReadAll(resp.Body)
773+
require.NoError(t, err)
774+
assert.Equal(t, tc.expectBody, data)
775+
assert.Equal(t, int64(len(tc.expectBody)), resp.ContentLength)
776+
resp.Body.Close()
777+
778+
// clean up
779+
conn.Close()
780+
})
781+
}
782+
}
783+
707784
func TestDefaultProxyTransport(t *testing.T) {
708785
tests := []struct {
709786
name,

Diff for: staging/src/k8s.io/kube-aggregator/pkg/apiserver/apiserver.go

+7
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ type ExtraConfig struct {
8686

8787
// Mechanism by which the Aggregator will resolve services. Required.
8888
ServiceResolver ServiceResolver
89+
90+
RejectForwardingRedirects bool
8991
}
9092

9193
// Config represents the configuration needed to create an APIAggregator.
@@ -155,6 +157,9 @@ type APIAggregator struct {
155157
// egressSelector selects the proper egress dialer to communicate with the custom apiserver
156158
// overwrites proxyTransport dialer if not nil
157159
egressSelector *egressselector.EgressSelector
160+
161+
// rejectForwardingRedirects is whether to allow to forward redirect response
162+
rejectForwardingRedirects bool
158163
}
159164

160165
// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
@@ -212,6 +217,7 @@ func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.Deleg
212217
openAPIV3Config: c.GenericConfig.OpenAPIV3Config,
213218
egressSelector: c.GenericConfig.EgressSelector,
214219
proxyCurrentCertKeyContent: func() (bytes []byte, bytes2 []byte) { return nil, nil },
220+
rejectForwardingRedirects: c.ExtraConfig.RejectForwardingRedirects,
215221
}
216222

217223
// used later to filter the served resource by those that have expired.
@@ -442,6 +448,7 @@ func (s *APIAggregator) AddAPIService(apiService *v1.APIService) error {
442448
proxyTransport: s.proxyTransport,
443449
serviceResolver: s.serviceResolver,
444450
egressSelector: s.egressSelector,
451+
rejectForwardingRedirects: s.rejectForwardingRedirects,
445452
}
446453
proxyHandler.updateAPIService(apiService)
447454
if s.openAPIAggregationController != nil {

Diff for: staging/src/k8s.io/kube-aggregator/pkg/apiserver/handler_proxy.go

+6
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ type proxyHandler struct {
6868
// egressSelector selects the proper egress dialer to communicate with the custom apiserver
6969
// overwrites proxyTransport dialer if not nil
7070
egressSelector *egressselector.EgressSelector
71+
72+
// reject to forward redirect response
73+
rejectForwardingRedirects bool
7174
}
7275

7376
type proxyHandlingInfo struct {
@@ -172,6 +175,9 @@ func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
172175
}
173176

174177
handler := proxy.NewUpgradeAwareHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w})
178+
if r.rejectForwardingRedirects {
179+
handler.RejectForwardingRedirects = true
180+
}
175181
utilflowcontrol.RequestDelegated(req.Context())
176182
handler.ServeHTTP(w, newReq)
177183
}

0 commit comments

Comments
 (0)