AWS AppSync OIDC - aws-appsync

I am using AWS AppSync with keycloak as the OIDC provider and left the clientID blanked. This means that I can generate an access token using any clientId and client secret and start making requests (query or mutation) to my AppSync GraphQL endpoint.
However, I have to ask...how do I define fine grained access control with the scopes in the jwt token. I don't really understand what benefit this authorisation flow provides apart from just leveraging existing clients previously setup in keycloak or any other oidc providers.
So...what's the real benefit of using oidc auth for AppSync? Am I missing anything important here? Any feedback appreciated!
Thankyou!

You get access to the OIDC claims in the $ctx.identity.claims map within the resolver mapping templates which you can basically use to do your fine grained access control logic. Imagine if you have a groups claim meaning your user belongs to a group such as Admin then you can write custom logic in your mapping template based on that.
Here is an example of how to do this (it uses Cognito but OIDC should be pretty similar).
https://adrianhall.github.io/cloud/2018/06/01/how-developers-can-auth-with-aws-appsync/

Related

Keycloak as IdP with own implementation of Resource Server

Is there a way of using Keycloak only to Authenticate user, but with own mapping to roles with Spring?
I would like to authenticate API Gateway in keycloak first, but then provide internal JWT Token with authorized roles inside my microservice world.
In this article, I do map Spring authorities from roles that Keycloak sets in JWTs. Is that what you are looking for?
If what you want is having a hand on access token claims, two cases:
the claim is already in the token but with a different value than what you expect (missing roles, outdated email, ...). Then, it is very likely that Keycloak admin API exposes what you need to update users data. Check that a "confidential" client with required roles is declared with client-credentials flow enabled (or declare a new one) and have relevent resource-server call admin API for updates (with WebClient, RestTemplate, #FeignClient or whatever is capable of using client-credentials flow).
the claim does not exist yet. Then, define a new Keycloak "mapper" to add a private claim. Here is a sample. You can have a look at security module to figure out how this new private claim is parsed (by ProxiesClaimSet) into an Authentication custom implementation.
In any case, the authorization-server (Keycloak) is the only place to define claims, issue JWT and sign it. JWT validation by JWT decoder on resource-server involves much more than just checking expiration date: issuer, issued-at, token integrity (server signs the payload with a private key and exposes a public one to ensure the token content was not modified), and more are verified too.
You want to make access control inside resource-servers? Great! Ensure that authorization header with Bearer access-token is forwarded by the gateway from client(s) to resource-server(s) and configure your resource-server(s) as described in the article above.
P.S.
In the article you'll also find a way to test security rules (both unit and integration) with mocked authentication. This is what, in my opnion, makes resource-server(s) a better place to implement access-control: security rules are of primary business importance and fine grained unit-testing is essential.
Other note, if you go for additional private claim(s) with Keycloak mapper(s), pay attention to pom.xml file, java/main/resources and implemented interfaces of ProxiesMapper into proxies-keycloak-mapper module.
Last, you should also follow the first 3 of those tutorials (for real: write the code and run the tests), it will take you less than an hour and will save you many more hours struggling with your resource-server(s) security implementation.

validate id token in Quarkus oidc extension

I have some questions regarding the Quarkus oidc extension for validating access to a service (not an oidc client, so I am not calling OIDC flows, only validating tokens):
In addition to validating the JWT access token (authorization bearer token), is it possible to validate the id token, defined in another header? (in my case x-id-token)
Would additional claims in the ID token be accessible somehow, for example through SecurityIdentity or something else?
I would like to avoid having to call the userInfo endpoint every time.
Also, in my case, the id token contains "groups", that I would have liked to be mapped to roles to be used in #RolesMapping: is this possible? In Microprofile JWT, for non-OpenID Connect cases, it seems like the groups claim is defined on the access token, but in OIDC from my interpretation, it seems logical that this kind of information is on the id token, isn't it?
I tried adding "quarkus.oidc.roles.source=idtoken" on my app, but this seems to be limited to oidc client applications.
Also, perhaps it's just me, but I am confused by the doc for OIDC for services (https://quarkus.io/guides/security-openid-connect), regarding what is client OIDC and what is server-side validation for services: this page seems to be focused on services, but then the configuration part references a lot of configuration properties that concern client applications that must call the OIDC endpoints, OIDC flows, etc. Am I missing / misunderstanding something?
(Note: otherwise the extension is great! And multi-tenancy is very useful…and is also the first reason why we initially preferred using this extension instead of the Quarkus Smallrye JWT)
Thank you.

OpenID Connect / oAuth: How to allow OpenId Provider to access user's data at the Relying Party (Client) side

We're planning integration between two services: A and B.
The service A is going to be an OpenID Provider, the service B relies on it to log users in and create new accounts.
The service A also provides access to its resources via REST API using OAuth authorization, the service B uses the OAuth Access Token obtained via OpenID Authorization Code Flow.
However, there are some cases when A wants to get data from B. There is an established agreement between these services, that A can access any data from B in the scope of a user that was created via OpenID Connect.
How could I design authorization for the service B API? What could A provide to B in an HTTP request?
I'm considering things like a classic API Key, but it doesn't look natural in this workflow.
There are no direct solution to your mentioned scenario from OAuth and OpenID Connect protocol perspective.
But from what you have explained, you have OAuth 2.0 access token protected services in service A. Also, A acts as an identity provider (with OpenID Connect support). If this the case, I believe you control token issuing process and validations.
One options is to enable services from B , which are protected from OAuth 2.0 access tokens. Which is similar to what you already have in A. And to consume those services, you will have some service/client implementations bound to A. What they would do is obtain tokens from A itself to communicate with B. This can follow client credential grant from OAuth 2.0 as there is no end user involvement (scenario involve service to service interaction).
This suggested solution is similar to API key usage but with added benefit of OAuth 2.0 protocol.This allows you to generate Access tokens with limited life time and allow refreshing them if required. Also, in case you want B's services to be consumed by another client, then things are straightforward.

Exposing Cognito Protected AWSGateway APIs to clients

Use-case:
We have a few AWSGateway APIs which our clients can use to do somethings in the backend. These APIs are Cognito protected. Currently our clients are using this APIS through an android app which was built using Cognito Mobile SDKs.
Now we are trying to expose these APIs to our clients to be integrated into their internal workflows.
I was trying to find what is the best way to do this. Currently I am not able to find any resources on how to do this.
I have seem the server side user of AWS Cognito but I don't think that is what we want to do here.
Thanks.
To answer your question correctly we need more information.
Can the internal workflows be configured to use REST Services?
What authentication processes does the internal workflows support?
SDK or no SDK
You can access the webservices in API Gateway via a generated SDK or your own code.
Instructions to generate an SDK from the API Gateway Console are found here.
To invoke the webservice with authentication can be done in four ways IAM, API Keys, Cognito, custom authoriser. I am going to mention the first three.
IAM
Step 1, create a user in IAM with an access key and secret key.
Step 2, is too setup a role to access the API using IAM. Go to
IAM, select roles, create a role, and grant it access to your
API Gateway functions. Which would look something like this:
Sample IAM Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::account-id:user/Alice",
"account-id"
]
},
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:region:account-id:api-id/stage/GET/pets"
]
}
]
}
allocate this role to the user you created. Policy examples are available here.. For more authentication options that include local certificates etc look here.
Step 3, call the API using the AWS Secret and Key SDK.
API Keys
If you add keys to your APIs the mobile app will fail as it does not have these keys. It would be best to deploy a different version of your APIs that could wrap the existing ones, could provide additional functionality specific to the workflow. To find out how to do this follow this link.
The advantage of API keys are that you can throttle access to your API Gateway functions, remove the keys at will, recycle them etc.
Cognito - Federated Users
Your mobile users are actually authenticating using federated users. However, one of the federated user channels happens to be cognito. You can add more, OpenAuth, Google, Facebook, SAML, etc, here you could add the Authentication type used by your client. A user would then use their username and password, to authenticate to the clients security provider, those credentials are then passed through to the API via federated users, and therefore federated users must be setup to use the same authentication mechanism as your client. See the following blog post
For this solution we have multiple options. 1. Pass the user credentials through to the API with federated users, this assumes the users interface calls the webservice but as you mentioned it is workflow, and I assume the user does not access the service directly as they do with the mobile application. i.e. services are called by a machine as a background process on a server. Which means this solution will not work. Option 2. is to create a new user, in cognito for the client. This is the same as accessing the service via the mobile app. To do this needs a little work extra work on the client as you need to retrieve the temporary access tokens.
Step 1. Use the SDK, or code the interface to the API on your own.
Step 2. Generate a user in Cognito for the backend system to use.
Step 3. Use the cognito user to obtain access tokens
Step 4. Use the access tokens to access the webservice in API
gateway.
Suggested solution
Create a second version of your API as a wrapper or extension to your mobile API and use API Keys as described above. Why?
Can throttle access to the APIs
A different version means you can extend it and add additional functionality specific to workflow
Easiest to implement as there is no key exchange, such updates to
the request header.
EDIT: My suggestion of solution 2 is incorrect. AWS Documentation says the following To include API methods in a usage plan, you must configure individual API methods to require an API key. For user authentication and authorization, don't use API keys. Use an IAM role, a Lambda authorizer, or an Amazon Cognito user pool.
AWS Also says the following is available for controlled access
Resource policies let you create resource-based policies to allow or deny access to your APIs and methods from specified source IP
addresses or VPC endpoints.
Standard AWS IAM roles and policies offer flexible and robust access controls that can be applied to an entire API or individual
methods.
Cross-origin resource sharing (CORS) lets you control how your API responds to cross-domain resource requests.
Lambda authorizers are Lambda functions that control access to your API methods using bearer token authentication as well as
information described by headers, paths, query strings, stage
variables, or context variables request parameters.
Amazon Cognito user pools let you create customizable authentication and authorization solutions.
Client-side SSL certificates can be used to verify that HTTP requests to your backend system are from API Gateway.
Usage plans let you provide API keys to your customers — and then track and limit usage of your API stages and methods for each API
key.
Not all the approaches above are intended for authorisation, for example CORS actually protects the user from cross site scripting, and as seen API Keys are only for usage plans. Resource policies just further secure the API by limiting access to IP Addresses, thus your only options really are IAM Roles as described in option 1, and federated users as described in option 3 or your own custom lambda authorize, if you are using Lambda, or your own authorizer if you are using something other than lambda wrapped with API Gateway.
I guess it will be service to service or (Server to Server) communication, for this terminology used is Oauth Standard is client_credentials grant type.
Please refer the documentation for getting token
Once the token is acquired, you need to pass this token either Authorization or API Gateway Custom Header for AWS Cognito.
You can use API Tokens alone for authorization (unless this has been removed recently)
I have used them on multiple applications.
This is not recommended for Authentication -- but it is application specific if they are sufficient for authorization
They have been supplemented by more secure methods at the expense of significant complication for both client and server.
API Tokens have the advantage of ease of use for issuer, client and server as they do not require complex signing or protocols -- however they are not as fundamentally secure as they may be reused and generally do not expire as quickly. Otherwise they are equivalent to bearer tokens.
Security is very context dependant -- consider these question:
what exactly are you protecting against (providing security for) ? What is the risk and cost of a security breach ? What is the cost/effort to implement and use it?
Many security 'holes' are not in the authentication protocol handling itself but rather in how data is managed 'outside the box' -- No security is perfect, meaning aiming for perfect security has unbounded cost with decreasing effectiveness. Generally, it is recommended to balance the risk and cost of potential loss vs cost to implement and maintain.
You can have a 'highly secure' API but also have a high risk of breach and data loss due to handling before and after passing through the protected gateway. There are many reasonable cases where instead of focusing on securing the 'front door' with bank vaults and armoured trucks, instead securing the data handling such that no data that is a significant security risk passes through the front door.
AWS Provides a range of technical features -- but it is ultimately up to each customer to implement them appropriate for their use. API Keys do have a range of appropriate use cases, particularly in server-to-server communications, especially where personal identity (and PI data) is not involved, or where the API involves mainly services instead of data (e.g say a image thumbnail API that stores no state and provides no access to data). When backed by use of HTTPS/SSL and possibly other security factors such as account passphrases, IP range whitelists, and a general policy of least-access.
Don't underestimate the "Sticky Note" factor. If you make secure access too painful to your users they will find a way to make it less painful, but less secure then simpler measures which they would not have had an incentive to circumvent.

Authentication without user credentials

I'm putting together a personal React site and want to send requests to an AWS API Gateway. However, I just want my site to be able to pull data. There will be no user model and every auth model I've ever used requires the user to do something with sign-in, be it user/pwd or AD. Can someone guide me to a model that covers this scenario?
One common approach is to use a Cognito Identity Pool with "Unauthenticated Identities" enabled. You can secure your API gateway endpoints using IAM, and require requests to be sig4 signed.
With this approach, Cognito is used only in a kind identity broker capacity, not as an actual identity provider. You do not need to create a User Pool or use any other identity management features of Cognito. In this capacity, Cognito is essentially just a thin layer between your code and the underlying STS APIs that produce the IAM keys your application needs.
Using the Cognito SDK, you request temporary IAM credentials (access key, secret key, session token) that can be used to sign the requests.
This answer outlines one way to accomplish this. When the protected AWS resource you want to access is API Gateway, your code may look something like the example near the end of this post.
I typically either use aws-api-gateway-client, as the example does, or aws4 with axios to sign requests.
As noted in the linked to answer above, I normally use AWS.config.credentials.get(), rather than AWS.CognitoIdentity.getCredentialsForIdentity() to actually get the IAM keys (as in this doc).
The signed requests then include an Authorization header that is very difficult to counterfeit. I don't want to suggest that this approach is bulletproof, but it does at least give you a reasonable level of confidence that your API Gateway endpoints are only being successfully invoked by your application.