3 ms·
By previous post, did you the bit about "Federation becomes moderately difficult"? I don't know if you've ever developed microservices, but building this logic
by lobster_johnson 10y ago
By previous post, did you the bit about "Federation becomes moderately difficult"?
I don't know if you've ever developed microservices, but building this logic into every single microservice would be a lot of work. We have dozens of microservices, written in different languages, so even if we wrote some generic glue as a library, we'd have to write it at least three times (Go, Ruby and Node.js).
- ams6110 10y agoStop using so many different languages?
- joshwa 10y agoPut it in the API gateway?
- DenisM 10y agoI haven't. If you use microservices you should have an API gateway with sticky sessions, there is no need to check permissions for each service. It's more secure that way too, as it uses less code.
- lobster_johnson 10y agoIt's an interesting idea, but that would mean every internal microservice request (they don't just service users) would have to go through an API gateway, and every call would have to be checked against a session store. It also means (if I understand the design correctly) that the API gateway has to munge every request envelope to add the actual user ID as an HTTP header (or something similar with gRPC), so that the internal microservices can see it, otherwise they'd have to ask the session store, which would defeat the purpose. This in turn would mean that every microservice has to trust the upstream, which would require some infrastructure to manage (i.e., microservices would no longer be simply exposed to the world; the API gateway would be a special trusted actor). You also now have a dependency on the API gateway, because the microservice wouldn't know how to deal with a session without it.
- DenisM 10y agoThe services are behind the firewall, unreachable from the internet, and only accept requests from the gateway, and from each other. The gateway strips your SSL (which I'm sure you are using :)), authenticates the request against its local security token store, then adds a bunch of headers: request id for tracing purposes, user IP for logging purposes, user id for authorizing access to various resources, etc. The service only accepts the request, it doesn't care where the request came from because it implicitly trust the environment to be protected from direct, unauthenticated calls. Request has the user id in it, so the service knows which data is being accessed. This way we have separated concerns of security from that of state management. This is what I'm arguing for - security without unnecessary public-facing crypto, and separation of authentication from authorization. The problem public-facing crypto is that there are tons of obscure of attacks on it - manipulating individual bits and sending it to the victim often yields information. New exploits come to light every now and again. I was caught with my pants around my ankles when padding oracle attack against signed cookies came out of the clear blue sky: http://robertheaton.com/2013/07/29/padding-oracle-attack/ http://robertheaton.com/2013/07/29/padding-oracle-attack/ Now, to keep the session state you have three options: - Do the same thing you do with JWT: send the data to the user and accept it back. You know the user has been authenticated already, he can only harm his own resources. When services call each other they pass the session state along with the call, same as JWT again. - Keep the session data in the centralized session store. Which kid of defeats the purpose of eliminating the centralized session store. :) There are many ways to make that scale well for throughput, e.g. once you know the user id you can trivially shard the session store, but I'm not sure about the latency from accessing yet another machine. This needs to be tested though, perhaps it's negligible. But let's keep that out for now, given the scope of the article. - Keep the session store at the gateway. When the service replies to the request, part of the payload is the new (additional) session data. The gateway strips that part and keeps it to itself. The next time gateway calls a service for the same user it passes the session data along. The service does not need to know anything about the gateway - it receives a request with user id and session state, then returns the result with new/updated session state. The nice thing is that the users never see the session state (shorter url, less data on the wire, lower chance of malformed data), and yet microservices never have to know where it came from. When services call each other they can attach the state along with it. It may get tricky having to pass the sate back and forth along the call chain of various services, but it's the same problem you would have with JWT anyways. The complexity is why I would circle back to sharded session state storage. Hopefully this answers all of your questions, let me know if it doesn't? It's an interesting conversation, thanks for that.