Welcome back to my blog post series dedicated to building authorization using Cedar and Amazon Verified Permissions. In a previous blog post, we learned about the usage of AVP getting started. Today, we will cover the topic of using Cognito Groups with AVP.
Related to AVP getting started, Cognito groups are now supported in the AVP, as you well know from the previous blogpost. However, in this blogpost we won't focus on building a getting started gateway with AVP, but we will focus on building authorization with AVP itself using cognito groups (So you can use it for API gateway, resource server, and enhance it for your use case pretty easily. If you want to see the finished result, you can use the scenario from avp-cli here.
In addition, we will also use the new BatchIsAuthorizedWithToken API operation that was recently released.
Cognito groups support
Currently, AVP only supports Cognito as an external identity provider(IdP). We create the reference from Cognito through the CreateIdentitySource action.
For configuration, we need to specify:
-
policyStoreID
-
userPoolArn
(ARN of the Cognito user pool),
-
-
clientIds
(optional, unique application client IDs that are associated with the specified Amazon Cognito user pool.) -
principalEntityType
(namespace and data type for the entity that will be a principal for our policy store)
What was introduced into the CognitoUserPoolConfiguration, that groupConfiguration is the entity type that the policy store maps to groups from the Cognito user pool identity source. In short, which entity from the policy store will be mapped from the Cognito group.
Below you can see example values for principalEntityType
and groupEntityType
in the case of namespace MyApp
for the AVP policy store to see how it will look in reality.
That is, in short, when building an identity source for a policy store, we need to pass it on, and there you go!
Practice
Today, we would like to build an authorization system for the banking transaction system. Within, we have a user who can perform operations such as:
View
Approve
-
Edit
for resources of typeTransactionRecord
.
We would like to introduce here RBAC based on groups:
transaction_viewers
transaction_approvers
-
transaction_editors
in Cognito, that is, depending on the role, the user can perform different operations.
Cognito part
Let's start with our IDP from Cognito, we will create a user pool with groups, app client id, and add users there and add them to groups. Then we will obtain a Cognito token and use it for testing.
In order not to build this from scratch, for the purpose of this blogpost I created a ready-made Cloudformation template that will create a Cognito user pool, groups, and app client, we just need to later create users and add them to groups.
Navigate to the AWS console, and open the AWS console, open Cloudformation, and upload the authentication.yaml
from the avp-cli repo.
After the deployment, as outputs you can see both the CognitoUserPoolId
as well as CognitoUserPoolId
.
Navigate to the Cognito user pool.
You will see 3 groups generated, now what you need to do, is create users and assign them to the groups:
Later we will need to copy the ARN of the Cognito User Pool, App Client Id (it is called avp-client
, and initiate the auth with our users.
I am aware I am showing the cognito user pool, however before publishing the blogpost the cognito user pool on my site will be already deleted. Never share credentials, ARNs, JWTs, ClientIds, or secrets over the internet!
Policy Store part
Let's start building a policy store, log in to your AWS console, open the AVP service, and create an empty policy store.
Go to the schema tab, and paste this schema. Save the changes, you should see this action diagram and entity types diagram:
As we can see, we have principal as user (i.e., who), actions like approve, edit, view (i.e., what operation we want to perform), and resource (i.e., on what resource we want to do), i.e., TransactionRecord.
In addition, we can see that we have an entity of type Group
, to which our user belongs (Hierarchy).
Identity Source.
Now, we can reference our IDP (so Cognito) with AVP. Navigate to the Identity sources
in the AVP console and create a new one. Fill the user pool ID (copy it from the user pool details from the Cognito details page, the same for the client application ID (you will find it in the App integration
section of the user pool).
For the principal details we will use the Principal
type as BankingTransationSystem::User
so this will map our user pool to Cognito as a principal. Moreover the principal ID so the token issued for the connected user pool will be mapped to a principal ID in the format β|β
Unfortunately, we cannot add groupEntityType
from the AWS console position (we cannot both see the value, modify it, or add it from the console). Although we can do it through AWS-CLI, AWS-SDK, Cloudformation, or through AVP-CLI.
AVP CLI for CreateIdentitySource
So if we want to do it via AVP-CLI, we can do it with:
β avp-cli git:(main) node index.js
π Welcome to the AVP CLI Tool!
Designed to streamline your interactions with the Amazon Verified Permissions (AVP) service.
π§ Create, manage, and delete policy stores, schemas, and policies. Plus, deploy and test with predefined scenarios!
β οΈ Ensure your AWS credentials are correctly set up before proceeding.
? What would you like to do? Manual approach
? What would you like to do? Create Identity Source
? Enter the ID of the policy store TKdiMU5n3DeypqsnEHb9d6
? Enter the entity type of the principal BankingTransactionSystem::User
? Enter the Amazon Cognito User Pool ARN arn:aws:cognito-idp:eu-west-1:ACCOUND_ID_GOES_HERE:userpool/eu-west-1_sXVC4jUDf
? Enter the Amazon Cognito App Client ID 5b33v2gf0cr1c4n6qj04rajjhf
? Enter the entity type for groups, or press enter to skip
Under the hood it will make an SDK call like this:
{
policyStoreId: 'TKdiMU5n3DeypqsnEHb9d6',
principalEntityType: 'BankingTransactionSystem::User',
configuration: {
cognitoUserPoolConfiguration: {
userPoolArn: 'arn:aws:cognito-idp:eu-west-1:ACCOUNT_ID_GOES_HERE:userpool/eu-west-1_sXVC4jUDf',
clientIds: [Array],
groupConfiguration: [Object]
}
}
}
In the console you will see it like:
Hopefully, soon we will see the group over there.
Policies
Now it's time to add three access policies, for each action separately, it will look like this:
permit (
principal in
BankingTransactionSystem::Group::"<user-pool-id-goes-here>|<cognito-group-name-here>",
action in [BankingTransactionSystem::Action::"View"],
resource
);
What we see is:
- we check if the principal is (with
in
operator which checks hierarchies) in a specific group (in the above exampletransaction_viewers
) from the Cognito user pool. - we check a specific action
- resource is any.
We need to add it for all three groups (per action) accordingly, and it will look like this:
Feel free to add those three policies from the AVP-CLI repo, remember to replace <user-pool-id-goes-here>
with your Cognito user pool ID (not the ARN!)
Remember about |
between cognito user pool id and group name from the Cognito!
Approach with AVP-CLI scenario
As you can see, a little has to be done to get everything ready. What you can do more simply is to use avp-cli to do the deployment of all the things you need.
Remember to first do the deployment of the authentication.yml file in the Cloudformation console if you haven't done it before.
Next, simply use the AVP-CLI:
β avp-cli git:(main) β AWS_PROFILE=personal node index.js
π Welcome to the AVP CLI Tool!
Designed to streamline your interactions with the Amazon Verified Permissions (AVP) service.
π§ Create, manage, and delete policy stores, schemas, and policies. Plus, deploy and test with predefined scenarios!
β οΈ Ensure your AWS credentials are correctly set up before proceeding.
? What would you like to do? Use prepared scenarios
? Choose a scenario Ecommerce with Cognito Groups Scenario
? Enter the ARN of the Cognito User Pool arn:aws:cognito-idp:eu-west-1:ACCOUNT_NUMBER:userpool/eu-west-1_sXVC4jUDf
? Enter the App Client ID 5b33v2gf0cr1c4n6qj04rajjhf
./scenarios/ecommerceCognitoGroupsScenario/ecommerceCognitoGroupsScenario.json
Starting creating scenario: Ecommerce Cognito Group Scenario
description: This is a basic scenario with a group cognito management platform schema and three policies.
Policy store created with ID: Ny9v75vt5cQGxzEovBgL9R
Schema put successfully for policy store ID: Ny9v75vt5cQGxzEovBgL9R
Creating an identity source...
Identity source created with ID: 9M6FTv52wSnLTR2LAJkRYa
Creating a static policy...
Static policy created with ID: W4Z31yfapD5jWJqvXr57XH
Creating a static policy...
Static policy created with ID: 5k1QXfuWxYJqQa9r3Mnygh
Creating a static policy...
Static policy created with ID: WDu7Pac7umBpHrY2o55TYF
ββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β Policy ID β Policy Store ID β Created Date β
ββββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ€
β W4Z31yfapD5jWJqvXr57XH β Ny9v75vt5cQGxzEovBgL9R β 2024-04-27 18:00 β
ββββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ€
β 5k1QXfuWxYJqQa9r3Mnygh β Ny9v75vt5cQGxzEovBgL9R β 2024-04-27 18:00 β
ββββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ€
β WDu7Pac7umBpHrY2o55TYF β Ny9v75vt5cQGxzEovBgL9R β 2024-04-27 18:00 β
ββββββββββββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββ
Generating of the undefined is finished. Open the AWS console to play around with that.
Consider testing it with our prepared test scenarios:
Either use `Test Scenario` in main CLI to select the specific test scenario, or use below path as argument to `IsAuthorized` from the manual approach option of the CLI:
Remember to update the policy-store-id within files.
- ./scenarios/ecommerceCognitoGroupsScenario/allow_test_1.json (Access for user who has transaction_viewer group can view) allow
- ./scenarios/ecommerceCognitoGroupsScenario/allow_test_2.json (Access for user who has transaction_approve group can approve) allow
- ./scenarios/ecommerceCognitoGroupsScenario/allow_test_3.json (Access for user who has transaction_edit group can edit) allow
Generating of the ecommerceCognitoGroupsScenario is finished. Open the AWS console to play around with that.
And that's it, you can test.
Prepration for tests
First, we need an access token (or ID token) from Cognito for our user.
Remember, when you create a new user, you must generate a new password for them, which can be done in the AWS CLI with:
aws cognito-idp admin-respond-to-auth-challenge
You can generate code via AWS-CLI, SDK, or by doing the HTTP request via POSTMAN or curl like this:
curl --location 'https://cognito-idp.<REGION>.amazonaws.com/<USER_POOL_HERE!!!!!>' \
--header 'Content-Type: application/x-amz-json-1.1' \
--header 'Accept: */*' \
--header 'X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth' \
--data-raw '{
"AuthFlow": "USER_PASSWORD_AUTH",
"ClientId": "<ID_HERE>",
"AuthParameters": {
"USERNAME": "<USERNAME>",
"PASSWORD": "<PASSWORD>"
}
}
'
As a response, you will obtain both an access token and an id token, use the access token.
If you decode the token with jwt.io you will see:
{
"sub": "sub",
"cognito:groups": [
"transaction_viewers"
],
"iss": 'BLABLA",
...
"auth_time": 1713899648,
"exp": 1713903248,
"iat": 1713899648,`
"username": "daniel"
}
```
so you can double check at this point, whether a proper group is within the JWT of a user.
## Testing
So we can't test it using the test bench because it doesn't support isAuthorizedWithToken operations and for Batch, so we can do it through AWS CLI, SDK, or through AVP-CLI.
### With isAuthorizedWithToken
For authorization with a token, we will use the [isAuthorizedWithToken](https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_IsAuthorizedWithToken.html) operation.
We can provide both an access token and an ID token, we will use the access token. It is worth reminding that our principal is a user from the Cognito user pool. AVP on its side will decode the token and check if it is ok, so we don't need to do it on our side.
**If you delete an Amazon Cognito user pool or user, tokens from that deleted pool or that deleted user continue to be usable until they expire.
**
The structure of the request is [here](https://github.com/Pigius/avp-cli/blob/main/structureAuthorizationWithTokenRequest.json). For use usecase we can use this [allow test](https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/allow_test_1.json). Generate the access token, and pass it together with policy store ID.
So I've generated an access token for a user which is in the `transaction_viewers` group, and based on the allow test I will try to access the `View` action.
now we will use AVP-CLI:
```shell
? What would you like to do? Manual approach
? What would you like to do? Make an authorization decision with Cognito Identity Token
? Enter the path for json test file scenarios/ecommerceCognitoGroupsScenario/allow_test_1.json
ββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β Decision β Determining Policies β Errors β Policy Store ID β Principal β Action β Resource β Context β
ββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β ALLOW β 7UQxoV3bvzpYvGnm939HZH β β TKdiMU5n3DeypqsnEHb9d6 β BankingTransactionSystem::Us β BankingTransactionSystem::Ac β BankingTransactionSystem::Tr β {} β
β β β β β er::eu-west-1_sXVC4jUDf|f245 β tion::View β ansactionRecord::* β β
β β β β β a454-90c1-7084-7709-1dfbfdb1 β β β β
β β β β β 0930 β β β β
```
If I will try the second test scenario I will be rejected, as my user is only allowed to view.
### With BatchIsAuthorizedWithToken
As recently [BatchIsAuthorizedWithToken](https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_BatchIsAuthorizedWithToken.html) has been released, we can use it to test our scenario.
With this operation, we can make up to 30 requests during a single request (and we paid per request, and performance is better). Note that the current request limit is 30, and also our batch can contain up to 100 resources and up to 99 user groups. Example structure is [here](https://github.com/Pigius/avp-cli/blob/main/structureBatchAuthorizationWithTokenRequest.json).
We can pass either an access token or an ID token. The request is either principal or resource oriented.
So, in our scenario, what we can do, is to check, whether my user can access multiple actions on a single resource by making one request to AVP.
![Batch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ibjhssbay8ss7vn7x6q1.png)
I've prepared test file for that [here](https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/batch_allow_test.json).
Let's try with AVP-CLI now:
```
β avp-cli AWS_PROFILE=personal node index.js
π Welcome to the AVP CLI Tool!
Designed to streamline your interactions with the Amazon Verified Permissions (AVP) service.
π§ Create, manage, and delete policy stores, schemas, and policies. Plus, deploy and test with predefined scenarios!
β οΈ Ensure your AWS credentials are correctly set up before proceeding.
? What would you like to do? Manual approach
? What would you like to do? Make a batch authorization decision with Cognito Identity Token
? Enter the path for batch authorization with token json test file scenarios/ecommerceCognitoGroupsScenario/batch_allow_test.json
Making batch with token authorization decision...
ββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β Decision β Determining Policies β Errors β Policy Store ID β Principal β Action β Resource β Context β
ββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β ALLOW β 7UQxoV3bvzpYvGnm939HZH β β TKdiMU5n3DeypqsnEHb9d6 β BankingTransactionSystem::Us β BankingTransactionSystem::Ac β BankingTransactionSystem::Tr β {} β
β β β β β er::eu-west-1_sXVC4jUDf|f245 β tion::View β ansactionRecord::123 β β
β β β β β a454-90c1-7084-7709-1dfbfdb1 β β β β
β β β β β 0930 β β β β
ββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β DENY β β β TKdiMU5n3DeypqsnEHb9d6 β BankingTransactionSystem::Us β BankingTransactionSystem::Ac β BankingTransactionSystem::Tr β {} β
β β β β β er::eu-west-1_sXVC4jUDf|f245 β tion::Edit β ansactionRecord::123 β β
β β β β β a454-90c1-7084-7709-1dfbfdb1 β β β β
β β β β β 0930 β β β β
ββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β DENY β β β TKdiMU5n3DeypqsnEHb9d6 β BankingTransactionSystem::Us β BankingTransactionSystem::Ac β BankingTransactionSystem::Tr β {} β
β β β β β er::eu-west-1_sXVC4jUDf|f245 β tion::Approve β ansactionRecord::123 β β
β β β β β a454-90c1-7084-7709-1dfbfdb1 β β β β
β β β β β 0930 β β β β
ββββββββββββ΄βββββββββββββββββββββββββββββββ΄ββββββββββ
```
We will obtain the array of authorization request decisions. As you can see, my user is only allowed to `View`.
## Sumup
That's it for today. We now know:
- how to build AVP policy stores with Cognito as IDP
- use Cognito groups within the access policy
- how to test it.
Now go build!
Top comments (0)