AWS Cognito JWT attribute-based routing - amazon-web-services

I'm new to AWS and it's services. What I want to achieve is a multi-tenancy SaaS application. What my concept looks like:
I use Cognito for user authentication. There all users no matter what tenant they belong to should use one frontend to login. For the tenant-recognition I use a custom attribute "custom:tenant" which I get from the JWT when the login is successful.
For the applicantion itself I want to use VPCs and to ensure encapsulation each tenant should have their own VPC.
Example:
User A of Tenant 1 login and gets back JWT with claim "custom:tenant":"1" should be routed to VPC 1
User B of Tenant 2 login and gets back JWT with claim "custom:tenant":"2" should be routed to VPC 2
Now my question is: how do I achieve this routing from the success of the login to the appropriate VPC? Do I need further Services for that or where do I find these settings?

There is a standard content based routing technique for routing based on the contents of JWTs. This type of thing is usually managed by a reverse proxy or API gateway placed in front of APIs, which runs some custom logic to read the JWT and route accordingly. This also keeps the plumbing outside of application components.
EXAMPLE
Here is an NGINX example coded in LUA, a high level scripting language, to read the JWT and extract a claim. In this example it is a zone whereas in your case it is a tenant ID:
NGINX Configuration
NGINX Plugin Code
Architecture Article
PREREQUISITES
Not all middleware supports this type of routing though. Eg you won't be able to do it in a simple load balancer. One option might be to use NGINX as a cloud managed service though it will cost money. A good gateway in front of APIs is an important architectural component though, so see if your company feels it is worth investing in.

Related

How to securely access API Gateway from a frontend application hosted in AWS amplify?

I have the following:
A Vue.js frontend app hosted in AWS Amplify.
An API Gateway that triggers several Lambdas that make changes in a MongoDB hosted in an EC2 instance.
My idea is that the frontend approaches the API Gateway and GET/POST data.
The problem is that I would like to make the API Gateway accessible only from my App (nobody could make requests without authorization).
How should I handle it?
If I provide API Keys to the API Gateway, how do I inject them securely in the frontend app? Those will be accessible to anyone, right? If so, where should I put that API Key? Inside an .env file? Would that be secure enough?
Using API Gateway authorizers?
I've seen some examples where people place an intermediate backend in Amplify in order to do so, but I'd like to avoid that if possible.
This answer isn't prescriptive, but hopefully has enough detail and buzzwords to start you on your journey.
Your front-end requests will should an Authorization header with a JWT token from Cognito or your auth provider.
API Gateway can wire-up to Cognito (or you can wire-up a "custom authorizer") and only pass-through requests that have a valid token.
Your Lambda will know the user is validated (as a known user or guest) but must still determine if they are authorized to perform the action they're attempting. If using something like AppSync, you can pass the user's Authorization header though to the AppSync API and the resolvers can allow/reject based on the authorization rules in your schema. I'm not familiar with EC2 hosted MongoDB, but imagine you'll need to wire it up to your auth so it can behave similarly.
I wouldn't recommend API keys. You can't put them client-side, they need to be managed and rotated, you're letting the "lambda" have permissions instead of the "user", etc.
I do recommend Amplify. You may be able to ditch MongoDB and the EC2 (yuck, you don't want to manage that) for AppSync backed by DynamoDB. And if you also use Cognito, you can do much of the above with very little effort.
EDIT To address your comment:
While your website may be hosted on your servers (or your account on a cloud provider's servers), it runs on people's personal devices. The HTTP requests (e.g. REST) your server receives don't indicate they originated from your website and there is no 'link' that ties YOUR front-end to your backend. HTTP does have a Referer Header that indicates the webpage the request is associated with, but you can't trust it.
Because your site is public, your API will receive requests from anywhere and everywhere. There is no way to prevent that. You can put less expensive request handlers in front of your API handlers to catch and discard invalid requests (or return cached responses when appropriate).
Your server could require requests include a special header (e.g. an API-KEY) that only your website will include in requests. But anyone can look at your website code and/or the network traffic (even simply via the browser debugging tools) and learn about that secret header.
You can look into XSRF tokens. This is where the front-end provides a unique token when serving a page (usually in conjunction with a form), and it must be included when sending data back to the server or the data will be considered invalid.
Cognito / Amplify will generate tokens for GUEST/un-authenticated users as well. So they can be used for what you want. It doesn't guarantee the requests are coming from your websites's javascript, but it'd be annoying to work around.
You can use CORS in your server responses. That prevents other websites from directly calling your APIs. Your server would still be called and return data, but an unmodified browser will see the CORS header and throw away the data before making it available to the calling javascript.
At the end of the day if your APIs are on the public internet, anyone and everyone can poke them.

Usage of ID tokens and Access tokens, with external Authentication, AWS backend and graphql language

I am currently working on building a mobile app which will require the users be authenticated, and have them specific privileges on what they can do (for example, a logged in user will only be able to manage some of their data held in the backend database).
I think I do understand the differences between ID token (user identity) and Access token (for authorizing between the mobile phone client and the back-end), but I am not sure what I intend to do conforms to the best practices regarding authentication and authorization.
Let me summarize what I am planning to do:
front end will be a Flutter/Dart mobile app
authentication will be done through Google Firebase Authentication service
my back end will be hosted in AWS:
API Gateway will serve a unique graphQL endpoint
API Gateway has an associated Lambda authorizer function which processes requests prior to the actual "application" Lambda functions
"application" Lambda function serves GraphQL requests (using python ariadne library), including authorization business logic
Database is a managed PostGreSQL inside AWS
The authentication / authorization workflow is as follow:
Not all of this has been implemented yet, but on the paper I think it could work.
However, it goes against several good practices regarding token usage:
the ID token is sent along an API call which is advised against (see this nice auth0 blog post)
I make no usage of access token between the front end and the back-end (could the AWS policy generated at step 5 fullfill this role?)
I do not leverage the audience claims in tokens
Note: as GraphQL exposes a single endpoint, I am not sure of what the content of the access token should be
I am new to Authentication / Authorization and would gladly have some insight regarding the best way to actually make everything work as per best practices, accounting to the following contraints:
authentication is outside of AWS
the APIs are GraphQL

What AWS service to use as OAUTH2 for the use with microservices

I have been doing some research about using some AWS service as OAUTH2 for our application running in 3 docker containers (backend, frontend, database). Backend has an API which is not open to public obviously and accessible only within docker network. We are looking for extending our app with a chat service, which we want to implement as a service, so we build our app following microservices architecture, since we will add other services later on. So when user logs into our app, his session will be also "shared" with chat service.
Our chat service will be using sockets and since sockets require direct connection to user resources, we can not just implement an integration layer which will supply all resources required by chat service, but we have to either:
implement sockets within our application API (which we dont want to do, we want it as microservice),
open API endpoints for chat service to use, but this option requires OAUTH2 and thats what we try to deal with.
I am not sure if there is some other way to handle this and be also ready for a long run, but if this works, which AWS service would fit the best for us to use, which would play OAUTH2 role for handling security in this matter?
I also checked this post but it didn't help me much in my case. I'm open to any suggestions, I've checked AWS lambda, AWS cognito, AWS amplify, pretty confusing, many features, we don't want to overload the architecture with features we don't need.
What exactly is the thing you want? User accounts managed by AWS? Use cognito.
Users logging in with Apple, Facebook, Etc? Use cognito again.
Just have some backend code that once a user logs in, create a token or session so they can chat with that.
There are many youtube videos on AWS cognito but a lot of them suck. The best one is written in React but before they came out with hooks. Here is part one. https://www.youtube.com/watch?v=EaDMG4amEfk

Enable User Acces Management in Amazon AWS for Webapp based on Spring Security

We have an enterprise web application implemented based on Spring-Security for authentication/authorization. This application is currently deployed on-premises on client side and usually we connect it to existing AD/LDAP systems.
Now we'd like to setup this web application within Amazon AWS for demo purposes. Therefore we need a kind of an user access frontend, where users can register and as soon as an admin approved this, the user should have access to the webapp ui. In addition a simple analytics layer is needed, to see some information about the user access.
It is important to have this "frontend" (could be a simple website based on a CMS like WordPress) just to explain the demo, to have the user registration functionality and the analytics layer. We explicitly don't want to include this in the existing web application, so it must be decoupled from each other.
What could be the right approach to setup such an environment? I just need the right direction to dig into the topics.
After a first research, we see that Amazon Cognito could be the right backend service for user data management. But we don't see "an easy way" to enable a simple frontend as described above (e.g. I didn't find a wordpress plugin to connect wordpress user data management with Apache Cognito). Also on the backend side I haven't find useful information how to integrate Apache Cognito with Spring Security.
If you are looking for a simple frontend we launched a new feature which gives you basic signup/login pages for your user pool.

Services Design and Authentication/Authorization across services

I'm working on developing my first SOA web-based application. I'm extremely new to SOA and still trying to wrap my head around best design principles for service design, especially in the way that services should talk to another.
The current problem I'm trying to figure out has to do with authentication and authorization. Lets say I have a trivial user service and event service, where the event service represents events in a calendar. Is it general practice to have the event service call the user service to authorize the request? Or, would it be better practice to implement user authorization on a system that exists between the client and the requested service? The system, which is essentially just another service, checks to user credentials to make sure they have access to the requested action (GET events/1, etc) and if so, sends the request to the service. This service could also act as a central load balancer and cache...I just like the idea of keeping user logic outside of each specific service.
You can use siteminder as authentication and authorization. Only the client who has valid token can invoke the service. you could also have roles assigned in siteminder.