Enriching Amazon Cognito features with an Amazon API Gateway proxy

海外精选
海外精选的内容汇集了全球优质的亚马逊云科技相关技术内容。同时,内容中提到的“AWS” 是 “Amazon Web Services” 的缩写,在此网站不作为商标展示。
25
0
{"value":"This post was co-written with Geoff Baskwill, member of the Architecture Enabling Team at Trend Micro. At Trend Micro, we use Amazon Web Services technologies to build secure solutions to help our customers improve their security posture.\n\nThis post builds on the architecture originally published in [ Protect public clients for Amazon Cognito with an Amazon CloudFront proxy](https://aws.amazon.com/blogs/security/protect-public-clients-for-amazon-cognito-by-using-an-amazon-cloudfront-proxy/). Read that post to learn more about public clients and why it is helpful to implement a proxy layer.\n\nWe’ll build on the idea of passing calls to [Amazon Cognito](http://aws.amazon.com/cognito)through a lightweight proxy. This pattern allows you to augment identity flows in your system with additional processing without having to change the client or the backend. For example, you can use the proxy layer to protect public clients as explained in the original post. You can also use this layer to apply additional fraud detection logic to prevent fraudulent sign up, propagate events to downstream systems for monitoring or enhanced logging, and replicate certain events to another Amazon Web Services Region (for example, to build high availability and multi-Region capabilities).\n\nThe solution in the original post used[Amazon CloudFront](https://aws.amazon.com/cloudfront/), [Lambda@Edge](https://aws.amazon.com/lambda/edge/), and [ Amazon Web Services WAF](https://aws.amazon.com/waf/) to implement protection of public clients, and hinted that there are multiple ways to do it. In this post, we explore one of these alternatives by using [Amazon API Gateway](Amazon API Gateway) and a proxy [ Amazon Web Services Lambda]( Amazon Web Services Lambda) function to implement the proxy to Amazon Cognito. This alternative offers improved performance and full access to request and response elements.\n\n#### **Solution overview**\nThe focus of this solution is to protect public clients of the Amazon Cognito user pool.\n\nThe workflow is shown in Figure 1 and works as follows:\n\n- Configure the client application (mobile or web client) to use the API Gateway endpoint as a proxy to an Amazon Cognito regional endpoint. You also create an application client in Amazon Cognito with a secret. This means that any unauthenticated API call must have the secret hash.\n- Use a Lambda function to add a secret hash to the relevant incoming requests before passing them on to the Amazon Cognito endpoint. This function can also be used for other purposes like logging, propagation of events, or additional validation.\n- In the Lambda function, you must have the app client secret to be able to calculate the secret hash and add it to the request. We recommend that you keep the secret in Amazon Web Services Secrets Manager and cache it for the lifetime of the function.\n- Use Amazon Web Services WAF with API Gateway to enforce rate limiting, implement allow and deny lists, and apply other rules according to your security requirements.\n- Clients that send unauthenticated API calls to the Amazon Cognito endpoint directly are blocked and dropped because of the missing secret.\n\nNot shown: You may want to set up a custom domain and certificate for your API Gateway endpoint.\n\n![image.png](https://dev-media.amazoncloud.cn/e281353cda53410d8290858d0e6342f0_image.png)\n\nFigure 1. A proxy solution to the Amazon Cognito regional endpoint\n\n#### **Deployment steps**\nYou can use the following [Amazon Web Services CloudFormation](http://aws.amazon.com/cloudformation) template to deploy this proxy pattern for your existing Amazon Cognito user pool.\n\nNote: This template references a Lambda code package from a bucket in the us-east-1 Region. For that reason, the template can be only created in us-east-1. If you need to create the proxy solution in another Region, download[the template](https://awsiammedia.s3.amazonaws.com/public/sample/495-arch-augmenting-cognito-api-gateway-proxy/template.yaml) and [Lambda code package](https://awsiammedia.s3.amazonaws.com/public/sample/495-arch-augmenting-cognito-api-gateway-proxy/proxy.zip), update the template to reference another [ Amazon Simple Storage Service (Amazon S3) ](http://aws.amazon.com/s3) bucket that you own in the desired Region, and upload the code package to that S3 bucket. Then you can deploy your modified template in the desired Region.\n\n[![image.png](https://dev-media.amazoncloud.cn/36270184258442dc919819b511293cf3_image.png)](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review?templateURL=https://awsiammedia.s3.amazonaws.com/public/sample/495-arch-augmenting-cognito-api-gateway-proxy/template.yaml&stackName=cognito-apigw-proxy)\n\nThis template requires the user pool ID as input and will create several resources in your Amazon Web Services account to support the following proxy pattern:\n\n- A new application client with a secret will be added to your Amazon Cognito user pool\n- The secret will be stored in Secrets Manager and will be read from the proxy Lambda function\n- The proxy Lambda function will be used to intercept Amazon Cognito API calls and attach client-secret to applicable requests\n- The API Gateway project provides the custom proxy endpoint that is used as the Amazon Cognito endpoint in your client applications\n- An Amazon Web Services WAF WebACL provides firewall protection to the API Gateway endpoint. The WebACL includes placeholder rules for Allow and Deny lists of IPs. It also includes a rate limiting rule that will block requests from IP addresses that exceed the number of allowed requests within a five-minute period (rate limit value is provided as input to the template)\n- Several helper resources will also be created like Lambda functions, necessary Amazon Web Services IAM policies, and roles to allow the solution to function properly\nAfter you create a successful stack, you can find the endpoint URL in the outputs section of your CloudFormation stack. This is the URL we use in the next section with client applications.\n\nNote: The template and code has been simplified for demonstration purposes. If you plan to deploy this solution in production, make sure to review these resources for compliance with your security and performance requirements. For example, you might need to enable certain logs or log encryption or use a customer managed key for encryption.\n\n#### **Integrating your client with proxy solution**\nIntegrate the client application with the proxy by changing the endpoint in your client application to use the endpoint URL for the proxy API Gateway. The endpoint URL and application client ID are located in the Outputs section of the CloudFormation stack.\n\nNext, edit your client-side code to forward calls to Amazon Cognito through the proxy endpoint and use the new application client ID. For example, if you’re using the [Identity SDK](https://github.com/aws-amplify/amplify-js/tree/master/packages/amazon-cognito-identity-js), you should change this property as follows.\n\n```\nvar poolData = {\n UserPoolId: '<USER-POOL-ID>',\n ClientId: '<APP-CLIENT-ID>',\n endpoint: 'https://<APIGATEWAY-URL>'\n};\n```\n\nIf you’re using [Amazon Web Services Amplify](https://docs.amplify.aws/lib/auth/getting-started/q/platform/js), change the endpoint in the\n```\naws-exports.js\n```\nfile by overriding the property\n```\naws_cognito_endpoint\n```\nOr, if you configure Amplify Auth in your code, you can provide the endpoint as follows.\n```\nAmplify.Auth.configure({\n userPoolId: '<USER-POOL-ID>',\n userPoolWebClientId: '<APP-CLIENT-ID>',\n endpoint: 'https://<APIGATEWAY-URL>'\n});\n```\nIf you have a mobile application that uses the Amplify mobile SDK, override the endpoint in your configuration as follows (don’t include\n```\nAppClientSecret\n```\nparameter in your configuration).\n\nNote that the \n```\nEndpoint\n```\n\n value contains the domain name only, not the full URL. This feature is available in the latest releases of the [iOS](https://github.com/aws-amplify/aws-sdk-ios/releases/tag/2.24.0) and [Android ](https://github.com/aws-amplify/aws-sdk-android/releases/tag/release_v2.23.0) SDKs.\n\n```\n\"CognitoUserPool\": {\n \"Default\": {\n \"AppClientId\": \"<APP-CLIENT-ID>\",\n \"Endpoint\": \"<APIGATEWAY-DOMAIN-NAME>\",\n \"PoolId\": \"<USER-POOL-ID>\",\n \"Region\": \"<REGION>\"\n }\n}\n```\n**WARNING**: If you do an \n```\namplify push\n```\n\n or \n```\namplify pull \n```\n\noperation, the Amplify CLI overwrites customizations to the \n```\nawsconfiguration.json\n```\n\n and \n```\namplifyconfiguration.json\n```\n\n files. You must manually re-apply the Endpoint customization and remove the \n```\nAppClientSecret\n```\n\n if you use the CLI to modify your cloud backend.\n\n#### **When to use this pattern**\nThe same guidance for using this pattern applies as in the original post.\n\nYou may prefer this solution if you are familiar with API Gateway or if you want to take advantage of the following:\n\n- Use CloudWatch metrics from API Gateway to monitor the behavior and health of your Amazon Cognito user pool.\n- Find and examine logs from your Lambda proxy function in the Region where you have deployed this solution.\n- Deploy your proxy function into an[Amazon Virtual Private Cloud (Amazon VPC)](http://aws.amazon.com/vpc) and access sensitive data or services in the Amazon VPC or through Amazon VPC endpoints.\n- Have full access to request and response in the proxy Lambda function\n\n#### **Extend the proxy features**\nNow that you are intercepting all of the API requests to Amazon Cognito, add features to your identity layer:\n\n- Emit events using [Amazon EventBridge ](https://aws.amazon.com/eventbridge/) when user data changes. You can do this when the proxy function receives mutating actions like \n```\nUpdateUserAttribute\n```\n\n (among others) and Amazon Cognito processes the request successfully.\n- Implement more complex rate limiting than what Amazon Web Services WAF supports, like per-user rate limits regardless of where IP address requests are coming from. This can also be extended to include fraud detection, request input validation, and integration with third-party security tools.\n- Build a geo-redundant user pool that transparently mitigates regional failures by replicating mutating actions to an Amazon Cognito user pool in another Region.\n\n#### **Limitations**\nThis solution has the same limitations highlighted in the original post. Keep in mind that resourceful authenticated users can still make requests to the Amazon Cognito API directly using the access token they obtained from authentication. If you want to prevent this from happening, adjust the proxy to avoid returning the access token to clients or return an encrypted version of the token.\n\n#### **Conclusion**\nIn this post, we explored an alternative solution that implements a thin proxy to Amazon Cognito endpoint. This allows you to protect your application against unwanted requests and enrich your identity flows with additional logging, event propagation, validations, and more.\n\nReady to get started? If you have questions about this post, start a new thread on the [Amazon Cognito forum](https://forums.aws.amazon.com/forum.jspa?forumID=173) or [ contact Amazon Web Services Support](https://console.aws.amazon.com/support/home).\n\n![image.png](https://dev-media.amazoncloud.cn/337db9938f28490a9a8fb623c0cfed83_image.png)\n\n**Mahmoud Matouk**\nMahmoud is a Principal Solutions Architect with Amazon Web Services Identity. He helps Amazon Web Services customers build secure and innovative solutions for various identity and access management scenarios.\n\n![image.png](https://dev-media.amazoncloud.cn/5b1793ce49304b7c97d347f7337dbaef_image.png)\n\n**Geoff Baskwill**\nGeoff (he/him) is a member of the Architecture Enabling Team at Trend Micro. These days he is learning more about Amazon Web Services services and how to use them to build better solutions for customers. He is an avid user of the Oxford comma, a terrible juggler, and is very slowly learning to play chess.","render":"<p>This post was co-written with Geoff Baskwill, member of the Architecture Enabling Team at Trend Micro. At Trend Micro, we use Amazon Web Services technologies to build secure solutions to help our customers improve their security posture.</p>\n<p>This post builds on the architecture originally published in <a href=\"https://aws.amazon.com/blogs/security/protect-public-clients-for-amazon-cognito-by-using-an-amazon-cloudfront-proxy/\" target=\"_blank\"> Protect public clients for Amazon Cognito with an Amazon CloudFront proxy</a>. Read that post to learn more about public clients and why it is helpful to implement a proxy layer.</p>\n<p>We’ll build on the idea of passing calls to <a href=\"http://aws.amazon.com/cognito\" target=\"_blank\">Amazon Cognito</a>through a lightweight proxy. This pattern allows you to augment identity flows in your system with additional processing without having to change the client or the backend. For example, you can use the proxy layer to protect public clients as explained in the original post. You can also use this layer to apply additional fraud detection logic to prevent fraudulent sign up, propagate events to downstream systems for monitoring or enhanced logging, and replicate certain events to another Amazon Web Services Region (for example, to build high availability and multi-Region capabilities).</p>\n<p>The solution in the original post used<a href=\"https://aws.amazon.com/cloudfront/\" target=\"_blank\">Amazon CloudFront</a>, <a href=\"https://aws.amazon.com/lambda/edge/\" target=\"_blank\">Lambda@Edge</a>, and <a href=\"https://aws.amazon.com/waf/\" target=\"_blank\"> Amazon Web Services WAF</a> to implement protection of public clients, and hinted that there are multiple ways to do it. In this post, we explore one of these alternatives by using [Amazon API Gateway](Amazon API Gateway) and a proxy [ Amazon Web Services Lambda]( Amazon Web Services Lambda) function to implement the proxy to Amazon Cognito. This alternative offers improved performance and full access to request and response elements.</p>\n<h4><a id=\"Solution_overview_8\"></a><strong>Solution overview</strong></h4>\n<p>The focus of this solution is to protect public clients of the Amazon Cognito user pool.</p>\n<p>The workflow is shown in Figure 1 and works as follows:</p>\n<ul>\n<li>Configure the client application (mobile or web client) to use the API Gateway endpoint as a proxy to an Amazon Cognito regional endpoint. You also create an application client in Amazon Cognito with a secret. This means that any unauthenticated API call must have the secret hash.</li>\n<li>Use a Lambda function to add a secret hash to the relevant incoming requests before passing them on to the Amazon Cognito endpoint. This function can also be used for other purposes like logging, propagation of events, or additional validation.</li>\n<li>In the Lambda function, you must have the app client secret to be able to calculate the secret hash and add it to the request. We recommend that you keep the secret in Amazon Web Services Secrets Manager and cache it for the lifetime of the function.</li>\n<li>Use Amazon Web Services WAF with API Gateway to enforce rate limiting, implement allow and deny lists, and apply other rules according to your security requirements.</li>\n<li>Clients that send unauthenticated API calls to the Amazon Cognito endpoint directly are blocked and dropped because of the missing secret.</li>\n</ul>\n<p>Not shown: You may want to set up a custom domain and certificate for your API Gateway endpoint.</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/e281353cda53410d8290858d0e6342f0_image.png\" alt=\"image.png\" /></p>\n<p>Figure 1. A proxy solution to the Amazon Cognito regional endpoint</p>\n<h4><a id=\"Deployment_steps_25\"></a><strong>Deployment steps</strong></h4>\n<p>You can use the following <a href=\"http://aws.amazon.com/cloudformation\" target=\"_blank\">Amazon Web Services CloudFormation</a> template to deploy this proxy pattern for your existing Amazon Cognito user pool.</p>\n<p>Note: This template references a Lambda code package from a bucket in the us-east-1 Region. For that reason, the template can be only created in us-east-1. If you need to create the proxy solution in another Region, download<a href=\"https://awsiammedia.s3.amazonaws.com/public/sample/495-arch-augmenting-cognito-api-gateway-proxy/template.yaml\" target=\"_blank\">the template</a> and <a href=\"https://awsiammedia.s3.amazonaws.com/public/sample/495-arch-augmenting-cognito-api-gateway-proxy/proxy.zip\" target=\"_blank\">Lambda code package</a>, update the template to reference another <a href=\"http://aws.amazon.com/s3\" target=\"_blank\"> Amazon Simple Storage Service (Amazon S3) </a> bucket that you own in the desired Region, and upload the code package to that S3 bucket. Then you can deploy your modified template in the desired Region.</p>\n<p><a href=\"https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review?templateURL=https://awsiammedia.s3.amazonaws.com/public/sample/495-arch-augmenting-cognito-api-gateway-proxy/template.yaml&amp;stackName=cognito-apigw-proxy\" target=\"_blank\"><img src=\"https://dev-media.amazoncloud.cn/36270184258442dc919819b511293cf3_image.png\" alt=\"image.png\" /></a></p>\n<p>This template requires the user pool ID as input and will create several resources in your Amazon Web Services account to support the following proxy pattern:</p>\n<ul>\n<li>A new application client with a secret will be added to your Amazon Cognito user pool</li>\n<li>The secret will be stored in Secrets Manager and will be read from the proxy Lambda function</li>\n<li>The proxy Lambda function will be used to intercept Amazon Cognito API calls and attach client-secret to applicable requests</li>\n<li>The API Gateway project provides the custom proxy endpoint that is used as the Amazon Cognito endpoint in your client applications</li>\n<li>An Amazon Web Services WAF WebACL provides firewall protection to the API Gateway endpoint. The WebACL includes placeholder rules for Allow and Deny lists of IPs. It also includes a rate limiting rule that will block requests from IP addresses that exceed the number of allowed requests within a five-minute period (rate limit value is provided as input to the template)</li>\n<li>Several helper resources will also be created like Lambda functions, necessary Amazon Web Services IAM policies, and roles to allow the solution to function properly<br />\nAfter you create a successful stack, you can find the endpoint URL in the outputs section of your CloudFormation stack. This is the URL we use in the next section with client applications.</li>\n</ul>\n<p>Note: The template and code has been simplified for demonstration purposes. If you plan to deploy this solution in production, make sure to review these resources for compliance with your security and performance requirements. For example, you might need to enable certain logs or log encryption or use a customer managed key for encryption.</p>\n<h4><a id=\"Integrating_your_client_with_proxy_solution_44\"></a><strong>Integrating your client with proxy solution</strong></h4>\n<p>Integrate the client application with the proxy by changing the endpoint in your client application to use the endpoint URL for the proxy API Gateway. The endpoint URL and application client ID are located in the Outputs section of the CloudFormation stack.</p>\n<p>Next, edit your client-side code to forward calls to Amazon Cognito through the proxy endpoint and use the new application client ID. For example, if you’re using the <a href=\"https://github.com/aws-amplify/amplify-js/tree/master/packages/amazon-cognito-identity-js\" target=\"_blank\">Identity SDK</a>, you should change this property as follows.</p>\n<pre><code class=\"lang-\">var poolData = {\n UserPoolId: '&lt;USER-POOL-ID&gt;',\n ClientId: '&lt;APP-CLIENT-ID&gt;',\n endpoint: 'https://&lt;APIGATEWAY-URL&gt;'\n};\n</code></pre>\n<p>If you’re using <a href=\"https://docs.amplify.aws/lib/auth/getting-started/q/platform/js\" target=\"_blank\">Amazon Web Services Amplify</a>, change the endpoint in the</p>\n<pre><code class=\"lang-\">aws-exports.js\n</code></pre>\n<p>file by overriding the property</p>\n<pre><code class=\"lang-\">aws_cognito_endpoint\n</code></pre>\n<p>Or, if you configure Amplify Auth in your code, you can provide the endpoint as follows.</p>\n<pre><code class=\"lang-\">Amplify.Auth.configure({\n userPoolId: '&lt;USER-POOL-ID&gt;',\n userPoolWebClientId: '&lt;APP-CLIENT-ID&gt;',\n endpoint: 'https://&lt;APIGATEWAY-URL&gt;'\n});\n</code></pre>\n<p>If you have a mobile application that uses the Amplify mobile SDK, override the endpoint in your configuration as follows (don’t include</p>\n<pre><code class=\"lang-\">AppClientSecret\n</code></pre>\n<p>parameter in your configuration).</p>\n<p>Note that the</p>\n<pre><code class=\"lang-\">Endpoint\n</code></pre>\n<p>value contains the domain name only, not the full URL. This feature is available in the latest releases of the <a href=\"https://github.com/aws-amplify/aws-sdk-ios/releases/tag/2.24.0\" target=\"_blank\">iOS</a> and <a href=\"https://github.com/aws-amplify/aws-sdk-android/releases/tag/release_v2.23.0\" target=\"_blank\">Android </a> SDKs.</p>\n<pre><code class=\"lang-\">&quot;CognitoUserPool&quot;: {\n &quot;Default&quot;: {\n &quot;AppClientId&quot;: &quot;&lt;APP-CLIENT-ID&gt;&quot;,\n &quot;Endpoint&quot;: &quot;&lt;APIGATEWAY-DOMAIN-NAME&gt;&quot;,\n &quot;PoolId&quot;: &quot;&lt;USER-POOL-ID&gt;&quot;,\n &quot;Region&quot;: &quot;&lt;REGION&gt;&quot;\n }\n}\n</code></pre>\n<p><strong>WARNING</strong>: If you do an</p>\n<pre><code class=\"lang-\">amplify push\n</code></pre>\n<p>or</p>\n<pre><code class=\"lang-\">amplify pull \n</code></pre>\n<p>operation, the Amplify CLI overwrites customizations to the</p>\n<pre><code class=\"lang-\">awsconfiguration.json\n</code></pre>\n<p>and</p>\n<pre><code class=\"lang-\">amplifyconfiguration.json\n</code></pre>\n<p>files. You must manually re-apply the Endpoint customization and remove the</p>\n<pre><code class=\"lang-\">AppClientSecret\n</code></pre>\n<p>if you use the CLI to modify your cloud backend.</p>\n<h4><a id=\"When_to_use_this_pattern_123\"></a><strong>When to use this pattern</strong></h4>\n<p>The same guidance for using this pattern applies as in the original post.</p>\n<p>You may prefer this solution if you are familiar with API Gateway or if you want to take advantage of the following:</p>\n<ul>\n<li>Use CloudWatch metrics from API Gateway to monitor the behavior and health of your Amazon Cognito user pool.</li>\n<li>Find and examine logs from your Lambda proxy function in the Region where you have deployed this solution.</li>\n<li>Deploy your proxy function into an<a href=\"http://aws.amazon.com/vpc\" target=\"_blank\">Amazon Virtual Private Cloud (Amazon VPC)</a> and access sensitive data or services in the Amazon VPC or through Amazon VPC endpoints.</li>\n<li>Have full access to request and response in the proxy Lambda function</li>\n</ul>\n<h4><a id=\"Extend_the_proxy_features_133\"></a><strong>Extend the proxy features</strong></h4>\n<p>Now that you are intercepting all of the API requests to Amazon Cognito, add features to your identity layer:</p>\n<ul>\n<li>Emit events using <a href=\"https://aws.amazon.com/eventbridge/\" target=\"_blank\">Amazon EventBridge </a> when user data changes. You can do this when the proxy function receives mutating actions like</li>\n</ul>\n<pre><code class=\"lang-\">UpdateUserAttribute\n</code></pre>\n<p>(among others) and Amazon Cognito processes the request successfully.</p>\n<ul>\n<li>Implement more complex rate limiting than what Amazon Web Services WAF supports, like per-user rate limits regardless of where IP address requests are coming from. This can also be extended to include fraud detection, request input validation, and integration with third-party security tools.</li>\n<li>Build a geo-redundant user pool that transparently mitigates regional failures by replicating mutating actions to an Amazon Cognito user pool in another Region.</li>\n</ul>\n<h4><a id=\"Limitations_145\"></a><strong>Limitations</strong></h4>\n<p>This solution has the same limitations highlighted in the original post. Keep in mind that resourceful authenticated users can still make requests to the Amazon Cognito API directly using the access token they obtained from authentication. If you want to prevent this from happening, adjust the proxy to avoid returning the access token to clients or return an encrypted version of the token.</p>\n<h4><a id=\"Conclusion_148\"></a><strong>Conclusion</strong></h4>\n<p>In this post, we explored an alternative solution that implements a thin proxy to Amazon Cognito endpoint. This allows you to protect your application against unwanted requests and enrich your identity flows with additional logging, event propagation, validations, and more.</p>\n<p>Ready to get started? If you have questions about this post, start a new thread on the <a href=\"https://forums.aws.amazon.com/forum.jspa?forumID=173\" target=\"_blank\">Amazon Cognito forum</a> or <a href=\"https://console.aws.amazon.com/support/home\" target=\"_blank\"> contact Amazon Web Services Support</a>.</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/337db9938f28490a9a8fb623c0cfed83_image.png\" alt=\"image.png\" /></p>\n<p><strong>Mahmoud Matouk</strong><br />\nMahmoud is a Principal Solutions Architect with Amazon Web Services Identity. He helps Amazon Web Services customers build secure and innovative solutions for various identity and access management scenarios.</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/5b1793ce49304b7c97d347f7337dbaef_image.png\" alt=\"image.png\" /></p>\n<p><strong>Geoff Baskwill</strong><br />\nGeoff (he/him) is a member of the Architecture Enabling Team at Trend Micro. These days he is learning more about Amazon Web Services services and how to use them to build better solutions for customers. He is an avid user of the Oxford comma, a terrible juggler, and is very slowly learning to play chess.</p>\n"}
目录
亚马逊云科技解决方案 基于行业客户应用场景及技术领域的解决方案
联系亚马逊云科技专家
亚马逊云科技解决方案
基于行业客户应用场景及技术领域的解决方案
联系专家
0
目录
关闭
contact-us