Why do communications between internal services need authorization like oauth if the outside world can't access the apis directly? - docker

This is just a general question about microservice architecture. Why do 2 or more internal services still need token auth like oauth2 to communicate with each other if the outside world doesn't have access to them? Couldn't their apis just filter internal IP addresses instead? What are the risks with that approach?

Why do 2 or more internal services still need token auth like oauth2 to communicate with each other if the outside world doesn't have access to them?
You don't need OAuth2 or token authentication, but you should use it. It depends on how much you trust your traffic. Now in the "cloud age" it is common to not own your own datacenters, so there is another part that own your server and network hardware. That part may do a misconfiguration, e.g. traffic from another customer is routed to your server. Or maybe you setup your own infrastructure and do a misconfiguration so that traffic from your test environment is unintendently routed to your production service. There is new practices to handle this new landscape and it is described in Google BeyondCorp and Zero Trust Networks.
Essentially, you should not trust the network traffic. Use authentication (e.g. OAuth2, OpenID Connect, JWT) on all requests, and encrypt all traffic with TLS or mTLS.
Couldn't their apis just filter internal IP addresses instead? What are the risks with that approach?
See above, maybe you should not trust the internal traffic either.
In addition, it is now common that your end-users is authenticated using OpenID Connect (OAuth2 based authentication) - JWT-tokens sent in the Authorization: Bearer header. Most of your system will operate in a user context when handling the request, that is located within the JWT-token, and it is easy to pass that token in requests to all services that are involved in the operation requested by the user.

For internal services it's usually less about verifying the token (which in theory was already done by the external-facing gateway/api), and more about passing through the identifying information on the user. It's very common for even internal services to want to know who the requesting/acting user is for permissions and access control, and sometimes it's just easier to tell every service creator who needs user-scoping to accept a JWT in the Authorization header than it is to say, "look for the user ID in the X-COMPANY-USER-ID header".

You can implement very granular role based access control(RBAC) on the apis exposed by Microservices using Oauth which you can not do using filtering IP address.

Related

How to exchange JWT tokens across IDP for single page apps?

Trying to understand how multiple IDPs can work together within a SPA.
My initial thoughts
User login with the default IDP and acquire the IDP1-JWT.
When the User needs to Access IDP-2's resources, he accesses through a reverse-proxy over IDP2.
The reverse-proxy send the sub(subject) and sid(session-id) to IDP2.
IDP2 negotiates with IDP1 (openid-connect) to provide the required token.
Reverse-proxy sends IDP2-JWT to IDP2 microservice to enable resource access.
I am still very confused that the above scheme is even sensical, or if there are standard ways to facilitate this kind of exchange. Are there any ways that two OAuth servers can exchange information?
Will this even work for SPA, since IDP2 and IDP-Resource-Server2 would have different domains?
What are the security risks I should look out for?
Thanks
Trying to use Keycloak as IDP2 (which is more under my control) with the steps https://keycloak.ch/keycloak-tutorials/tutorial-token-exchange/#configuring-token-for-an-identity-provider

Inject OAuth2 token via reverse proxy

We have a service that sends delivery notification messages to a client via HTTP requests - meaning, the client must also act as a Server (must expose an HTTP endpoint) in order to receive these notifications.
Some of our clients are asking that our requests authenticate against their endpoints via OAuth. We would prefer to implement this using a third-party so as to avoid having security features implemented in-house (and avoid security issues/not well-handled edge cases that we could end up introducing); More specifically, we'd prefer to have a reverse-proxy.
The idea would be that our service would send a request to the client through the reverse proxy, which would identify that the request is missing a token and would be responsible for getting a token and injecting it into the request.
I googled for this but couldn't find anything; perhaps I'm not searching for the correct keywords. Is there a packaged/"market" reverse-proxy solution for this? Or perhaps a programmable reverse-proxy that could bootstrap a solution for us?
I can see two approaches for this:
have an oauth2 client library in your own code to handle the oauth2 authentication flow for your app. Most programming languages have an oauth2 client so you wouldn't re-implement anything and have a secure authentication mechanism,
use a proxy that implements an oauth2 client so it would do that part of the flow for your service but I'm not sure it exists. I couldn't find anything also related to this because of the fact that most of the languages have an oauth2 client that's readily available.
I hope you find the solution to your problem :)

Best practices for securely granting user credential access to other internal services (API key)?

I have a Ruby on Rails application with a database that stores sensitive user information (hashed with Devise). I now need to pass some of this sensitive information to another internal service on another server that needs it to make calls to third party APIs, so it needs a way to request that information from the RoR app.
What's the best approach to something like this? My first intuition was to grant an internal API key that would grant access to all sensitive information in the DB (via a private endpoint), the same way developer keys give access to a subset of API endpoints. Is this secure enough as long as I hash the API key? What's the best approach to passing sensitive information around through internal services?
Private APIs
My first intuition was to grant an internal API key that would grant access to all sensitive information in the DB (via a private endpoint), the same way developer keys give access to a subset of API endpoints
Well private endpoints or private APIs don't exist in the sense of only protecting them by using an API key. From a web app you only need to see the html source code to be able to find the API keys. In mobile devices you can see how easy is to reverse engineer API keys in this series of articles about Mobile API Security Techniques. While the articles are in the context of mobile devices, some of the techniques used are also valid in other type of APIs. I hope you can see now how someone could grab the API key and abuse from the API you are trying to secure.
Now even if you don't expose the API key in a mobile app or web app, the API is still discoverable, specially if the endpoint is served by the same API used for the other public endpoints. This is made even easier when you tell in robots.txt that bots should not access some of the endpoints, because this is the first place where hackers look into for trying to enumerate attack vectors into your APIs.
Possible Solutions
Private API Solution
What's the best approach to something like this? My first intuition was to grant an internal API key that would grant access to all sensitive information in the DB (via a private endpoint)
In order to have a private API the server hosting it needs to be protected by a firewall and locked to the other internal server consuming it with certificate pinning and maybe also by IP address. In order to be able to properly secure and lock down the internal server hosting the supposed private API it MUST not support any public requests.
Certificate Pinning:
Pinning effectively removes the "conference of trust". An application which pins a certificate or public key no longer needs to depend on others - such as DNS or CAs - when making security decisions relating to a peer's identity. For those familiar with SSH, you should realize that public key pinning is nearly identical to SSH's StrictHostKeyChecking option. SSH had it right the entire time, and the rest of the world is beginning to realize the virtues of directly identifying a host or service by its public key.
Database Direct Access Solution
What's the best approach to passing sensitive information around through internal services?
Personally I would prefer to access the database directly from the other server and have the database software itself configured to only accept requests from specific internal servers for specific users with the less privileges possible to perform the action they need. Additionally you would employ the firewall locking to and use certificate pinning between the internal servers.
Conclusion
No matter what solution you choose place your database with the sensitive data in server that only hosts that database and is very well lock-down to your internal network.
Anyone needing to access that sensitive data MUST have only read privileges for that specific database table.

Access Token/Authorization Between Microservices

I'm creating an online store REST API that will mainly be used by a mobile app. The plan is for a microservices architecture using the Spring Cloud framework and Spring Cloud OAuth for security.
My question is really on best practices for communication between microservices: Should I have each service register for their own token, or should they just pass the user's token around?
For example, I have 3 services: user-service, account-service, order-service.
I've been able to implement two procedures for creating an order: One passes the user's token around, and in the other each service gets their own token. I use Feign for both approaches.
So for option 1: order-service -> GET account-service/account/current
order-service calls the account-service which returns the account based on a userId in the token. Then the order-service creates an order for the account.
Or for option 2: order-service -> GET account-service/account/user-id/{userId}
order-service gets the userId from the sent token, calls the account-service with it's own token, then creates the order with the retrieved account.
I'm really not sure which option is best to use. One better separates information but then requires two Feign Clients. However the other doesn't require the 2 clients and it becomes easier to block off end certain endpoints to outside clients, however it requires extra endpoints to be created and almost every service to go digging into the Authentication object.
What are all your thoughts? Has anyone implemented their system in one way or another way entirely? Or perhaps I've got the completely wrong idea.
Any help is appreciated.
I have found below 3 options:
If each microservice is verifying the token then we can pass the same token. But the problem is - in between same token can be expired.
If we use client_credentials grant then there we are having two issues: one is, we need to send the username/id in next microservice. Another one is, we need to request two times - first for getting the access token, next for actual call.
If we do the token verification in API gateway only (not in microservices) then from the API gateway we need to send the username in every microservices. And microservices implementation needs to be changed to accept that param/header.
When you do server to server communication, you're not really acting on behalf of a user, but you're acting on behalf of the server itself. For that client credentials are used.
Using curl for exemple :
curl acme:acmesecret#localhost:9999/oauth/token -d grant_type=client_credentials
You should do the same with your http client and you will get the access token. use it to call other services.
You should use client tokens using the client_credentials flow for interservice communication. This flow is exposed by default on the /oauth/token endpoint in spring security oauth.
In addition to this, you could use private apis that are not exposed to the internet and are secured with a role that can only be given to oauth clients. This way, you can expose privileged apis that are maybe less restrictive and have less validation since you control the data passed to it.
In your example, you could expose an public endpoint GET account-service/account/current (no harm in getting information about yourself) and a private api GET account-service/internal/account/user-id/{userId} that could be used exclusively by oauth clients to query any existing user.

OAuth2 "client credentials" grant: remote IP check?

I'm developing an API which only needs to be accessed by servers, as opposed to specific, human users. I've been using the client credentials grant which, if I'm not mistaken, is appropriate for this use case.
So the remote websites/apps, after registering their corresponding OAuth2 clients, are simply requesting an an access token using their client ID/secret combination, via a SSL POST request + HTTP Basic authentication.
Now I was wondering if it would be a good idea, during said access token request, to check the remote IP to make sure it actually belongs to the client that was registered (you'd have to state one or several IPs when declaring your app, then it would be checked against the remote IP of the server making the POST /token request).
I feel like this would be an easy way to make sure that, even if the client ID/secret are somehow stolen, they wouldn't be just usable from anywhere.
Being fairly new to the OAuth2 protocol, I need some input as to whether this is a valid approach. Is there a more clever way to do this, or is it straight up unnecessary (in which case, for what reasons)?
Thanks in advance
That's certainly a valid approach but binds the token tightly to the network layer and deployment which may make it difficult to change the network architecture. The way that OAuth addresses your concern is by the so-called Proof-of-Possession extensions https://datatracker.ietf.org/doc/html/draft-ietf-oauth-pop-architecture.
It may be worth considering implementing that: even though it is not a finalized specification yet, it binds the token to the client instead of the IP address which safeguards against network changes and is more future proof.

Resources