Oauth2 grant for server-to-server communication - web-services

I'm working in a microservice architecture, which has its own oauth2 provider in order to allow services interaction.
I need to develop a service that is granted to access users' resources in order to perform internal tasks on user accounts. Since the service needing to access user resource is an internal one it's not a viable solution to ask the user to allow access to their own resources.
I'm concerned about the choice of picking the right grant to perform this tasks, as the client_credentials seems the right one, it also seems to be used to only allow to only update service data, instead of accessing user resources. Another solution I thought is to automatically provide the authorization code at users signup, as if the user has clicked an "allow" button, and then perform requests with that code grant. The downside here is that I have to create new authorization codes each time a service with that needs is created, but it seems to be a more clear solution (as auth code for user XXX only allows to access resources of user XXX).
I also understand that implementations are different as the standard gives a lot of flexibility, but
Which one, in your opinion, is the appropriate solution? How would you handle it? Would it be more clear to say, "statistic service" is allowed to access all users resources or "statistic service" is granted by all users to access their resources?

As you state this is an internal use case where you control the resources protected by your Resource Server, the Authorization Server and the clients accessing the resources so you may choose to use client_credentials for accessing user data.
It compares to (or actually is) a "service account" that may be used to manipulate user data. If that service is under your control and you trust it i.e. you trust that it does not leak it's credentials to other parties and does not abuse its powers it is OK. Since you also control the client it would not be a problem.

Related

Multi level authentication/authorization or approvals for access/delete resource in AWS

I want to implement a security measure that enables any authenticated user to delete any AWS resource only on approval from any other member.
The main objective is to make sure that, if the creds are compromised, the user should not be able to delete any resource without approval.
Looking forward to get some expert advise and discussion on this.
I understand, the least access privilege and MFA, but still it is fulfilling our requirements.
Since this is not directly supported by AWS, you will have to set up a custom solution for this.
This is one possible solution:
Create a role with delete permissions.
Create a Lambda to use that role to delete a resource.
Implement the Lambda to only processes the delete request if the input includes at least two approvals. (This part depends on your org authentication mechanism. Could be LDAP, short term access tokens, etc)
This fulfills the two requirements you mentioned:
a security measure that enables any authenticated user to delete any AWS resource only on approval from any other member.
The Lambda will only process the request if there is at least 2 approvals.
if the creds are compromised, the user should not be able to delete any resource without approval.
In this design there are no credentials. The role you created can only be assumed by the Lambda. You can further improve the security by only allowing certain Users, Roles or Groups to be able to execute the Lambda.

Different access tokens for users using aws Cognito for authorisation

I am trying to provide differential access to services behind an aws api-gateway, lets say simplistically split into 2 user groups user-a and user-b that each can access /routeA or /routeB but not the other.
User Authentication is via Cognito User Pool with 2 user groups defined. Front End is React and Amplify.
I am going round in circles with this having tried a few approaches. Running this decision tree select-auth-method points to using Cognito AuthZ which is fine in itself as I am using Cognito for AuthN.
So far none of the examples/tutorials/articles/videos have demonstrated how to block some users while enabling others. I have tried:
Cognito User Pool Authorizer - identity token based but seems to just AuthZ any logged in user. I could possibly attach IAM Roles to the user groups ?
Custom Lambda Authorizer - Works well on checking for the valid user-group in the Access Token and dynamically creating the required permissions but, some additional latency from a λ and no check that the access token is current. Starts to feel like I am writing code for a system that exists somewhere else?
Cognito OAuth - Spent some time trying to understand this. So I create a Resource Server attached to the Cognito app client and create some custom scopes that I can then reference in the Api-g Authorizers. Fine, but how to I create two different access tokens for the users that have different scopes? So far my understanding seems to suggest that it is another binary AuthZ approach, but articles suggest (but don't demonstrate!) it is capable of granular permissions? I must be missing something.
I also saw this 2017 answer but things may have moved on with better approaches?
I am minded to go OAuth route as it seems more of an industry standard approach and promises much but need a bit of insight as to how to enable different access tokens for different users.
So the answer is that Cognito does not implement the OAuth2 functionality that I need but others do. Given the following excerpt from AuthO docs, this feels like a better solution path...
It would be very useful if we could just restrict endpoints on the cognito:groups that are in the tokens,but this functionality isn't there.
There are a few options that might suit you, one is just put the users in different user pools and create different authorizers for those pools and assign them the routes.
Another is OAuth scopes, you can create two app clients each with different scopes then configure the scopes in APIGW. Note that in this case you need to pass the access token to APIGW not the ID token.
In either case if you are using Hosted UI you will have a problem as you will now have two Hosted UIs and it may not be straightforward knowing which one to display to a user until they have entered their email address.
BTW if you are not using Hosted UI you will be unable to use OAuth scopes.
You can also assign IAM roles to the cognito:groups and allow these access to the APIGW resources you want. This is probably the easiest method although it is not as simple as you would probably like.
The final way I can think of is writing a custom authorizer, I would avoid this if you can, I have done it a few times now and it has never been enjoyable.
Your requirement seems to be to authorise users depending on their permissions, as opposed to needing different types of access token.
I would recommend sending the Cognito access token to the API and receiving it like this in the API:
Level 1: Validate the access token first to check it is not expired etc
Level 2: Consider checking a scope to ensure that the token is for your API
Level 3: Check finer grained claims such as group membership or anything else that makes sense for your scenario. Your API can get groups by sending the access token to the Cognito user info endpoint.
DESIGN PATTERN
This blog post of mine describes the pattern and use of claims caching.
Here is some lambda authorizer sample code, though the same behaviour can be implemented in your API directly and my blog has some examples of this:
Cognito Claims Based Authorization

Confused about Cognito app clients and custom scopes

Please correct me if otherwise. OAuth scopes defines an application's access to a user's account while custom scopes define an application's access to a resource server. After signing in, an access token is returned containing the custom scopes, which depend on the query string parameters in the Cognito domain.
Is the purpose of an app client's custom scopes to define its permission to protected resources just to ensure users are logged in from a specified app?
A User Pool can have multiple app clients, each with their own custom scopes. Why not grant all app clients access to all custom scopes? Most apps allow anyone to signup, couldn't users just login in through an app client that has a different set of custom scopes anyway? Is it a least privilege thing? Is it meant for apps that have a restricted sign up, such as paid membership? And if using a web client, the client id is exposed and there's no secret, so how does a client id prevent others from obtaining the id and posing as an app client?
How does this tie in with user specific permissions? Seems like custom scopes are only for resources that are app specific, but not user specific. Do you implement custom logic for authorizing access to specific resources, or can this also be also done with User Pools?
Also, please recommend any resources besides AWS documentation (which I've read) regarding Cognito that really help explain the use cases and entire process.

How to restrict AWS Cognito users from taking certain actions?

Help is required in the following problem we're facing 😔
Any tip would be much appreciated!
Details and environment:
A multi-tenant application that aims to provide a dedicated tenant per customer (organization), in order to achieve full separation.
AWS Cognito user pool as my users' datastore and authentication provider.
an "AWS Cognito user pool" per customer (org).
Role management - based on the built-in user pool groups. Group per role and the server-side verifies that a user's access token includes a group name in it's embedded group's list.
So far so good and everything is working as expected, using AWS Amplify's SDK, for the client side's implementation. Amplify performs well and allows me to do whatever I want. The server verifies group belonging etc.
The problem:
I want to restrict non-admin users (that doesn't belong to the "admin" group) from performing certain Cognito actions via Amplify.
2 Examples:
I want to disable non-admin users' ability to modify a specific attribute's value, via Amplify.
I want to disable non-admin users' ability to modify MFA settings for themselves, via Amplify.
The actual problem started when I wanted administrators to be able to set MFA (enable/disable) for other users, but in Cognito (as I understand it) only a user can set his own MFA settings.
What I saw and already tried:
Set read/write permissions for user attributes. So the specific attribute I want to protect is modifiable only via API calls with developer credentials. That way, admins can call my server to ask for attribute modification. The server verifies the role by a group belonging according to the access token and calls Cognito API. The problem with that solution is that it covers only the attribute modification scenario.
Create an AWS Cognito identity pool for each of the user pools. For every group in every user pool, create an AWS IAM role with a policy that would restrict or allow the wanted behavior. The could actually work. The problem with that solution is that it feels like a super-duper overkill, plus it requires me to create an extra identity pool and an IAM role for each user pool. It means that every new customer that joins the service, would require (1) user pool, (2) Cognito client application, (3) identity pool and (4) IAM Role (instead of just a user pool and Cognito client app). Essentially, implementing this solution.
The real question:
Can I restrict users in a certain group from performing actions on themselves, such as disabling the MFA (even that the user-pool's MFA is set to "Optional")?
Thank you all so much! any help would be appreciated!
Well... After long research, we have come to the understanding that there is no proper right way. Every possible solution has its own pros and cons. A consultant meeting with AWS's experts taught us that:
Options Overview:
[Server Side Only] - Solution #1 that I proposed is exactly as described. Drawbacks are the same. It could work, and access to user-attributes will be restricted. Any other action that another client would make will not be blocked.
[Identity Pools] - Solution #2 that I proposed is the most accurate one. Yet I described it with one big mistake: one identity-pool can serve multiple user-pools! So essentially, we could create only one IAM role and one identity-pool per app's role. Then we match every user-pool we want to that same identity-pool and when introducing a new role to the app - just create a new group in the user-pool and match it to the IAM role. This solution is not as complicated as thought, and it would definitely do the trick. As a bonus, you'll get the ability to control and allow access to different AWS services. That being said, it still requires management and effort.
[Post-Auth Lambda] - Solution #3 that was not mentioned here, and I started to work on a day after posting this post. I blocked the write permissions of a new boolean custom attribute called "MFA". It indicates the desired MFA configuration for the user. Only a server could edit its value (and users with the admin role will have access to the server's API endpoint that can modify it). We've deployed a lambda function that would be triggered after successful authentication (post auth trigger in Cognito user-pool). It would verify a match between the desired and current MFA configurations for the authenticated user. If there is a mismatch, throw the user out because he did something that is not allowed.
*To be exact, we created one more custom attribute called "mfa_status" and it is set to true after the user has set it's MFA configurations. The lambda checks if both MFA and mfa_status are true and the real current MFA Configurations are false. if this is the case - the user is thrown out.
The Chosen One:
The solution we picked eventually is #3 (Post-Auth lambda) as it is the most detached solution. It does not require any mix with our server or client's code, any special configurations that are specific to a user pool and it still allows us to keep working with the Cognito's Amplify SDK as a client.
Thank you all for your time, I hope this post would help someone in the future.

AWS cognito: allowing only a certain users (identities) to get credentials

My production environment uses AWS cognito federated identities (AKA: identity pool) for allowing users to sign in with their Google/FB accounts. This is working fine.
However, for my staging environment I want to offer a similar sign in functionality (that is: users sign in in via Google) but I want to restrict the ability to sign in only to a specific whitelist (of, say, #gmail.com accounts). This is because the staging environment should only be accessed by team members and a bunch of trusted users.
My question is this: is it possible to define a Cognito identity pool that allows only the whitelisted users to sign in? if the answer is "yes", then how?
I know that I can do the whitelist checking at my backend (that is: at the backend of my staging env. I will reject every request not coming from these whitelisted users) but this is a bit unclean. In particular, I want the rejection to happen as early and possible and, ideally, to be carried out by cognito itself, and not by my backend.
Clarifications:
I mentioned a list of #gmail.com accounts as the whitelist. I am open to any other mechanism for defining the whitelist.
In a way I am asking whether I can have user directory functionality (in particular: determining if a user is in a certain group of users) with an cognito identity pool.
The purpose of the Identity pool is to provide access to authenticated identities. Therefore, this resource cannot manage users (ie: white listing a user group).
There are two ways to do this:
Link 3rd Party Identity into a User Pool and white list by User Group. Your user group will have a Roles and permission it will assume that will allow your test users to have the functionality they need without allowing other users who log to have that functionality.
Manage users from the 3rd Party Identity - I am not an expert at Google authentication.. but some OpenID providers allow you to create user groups with different access roles. This is an example for Google.
You can invoke a trigger and execute a lambda function when the user submits their information to accept or deny the sign in request.