未知数据源 2024年10月02日
How to enforce user quota on AWS AppSync with Lambda Authorizer
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

文章介绍了一种管理API调用限额的方案,包括定义API Quotas的作用,AWS AppSync的功能,以及通过多种组件实现额外的限额管理层,如利用Cognito User Pool进行认证、Lambda函数进行授权、ElastiCache for Redis跟踪调用计数等,还详细说明了方案的各个步骤及所需的前提条件。

📋API Quotas可防止API被无意滥用、减少数据泄露并保护资源,还能实现数字资产的货币化。AWS AppSync是全托管服务,可轻松开发GraphQL APIs,并能自动根据请求量调整执行引擎,其基于tokens管理API quotas。

🔑解决方案的主要组件包括:以Cognito User Pool作为OIDC身份提供者进行认证,添加'custom:quota'属性存储限额值;以Lambda函数作为AWS AppSync API的自定义授权器,通过ElastiCache集群跟踪调用次数,两者部署在Amazon VPC的两个私有子网中;API托管在AWS AppSync上,运行GraphQL引擎,数据来自DynamoDB表,提供查询和写入操作。

🧠Lambda Authorizer中,将认证逻辑和Cognitojwt库封装在Lambda层,从中导入'auth'方法获取用户属性。同时打开与redis数据库的连接,用于跟踪每个用户的调用计数,每天午夜清除用户的计数记录。函数会根据用户的情况进行相应的处理,如对比计数与限额值等。

🚶‍♂️实施该方案的步骤包括:通过AWS CloudFormation部署堆栈,上传测试数据到DynamoDB,在Cognito用户池中创建测试用户并添加自定义属性,运行测试查询。CloudFormation堆栈包含多种资源,部署通过deploy.sh脚本执行,该脚本包含多个阶段,并需要一些参数才能成功部署。

<section class="blog-post-content"><p>API Quotas define the valid amount of calls available for a consumer during a specific amount of time. Enforcing quotas protects your API from unintentional abuse, minimizes data exfiltration and protects your resources from excessive usage. Beyond the mentioned security benefits, it can also unlock your capabilities to monetize the digital assets sitting behind the API.</p><p><a href="https://aws.amazon.com/appsync/&quot;&gt;AWS AppSync</a> is a fully managed service that makes it easy to develop <a href="https://aws.amazon.com/graphql/&quot;&gt;GraphQL&lt;/a&gt; APIs by handling the heavy lifting of securely connecting to data sources like <a href="https://aws.amazon.com/dynamodb/&quot;&gt;Amazon DynamoDB</a>, <a href="https://aws.amazon.com/lambda/&quot;&gt;AWS Lambda</a>, and more. Once deployed, it automatically scales your <a href="https://aws.amazon.com/graphql/&quot;&gt;GraphQL&lt;/a&gt; API execution engine up and down to meet API request volumes. AWS AppSync manages API quotas based on <a href="https://docs.aws.amazon.com/appsync/latest/devguide/monitoring.html#aws-appsync-using-token-counts-to-optimize-requests&quot;&gt;tokens&lt;/a&gt; that effectively measure how different GraphQL queries use resources depending on their complexity. The number of available tokens is a soft limit and can be increased with a support case. This blog post showcases building blocks for applying an additional extra layer to manage quotas  based on the number of API calls a user makes using <a href="https://aws.amazon.com/lambda/&quot;&gt;AWS Lambda</a> Authorizer.  Thanks to its sub-millisecond latency, <a href="https://aws.amazon.com/elasticache/redis/&quot;&gt;Amazon ElastiCache for Redis</a>  is used to track the call count in real time. For the end-to-end test of the solution, <a href="https://aws.amazon.com/cognito/&quot;&gt;Amazon Cognito User Pool </a>serves as the OIDC identity provider.</p><h2>Solution Overview</h2><div id="attachment_8838" class="wp-caption aligncenter c4"><img aria-describedby="caption-attachment-8838" class="wp-image-8838" src="https://d2908q01vomqb2.cloudfront.net/0a57cb53ba59c46fc4b692527a38a87c78d84028/2022/09/26/mobile_1691_1.png&quot; alt="Figure 1. Solution Overview" width="700" height="421" /><p id="caption-attachment-8838" class="wp-caption-text">Figure 1. Solution Overview</p></div><p>The solution consists of the following main components:</p><ul><li>Authentication – A Cognito User Pool serves as the OIDC Identity Provider. It stores a set of users that are allowed to consume the AWS AppSync API. A custom attribute “custom:quota” is added to the user profile in order to store the quota value. This attribute can be passed via the CLI at user creation or later by editing it. Please note that this solution is not bounded exclusively to Cognito specifications. With few adjustments you can opt in for another identity provider as long as it follows the OIDC protocol.</li><li>Authorization – A Lambda function acts as the custom authorizer for the AWS AppSync API. It contains the necessary logic to validate the access token provided by the user and authorize the call based on the “custom:quota” attribute. The current number of calls are tracked via an ElastiCache cluster running Redis engine, in the form of hash data type. Every day at midnight hash-es are expired from the cache. Both the Lambda function and the ElastiCache cluster are deployed inside an <a href="https://docs.aws.amazon.com/vpc/?id=docs_gateway&quot;&gt;Amazon VPC</a> on two private subnets. The pre-requisite section provides the necessary information on how to setup.</li><li>Interface – The API is hosted on AWS AppSync and runs the GraphQL engine. Data is sourced from a DynamoDB Table which hosts the moviedata.json dataset.  The GraphQL schema is defined according to this dataset attributes. A DynamoDB resolver is used to convert the GraphQL payload to DynamoDB specifications. Two operations are provided from the API. A query for consuming the dataset and a mutation to write new data.</li></ul><h2>Lambda Authorizer</h2><p>Next, we explore the anatomy of the Lambda Function which acts as the authorizer for the AWS AppSync API.</p><p>The authentication logic and <a href="https://pypi.org/project/cognitojwt/&quot;&gt;Cognitojwt&lt;/a&gt; library are encapsulated in a <a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-layers.html&quot;&gt;Lambda layer</a>. From there we import the “auth” method which returns a dictionary (upon successful authentication) with the user attributes fetched from Cognito <a href="https://docs.aws.amazon.com/cognito/latest/developerguide/userinfo-endpoint.html&quot;&gt;Userinfo endpoint</a>. For our purpose we need to extract the “username” and “custom:quota” keys.</p><div id="attachment_8839" class="wp-caption alignnone c5"><img aria-describedby="caption-attachment-8839" class="wp-image-8839" src="https://d2908q01vomqb2.cloudfront.net/0a57cb53ba59c46fc4b692527a38a87c78d84028/2022/09/26/mobile_1691_2.png&quot; alt="Figure 2. Authentication Method" width="450" height="166" /><p id="caption-attachment-8839" class="wp-caption-text">Figure 2. Authentication Method</p></div><p>In the meantime, we open the connection to the redis database which we will use to keep track of the count of calls per user. Daily at 00:00 the entry for every user gets erased.</p><div id="attachment_8840" class="wp-caption alignnone c5"><img aria-describedby="caption-attachment-8840" class="wp-image-8840" src="https://d2908q01vomqb2.cloudfront.net/0a57cb53ba59c46fc4b692527a38a87c78d84028/2022/09/26/mobile_1691_3.png&quot; alt="Figure 3. Redis Connection" width="450" height="94" /><p id="caption-attachment-8840" class="wp-caption-text">Figure 3. Redis Connection</p></div><p>As a next step the function will query redis to check if the user has already an entry in the database. If the user exists, it will compare the current count to the quota value extracted earlier. If the count is below the quota value, it increments the count for the user by 1, updates the hash in the database and returns a positive response to authorize the query. On the other hand, if the current count is equal or above the quota value, it returns an un-authorized response. For users who are querying the API for the first time that day, the function creates a new hash into the database and sets it to expire by 00:00.</p><div id="attachment_8841" class="wp-caption alignnone c5"><img aria-describedby="caption-attachment-8841" class="wp-image-8841" src="https://d2908q01vomqb2.cloudfront.net/0a57cb53ba59c46fc4b692527a38a87c78d84028/2022/09/26/mobile_1691_4.png&quot; alt="Figure 4. Response model/Quota check logic" width="450" height="362" /><p id="caption-attachment-8841" class="wp-caption-text">Figure 4. Response model/Quota check logic</p></div><h2>Walkthrough</h2><p>Now we walk you through the various steps in implementing the solution.</p><p>Breakdown of the steps to successfully implement and test the solution:</p><ul><li>Step 1: <a href="https://docs.aws.amazon.com/cloudformation/?id=docs_gateway&quot;&gt;AWS CloudFormation</a> stack deployment</li><li>Step 2: Upload the test data into DynamoDB</li><li>Step 3: Create a test user in Cognito user pool and add the custom attribute</li><li>Step 4: Run a test query</li></ul><h2>Prerequisites</h2><p>For this walkthrough, you should have the following prerequisites:</p><h2>Step 1: CloudFormation Stack</h2><p>The resources are created via CloudFormation. The CloudFormation template and the source code for the Lambda function and layer are available in <a href="https://github.com/aws-samples/amazon-user-quota-blog&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Following resources are part of the CloudFormation stack:</p><ul><li>AWS AppSync GraphQL API</li><li>Amazon DynamoDB table</li><li>Cognito user pool</li><li>Lambda Authorization function</li><li>Lambda layer containing authentication logic</li><li>ElastiCache for Redis cluster</li><li>Security groups</li><li><a href="https://docs.aws.amazon.com/iam/?id=docs_gateway&quot;&gt;AWS IAM</a> roles &amp; policies</li></ul><p>The deployment is done using the <a href="https://github.com/aws-samples/amazon-user-quota-blog/blob/main/deployment_scripts/deploy.sh&quot;&gt;deploy.sh&lt;/a&gt; script.</p><p>The script executes the following phases:</p><ol><li>Checks for dependencies</li><li>Builds the Lambda layer</li><li>Builds the Lambda package</li><li>Builds the CloudFormation package</li><li>Deploys the CloudFormation package</li></ol><p>Following parameters are required for the deployment to be successful:</p><ul><li>STACK_NAME – CloudFormation stack name</li><li>AWS_REGION – AWS region where the solution will be deployed</li><li>AWS_PROFILE – Named profile that will apply to the AWS CLI command</li><li>ARTEFACT_S3_BUCKET – S3 bucket where the infrastructure code will be stored. (The bucket must be created in the same region where the solution lives)</li><li>VPC – VPC id where the Lambda function and redis cluster will be deployed</li><li>SUBNET_A – Private subnet id where the Lambda function and redis node will be deployed</li><li>SUBNET_B – Private subnet id where the Lambda function and redis node will be deployed</li></ul><p>Upon successful deployment, the script will display the CloudFormation output on the console. Take note of the output as it will be used in the following steps.</p><h2>Step 2: Upload the test data into DynamoDB</h2><p>In this step we are going to populate the DynamoDB table created with sample data to test the connection to the AWS AWS AppSync API.</p><p>To perform this step, we are going to use the script <a href="https://github.com/aws-samples/amazon-user-quota-blog/blob/main/batch_upload_ddb.py&quot;&gt;batch_upload_dbb.py&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Following parameters are required for the script to run successfully:</p><ul><li>DynamoDBTableName – Value Outputted by the CloudFormation deployment</li><li>AWS_PROFILE – Named profile that will apply to the AWS CLI command</li><li>AWS_REGION – AWS region where the solution will be deployed</li><li>moviedata.json – File already provided with sample data. Located in the git repository, <a href="https://github.com/aws-samples/amazon-user-quota-blog/blob/main/moviedata.json&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Step 3: Create a Test User in Cognito user pool and add the custom attribute</h2><p>In this step we are going to create a Cognito test user and add a custom attribute which will be read by the Lambda Function as an extra validation step during authorization.</p><p>Following parameters are required for the command to run successfully:</p><ul><li>AWS_REGION – AWS region where the solution will be deployed</li><li>CognitoUserPoolId – Output value from the CloudFormation deployment</li></ul><p>The following AWS CLI command can be used to create a new user in Cognito User Pool:</p><p>Upon successful run of the CLI Commands, a new user will be present in the user pool with a custom attribute quota value = 10.</p><h2>Step 4: Run Test Query</h2><p>In this step we are going to configure <a href="https://www.postman.com/&quot;&gt;Postman&lt;/a&gt; and send a test query toward the AWS AppSync API, so you need to make sure Postman is installed in your machine. Upon successful authorization, the API will return the requested values. Once the quota attribute value is hit, all following requests will be DENIED automatically.</p><p>Following parameters are required to create a complete request in Postman</p><ul><li>GraphQLUrl – Output Value from CloudFormation deployment</li><li>CognitoAuthUrl – Output Value from CloudFormation deployment</li><li>CognitoAccessTokenUrl – Output Value from CloudFormation deployment</li><li>CognitoAppClientId – Output Value from CloudFormation deployment</li><li>CognitoAppClientSecret – This value needs to be retrieved from the AWS console, in the Cognito user pool service as described <a href="https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html&quot;&gt;here&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Follow these steps to setup Postman</p><ol><li>Start Postman in your machine</li><li>Go to <strong>File</strong> -&gt; <strong>Import</strong></li><li>Import the <a href="https://github.com/aws-samples/amazon-user-quota-blog/blob/main/test/QuotaEnforcement.postman_collection.json&quot;&gt;postman collection</a></li><li>From the collection folder navigate to <strong>Sample Request</strong></li><li>Replace all variables in the <strong>Sample Request</strong> with the parameters mentioned above.</li><li>Navigate to the <strong>Authorization</strong> tab</li><li>Click on Get <strong>New Access Token</strong><ol type="a"><li>Postman will pop up a new window where you need to type the username and password for the user previously created via CLI</li><li>Once authenticated, a new token will appear in Postman.</li><li>Click on <strong>Use Token</strong> to add it to the request</li></ol></li></ol><ol start="8"><li> Click <strong>Send</strong> on the request to POST the HTTP/s request to the API<ol type="a"><li>The API will return in the body of the response a JSON datatype similar to:</li></ol></li></ol><ol start="9"><li>Click on <strong>Send</strong> multiple times to surpass the quota attribute value added to the user.</li></ol><ol><li class="c6"><ol type="a"><li>Once the quota limit is hit, the following response will be sent by the API:</li></ol></li></ol><h2>Cleaning up</h2><p>To avoid incurring future charges, delete the resources. You can delete the CloudFormation stack by running <a href="https://github.com/aws-samples/amazon-user-quota-blog/blob/main/deployment_scripts/destroy.sh&quot;&gt;destroy.sh&lt;/a&gt; script.</p><p>Following parameters are required to run the script successfully</p><ul><li>STACK_NAME – CloudFormation stack name</li><li>AWS_REGION – AWS region where the solution will be deployed</li><li>AWS_PROFILE – Named profile that will apply to the AWS CLI command</li></ul><p>The following commands can be used to run the “destroy.sh” script:</p><h2>Conclusion</h2><p>In this blog post, we showed how to apply quota enforcement on AWS AppSync using a Lambda Authorizer with the aid of ElastiCache for Redis. We dove deep in the Lambda function and the authorization logic. Step by step, we walked through the implementation phases. Finally, we showed how to test the solution end-to-end.</p><p>If you want to learn more about AWS AppSync, please follow the <a href="https://docs.aws.amazon.com/appsync/latest/devguide/what-is-appsync.html&quot;&gt;official documentation</a>.</p><p>“Get started with AWS AppSync for free.” <a href="https://aws.amazon.com/appsync/&quot;&gt;https://aws.amazon.com/appsync/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;About the authors:</strong></p></section>

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

API Quotas AWS AppSync 限额管理 Lambda Authorizer
相关文章