-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Handle resolving proxy tokens when parsing HTTP requests #4453
Conversation
The travis failures seem like just flaky tests. I ran them all locally and they passed.
|
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.
We can test this without starting actual proxies too so we should probably do that.
agent/http.go
Outdated
s.parseTokenProxyResolve(req, token, true) | ||
} | ||
|
||
func (s *HTTPServer) parseTokenProxyResolve(req *http.Request, token *string, resolve bool) { |
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.
nit a comment about what resolve does and why it's needed (maybe link to this PR if you like) might be useful
agent/agent_endpoint.go
Outdated
// Store DC in the ConnectCALeafRequest but query opts separately | ||
if done := s.parse(resp, req, &args.Datacenter, &qOpts); done { | ||
s.parseDC(req, &args.Datacenter) | ||
s.parseTokenProxyResolve(req, &qOpts.Token, false) |
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.
It's a bit janky that when we want to use the extended verification the boiler plate increases.
I realise this probably had the advantage of being a tiny change compared with refactoring verify method a bit but I feel like that might be worth it.
I'm in two minds about whether to untangle this now or just land it as a fix and come back later.
I think it is important enough to fix nicely though? What do you think?
Oh how about:
- make a
parseWithoutResolvingProxyToken
(yay names) that does all of the same asparse
but with false here.
Or alternatively, leave this just as parse
as it is here, but change verifyProxyToken
to accept the req
directly and do it's own unpacking of the raw value rather than relying on qOpts
?
0e45b62
to
79a6abc
Compare
This makes the case where we want to call verifyProxyToken later less clunky. Also add some comments about why the verifyProxyToken calls are needed for some connect endpoints.
79a6abc
to
91d95bb
Compare
I retested the latest changes in my manual test scenario. Additionally the new unit tests I added checks a bunch of endpoints to make sure that passing proxy tokens to them works in place of acl tokens (tests out resolving proxy tokens to acl tokens). |
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.
Great. Good catches on the security quirks we are relying on with verify too!
// Parse the token | ||
// Parse the token - don't resolve a proxy token to a real token | ||
// that will be done with a call to verifyProxyToken later along with | ||
// other security relevant checks. |
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.
Like this. Is it worth adding to CALeadCert too?
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.
I added similar wording there too now.
agent/http.go
Outdated
// to use both parseWait and parseDC. | ||
func (s *HTTPServer) parse(resp http.ResponseWriter, req *http.Request, dc *string, b *structs.QueryOptions) bool { | ||
func (s *HTTPServer) parseResolveProxy(resp http.ResponseWriter, req *http.Request, dc *string, b *structs.QueryOptions, resolveProxyToken bool) bool { |
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.
Names are hard :(
I can't think of anything better but it's a bit unintuitive that parseResolveProxy optionally doesn't resolve the proxy! I'd be tempted to name it something like parseInternal
or parseWithOptions
to indicate that it's mostly a way to de-duplicate logic from higher level callers?
Not a blocker at all though.
agent/http_test.go
Outdated
handler func(s *HTTPServer, resp http.ResponseWriter, req *http.Request) (interface{}, error) | ||
} | ||
|
||
// This is no exhaustive list of all of our endpoints and is only testing GET endpoints |
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.
"not an exhaustive list"?
|
||
type endpointCheck struct { | ||
endpoint string | ||
handler func(s *HTTPServer, resp http.ResponseWriter, req *http.Request) (interface{}, error) |
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.
Huh TIL type of a method can be expressed this way with receiver as first arg. I knew that receivers are just syntax sugar on that generally but not that this was possible...
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.
Yeah, I learned that by reading how we register HTTP endpoints because we do the same thing there.
Another note is that I ran tests locally and everything passed. |
Fixes: #4441
The underlying problem with managed proxies and ACLs was that many HTTP endpoints were not ProxyToken aware. They passed along the proxy token to the RPC endpoints on the servers which knew nothing about proxy tokens.
This PR puts proxy token -> service token translation logic into our HTTP token handling. Additionally I added the parseTokenProxyResolve to be able to disable this auto-translation in the case of a few connect specific endpoints that want to run verifyProxyToken themselves (which has a few more checks - even though they may provide only marginal benefit in the case where each service has their own ACL token).
How I tested:
python -m SimpleHTTPServer 8080
running in the background to provide the "web" service on port 8080consul connect proxy -service test -upstream web:9191
on one of my consul servers (the cluster was in docker behind a nat bridge so I needed to get into the network and doing it on the server was the easiest way (although I could have done it elsewhere)Currently getting this all setup for a unit test is impractical at best and impossible at worst or I would have implemented that too.