-
Notifications
You must be signed in to change notification settings - Fork 40k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Limit Apiserver Proxy Redirects #95128
Conversation
/assign @deads2k |
@@ -207,7 +208,7 @@ func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request | |||
// Redirect requests with an empty path to a location that ends with a '/' | |||
// This is essentially a hack for http://issue.k8s.io/4958. | |||
// Note: Keep this code after tryUpgrade to not break that flow. | |||
if len(loc.Path) == 0 { | |||
if len(loc.Path) == 0 && (method == http.MethodGet || method == http.MethodHead) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
limiting the redirect to GET/HEAD requests looks good to me.
by continuing with the normal proxy path for other methods (e.g. PUT/POST), what is the HTTP request this change would end up passing to the underlying pod if len(loc.Path)
was 0 here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my tests the other methods will pass through to the pod unaffected. Using kubectl proxy
, porter
and curl
I can get 200 OK response back from the pod for the other http methods.
$ curl -I -X POST http://localhost:9999/api/v1/namespaces/default/pods/agnhost-7bb97c7fb7-6k9dq/proxy
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Content-Length: 3
Content-Type: text/plain; charset=utf-8
Date: Wed, 30 Sep 2020 18:43:36 GMT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using this PR with an updated e2e test for NamespacedPodProxy endpoints gives
STEP: Creating a Pod
Oct 1 01:17:33.579: INFO: pod created
Oct 1 01:17:33.591: INFO: Pod Quantity: 1 Status: Pending
Oct 1 01:17:34.596: INFO: Pod Quantity: 1 Status: Pending
Oct 1 01:17:35.597: INFO: Pod Quantity: 1 Status: Pending
Oct 1 01:17:36.596: INFO: Pod Status: Running
Oct 1 01:17:36.596: INFO: Starting http.Client for https://127.0.0.1:41813/api/v1/namespaces/proxy-9664/pods/proxy-pod-target/proxy
Oct 1 01:17:36.600: INFO: http.Client request:GET StatusCode:301
Oct 1 01:17:36.603: INFO: http.Client request:HEAD StatusCode:301
Oct 1 01:17:36.608: INFO: http.Client request:DELETE StatusCode:200
Oct 1 01:17:36.612: INFO: http.Client request:OPTIONS StatusCode:200
Oct 1 01:17:36.616: INFO: http.Client request:PATCH StatusCode:200
Oct 1 01:17:36.621: INFO: http.Client request:POST StatusCode:200
Oct 1 01:17:36.624: INFO: http.Client request:PUT StatusCode:200
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the HTTP request this change would end up passing to the underlying pod if len(loc.Path) was 0 here?
I wanted to make sure the request sent to the underlying pod was a valid HTTP request (especially that a non-empty request-uri was sent to the backing pod)
https://www.w3.org/Protocols/HTTP/1.1/rfc2616bis/draft-lafon-rfc2616bis-03.html#request-uri
Note that the absolute path cannot be empty; if none is present in the original URI, it must be given as "/" (the server root).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Updated PR so 'absolute path cannot be empty' now.
- Checked how the pod handles the request & payload sent back to the client.
- Tested with
kubectl proxy
,curl
,porter
andtcpdump
10.244.0.1.42256 > 10.244.0.5.80: Flags [P.], cksum 0x16e4 (incorrect -> 0x7749), seq 211:419, ack 120, win 502, options [nop,nop,TS val 1754840149 ecr 1101893751], length 208: HTTP, length: 208
DELETE / HTTP/1.1
Host: localhost:9999
User-Agent: via-proxy
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 127.0.0.1, 172.18.0.1
X-Forwarded-Uri: /api/v1/namespaces/default/pods/agnhost2/proxy/
02:58:21.755520 IP (tos 0x0, ttl 64, id 11616, offset 0, flags [DF], proto TCP (6), length 52)
10.244.0.5.80 > 10.244.0.1.42256: Flags [.], cksum 0x1614 (incorrect -> 0x25f4), ack 419, win 507, options [nop,nop,TS val 1101914757 ecr 1754840149], length 0
02:58:21.755774 IP (tos 0x0, ttl 64, id 11617, offset 0, flags [DF], proto TCP (6), length 171)
10.244.0.5.80 > 10.244.0.1.42256: Flags [P.], cksum 0x168b (incorrect -> 0x5f0d), seq 120:239, ack 419, win 507, options [nop,nop,TS val 1101914758 ecr 1754840149], length 119: HTTP, length: 119
HTTP/1.1 200 OK
Date: Tue, 06 Oct 2020 02:58:21 GMT
Content-Length: 3
Content-Type: text/plain; charset=utf-8
foo[!http]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would we limit to GET & HEAD? Why couldn't people be using POST PUT etc? Isn't this a compatibility breakage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The request body associated with a PUT/POST/PATCH/etc request doesn't get sent to the backend, and the clients I know of drop their PUT/POST/PATCH content in response to a 301 request, and switch to making a GET request to the new location (including golang and browsers, which is what this redirect was originally added for)
That makes returning a 301 redirect for anything other than GET/HEAD lose data and not be usable in the scenarios I can see
return | ||
default: | ||
path := req.URL.Path | ||
req.URL.Path = path + "/" + queryPart |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is doing a few things that don't seem quite right:
- it is adding duplicating query data into the path (I think a request with query parameters would get an incorrect path, need to add a unit test to exercise this)
- it is modifying
req.URL.Path
but notloc.Path
(which means thenewReq.URL = &loc
code path below is still wrong... need a unit test to exercise that path as well)
My question in #95128 (comment) was more of a question about behavior ... I'm not actually sure we need to append a /
... the go http client might default to sending /
if there is not path present... if this default case is simply dropped, does the pod still get a $METHOD / HTTP/1.1
call?
Issues go stale after 90d of inactivity. If this issue is safe to close now please do so with Send feedback to sig-testing, kubernetes/test-infra and/or fejta. |
/remove-lifecycle stale |
/test pull-kubernetes-node-e2e-containerd |
After retesting the original fix with kind,
Checking APISnoop results
@liggitt Can you please confirm that the logs above do address your outstanding query and the PR can now be lgtm & approved? TIA |
thanks for checking the impact on backend behavior, the change lgtm unit test coverage of client side behavior (redirect received for get/head, no redirect received for put/post/delete/etc) and backend behavior (request with |
If jordan's question is answered to his satisfaction this is approved and also lgtm, will tag as such unless he comments otherwise in next day. /approve |
the change lgtm but without test coverage nothing would catch a regression |
@liggitt For the new unit test to check the status code (either 301/200) for various methods I'm having an issue getting passed the following code block kubernetes/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go Lines 210 to 212 in 92ddd4d
Using the current
Question: Based on the output below does that get processed somewhere inside of pkg/registry/core/pod/rest/subresources.go or have I missed something in the process of getting from
TIA for any tips you can provide. |
You can't send a completely empty path to a server. If the test server roots the proxy handler at In real use, the proxy handler is rooted at |
5787c1e
to
0dcf9cf
Compare
/test pull-kubernetes-node-e2e-containerd
|
- Extract the current redirect code into a function (proxyRedirectsforRootPath) and redirect for only http.MethodGet or http.MethodHead - Create a unit test that confirms that only GET & HEAD methods are redirected
0dcf9cf
to
be65bc3
Compare
@liggitt I've moved the redirect code into a function so I have a more direct way of unit testing the various methods. The unit test checks
Is this okay to lgtm now? |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: liggitt, Riaankl, smarterclayton The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/test pull-kubernetes-e2e-gce-ubuntu-containerd Unreleated flake
|
/test pull-kubernetes-e2e-gce-ubuntu-containerd Unrelated flake
|
/test pull-kubernetes-e2e-gce-ubuntu-containerd
|
/test pull-kubernetes-e2e-gce-100-performance
|
What type of PR is this?*
/kind cleanup
What this PR does / why we need it:
Which issue(s) this PR fixes:
Fixes #95129
Testgrid Link:
Special notes for your reviewer:
Does this PR introduce a user-facing change?:
Release note:
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:
/sig testing
/sig architecture
/networking